@cleocode/goal 0.0.0-stage → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +328 -0
- package/LICENSE +21 -0
- package/README.md +141 -2
- package/cli/ocg.ts +149 -0
- package/dist/cli.js +8708 -0
- package/dist/tui.d.ts +2 -0
- package/dist/tui.js +1920 -0
- package/package.json +79 -4
- package/rpc.ts +2 -0
- package/server.ts +3 -0
- package/skills/write-goal/SKILL.md +211 -0
- package/skills/write-goal/assets/goal.template.yaml +38 -0
- package/skills/write-goal/references/examples.md +283 -0
- package/skills/write-goal/references/goal-schema.md +53 -0
- package/skills/write-goal/references/interview.md +36 -0
- package/src/cli/install.ts +125 -0
- package/src/cli/status.ts +116 -0
- package/src/contract/parse.ts +454 -0
- package/src/contract/render.ts +134 -0
- package/src/contract/types.ts +158 -0
- package/src/engine/amendment.ts +51 -0
- package/src/engine/amendments.ts +72 -0
- package/src/engine/cleo-bridge.ts +339 -0
- package/src/engine/cleo-link.ts +150 -0
- package/src/engine/continue-work.ts +131 -0
- package/src/engine/decisions.ts +44 -0
- package/src/engine/dogfood-record.ts +278 -0
- package/src/engine/handoff.ts +102 -0
- package/src/engine/interrupt-policy.ts +45 -0
- package/src/engine/inventory.ts +70 -0
- package/src/engine/launches.ts +82 -0
- package/src/engine/loop-stop.ts +50 -0
- package/src/engine/loop.ts +109 -0
- package/src/engine/next-work.ts +82 -0
- package/src/engine/owner-intent.ts +71 -0
- package/src/engine/owner-reviews.ts +178 -0
- package/src/engine/peer-announce.ts +67 -0
- package/src/engine/peer-transport.ts +78 -0
- package/src/engine/policy.ts +42 -0
- package/src/engine/registry.ts +119 -0
- package/src/engine/similarity.ts +65 -0
- package/src/engine/stale-decisions.ts +68 -0
- package/src/engine/state.ts +185 -0
- package/src/engine/store.ts +263 -0
- package/src/engine/tick-record.ts +129 -0
- package/src/engine/tick.ts +207 -0
- package/src/rpc.ts +182 -0
- package/src/server/app.ts +4320 -0
- package/src/server/help.ts +50 -0
- package/src/server/index.ts +23 -0
- package/src/server/intent.ts +22 -0
- package/src/server/messages.ts +228 -0
- package/src/summary/audit.ts +76 -0
- package/src/summary/build.ts +314 -0
- package/src/tui/dashboard.ts +322 -0
- package/src/tui/decision-form.ts +12 -0
- package/src/tui/format.ts +127 -0
- package/src/tui/index.tsx +718 -0
- package/src/tui/manager.ts +94 -0
- package/src/tui/navigation.ts +11 -0
- package/src/tui/pointer-select.ts +20 -0
- package/src/tui/tracer.ts +51 -0
- package/src/util/git.ts +102 -0
- package/src/util/ids.ts +20 -0
- package/src/util/shell.ts +42 -0
- package/src/verify/artifact.ts +95 -0
- package/src/verify/pipeline.ts +200 -0
- package/tui.tsx +2 -0
package/cli/ocg.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The `cleo-goal` bin (alias `ocg`, "open cleo goal"). Published as
|
|
3
|
+
// dist/cli.js (built by scripts/build-cli.mjs) so it runs on plain Node.
|
|
4
|
+
//
|
|
5
|
+
// cleo-goal --version the package version
|
|
6
|
+
// cleo-goal status --json the live goal, schemaVersion 1 (CLEO's read contract)
|
|
7
|
+
// cleo-goal install --project [--spec <npm-or-git spec>] [--json] [--dry-run]
|
|
8
|
+
// register the plugin in .opencode/opencode.json
|
|
9
|
+
// ocg tick CLEO's Stop dispatcher spawns this with the harness Stop JSON on
|
|
10
|
+
// stdin. JSON ONLY on stdout, logs on stderr, nothing when no goal
|
|
11
|
+
// is live. It records the turn, decides, and runs the verification
|
|
12
|
+
// of a claim.
|
|
13
|
+
// ocg claim The agent-side claim surface for a harness that has no OCG tools:
|
|
14
|
+
// it records a claim on the live run through OCG's own store, so the
|
|
15
|
+
// next tick can verify it. (OpenCode agents use the goal_claim tool.)
|
|
16
|
+
//
|
|
17
|
+
// We deliberately do NOT install our own Stop hook in any harness: CLEO's
|
|
18
|
+
// dispatcher owns Stop, and a second entry would tick twice.
|
|
19
|
+
import { readFileSync } from "node:fs"
|
|
20
|
+
import pkg from "../package.json"
|
|
21
|
+
import { InstallError, installProject, PACKAGE_NAME } from "../src/cli/install"
|
|
22
|
+
import { goalStatus } from "../src/cli/status"
|
|
23
|
+
import { fingerprint } from "../src/util/git"
|
|
24
|
+
import { Store } from "../src/engine/store"
|
|
25
|
+
import { tick } from "../src/engine/tick"
|
|
26
|
+
import { verifyClaim } from "../src/verify/pipeline"
|
|
27
|
+
|
|
28
|
+
const argv = process.argv.slice(2)
|
|
29
|
+
const sub = argv[0]
|
|
30
|
+
const flag = (name: string): string | undefined => {
|
|
31
|
+
const i = argv.indexOf(name)
|
|
32
|
+
return i === -1 ? undefined : argv[i + 1]
|
|
33
|
+
}
|
|
34
|
+
const root = process.cwd()
|
|
35
|
+
const store = new Store(root)
|
|
36
|
+
const USAGE = [
|
|
37
|
+
"usage: cleo-goal --version",
|
|
38
|
+
" cleo-goal status --json",
|
|
39
|
+
" cleo-goal install --project [--spec <npm-or-git spec>] [--json] [--dry-run]",
|
|
40
|
+
" cleo-goal tick (reads the harness Stop JSON on stdin; writes JSON on stdout)",
|
|
41
|
+
"usage: ocg tick (alias; same contract)",
|
|
42
|
+
" cleo-goal claim --summary <text> [--evidence C1=<note> ...]",
|
|
43
|
+
]
|
|
44
|
+
const usage = (): never => {
|
|
45
|
+
for (const line of USAGE) console.error(line)
|
|
46
|
+
process.exit(2)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (sub === "--version" || sub === "-v" || sub === "version") {
|
|
50
|
+
process.stdout.write(`cleo-goal ${pkg.version}\n`)
|
|
51
|
+
process.exit(0)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (sub === "status") {
|
|
55
|
+
if (!argv.includes("--json")) usage()
|
|
56
|
+
try {
|
|
57
|
+
process.stdout.write(`${JSON.stringify(goalStatus(store))}\n`)
|
|
58
|
+
process.exit(0)
|
|
59
|
+
} catch (error) {
|
|
60
|
+
process.stdout.write(`${JSON.stringify({ schemaVersion: 1, error: error instanceof Error ? error.message : String(error) })}\n`)
|
|
61
|
+
process.exit(1)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (sub === "install") {
|
|
66
|
+
const spec = flag("--spec") ?? `${PACKAGE_NAME}@${pkg.version}`
|
|
67
|
+
if (!argv.includes("--project") || spec.startsWith("--")) usage()
|
|
68
|
+
const json = argv.includes("--json")
|
|
69
|
+
try {
|
|
70
|
+
const result = installProject(root, spec, { dryRun: argv.includes("--dry-run") })
|
|
71
|
+
process.stdout.write(json ? `${JSON.stringify(result)}\n` : `${result.action}: ${result.spec} in ${result.file}\n`)
|
|
72
|
+
process.exit(0)
|
|
73
|
+
} catch (error) {
|
|
74
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
75
|
+
if (!(error instanceof InstallError)) console.error(`cleo-goal install: ${message}`)
|
|
76
|
+
process.stdout.write(json ? `${JSON.stringify({ schemaVersion: 1, error: message })}\n` : `error: ${message}\n`)
|
|
77
|
+
process.exit(1)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (sub === "claim") {
|
|
82
|
+
const summary = flag("--summary") ?? ""
|
|
83
|
+
if (!summary) {
|
|
84
|
+
console.error("usage: ocg claim --summary <text> [--evidence C1=<note> ...]")
|
|
85
|
+
process.exit(2)
|
|
86
|
+
}
|
|
87
|
+
const evidence: Record<string, string> = {}
|
|
88
|
+
for (let i = 0; i < argv.length; i++) {
|
|
89
|
+
if (argv[i] !== "--evidence") continue
|
|
90
|
+
const pair = argv[i + 1] ?? ""
|
|
91
|
+
const eq = pair.indexOf("=")
|
|
92
|
+
if (eq > 0) evidence[pair.slice(0, eq)] = pair.slice(eq + 1)
|
|
93
|
+
}
|
|
94
|
+
const live = store
|
|
95
|
+
.slugs()
|
|
96
|
+
.map((slug) => store.readRun(slug))
|
|
97
|
+
.filter((state): state is NonNullable<typeof state> => Boolean(state) && !["complete", "failed", "aborted", "superseded"].includes(state!.status))
|
|
98
|
+
.sort((a, b) => (b!.updatedAt ?? 0) - (a!.updatedAt ?? 0))[0]
|
|
99
|
+
if (!live) {
|
|
100
|
+
console.error("no live goal here; nothing to claim")
|
|
101
|
+
process.exit(1)
|
|
102
|
+
}
|
|
103
|
+
live.claim = { at: Date.now(), turn: live.turn, summary, evidence }
|
|
104
|
+
live.updatedAt = Date.now()
|
|
105
|
+
store.writeRun(live)
|
|
106
|
+
store.ledger(live.slug, { type: "claim", turn: live.turn, source: "ocg-claim", evidence: Object.keys(evidence).length })
|
|
107
|
+
console.error(`ocg claim: recorded on ${live.slug} (turn ${live.turn})`)
|
|
108
|
+
process.stdout.write(`${JSON.stringify({ ok: true, slug: live.slug, turn: live.turn, criteria: Object.keys(evidence) })}\n`)
|
|
109
|
+
process.exit(0)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (sub !== "tick") usage()
|
|
113
|
+
|
|
114
|
+
// Read stdin to EOF (the harness Stop JSON). Its content is mined for a
|
|
115
|
+
// transcript path when the harness supplies one; otherwise the tick degrades.
|
|
116
|
+
const readStdin = async (): Promise<string> => {
|
|
117
|
+
let text = ""
|
|
118
|
+
process.stdin.setEncoding("utf8")
|
|
119
|
+
for await (const chunk of process.stdin) text += chunk
|
|
120
|
+
return text
|
|
121
|
+
}
|
|
122
|
+
const payload = await readStdin().catch(() => "")
|
|
123
|
+
if (payload.trim()) console.error(`ocg tick: received ${payload.length} bytes of Stop payload`)
|
|
124
|
+
|
|
125
|
+
const result = await tick({
|
|
126
|
+
root,
|
|
127
|
+
store,
|
|
128
|
+
fingerprint: () => fingerprint(root),
|
|
129
|
+
payload,
|
|
130
|
+
readTranscript: (path: string) => {
|
|
131
|
+
try {
|
|
132
|
+
return readFileSync(path, "utf8")
|
|
133
|
+
} catch {
|
|
134
|
+
return undefined
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
// Host checks only: a contract that asks for the independent verifier child is
|
|
138
|
+
// the adapter's mechanism, and the tick does not claim to run one.
|
|
139
|
+
verify: (state, contract, contractText) => verifyClaim(contract, state, { root, contractText }),
|
|
140
|
+
}).catch((error: unknown) => {
|
|
141
|
+
// A crash is never the answer. Empty stdout means "no live goal" to the
|
|
142
|
+
// dispatcher, which would silently drop the run; holding keeps the session
|
|
143
|
+
// alive and the reason goes to stderr where it belongs.
|
|
144
|
+
console.error(`ocg tick: failed (${error instanceof Error ? error.message : String(error)}); holding the session`)
|
|
145
|
+
return { stdout: JSON.stringify({ final: false }), log: [] }
|
|
146
|
+
})
|
|
147
|
+
for (const line of result.log) console.error(line) // logs ONLY on stderr
|
|
148
|
+
if (result.stdout) process.stdout.write(`${result.stdout}\n`) // JSON ONLY on stdout
|
|
149
|
+
process.exit(0)
|