feat: port opensoft/oh-my-opencode as learn-only external project review

This commit is contained in:
artale 2026-07-04 15:26:33 +02:00
parent 73b55e1684
commit 78667dd93c
5 changed files with 40 additions and 3 deletions

View File

@ -388,6 +388,8 @@ fable-agent plinius godmode "improve explanation quality"
- `--output <path>`
- `fable5 opencoven-review`
- `--output <path>`
- `fable5 opencode-review`
- `--output <path>`
- `fable5 permission-posture`
- `--mode <mode>`
- `--output <path>`

View File

@ -47,6 +47,14 @@ describe("external project review receipts", () => {
expect(receipt.risks).toContain("security findings need local repro receipts");
});
it("records oh-my-opencode as learn-only OpenCode config research", () => {
const receipt = createSkillsRepoReviewReceipt("opensoft/oh-my-opencode", new Date("2026-07-03T00:00:00.000Z"));
expect(receipt).toMatchObject({ repo: "opensoft/oh-my-opencode", license: "NOASSERTION", safeToVendor: false, decision: "learn-only", deployAttempted: false });
expect(receipt.patternsLearned).toContain("OpenCode workflow/config packaging");
expect(receipt.risks).toContain("OpenCode config must not become deploy authority");
});
it("records deploy-gated permission posture without opening 8098", () => {
const receipt = createPermissionPostureReceipt("deploy-gated", new Date("2026-07-01T00:00:00.000Z"));

View File

@ -60,8 +60,10 @@ export function createOpenCovenReviewReceipt(now = new Date()): ExternalProjectR
}
export function createSkillsRepoReviewReceipt(repo: "mattpocock/skills" | "AI-Builder-Club/skills" | "affaan-m/ECC" | "ashp15205/scankii", now = new Date()): ExternalProjectReviewReceipt {
const rows: Record<typeof repo, Omit<ExternalProjectReviewReceipt, "schema" | "createdAt" | "repo" | "deployAttempted">> = {
export type ReviewedExternalRepo = "mattpocock/skills" | "AI-Builder-Club/skills" | "affaan-m/ECC" | "ashp15205/scankii" | "opensoft/oh-my-opencode";
export function createSkillsRepoReviewReceipt(repo: ReviewedExternalRepo, now = new Date()): ExternalProjectReviewReceipt {
const rows: Record<ReviewedExternalRepo, Omit<ExternalProjectReviewReceipt, "schema" | "createdAt" | "repo" | "deployAttempted">> = {
"mattpocock/skills": {
url: "https://github.com/mattpocock/skills",
license: "MIT",
@ -102,6 +104,16 @@ export function createSkillsRepoReviewReceipt(repo: "mattpocock/skills" | "AI-Bu
decision: "learn-only",
policy: "learn-patterns-no-vendored-code",
},
"opensoft/oh-my-opencode": {
url: "https://github.com/opensoft/oh-my-opencode",
license: "NOASSERTION",
safeToVendor: false,
patternsLearned: ["OpenCode workflow/config packaging", "agent CLI ergonomics", "portable local agent defaults"],
adaptations: ["keep OpenCode behind existing CLI executor seams", "record repo as advisory until contents/license are verified", "rewrite useful config patterns locally with tests"],
risks: ["repository content was not fetched or verified", "license is not asserted so vendoring stays blocked", "OpenCode config must not become deploy authority"],
decision: "learn-only",
policy: "learn-patterns-no-vendored-code",
},
};
return { schema: "fable.external_project.review.v1", createdAt: now.toISOString(), repo, ...rows[repo], deployAttempted: false };
}

View File

@ -64,7 +64,7 @@ export { createExternalToolAuditReceipt, DICKLESWORTHSTONE_TOOL_ROWS, writeExter
export type { ExternalToolAuditReceipt, ExternalToolAuditRow, ExternalToolAuditStatus } from "./external-tool-audit.js";
export { createOpenCovenReviewReceipt, createPermissionPostureReceipt, createSkillsRepoReviewReceipt, writeExternalProjectReviewReceipt } from "./external-project-review.js";
export type { ExternalProjectDecision, ExternalProjectReviewReceipt, PermissionMode, PermissionPostureReceipt } from "./external-project-review.js";
export type { ExternalProjectDecision, ExternalProjectReviewReceipt, PermissionMode, PermissionPostureReceipt, ReviewedExternalRepo } from "./external-project-review.js";
export { createFactoryMemoryQuarantineReceipt, createStaleMemoryQuarantineReceipt, writeStaleMemoryQuarantineReceipt } from "./stale-memory-quarantine.js";
export type { StaleMemoryClaim, StaleMemoryQuarantineReceipt, StaleMemorySeverity } from "./stale-memory-quarantine.js";

View File

@ -2287,6 +2287,21 @@ fable
`);
});
fable
.command("opencode-review")
.description("Write a learn-only opensoft/oh-my-opencode external project review receipt")
.option("--output <path>", "Receipt output path", path.join(".fable", "research", "opencode-review-live.json"))
.action(async (opts: { output?: string }) => {
const { createSkillsRepoReviewReceipt, writeExternalProjectReviewReceipt } = await import("./fable5/external-project-review.js");
const receipt = createSkillsRepoReviewReceipt("opensoft/oh-my-opencode");
const out = opts.output ?? path.join(".fable", "research", "opencode-review-live.json");
writeExternalProjectReviewReceipt(out, receipt);
console.log(JSON.stringify(receipt, null, 2));
console.log(`
Receipt: ${out}
`);
});
fable
.command("permission-posture")
.description("Write an explicit permission posture receipt")