@magnusekdahl/parallix 1.3.0 → 1.3.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/README.md +4 -2
- package/config/integration-pipelines.json +5 -0
- package/docs/adr/0048-fail-closed-harness-defense-against-agent-hallucinations.md +161 -0
- package/docs/adr/index.md +2 -0
- package/docs/authority-reference.md +8 -5
- package/lib/agents/agents.js +37 -5
- package/lib/agents/agents.ts +43 -6
- package/lib/agents/claude.js +3 -1
- package/lib/agents/claude.ts +3 -1
- package/lib/agents/codex.js +3 -1
- package/lib/agents/codex.ts +3 -1
- package/lib/agents/opencode.js +5 -3
- package/lib/agents/opencode.ts +5 -3
- package/lib/commands/active.js +21 -3
- package/lib/commands/active.ts +7 -2
- package/lib/commands/config.js +6 -1
- package/lib/commands/config.ts +6 -1
- package/lib/commands/coverage-gate.js +19 -1
- package/lib/commands/coverage-gate.ts +6 -1
- package/lib/commands/diff.js +6 -1
- package/lib/commands/diff.ts +6 -1
- package/lib/commands/draft.js +31 -1
- package/lib/commands/draft.ts +6 -1
- package/lib/commands/handoff.js +12 -1
- package/lib/commands/handoff.ts +6 -1
- package/lib/commands/integrate.js +103 -27
- package/lib/commands/integrate.ts +67 -31
- package/lib/commands/mission-start.js +12 -3
- package/lib/commands/mission-start.ts +7 -2
- package/lib/commands/rebase.js +10 -2
- package/lib/commands/rebase.ts +6 -2
- package/lib/commands/repair-handoff.js +13 -3
- package/lib/commands/repair-handoff.ts +7 -2
- package/lib/commands/resolve-conflict.js +8 -2
- package/lib/commands/resolve-conflict.ts +7 -2
- package/lib/commands/review.js +6 -1
- package/lib/commands/review.ts +6 -1
- package/lib/commands/setup-review.js +8 -3
- package/lib/commands/setup-review.ts +8 -3
- package/lib/commands/setup.js +8 -2
- package/lib/commands/setup.ts +7 -2
- package/lib/commands/stats-backfill.js +14 -3
- package/lib/commands/stats-backfill.ts +7 -2
- package/lib/commands/stats.js +33 -1
- package/lib/commands/stats.ts +7 -2
- package/lib/commands/status.js +8 -1
- package/lib/commands/status.ts +6 -1
- package/lib/commands/verify.js +11 -2
- package/lib/commands/verify.ts +7 -2
- package/lib/core/gitignore.js +9 -1
- package/lib/core/gitignore.ts +6 -1
- package/lib/core/persistent-data-migration.js +4 -2
- package/lib/core/persistent-data-migration.ts +4 -2
- package/lib/index.js +36 -36
- package/lib/index.ts +18 -18
- package/lib/review/review-loop.js +12 -7
- package/lib/review/review-loop.ts +10 -7
- package/lib/review/review.js +51 -1
- package/lib/review/review.ts +6 -1
- package/lib/tools/setup-review.js +7 -4
- package/lib/tools/setup-review.ts +2 -2
- package/package.json +1 -1
- package/px.js +26 -14
package/README.md
CHANGED
|
@@ -145,11 +145,13 @@ px active task-042
|
|
|
145
145
|
|
|
146
146
|
# Land it: runs configured integration gates, squash-merges to
|
|
147
147
|
# the primary branch, updates board state, removes the branch
|
|
148
|
-
# and worktree.
|
|
148
|
+
# and worktree. In this repo that means a fast general verifier
|
|
149
|
+
# during earlier phases and a stricter lifecycle E2E gate before
|
|
150
|
+
# integrate lands.
|
|
149
151
|
px integrate task-042
|
|
150
152
|
```
|
|
151
153
|
|
|
152
|
-
The verification gate that runs at each
|
|
154
|
+
The verification gate that runs at each phase is whatever you declare in `workflow.config.json`. In this repo that dispatcher is `./scripts/verify-local.sh {{area}}`: earlier phases use the fast general suite, while `px integrate` calls `verify-local.sh integrate`, which resolves repo-side integration gates from `config/integration-pipelines.json` and runs the stricter pre-merge checks there.
|
|
153
155
|
|
|
154
156
|
## Use cases
|
|
155
157
|
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# ADR 0048: Fail-closed harness defense against agent hallucinations
|
|
2
|
+
|
|
3
|
+
Status: Accepted
|
|
4
|
+
Date: 2026-06-29
|
|
5
|
+
|
|
6
|
+
Related: ADR 0041 (integration pipeline gates), ADR 0047 (NEL budget), task-1268 (shift-left verification), task-1335 (harden publish path)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
Parallix already has meaningful defenses against agent hallucinations and incomplete work, but they are fragmented across commands and missions rather than expressed as one coherent harness policy. The repo has exact-tree verification proof (task-1335), handoff pre-checks, gatekeeper mandatory-artifact checks (gatekeeper.js), integration-time gates (ADR 0041), and a narrow auto-repair path (repair-handoff.js). It also has open work on shift-left verification (task-1268).
|
|
11
|
+
|
|
12
|
+
What it does not yet have is one explicit answer to a repository-level question: **given a failed or incomplete agent handoff, which failure classes should auto-repair, which should auto-send-back to the implementer, and which genuinely require human intervention?**
|
|
13
|
+
|
|
14
|
+
The current `repair-handoff.js` handles only two mechanical error classes (dirty mission artifacts, branch behind primary) and one relaunchable content error (empty goal-check table). All other failures — including genuine gate failures on code issues, the single largest consumer of human time — strand with a generic "not automatically repairable" message that requires manual re-invocation.
|
|
15
|
+
|
|
16
|
+
This ADR consolidates the existing evidence, classifies the failure modes, and recommends a fully backlog-tracked implementation plan for fail-closed harness behavior. Nothing in the recommended control set is left as an untracked "defer later" idea: every control gets an explicit backlog task, even when the runtime outcome remains "human required".
|
|
17
|
+
|
|
18
|
+
## Inputs
|
|
19
|
+
|
|
20
|
+
This decision draws on four prior Parallix artifacts:
|
|
21
|
+
|
|
22
|
+
1. **Task-1268** (`backlog/tasks/task-1268 - Shift-left.md`): Shift-left verification concept — run the verification gate mechanically before each review round, auto-bounce on failure without consuming a reviewer cycle. Key insight: the machinery exists (`captureVerifiedTreeProof` / `assertVerifiedTreeProof` in `lib/core/verification.js`), but enforcement before review rounds is missing.
|
|
23
|
+
|
|
24
|
+
2. **Task-1335** (`backlog/completed/task-1335 - Harden-parallix-self-hosting-publish-path...md`): Exact-tree verification proof, implemented and completed. Established the principle that a verification proof must be tied to the exact tree being published — a green run from a different checkout, commit, or pre-squash state cannot satisfy the guard.
|
|
25
|
+
|
|
26
|
+
3. **ADR 0041** (`docs/adr/0041-integration-pipeline-gates.md`): Integration-time pipeline gates with per-area dispatch, config-driven gate plan, and `--no-integration-gates` escape hatch. Established the pattern of gate execution before squash-merge.
|
|
27
|
+
|
|
28
|
+
4. **ADR 0047** (`docs/adr/0047-per-mission-change-size-budget.md`): NEL budget with observational capture at handoff. Demonstrates the pattern of observational instrumentation without enforcement — a template for what NOT to do when enforcement is needed.
|
|
29
|
+
|
|
30
|
+
## Inventory of Existing Checks
|
|
31
|
+
|
|
32
|
+
The following checks are currently implemented across the harness lifecycle. Each is mapped to the failure class it catches.
|
|
33
|
+
|
|
34
|
+
### Before Handoff
|
|
35
|
+
|
|
36
|
+
| # | Check | Location | Failure Class |
|
|
37
|
+
|---|-------|----------|---------------|
|
|
38
|
+
| 1 | Verification gate at checkpoint | `lib/commands/checkpoint.js:44` | Unverifiable test claims (Class 1) |
|
|
39
|
+
| 2 | Checkpoint existence validation | `lib/commands/active.js:386-391` | Missing artifacts (Class 3) |
|
|
40
|
+
| 3 | Checkpoint committed check | `lib/commands/active.js:407-414` | Uncommitted state (Class 4) |
|
|
41
|
+
|
|
42
|
+
### During Handoff
|
|
43
|
+
|
|
44
|
+
| # | Check | Location | Failure Class |
|
|
45
|
+
|---|-------|----------|---------------|
|
|
46
|
+
| 4 | Mission branch verification | `lib/commands/handoff.js:37-39` | Git blockers (Class 5) |
|
|
47
|
+
| 5 | MISSION.md existence | `lib/commands/handoff.js:42-44` | Missing artifacts (Class 3) |
|
|
48
|
+
| 6 | MISSION.md uncommitted check | `lib/commands/handoff.js:96-99` | Uncommitted state (Class 4) |
|
|
49
|
+
| 7 | Auto-checkpoint generation | `lib/commands/handoff.js:103-126` | Missing artifacts — auto-repair (Class 3) |
|
|
50
|
+
| 8 | Goal Check heading validation | `lib/commands/handoff.js:141-147` | Incomplete evidence (Class 4) |
|
|
51
|
+
| 9 | Goal Check evidence rows | `lib/commands/handoff.js:152-179` | Incomplete evidence (Class 4) |
|
|
52
|
+
| 10 | Verification gate execution | `lib/commands/handoff.js:200-209` | Gate failure (Class 1, 6) |
|
|
53
|
+
| 11 | Rebase onto primary | `lib/commands/handoff.js:214-229` | Git blockers (Class 5) |
|
|
54
|
+
| 12 | Gatekeeper mandatory artifacts | `lib/commands/handoff.js:322-335` | Missing artifacts (Class 3) |
|
|
55
|
+
| 13 | Declared gates execution | `lib/commands/handoff.js:429-480` | Gate failure (Class 2, 6) |
|
|
56
|
+
|
|
57
|
+
### Before Review
|
|
58
|
+
|
|
59
|
+
| # | Check | Location | Failure Class |
|
|
60
|
+
|---|-------|----------|---------------|
|
|
61
|
+
| 14 | Mission dir + branch + status | `lib/review/review-commands.js:367-401` | State violations (Class 8) |
|
|
62
|
+
| 15 | PR existence and state | `lib/review/review-commands.js:403-430` | Infra blockers (Class 7) |
|
|
63
|
+
| 16 | Verification gate | `lib/review/review-commands.js:438-445` | Gate failure (Class 1, 6) |
|
|
64
|
+
|
|
65
|
+
### During Integration
|
|
66
|
+
|
|
67
|
+
| # | Check | Location | Failure Class |
|
|
68
|
+
|---|-------|----------|---------------|
|
|
69
|
+
| 17 | Integration preflight | `lib/commands/integrate.js:500-504` | Multiple classes |
|
|
70
|
+
| 18 | Integration gates | `lib/commands/integrate.js:507-534` | Gate failure (Class 6) |
|
|
71
|
+
| 19 | Exact-tree proof capture | `lib/commands/integrate.js:742-749` | Unverifiable claims (Class 1) |
|
|
72
|
+
| 20 | Exact-tree proof assertion | `lib/commands/integrate.js:753-757` | Stale proof (Class 1) |
|
|
73
|
+
|
|
74
|
+
### Repair Path
|
|
75
|
+
|
|
76
|
+
| # | Mechanism | Location | Coverage |
|
|
77
|
+
|---|-----------|----------|----------|
|
|
78
|
+
| 21 | Auto-commit mission artifacts | `lib/commands/repair-handoff.js:130-191` | Dirty mission files only (Class 5) |
|
|
79
|
+
| 22 | Auto-rebase | `lib/commands/repair-handoff.js:194-223` | Simple rebase only (Class 5) |
|
|
80
|
+
| 23 | Agent relaunch (empty goal-check) | `lib/commands/active.js:462-483` | Single error sub-class only (Class 4) |
|
|
81
|
+
|
|
82
|
+
**Total: 23 check points across 5 lifecycle phases.**
|
|
83
|
+
|
|
84
|
+
## Failure Classification
|
|
85
|
+
|
|
86
|
+
Eight failure classes have been identified, each classified as auto-repair, auto-send-back, or human-only:
|
|
87
|
+
|
|
88
|
+
| # | Failure Class | Proposed | Rationale |
|
|
89
|
+
|---|---------------|----------|-----------|
|
|
90
|
+
| 1 | Unverifiable "tests passed" claims | **Auto-send-back** | Gate exit code is deterministic; agent prose is never sufficient |
|
|
91
|
+
| 2 | Malformed or non-runnable declared gates | **Auto-repair** | Static validation (file existence, syntax) can catch before execution |
|
|
92
|
+
| 3 | Missing mandatory mission artifacts | **Auto-send-back** | Unambiguously the implementer's responsibility; no human judgment needed |
|
|
93
|
+
| 4 | Incomplete checkpoint evidence | **Auto-send-back** | Agent-fixable content errors; fix prompt already exists for one sub-class |
|
|
94
|
+
| 5 | Mechanical git/handoff blockers | **Auto-repair** (mission-only); **Human-only** (shared files) | Mission conflicts auto-resolvable; shared-file conflicts require judgment |
|
|
95
|
+
| 6 | Genuine gate failure (code issues) | **Auto-send-back** | Gate output sufficient for agent to diagnose; highest-ROI improvement |
|
|
96
|
+
| 7 | Forgejo/infra blockers | **Human-only** | No agent relaunch will fix infrastructure issues |
|
|
97
|
+
| 8 | Task state machine violations | **Human-only** | State confusion requires human determination of correct state |
|
|
98
|
+
|
|
99
|
+
## Decision Matrix: Candidate Harness Controls
|
|
100
|
+
|
|
101
|
+
Seven candidate controls are evaluated and prioritized. The classification column answers backlog treatment, not runtime disposition: every control below is scheduled work with an explicit task.
|
|
102
|
+
|
|
103
|
+
| # | Candidate Control | Complexity | ROI | Risk | Backlog Treatment |
|
|
104
|
+
|---|-------------------|-----------|-----|------|-------------------|
|
|
105
|
+
| C1 | Pre-review-round gate enforcement with auto-bounce | Medium | High | Low — gate machinery already exists; enforcement is the missing piece | **Implement now** (`TASK-1385`) |
|
|
106
|
+
| C2 | Gate-failure auto-send-back with captured output | Low | High | Low — capture stdout/stderr, build fix prompt, relaunch with retry limit | **Implement now** (`TASK-1387`) |
|
|
107
|
+
| C3 | Error classifier and dispatch table replacing generic strand | Medium | Medium | Low — refactor, not new behavior; existing repair-handoff.js is the seam | **Implement now** (`TASK-1389`) |
|
|
108
|
+
| C4 | Declared-gate pre-validation (syntax + file existence) | Low | Medium | Low — static check before execution | **Implement next wave** (`TASK-1386`) |
|
|
109
|
+
| C5 | Gatekeeper auto-send-back with agent relaunch | Low | Medium | Medium — must avoid relaunch loops when artifacts genuinely cannot be created | **Implement next wave** (`TASK-1388`) |
|
|
110
|
+
| C6 | Forgejo/infrastructure blocker classification and operator handoff | Low | Low | Low — mostly classification and operator guidance, but still worth making explicit | **Implement next wave** (`TASK-1392`) |
|
|
111
|
+
| C7 | Pre-review checkpoint evidence reference validation | Medium | Low | Medium — keep the check mechanical and avoid semantic-quality scoring | **Implement next wave** (`TASK-1393`) |
|
|
112
|
+
|
|
113
|
+
### Implement Now (C1, C2, C3)
|
|
114
|
+
|
|
115
|
+
**C1: Pre-review-round gate enforcement** (task-1268 / task-1385). Run the configured verification gate mechanically before each review round. On gate failure, auto-bounce to the implementer with the gate output as a fix prompt. No reviewer cycle consumed. This is the single highest-impact control because it closes the fail-open path where an agent can hand off with a green gate, receive review feedback, "fix" the code, and re-submit without the gate re-running.
|
|
116
|
+
|
|
117
|
+
**C2: Gate-failure auto-send-back** (task-1387). When the verification gate fails at handoff time (`handoff.js:200-209`), capture the gate stdout/stderr, classify the error as "genuine gate failure — code issue", and relaunch the implementer with the captured output. Limit relaunch attempts to 2 to prevent infinite loops. This is the highest-ROI single control because it eliminates the most common human-intervention scenario: manually copying gate output and re-invoking the agent.
|
|
118
|
+
|
|
119
|
+
**C3: Error classifier and dispatch table** (task-1389). Replace the binary `isRelaunchableError` / `isDirtyError` / `isBehind` classification in `repair-handoff.js` with a structured error classifier that maps each error message pattern to a failure class and a dispatch action (auto-repair, auto-send-back with prompt, or human-only with clear message). This is foundational work that makes C1 and C2 cleaner to implement.
|
|
120
|
+
|
|
121
|
+
### Implement Next Wave (C4, C5, C6, C7)
|
|
122
|
+
|
|
123
|
+
**C4: Declared-gate pre-validation** (`TASK-1386`). Validate that gate commands reference existing files and are syntactically valid before executing them. This stays after C1-C3 only because the earlier controls close larger fail-open paths first, not because C4 is optional.
|
|
124
|
+
|
|
125
|
+
**C5: Gatekeeper auto-send-back** (`TASK-1388`). When gatekeeper detects missing mandatory artifacts and the task strands in `active`, auto-send-back to the implementer with explicit artifact creation instructions. The auto-checkpoint generation at `handoff.js:103-126` already covers one sub-case, but the remaining cases still deserve explicit automation and therefore explicit backlog tracking.
|
|
126
|
+
|
|
127
|
+
**C6: Forgejo/infrastructure blocker classification and operator handoff** (`TASK-1392`). Label Forgejo and related infrastructure failures as "infrastructure — human required", preserve the existing runtime outcome, and make the operator message deterministic and actionable. Human-required runtime behavior is still harness work and therefore still gets a backlog task.
|
|
128
|
+
|
|
129
|
+
**C7: Pre-review checkpoint evidence reference validation** (`TASK-1393`). Validate that checkpoint evidence rows cite real file:line references, ADR references, or test names rather than placeholder prose. The task must stay mechanical: it should verify reference shape and existence, not attempt to score evidence quality semantically.
|
|
130
|
+
|
|
131
|
+
## Implementation Order
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
C3 (error classifier) → C2 (gate-failure send-back) → C1 (pre-review gate) → C4 → C5 → C6 → C7
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
C3 first because it provides the dispatch framework that C1 and C2 plug into. C2 before C1 because C2 is lower complexity and higher immediate ROI (handoff-time gate failures are already the blocking point; pre-review-round enforcement adds a new check point). C4-C7 remain sequenced backlog work rather than untracked ideas.
|
|
138
|
+
|
|
139
|
+
## Consequences
|
|
140
|
+
|
|
141
|
+
### Positive
|
|
142
|
+
|
|
143
|
+
- The most common human-intervention scenario (copying gate output and re-invoking agent) is eliminated by C2
|
|
144
|
+
- The fail-open path between review rounds is closed by C1 (task-1268)
|
|
145
|
+
- Error handling moves from binary (repairable / not) to a classified dispatch table (C3)
|
|
146
|
+
- Each failure class has an explicit owner (auto-repair, auto-send-back, or human)
|
|
147
|
+
|
|
148
|
+
### Negative
|
|
149
|
+
|
|
150
|
+
- Automatic relaunching (C2) increases compute cost per failed handoff (bounded by retry limit)
|
|
151
|
+
- The error classifier (C3) adds a maintenance surface — new error patterns must be classified
|
|
152
|
+
- Pre-review gate enforcement (C1) adds wall-time to each review round (bounded by gate duration)
|
|
153
|
+
|
|
154
|
+
## See Also
|
|
155
|
+
|
|
156
|
+
- Task-1268: Shift-left verification concept (backlog)
|
|
157
|
+
- Task-1335: Exact-tree verification proof (completed)
|
|
158
|
+
- ADR 0041: Integration pipeline gates
|
|
159
|
+
- ADR 0047: NEL budget (observational pattern)
|
|
160
|
+
- `lib/commands/repair-handoff.js`: Current repair path
|
|
161
|
+
- `lib/commands/active.js:426-498`: Automated handoff-and-repair flow
|
package/docs/adr/index.md
CHANGED
|
@@ -17,5 +17,7 @@ ADR 0023 remains in WrGroceries and is cross-referenced here instead of copied.
|
|
|
17
17
|
- `docs/adr/0046-npm-publish-process-and-security.md` — Adopt public npm registry publication for `@magnusekdahl/parallix` alongside the local tarball path; zero-dependency security posture, manual publish process, and rollback considerations
|
|
18
18
|
- `docs/adr/0047-per-mission-change-size-budget.md` — Change the mission size-estimation basis from agent-usage % to **Net Engineering Lines (NEL)** — code+test diff, excluding docs and workflow/admin bookkeeping (the +0.65 reverse-causation confound). Draft estimate becomes a NEL bucket (0–80 / 81–235 / 235+, the empirical risk terciles); capture actual NEL at handoff to calibrate the estimate. No enforcement until the draft bucket is shown reliable.
|
|
19
19
|
|
|
20
|
+
- `docs/adr/0048-fail-closed-harness-defense-against-agent-hallucinations.md` — Fail-closed harness defense against agent hallucinations: error classification, auto-send-back policy, and prioritized implementation plan for closing fail-open paths in the handoff/review/integrate lifecycle
|
|
21
|
+
|
|
20
22
|
## Cross-reference
|
|
21
23
|
- `docs/adr/0023-ai-sdlc-configuration.md` remains in WrGroceries at `/home/magnus/code/visualBoard-task-1302/docs/adr/0023-ai-sdlc-configuration.md`.
|
|
@@ -153,7 +153,7 @@ Complete when: mission reviewed, landing from the correct integration checkout,
|
|
|
153
153
|
|
|
154
154
|
- **Config location:** `config/integration-pipelines.json`
|
|
155
155
|
- **Schema:** `{"gates": {"<area>": {"command": "<shell-command>", "order": <number>, "run_last": <boolean>}}}`
|
|
156
|
-
- **Supported areas:** `server`, `auth-server`, `web-client`, `web-e2e`
|
|
156
|
+
- **Supported areas:** `lib`, `workflow`, `server`, `auth-server`, `web-client`, `web-e2e`, `docs`, `android`, `kubernetes`
|
|
157
157
|
- **Ordering:** Gates are executed in ascending `order` value; `run_last: true` ensures the gate runs after all others (regardless of order value)
|
|
158
158
|
- **Change detection:** Gates are only invoked for areas with changed files in the mission branch vs the primary branch
|
|
159
159
|
- **Opt-out:** `px integrate <slug> --no-integration-gates` skips all integration gates
|
|
@@ -163,16 +163,19 @@ Example config:
|
|
|
163
163
|
```json
|
|
164
164
|
{
|
|
165
165
|
"gates": {
|
|
166
|
-
"
|
|
167
|
-
"
|
|
168
|
-
"web-client": {"command": "SKIP_E2E=1 ./web-client/updateStaging.sh", "order": 3, "run_last": false},
|
|
169
|
-
"web-e2e": {"command": "./web-client/scripts/run-playwright-stage.sh", "order": 4, "run_last": true}
|
|
166
|
+
"lib": {"command": "./scripts/verify-local.sh static-analysis", "order": 1, "run_last": false},
|
|
167
|
+
"workflow": {"command": "node test/e2e-mission-lifecycle.test.js", "order": 50, "run_last": true}
|
|
170
168
|
}
|
|
171
169
|
}
|
|
172
170
|
```
|
|
173
171
|
|
|
174
172
|
If the config file is missing or empty, `px integrate` logs `integration-gates: no config present, skipping` and proceeds without error.
|
|
175
173
|
|
|
174
|
+
In this repo, `workflow.config.json` points verification at `./scripts/verify-local.sh {{area}}`. That gives Parallix two validation layers:
|
|
175
|
+
|
|
176
|
+
- earlier phases such as draft/active/review run the repo's fast general verifier (`all`, currently `npm test`)
|
|
177
|
+
- `px integrate` invokes `verify-local.sh integrate`, which resolves the stricter integration gate plan from `config/integration-pipelines.json` after the target tree is exact
|
|
178
|
+
|
|
176
179
|
## 5. Checkpoint Model
|
|
177
180
|
|
|
178
181
|
Each completed checkpoint must produce: (1) checkpoint doc under the configured mission base dir for the repo (`missions/<slug>/` in this repo), (2) non-generic `Next action:`, (3) passing relevant gate, (4) commit on `mission/<slug>`. Checkpoint docs make resume and handoff deterministic.
|
package/lib/agents/agents.js
CHANGED
|
@@ -51,6 +51,7 @@ exports.isInvalidAgentConfigError = isInvalidAgentConfigError;
|
|
|
51
51
|
exports.updateAgentBlock = updateAgentBlock;
|
|
52
52
|
exports.resolveBlocklistTargetPath = resolveBlocklistTargetPath;
|
|
53
53
|
exports.resolveNoOutputWatchdogConfig = resolveNoOutputWatchdogConfig;
|
|
54
|
+
exports.shouldPersistLaunchFailureBlock = shouldPersistLaunchFailureBlock;
|
|
54
55
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
55
56
|
const node_path_1 = __importDefault(require("node:path"));
|
|
56
57
|
const node_child_process_1 = require("node:child_process");
|
|
@@ -63,9 +64,11 @@ const limit_hit_js_1 = require("./limit-hit.js");
|
|
|
63
64
|
const storage = __importStar(require("../core/storage.js"));
|
|
64
65
|
const product_config_js_1 = require("../core/product-config.js");
|
|
65
66
|
const persistent_data_migration_js_1 = require("../core/persistent-data-migration.js");
|
|
67
|
+
const node_module_1 = require("node:module");
|
|
66
68
|
// tools/sessions is still CJS (not converted in this wave); require keeps it
|
|
67
69
|
// untyped (any) without pulling a non-included .js into the typecheck program.
|
|
68
|
-
const
|
|
70
|
+
const _require = (0, node_module_1.createRequire)(__filename);
|
|
71
|
+
const sessions = _require('../tools/sessions');
|
|
69
72
|
// Launchers whose CLI accepts a per-call resume flag threaded by startAgent.
|
|
70
73
|
// Each launcher outputs a session resume hint at the end of its run (e.g.
|
|
71
74
|
// "codex resume <id>", "opencode -s ses_<id>",
|
|
@@ -107,6 +110,17 @@ const KNOWN_AGENT_NAMES = Object.freeze([
|
|
|
107
110
|
'human'
|
|
108
111
|
]);
|
|
109
112
|
exports.KNOWN_AGENT_NAMES = KNOWN_AGENT_NAMES;
|
|
113
|
+
const NON_BLOCKING_LAUNCH_ERROR_PATTERNS = Object.freeze([
|
|
114
|
+
/\b(?:invalid|unknown|unsupported|unrecognized)\s+model\b/i,
|
|
115
|
+
/\bmodel\s+(?:identifier|id)\s+(?:is\s+)?invalid\b/i,
|
|
116
|
+
/\b(?:model\s+not\s+found|no\s+such\s+model)\b/i,
|
|
117
|
+
/\bunknown\s+option\b/i,
|
|
118
|
+
/\bauth(?:entication)?\b/i,
|
|
119
|
+
/\bunauthorized\b/i,
|
|
120
|
+
/\bforbidden\b/i,
|
|
121
|
+
/\bapi\s+key\b/i,
|
|
122
|
+
/\bread-only file system\b/i
|
|
123
|
+
]);
|
|
110
124
|
function workflowLauncherStatus(agent) {
|
|
111
125
|
const resolver = RESOLVERS[agent];
|
|
112
126
|
if (!resolver) {
|
|
@@ -148,6 +162,21 @@ function commandInPath(name) {
|
|
|
148
162
|
});
|
|
149
163
|
return result.status === 0 && result.stdout.trim().length > 0;
|
|
150
164
|
}
|
|
165
|
+
function shouldPersistLaunchFailureBlock(agent, result) {
|
|
166
|
+
if (!result || agent === 'custom') {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const combined = [
|
|
170
|
+
result.stderr || '',
|
|
171
|
+
result.stdout || '',
|
|
172
|
+
result.error?.message || '',
|
|
173
|
+
result.error?.code || ''
|
|
174
|
+
].join('\n');
|
|
175
|
+
if (!combined.trim()) {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
return !NON_BLOCKING_LAUNCH_ERROR_PATTERNS.some(pattern => pattern.test(combined));
|
|
179
|
+
}
|
|
151
180
|
function buildInvalidAgentConfigError(configPath, scope, originalError) {
|
|
152
181
|
const location = node_path_1.default.resolve(configPath);
|
|
153
182
|
const detail = originalError && originalError.message ? originalError.message : 'invalid JSON';
|
|
@@ -790,10 +819,10 @@ async function startAgent(step, opts = { prompt: '' }) {
|
|
|
790
819
|
});
|
|
791
820
|
tried.add(chosen || '');
|
|
792
821
|
launched.add(chosen || '');
|
|
793
|
-
// Block
|
|
794
|
-
//
|
|
795
|
-
//
|
|
796
|
-
if (chosen
|
|
822
|
+
// Block retry candidates only when the failure looks transient. Deterministic
|
|
823
|
+
// setup/config errors (invalid model id, auth failure, read-only HOME, etc.)
|
|
824
|
+
// should fall through to the next family without poisoning agents.local.json.
|
|
825
|
+
if (shouldPersistLaunchFailureBlock(chosen || '', result)) {
|
|
797
826
|
const blockUntil = (0, limit_hit_js_1.formatBlockUntil)(new Date(Date.now() + limit_hit_js_1.DEFAULT_FALLBACK_HOURS * 60 * 60 * 1000));
|
|
798
827
|
try {
|
|
799
828
|
const blockResult = updateAgentBlockFn(chosen || '', blockUntil);
|
|
@@ -803,6 +832,9 @@ async function startAgent(step, opts = { prompt: '' }) {
|
|
|
803
832
|
log(fmt.status('WARN', `Could not persist blocklist entry for ${fmt.agent(chosen || '')}: ${err.message}`));
|
|
804
833
|
}
|
|
805
834
|
}
|
|
835
|
+
else {
|
|
836
|
+
log(fmt.status('INFO', `Skipping blocklist write for ${fmt.agent(chosen || '')}; launch failure looks like a deterministic config/setup error.`));
|
|
837
|
+
}
|
|
806
838
|
chosen = undefined;
|
|
807
839
|
continue;
|
|
808
840
|
}
|
package/lib/agents/agents.ts
CHANGED
|
@@ -10,9 +10,11 @@ import { detectLimitHit, formatBlockUntil, DEFAULT_FALLBACK_HOURS } from './limi
|
|
|
10
10
|
import * as storage from '../core/storage.js';
|
|
11
11
|
import { resolveAgentModel } from '../core/product-config.js';
|
|
12
12
|
import { migrateAgentBlocklists } from '../core/persistent-data-migration.js';
|
|
13
|
+
import { createRequire } from 'node:module';
|
|
13
14
|
// tools/sessions is still CJS (not converted in this wave); require keeps it
|
|
14
15
|
// untyped (any) without pulling a non-included .js into the typecheck program.
|
|
15
|
-
const
|
|
16
|
+
const _require = createRequire(__filename);
|
|
17
|
+
const sessions = _require('../tools/sessions');
|
|
16
18
|
|
|
17
19
|
interface LauncherStatus {
|
|
18
20
|
agent: string;
|
|
@@ -22,6 +24,14 @@ interface LauncherStatus {
|
|
|
22
24
|
reason?: string;
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
interface LaunchResultLike {
|
|
28
|
+
stdout?: string;
|
|
29
|
+
stderr?: string;
|
|
30
|
+
status?: number | null;
|
|
31
|
+
signal?: string | null;
|
|
32
|
+
error?: {code?: string, message?: string} | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
25
35
|
type AgentConfig = { blocklist?: {[key: string]: any}, steps?: {[key: string]: any} };
|
|
26
36
|
|
|
27
37
|
interface StartAgentOptions {
|
|
@@ -100,6 +110,18 @@ const KNOWN_AGENT_NAMES = Object.freeze([
|
|
|
100
110
|
'human'
|
|
101
111
|
]);
|
|
102
112
|
|
|
113
|
+
const NON_BLOCKING_LAUNCH_ERROR_PATTERNS = Object.freeze([
|
|
114
|
+
/\b(?:invalid|unknown|unsupported|unrecognized)\s+model\b/i,
|
|
115
|
+
/\bmodel\s+(?:identifier|id)\s+(?:is\s+)?invalid\b/i,
|
|
116
|
+
/\b(?:model\s+not\s+found|no\s+such\s+model)\b/i,
|
|
117
|
+
/\bunknown\s+option\b/i,
|
|
118
|
+
/\bauth(?:entication)?\b/i,
|
|
119
|
+
/\bunauthorized\b/i,
|
|
120
|
+
/\bforbidden\b/i,
|
|
121
|
+
/\bapi\s+key\b/i,
|
|
122
|
+
/\bread-only file system\b/i
|
|
123
|
+
]);
|
|
124
|
+
|
|
103
125
|
function workflowLauncherStatus(agent: string): LauncherStatus {
|
|
104
126
|
const resolver = RESOLVERS[agent];
|
|
105
127
|
if (!resolver) {
|
|
@@ -146,6 +168,18 @@ function commandInPath(name: string) {
|
|
|
146
168
|
return result.status === 0 && result.stdout.trim().length > 0;
|
|
147
169
|
}
|
|
148
170
|
|
|
171
|
+
function shouldPersistLaunchFailureBlock(agent: string, result: LaunchResultLike | null | undefined) {
|
|
172
|
+
if (!result || agent === 'custom') {return false;}
|
|
173
|
+
const combined = [
|
|
174
|
+
result.stderr || '',
|
|
175
|
+
result.stdout || '',
|
|
176
|
+
result.error?.message || '',
|
|
177
|
+
result.error?.code || ''
|
|
178
|
+
].join('\n');
|
|
179
|
+
if (!combined.trim()) {return true;}
|
|
180
|
+
return !NON_BLOCKING_LAUNCH_ERROR_PATTERNS.some(pattern => pattern.test(combined));
|
|
181
|
+
}
|
|
182
|
+
|
|
149
183
|
function buildInvalidAgentConfigError(configPath: string, scope: string, originalError: {message?: string} | null) {
|
|
150
184
|
const location = path.resolve(configPath);
|
|
151
185
|
const detail = originalError && originalError.message ? originalError.message : 'invalid JSON';
|
|
@@ -869,10 +903,10 @@ async function startAgent(step: string, opts: StartAgentOptions = { prompt: '' }
|
|
|
869
903
|
});
|
|
870
904
|
tried.add(chosen || '');
|
|
871
905
|
launched.add(chosen || '');
|
|
872
|
-
// Block
|
|
873
|
-
//
|
|
874
|
-
//
|
|
875
|
-
if (chosen
|
|
906
|
+
// Block retry candidates only when the failure looks transient. Deterministic
|
|
907
|
+
// setup/config errors (invalid model id, auth failure, read-only HOME, etc.)
|
|
908
|
+
// should fall through to the next family without poisoning agents.local.json.
|
|
909
|
+
if (shouldPersistLaunchFailureBlock(chosen || '', result)) {
|
|
876
910
|
const blockUntil = formatBlockUntil(new Date(Date.now() + DEFAULT_FALLBACK_HOURS * 60 * 60 * 1000));
|
|
877
911
|
try {
|
|
878
912
|
const blockResult = updateAgentBlockFn(chosen || '', blockUntil);
|
|
@@ -880,6 +914,8 @@ async function startAgent(step: string, opts: StartAgentOptions = { prompt: '' }
|
|
|
880
914
|
} catch (err) {
|
|
881
915
|
log(fmt.status('WARN', `Could not persist blocklist entry for ${fmt.agent(chosen || '')}: ${(err as any).message}`));
|
|
882
916
|
}
|
|
917
|
+
} else {
|
|
918
|
+
log(fmt.status('INFO', `Skipping blocklist write for ${fmt.agent(chosen || '')}; launch failure looks like a deterministic config/setup error.`));
|
|
883
919
|
}
|
|
884
920
|
chosen = undefined;
|
|
885
921
|
continue;
|
|
@@ -926,5 +962,6 @@ export {
|
|
|
926
962
|
isInvalidAgentConfigError,
|
|
927
963
|
updateAgentBlock,
|
|
928
964
|
resolveBlocklistTargetPath,
|
|
929
|
-
resolveNoOutputWatchdogConfig
|
|
965
|
+
resolveNoOutputWatchdogConfig,
|
|
966
|
+
shouldPersistLaunchFailureBlock
|
|
930
967
|
};
|
package/lib/agents/claude.js
CHANGED
|
@@ -10,9 +10,11 @@ exports.__setSessionsForTest = __setSessionsForTest;
|
|
|
10
10
|
const spawn_tee_js_1 = require("../core/spawn-tee.js");
|
|
11
11
|
const claude_telemetry_js_1 = require("./claude-telemetry.js");
|
|
12
12
|
Object.defineProperty(exports, "extractClaudeTelemetryFromStdout", { enumerable: true, get: function () { return claude_telemetry_js_1.extractClaudeTelemetryFromStdout; } });
|
|
13
|
+
const node_module_1 = require("node:module");
|
|
13
14
|
// tools/sessions is still CJS (not converted in this wave); require keeps it
|
|
14
15
|
// untyped (any) without pulling a non-included .js into the typecheck program.
|
|
15
|
-
const
|
|
16
|
+
const _require = (0, node_module_1.createRequire)(__filename);
|
|
17
|
+
const sessions = _require('../tools/sessions');
|
|
16
18
|
// Injectable I/O for tests. Production uses the real spawn-tee / export capture.
|
|
17
19
|
let _spawnAndTee = spawn_tee_js_1.spawnAndTee;
|
|
18
20
|
let _sessions = sessions;
|
package/lib/agents/claude.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { spawnAndTee } from '../core/spawn-tee.js';
|
|
2
2
|
import { extractClaudeTelemetryFromStdout } from './claude-telemetry.js';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
3
4
|
// tools/sessions is still CJS (not converted in this wave); require keeps it
|
|
4
5
|
// untyped (any) without pulling a non-included .js into the typecheck program.
|
|
5
|
-
const
|
|
6
|
+
const _require = createRequire(__filename);
|
|
7
|
+
const sessions = _require('../tools/sessions');
|
|
6
8
|
|
|
7
9
|
interface ClaudeInvocationOptions {
|
|
8
10
|
prompt: string;
|
package/lib/agents/codex.js
CHANGED
|
@@ -21,9 +21,11 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
21
21
|
const spawn_tee_js_1 = require("../core/spawn-tee.js");
|
|
22
22
|
const codex_telemetry_js_1 = require("./codex-telemetry.js");
|
|
23
23
|
Object.defineProperty(exports, "extractCodexTelemetry", { enumerable: true, get: function () { return codex_telemetry_js_1.extractCodexTelemetry; } });
|
|
24
|
+
const node_module_1 = require("node:module");
|
|
24
25
|
// tools/sessions is still CJS (not converted in this wave); require keeps it
|
|
25
26
|
// untyped (any) without pulling a non-included .js into the typecheck program.
|
|
26
|
-
const
|
|
27
|
+
const _require = (0, node_module_1.createRequire)(__filename);
|
|
28
|
+
const sessions = _require('../tools/sessions');
|
|
27
29
|
// Injectable I/O for tests. Production uses the real spawn-tee / export capture.
|
|
28
30
|
let _spawnAndTee = spawn_tee_js_1.spawnAndTee;
|
|
29
31
|
let _sessions = sessions;
|
package/lib/agents/codex.ts
CHANGED
|
@@ -3,9 +3,11 @@ import os from 'node:os';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { spawnAndTee } from '../core/spawn-tee.js';
|
|
5
5
|
import { extractCodexTelemetry } from './codex-telemetry.js';
|
|
6
|
+
import { createRequire } from 'node:module';
|
|
6
7
|
// tools/sessions is still CJS (not converted in this wave); require keeps it
|
|
7
8
|
// untyped (any) without pulling a non-included .js into the typecheck program.
|
|
8
|
-
const
|
|
9
|
+
const _require = createRequire(__filename);
|
|
10
|
+
const sessions = _require('../tools/sessions');
|
|
9
11
|
|
|
10
12
|
interface CodexInvocationOptions {
|
|
11
13
|
prompt: string;
|
package/lib/agents/opencode.js
CHANGED
|
@@ -17,11 +17,13 @@ const spawn_tee_js_1 = require("../core/spawn-tee.js");
|
|
|
17
17
|
const opencode_telemetry_js_1 = require("./opencode-telemetry.js");
|
|
18
18
|
const opencode_export_js_1 = require("./opencode-export.js");
|
|
19
19
|
const limit_hit_js_1 = require("./limit-hit.js");
|
|
20
|
+
const node_module_1 = require("node:module");
|
|
20
21
|
// tools/sessions and core/subagent-limit are still CJS (not converted in this
|
|
21
22
|
// wave); require keeps them untyped (any) without pulling non-included .js into
|
|
22
23
|
// the typecheck program.
|
|
23
|
-
const
|
|
24
|
-
const
|
|
24
|
+
const _require = (0, node_module_1.createRequire)(__filename);
|
|
25
|
+
const sessions = _require('../tools/sessions');
|
|
26
|
+
const { buildSubagentLimitPrefix } = _require('../core/subagent-limit');
|
|
25
27
|
// Injectable I/O for tests. Production uses the real spawn-tee / export capture.
|
|
26
28
|
let _spawnAndTee = spawn_tee_js_1.spawnAndTee;
|
|
27
29
|
let _captureExport = opencode_export_js_1.captureOpencodeExport;
|
|
@@ -93,7 +95,7 @@ function checkJsonFormatSupport() {
|
|
|
93
95
|
return _jsonFormatSupported;
|
|
94
96
|
}
|
|
95
97
|
try {
|
|
96
|
-
const { spawnSync } =
|
|
98
|
+
const { spawnSync } = _require('node:child_process');
|
|
97
99
|
const result = spawnSync('opencode', ['--format', 'json', '--help'], {
|
|
98
100
|
timeout: 3000,
|
|
99
101
|
stdio: ['ignore', 'pipe', 'pipe'],
|
package/lib/agents/opencode.ts
CHANGED
|
@@ -2,11 +2,13 @@ import { spawnAndTee } from '../core/spawn-tee.js';
|
|
|
2
2
|
import { extractOpencodeTelemetryFromExport } from './opencode-telemetry.js';
|
|
3
3
|
import { captureOpencodeExport } from './opencode-export.js';
|
|
4
4
|
import { detectLimitHit } from './limit-hit.js';
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
5
6
|
// tools/sessions and core/subagent-limit are still CJS (not converted in this
|
|
6
7
|
// wave); require keeps them untyped (any) without pulling non-included .js into
|
|
7
8
|
// the typecheck program.
|
|
8
|
-
const
|
|
9
|
-
const
|
|
9
|
+
const _require = createRequire(__filename);
|
|
10
|
+
const sessions = _require('../tools/sessions');
|
|
11
|
+
const { buildSubagentLimitPrefix } = _require('../core/subagent-limit');
|
|
10
12
|
|
|
11
13
|
interface BuildOpencodeInvocationOptions {
|
|
12
14
|
prompt: string;
|
|
@@ -105,7 +107,7 @@ function checkJsonFormatSupport() {
|
|
|
105
107
|
return _jsonFormatSupported;
|
|
106
108
|
}
|
|
107
109
|
try {
|
|
108
|
-
const { spawnSync } =
|
|
110
|
+
const { spawnSync } = _require('node:child_process');
|
|
109
111
|
const result = spawnSync('opencode', ['--format', 'json', '--help'], {
|
|
110
112
|
timeout: 3000,
|
|
111
113
|
stdio: ['ignore', 'pipe', 'pipe'],
|
package/lib/commands/active.js
CHANGED
|
@@ -32,12 +32,26 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.active = void 0;
|
|
40
|
+
exports.buildExecutePrompt = buildExecutePrompt;
|
|
41
|
+
exports.buildCheckpointContext = buildCheckpointContext;
|
|
42
|
+
exports.runHandoffAndReview = runHandoffAndReview;
|
|
43
|
+
exports.applyExecuteFallback = applyExecuteFallback;
|
|
44
|
+
exports.selectLaunchAndRecord = selectLaunchAndRecord;
|
|
45
|
+
exports.validateCheckpointsBeforeHandoff = validateCheckpointsBeforeHandoff;
|
|
46
|
+
exports.attemptAgentRelaunch = attemptAgentRelaunch;
|
|
47
|
+
exports.enforceExecuteCommitSafety = enforceExecuteCommitSafety;
|
|
48
|
+
exports.unquoteGitStatusPath = unquoteGitStatusPath;
|
|
35
49
|
// @ts-nocheck
|
|
36
50
|
const git_js_1 = require("../core/git.js");
|
|
37
51
|
const fs = __importStar(require("node:fs"));
|
|
38
52
|
const path = __importStar(require("node:path"));
|
|
39
53
|
const fmt = __importStar(require("../core/fmt.js"));
|
|
40
|
-
const
|
|
54
|
+
const mission_start_js_1 = __importDefault(require("./mission-start.js"));
|
|
41
55
|
const agents = __importStar(require("../agents/agents.js"));
|
|
42
56
|
const mission_utils_js_1 = require("../core/mission-utils.js");
|
|
43
57
|
const handoff = __importStar(require("./handoff.js"));
|
|
@@ -53,7 +67,7 @@ const EXECUTE_PROMPT_PATH = path.join(__dirname, '..', '..', 'prompts', 'execute
|
|
|
53
67
|
* @param {{inferSlugFn?: Function, missionStartFn?: Function, resolveWorktreeFn?: Function, readAgentConfigOrExitFn?: Function, resolveTaskFileFn?: Function, buildCheckpointContextFn?: Function, buildExecutePromptFn?: Function, selectLaunchAndRecordFn?: Function, enforceExecuteCommitSafetyFn?: Function, runHandoffAndReviewFn?: Function, exitFn?: Function, logFn?: Function, errorFn?: Function}} [options]
|
|
54
68
|
*/
|
|
55
69
|
async function active(args, options = {}) {
|
|
56
|
-
const { inferSlugFn = mission_utils_js_1.inferSlug, missionStartFn =
|
|
70
|
+
const { inferSlugFn = mission_utils_js_1.inferSlug, missionStartFn = mission_start_js_1.default, resolveWorktreeFn = mission_utils_js_1.resolveWorktree, readAgentConfigOrExitFn = agents.readAgentConfigOrExit, resolveTaskFileFn = backlog_js_1.resolveTaskFile, buildCheckpointContextFn = buildCheckpointContext, buildExecutePromptFn = buildExecutePrompt, selectLaunchAndRecordFn = selectLaunchAndRecord, enforceExecuteCommitSafetyFn = enforceExecuteCommitSafety, runHandoffAndReviewFn = runHandoffAndReview, exitFn = process.exit, logFn = fmt.log.info, errorFn = fmt.log.fail } = options;
|
|
57
71
|
const explicitSlug = args[0];
|
|
58
72
|
const slug = inferSlugFn(explicitSlug);
|
|
59
73
|
if (!slug) {
|
|
@@ -591,4 +605,8 @@ function enforceExecuteCommitSafety(opts) {
|
|
|
591
605
|
}
|
|
592
606
|
/** @type {typeof active & {buildExecutePrompt: typeof buildExecutePrompt, buildCheckpointContext: typeof buildCheckpointContext, runHandoffAndReview: typeof runHandoffAndReview, applyExecuteFallback: typeof applyExecuteFallback, selectLaunchAndRecord: typeof selectLaunchAndRecord, validateCheckpointsBeforeHandoff: typeof validateCheckpointsBeforeHandoff, attemptAgentRelaunch: typeof attemptAgentRelaunch, enforceExecuteCommitSafety: typeof enforceExecuteCommitSafety, unquoteGitStatusPath: typeof unquoteGitStatusPath}} */
|
|
593
607
|
const _activeExport = Object.assign(active, { buildExecutePrompt, buildCheckpointContext, runHandoffAndReview, applyExecuteFallback, selectLaunchAndRecord, validateCheckpointsBeforeHandoff, attemptAgentRelaunch, enforceExecuteCommitSafety, unquoteGitStatusPath });
|
|
594
|
-
|
|
608
|
+
exports.active = _activeExport;
|
|
609
|
+
exports.default = _activeExport;
|
|
610
|
+
if (typeof module !== 'undefined') {
|
|
611
|
+
module.exports = _activeExport;
|
|
612
|
+
}
|
package/lib/commands/active.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { git, getWorktreeStatus } from '../core/git.js';
|
|
|
3
3
|
import * as fs from 'node:fs';
|
|
4
4
|
import * as path from 'node:path';
|
|
5
5
|
import * as fmt from '../core/fmt.js';
|
|
6
|
-
import
|
|
6
|
+
import missionStart from './mission-start.js';
|
|
7
7
|
import * as agents from '../agents/agents.js';
|
|
8
8
|
import { findMissionDir, findCheckpoints, getFirstLine, resolveWorktree, inferSlug, getMissionYear, missionDirForSlug, isWorkflowGeneratedArtifact } from '../core/mission-utils.js';
|
|
9
9
|
import * as handoff from './handoff.js';
|
|
@@ -662,4 +662,9 @@ function enforceExecuteCommitSafety(opts) {
|
|
|
662
662
|
|
|
663
663
|
/** @type {typeof active & {buildExecutePrompt: typeof buildExecutePrompt, buildCheckpointContext: typeof buildCheckpointContext, runHandoffAndReview: typeof runHandoffAndReview, applyExecuteFallback: typeof applyExecuteFallback, selectLaunchAndRecord: typeof selectLaunchAndRecord, validateCheckpointsBeforeHandoff: typeof validateCheckpointsBeforeHandoff, attemptAgentRelaunch: typeof attemptAgentRelaunch, enforceExecuteCommitSafety: typeof enforceExecuteCommitSafety, unquoteGitStatusPath: typeof unquoteGitStatusPath}} */
|
|
664
664
|
const _activeExport = Object.assign(active, { buildExecutePrompt, buildCheckpointContext, runHandoffAndReview, applyExecuteFallback, selectLaunchAndRecord, validateCheckpointsBeforeHandoff, attemptAgentRelaunch, enforceExecuteCommitSafety, unquoteGitStatusPath });
|
|
665
|
-
export
|
|
665
|
+
export default _activeExport;
|
|
666
|
+
export { _activeExport as active, buildExecutePrompt, buildCheckpointContext, runHandoffAndReview, applyExecuteFallback, selectLaunchAndRecord, validateCheckpointsBeforeHandoff, attemptAgentRelaunch, enforceExecuteCommitSafety, unquoteGitStatusPath };
|
|
667
|
+
|
|
668
|
+
// CJS compat: ensure require() returns the function directly
|
|
669
|
+
declare const module: { exports: any } | undefined;
|
|
670
|
+
if (typeof module !== 'undefined') { module.exports = _activeExport; }
|
package/lib/commands/config.js
CHANGED
|
@@ -33,6 +33,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
return result;
|
|
34
34
|
};
|
|
35
35
|
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.config = config;
|
|
36
38
|
const fmt = __importStar(require("../core/fmt.js"));
|
|
37
39
|
const product_config_js_1 = require("../core/product-config.js");
|
|
38
40
|
// `node parallix config` — read-only. Prints the effective configuration:
|
|
@@ -68,4 +70,7 @@ async function config(_args = [], opts = {}) {
|
|
|
68
70
|
}
|
|
69
71
|
logFn(JSON.stringify((0, product_config_js_1.loadEffectiveConfig)(rootDir), null, 2));
|
|
70
72
|
}
|
|
71
|
-
|
|
73
|
+
exports.default = config;
|
|
74
|
+
if (typeof module !== 'undefined') {
|
|
75
|
+
module.exports = config;
|
|
76
|
+
}
|
package/lib/commands/config.ts
CHANGED
|
@@ -44,4 +44,9 @@ async function config(_args: string[] = [], opts: ConfigOptions = {}) {
|
|
|
44
44
|
logFn(JSON.stringify(loadEffectiveConfig(rootDir), null, 2));
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export
|
|
47
|
+
export default config;
|
|
48
|
+
export { config };
|
|
49
|
+
|
|
50
|
+
// CJS compat: ensure require() returns the function directly
|
|
51
|
+
declare const module: { exports: any } | undefined;
|
|
52
|
+
if (typeof module !== 'undefined') { module.exports = config; }
|