opencode-codeops 2.1.1 → 2.2.0
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 +80 -0
- package/README.md +11 -0
- package/bin/lib/codeops-progress.d.mts +236 -0
- package/bin/lib/codeops-progress.mjs +564 -0
- package/bin/lib/codeops-rpc.d.mts +160 -0
- package/bin/lib/codeops-rpc.mjs +177 -0
- package/package.json +24 -2
- package/plugin/index.ts +55 -2
- package/plugin/tui.tsx +112 -0
- package/scripts/__pycache__/codeops_plan.cpython-312.pyc +0 -0
- package/scripts/__pycache__/install_agents.cpython-312.pyc +0 -0
- package/scripts/codeops_plan.py +67 -3
- package/scripts/codeops_plan_migrate.py +17 -3
- package/skills/exec-plan/SKILL.md +5 -0
- package/skills/exec-plan/execution-protocol.md +29 -0
- package/plugin/temp-lifecycle.spec.test.mjs +0 -55
|
@@ -17,9 +17,21 @@ from dataclasses import dataclass
|
|
|
17
17
|
from pathlib import Path
|
|
18
18
|
|
|
19
19
|
try:
|
|
20
|
-
from scripts.codeops_plan import
|
|
20
|
+
from scripts.codeops_plan import (
|
|
21
|
+
BLOCKED_REASON_RE,
|
|
22
|
+
IMPLEMENTS_RE,
|
|
23
|
+
has_checkbox_lines,
|
|
24
|
+
parse_implements,
|
|
25
|
+
parse_tasks,
|
|
26
|
+
)
|
|
21
27
|
except ModuleNotFoundError: # Direct execution adds scripts/, not the repository root, to sys.path.
|
|
22
|
-
from codeops_plan import
|
|
28
|
+
from codeops_plan import (
|
|
29
|
+
BLOCKED_REASON_RE,
|
|
30
|
+
IMPLEMENTS_RE,
|
|
31
|
+
has_checkbox_lines,
|
|
32
|
+
parse_implements,
|
|
33
|
+
parse_tasks,
|
|
34
|
+
)
|
|
23
35
|
|
|
24
36
|
|
|
25
37
|
TARGET_ID_RE = re.compile(
|
|
@@ -231,7 +243,9 @@ def inspect_migration(codeops_root: Path) -> Migration:
|
|
|
231
243
|
continue
|
|
232
244
|
execution_text = execution.read_text(encoding="utf-8")
|
|
233
245
|
tasks = parse_tasks(execution_text)
|
|
234
|
-
|
|
246
|
+
# Presence stays checkbox-based (id-agnostic) so legacy id-less
|
|
247
|
+
# checklists keep migrating; only real tasks are checked further.
|
|
248
|
+
if not has_checkbox_lines(execution_text):
|
|
235
249
|
problems.append(f"{execution}: contains no execution tasks")
|
|
236
250
|
for task in tasks:
|
|
237
251
|
if task.marker == "!" and not BLOCKED_REASON_RE.search(task.text):
|
|
@@ -172,6 +172,11 @@ For each task, in order:
|
|
|
172
172
|
the Master Progress Checklist — see the protocol's dual-format detection) and bump the Progress
|
|
173
173
|
counter / Last Updated stamp as soon as implementation finishes (crash-safe), promote it to
|
|
174
174
|
`[x]` only after its verification passes. A task never shows `[x]` with a failing verify.
|
|
175
|
+
|
|
176
|
+
- **Report progress** — when the `codeops_progress` tool is available — at the transition
|
|
177
|
+
points in [execution-protocol.md](execution-protocol.md) §Progress Reporting; a failed or
|
|
178
|
+
missing report never blocks any step.
|
|
179
|
+
|
|
175
180
|
3. **Verify** — run your project's verify command (from the project's AGENTS.md, or detected
|
|
176
181
|
project conventions), output captured per the protocol's **Verify-output capture rule**
|
|
177
182
|
(PASS one-liner; on failure the last 50 log lines + log path). Pass → promote `[~]` → `[x]`;
|
|
@@ -444,6 +444,35 @@ otherwise still `[~]` — with the progress counter and Last Updated stamp curre
|
|
|
444
444
|
|
|
445
445
|
---
|
|
446
446
|
|
|
447
|
+
## Progress Reporting (fail-soft)
|
|
448
|
+
|
|
449
|
+
While a plan executes, the agent may report live progress through the `codeops_progress` tool so
|
|
450
|
+
the sidebar shows the current run. Reporting is an observability aid only: the Markdown execution
|
|
451
|
+
plan remains the single progress source of truth, and a missing tool or a failed call never
|
|
452
|
+
blocks, delays, or changes any verify, commit, or plan update — when the tool is unavailable,
|
|
453
|
+
execution proceeds silently.
|
|
454
|
+
|
|
455
|
+
Report at these moments; `plan` is the plan folder name, and every call carries `plan` and
|
|
456
|
+
`activity` (absent optional fields are carried by the run state):
|
|
457
|
+
|
|
458
|
+
| Moment | Report payload |
|
|
459
|
+
| ------ | -------------- |
|
|
460
|
+
| Run start (start point determined) | `{ plan, phase, task, activity: "implementing" }` |
|
|
461
|
+
| Phase start (subsequent phases) | `{ plan, phase, activity: "starting" }` |
|
|
462
|
+
| Task implemented (after the `[~]` mark) | `{ plan, task, activity: "implementing" }` |
|
|
463
|
+
| Verification (before running verify) | `{ plan, activity: "verifying" }` |
|
|
464
|
+
| Task verified (after `[x]` + the progress-bar display) | `{ plan, verified, total, activity: "implementing" }` — counts from that display |
|
|
465
|
+
| Blocker (after the `[!]` mark) | `{ plan, activity: "blocked", detail: "<short reason>" }` |
|
|
466
|
+
| Delegation (around an executor/reviewer dispatch) | `{ plan, activity: "delegating", detail: "<role>" }` |
|
|
467
|
+
| Review step (post-phase quality loop) | `{ plan, activity: "reviewing" }` |
|
|
468
|
+
| Waiting (before pausing for an explicit user decision) | `{ plan, activity: "waiting" }` |
|
|
469
|
+
| Run done (all tasks complete) | `{ plan, activity: "done" }` |
|
|
470
|
+
|
|
471
|
+
One call per listed moment, no other calls (noise control). A reporting failure or a host without
|
|
472
|
+
the tool never blocks, delays, or changes any step.
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
447
476
|
## Step 3: Session Wrap-Up
|
|
448
477
|
|
|
449
478
|
1. Complete the current task before stopping.
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Specification tests for the scratch-directory lifecycle.
|
|
3
|
-
*
|
|
4
|
-
* The plugin exports one scratch directory (`$CODEOPS_TMPDIR`) per plugin
|
|
5
|
-
* runtime, and every session served by that runtime shares it. Deleting the
|
|
6
|
-
* directory when a plugin instance unloads destroys in-flight scratch files of
|
|
7
|
-
* sessions that are still running, so the contract is: the plugin never
|
|
8
|
-
* deletes the shared directory; the age-based sweep reclaims abandoned
|
|
9
|
-
* directories instead.
|
|
10
|
-
*
|
|
11
|
-
* This is the regression oracle for that contract: a failure here means the
|
|
12
|
-
* repository reintroduced early deletion, never that the test is wrong.
|
|
13
|
-
*
|
|
14
|
-
* @module temp-lifecycle.spec.test
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import assert from "node:assert/strict"
|
|
18
|
-
import { readFileSync } from "node:fs"
|
|
19
|
-
import { dirname, join, resolve } from "node:path"
|
|
20
|
-
import { describe, it } from "node:test"
|
|
21
|
-
import { fileURLToPath } from "node:url"
|
|
22
|
-
|
|
23
|
-
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..")
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Read a repository file as UTF-8 text.
|
|
27
|
-
* @param {string} relativePath - Path relative to the repository root.
|
|
28
|
-
* @returns {string} The file contents.
|
|
29
|
-
*/
|
|
30
|
-
function read(relativePath) {
|
|
31
|
-
return readFileSync(join(ROOT, relativePath), "utf8")
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
describe("scratch-directory lifecycle", () => {
|
|
35
|
-
it("keeps the plugin free of scratch-directory deletion", () => {
|
|
36
|
-
const plugin = read("plugin/index.ts")
|
|
37
|
-
assert.doesNotMatch(plugin, /removeSessionTmpDir/)
|
|
38
|
-
assert.match(plugin, /cleanStaleTmpDirs\(\)/)
|
|
39
|
-
assert.match(plugin, /controller\.abort\(\)/)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it("keeps the temp hygiene module free of exact-directory deletion", () => {
|
|
43
|
-
assert.doesNotMatch(read("bin/lib/tmp-hygiene.mjs"), /removeSessionTmpDir/)
|
|
44
|
-
assert.doesNotMatch(read("bin/lib/tmp-hygiene.d.mts"), /removeSessionTmpDir/)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
it("documents the age-based sweep as the automatic cleanup", () => {
|
|
48
|
-
const hygiene = read("_shared/workspace-hygiene.md")
|
|
49
|
-
assert.doesNotMatch(hygiene, /removes that runtime's\s+directory when the plugin unloads/i)
|
|
50
|
-
assert.match(hygiene, /seven days/i)
|
|
51
|
-
const readme = read("README.md")
|
|
52
|
-
assert.doesNotMatch(readme, /removes the\s+directory when it unloads/i)
|
|
53
|
-
assert.match(readme, /sweeps\s+directories abandoned/i)
|
|
54
|
-
})
|
|
55
|
-
})
|