@aperant/framework 0.7.4 → 0.8.1
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 +65 -0
- package/README.md +12 -0
- package/agents/apt-executor.md +12 -0
- package/agents/apt-team-docs-narrator.md +11 -0
- package/dist/cli/ci-watch/stop-matrix.d.mts +17 -4
- package/dist/cli/ci-watch/stop-matrix.d.mts.map +1 -1
- package/dist/cli/ci-watch/stop-matrix.mjs +41 -4
- package/dist/cli/ci-watch/stop-matrix.mjs.map +1 -1
- package/dist/cli/commands/fan-out.d.mts +2 -0
- package/dist/cli/commands/fan-out.d.mts.map +1 -0
- package/dist/cli/commands/fan-out.mjs +123 -0
- package/dist/cli/commands/fan-out.mjs.map +1 -0
- package/dist/cli/commands/init.d.mts.map +1 -1
- package/dist/cli/commands/init.mjs +67 -27
- package/dist/cli/commands/init.mjs.map +1 -1
- package/dist/cli/commands/modes.d.mts +22 -0
- package/dist/cli/commands/modes.d.mts.map +1 -1
- package/dist/cli/commands/modes.mjs +4 -1
- package/dist/cli/commands/modes.mjs.map +1 -1
- package/dist/cli/commands/pr-review-audit-fixer.d.mts.map +1 -1
- package/dist/cli/commands/pr-review-audit-fixer.mjs +86 -6
- package/dist/cli/commands/pr-review-audit-fixer.mjs.map +1 -1
- package/dist/cli/commands/roadmap.d.mts +1 -1
- package/dist/cli/commands/roadmap.d.mts.map +1 -1
- package/dist/cli/commands/roadmap.mjs +47 -4
- package/dist/cli/commands/roadmap.mjs.map +1 -1
- package/dist/cli/commands/task.d.mts.map +1 -1
- package/dist/cli/commands/task.mjs +15 -0
- package/dist/cli/commands/task.mjs.map +1 -1
- package/dist/cli/commands/validate-evidence.d.mts +1 -1
- package/dist/cli/commands/validate-evidence.d.mts.map +1 -1
- package/dist/cli/commands/validate-evidence.mjs +72 -47
- package/dist/cli/commands/validate-evidence.mjs.map +1 -1
- package/dist/cli/commands/wave.d.mts.map +1 -1
- package/dist/cli/commands/wave.mjs +91 -61
- package/dist/cli/commands/wave.mjs.map +1 -1
- package/dist/cli/commands/worktree.mjs +62 -3
- package/dist/cli/commands/worktree.mjs.map +1 -1
- package/dist/cli/config/load.mjs +1 -1
- package/dist/cli/config/load.mjs.map +1 -1
- package/dist/cli/config/parallelization.d.mts +14 -0
- package/dist/cli/config/parallelization.d.mts.map +1 -0
- package/dist/cli/config/parallelization.mjs +19 -0
- package/dist/cli/config/parallelization.mjs.map +1 -0
- package/dist/cli/coordination/agent-identity.d.mts.map +1 -1
- package/dist/cli/coordination/agent-identity.mjs +7 -1
- package/dist/cli/coordination/agent-identity.mjs.map +1 -1
- package/dist/cli/design/frontmatter-schema.d.mts +4 -4
- package/dist/cli/dispatch.d.mts.map +1 -1
- package/dist/cli/dispatch.mjs +2 -0
- package/dist/cli/dispatch.mjs.map +1 -1
- package/dist/cli/install/cli-to-install-root.d.mts.map +1 -1
- package/dist/cli/install/cli-to-install-root.mjs +0 -2
- package/dist/cli/install/cli-to-install-root.mjs.map +1 -1
- package/dist/cli/install/runtime-detect.d.mts +2 -6
- package/dist/cli/install/runtime-detect.d.mts.map +1 -1
- package/dist/cli/install/runtime-detect.mjs +8 -3
- package/dist/cli/install/runtime-detect.mjs.map +1 -1
- package/dist/cli/install/transforms/pi.d.mts +6 -0
- package/dist/cli/install/transforms/pi.d.mts.map +1 -0
- package/dist/cli/install/transforms/pi.mjs +37 -0
- package/dist/cli/install/transforms/pi.mjs.map +1 -0
- package/dist/cli/personas/sidecar.d.mts +1 -1
- package/dist/cli/roadmap/convex-mirror.d.mts +21 -0
- package/dist/cli/roadmap/convex-mirror.d.mts.map +1 -0
- package/dist/cli/roadmap/convex-mirror.mjs +133 -0
- package/dist/cli/roadmap/convex-mirror.mjs.map +1 -0
- package/dist/cli/roadmap/lifecycle.d.mts +1 -1
- package/dist/cli/roadmap/lifecycle.d.mts.map +1 -1
- package/dist/cli/roadmap/lifecycle.mjs +54 -0
- package/dist/cli/roadmap/lifecycle.mjs.map +1 -1
- package/dist/cli/roadmap/rollup.d.mts +2 -2
- package/dist/cli/wfrun/unit-shape.d.mts +27 -0
- package/dist/cli/wfrun/unit-shape.d.mts.map +1 -0
- package/dist/cli/wfrun/unit-shape.mjs +38 -0
- package/dist/cli/wfrun/unit-shape.mjs.map +1 -0
- package/dist/plugin/.claude-plugin/plugin.json +2 -1
- package/dist/plugin/agents/apt-executor.md +12 -0
- package/dist/plugin/agents/apt-team-docs-narrator.md +11 -0
- package/dist/plugin/skills/apt/SKILL.md +3 -2
- package/dist/plugin/skills/apt-execute/SKILL.md +13 -0
- package/dist/plugin/skills/apt-fan-out/SKILL.md +124 -0
- package/dist/plugin/skills/apt-pr-review/SKILL.md +8 -1
- package/dist/plugin/skills/apt-review/SKILL.md +4 -0
- package/dist/plugin/skills/apt-run/SKILL.md +20 -5
- package/dist/plugin/skills/apt-spar/SKILL.md +12 -9
- package/dist/plugin/skills/apt-verify/SKILL.md +11 -0
- package/dist/plugin/skills/apt-watch-ci/SKILL.md +2 -2
- package/dist/schemas/quick-task.d.ts +17 -17
- package/package.json +133 -133
- package/skills/apt/SKILL.md +3 -2
- package/skills/apt-execute/SKILL.md +13 -0
- package/skills/apt-fan-out/SKILL.md +124 -0
- package/skills/apt-review/SKILL.md +4 -0
- package/skills/apt-run/SKILL.md +20 -5
- package/skills/apt-spar/SKILL.md +12 -9
- package/skills/apt-verify/SKILL.md +11 -0
- package/skills/apt-watch-ci/SKILL.md +2 -2
- package/src/cli/ci-watch/stop-matrix.mjs +44 -4
- package/src/cli/commands/fan-out.mjs +129 -0
- package/src/cli/commands/init.mjs +66 -27
- package/src/cli/commands/modes.mjs +4 -1
- package/src/cli/commands/pr-review-audit-fixer.mjs +82 -6
- package/src/cli/commands/roadmap.mjs +48 -4
- package/src/cli/commands/task.mjs +15 -0
- package/src/cli/commands/validate-evidence.mjs +75 -50
- package/src/cli/commands/wave.mjs +91 -58
- package/src/cli/commands/worktree.mjs +56 -3
- package/src/cli/config/load.mjs +1 -1
- package/src/cli/config/parallelization.mjs +18 -0
- package/src/cli/coordination/agent-identity.mjs +9 -1
- package/src/cli/dispatch.mjs +2 -0
- package/src/cli/install/cli-to-install-root.mjs +0 -2
- package/src/cli/install/runtime-detect.mjs +8 -3
- package/src/cli/install/transforms/pi.mjs +37 -0
- package/src/cli/roadmap/convex-mirror.mjs +131 -0
- package/src/cli/roadmap/lifecycle.mjs +48 -0
- package/src/cli/wfrun/unit-shape.mjs +39 -0
- package/templates/config.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,71 @@ All notable changes to `@aperant/framework` are documented here. See
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## 0.8.1 — 2026-05-20 — Pi runtime + idempotent re-init repair
|
|
9
|
+
|
|
10
|
+
Patch release making `apt-tools init` safe to rerun on another machine after
|
|
11
|
+
pulling a current `.aperant/config.json`.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Current-schema `init` no longer returns `up_to_date` when explicit runtime
|
|
16
|
+
flags were passed or when suggested runtime roots are missing
|
|
17
|
+
`apt-file-manifest.json`; it reruns the runtime installer for those roots.
|
|
18
|
+
- True no-op behavior is preserved when no runtime roots are suggested and no
|
|
19
|
+
explicit runtime flags are passed.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- Pi is now an installable runtime via `--pi`, with files written under
|
|
24
|
+
`.pi/skills/` and `.pi/prompts/`.
|
|
25
|
+
- `cliToInstallRoot('pi')` now resolves to `.pi`.
|
|
26
|
+
|
|
27
|
+
### Version
|
|
28
|
+
|
|
29
|
+
- `packages/framework/package.json`: 0.8.0 → 0.8.1
|
|
30
|
+
- CLI golden fixtures refreshed
|
|
31
|
+
|
|
32
|
+
## 0.8.0 — 2026-05-20 — cross-task fan-out + 5 framework defects (BUG-033..038)
|
|
33
|
+
|
|
34
|
+
Minor release. Ships the new `/apt:fan-out` skill (cross-task parallelization from a single conductor terminal) and closes five framework defects surfaced during real `/apt:run` pipelines. Includes one behavioral default change (`task_isolation.from_branch` now defaults to `main`, not `current`).
|
|
35
|
+
|
|
36
|
+
### New capability: `/apt:fan-out`
|
|
37
|
+
|
|
38
|
+
Cross-task parallelization from one conductor terminal. The host CLI's main thread spawns N `apt-executor` sub-agents via Task tool `run_in_background: true`, each pinned to its own task-level worktree. Accepts `--tasks <id-list>` (canonical), `--phases <m/p>` (policy front), `--unblocked` (auto-pick from roadmap ready-state). Default concurrency cap `parallelization.max_tasks: 4`.
|
|
39
|
+
|
|
40
|
+
Built on the **generalized wave engine**: `wave.mjs` + `wfrun/dag.mjs` now accept `unit_kind: "subtask" | "task"` so task-level fan-out reuses the same primitives (`apt-tools lock`, JSONL event log, `max_agents` quota) as the existing subtask wave-parallel mode. Subtask path is bit-equivalent (locked by snapshot test).
|
|
41
|
+
|
|
42
|
+
ADRs documenting the locked decisions:
|
|
43
|
+
- ADR-0001 worker subagent topology (host CLI Task tool background spawn)
|
|
44
|
+
- ADR-0002 paired skill surface (mechanism + policy split)
|
|
45
|
+
- ADR-0003 conductor identity (host CLI main thread; never daemon)
|
|
46
|
+
|
|
47
|
+
### Defects fixed
|
|
48
|
+
|
|
49
|
+
- **FRAMEWORK-BUG-033** — cross-task fan-out gap (the umbrella above) bundled the four lifecycle/identity sub-defects:
|
|
50
|
+
- Phase auto-completion sibling-guard bug in `lifecycle.mjs` (16-task phase flipping to `completed` on first close)
|
|
51
|
+
- Durable `assigned_to` field on task records
|
|
52
|
+
- `APT_AGENT_ID=fanout-${batch_id}-${task_id}` export from `apt-executor` for stable per-worker identity
|
|
53
|
+
- Wave engine generalization to accept either subtask or task as `unit_id`
|
|
54
|
+
- **FRAMEWORK-BUG-034** — `validate-evidence` parser self-reference. Stamper inserted `- **Validation Status**: ...` using the same `- **...**:` field-form shape its own regex matched; on subsequent passes the parser dismissed 88% of LLM-validated findings as `evidence_not_literal` by reading its own stamped text as the cited evidence. Fix: writer emits trailing `### Validation Metadata` section; reader strips legacy field-form Status/Note before evidence extraction. Dual-shape reader for back-compat.
|
|
55
|
+
- **FRAMEWORK-BUG-035** — `pr-review-audit-fixer` parser only matched `### {ID}` finding headers, not the canonical `## Fix N` shape per FRAMEWORK-BUG-030. Returned `<none parsed>` + false-positive `hallucinated` verdict despite real commits. Fix: new `parseFixNEntries` with finding-ID extraction via priority chain `**Finding ID**:` → `**Fix**:` → `**ID**:` → synthetic.
|
|
56
|
+
- **FRAMEWORK-BUG-036** — lifecycle phase didn't auto-advance through `apt:execute` / `apt:verify` / `apt:review` SKILL.md success-paths. Only `/apt:ship` flipped the phase (and only from `reviewing`, which never happened). Fix: each skill adds ONE `task update --lifecycle-phase` call at success-end, advancing `executing` → `verifying` → `reviewing`. `/apt:ship` atomic `reviewing → shipped-pending-merge` flip now fires reliably.
|
|
57
|
+
- **FRAMEWORK-BUG-037** — `task_isolation.from_branch: "current"` default silently chained WIP commits into new task PRs. **Behavioral default change**: now `"main"` with main-detection chain (`origin/HEAD` → `origin/main` → `origin/master` → local `main` / `master`). Explicit `--from-branch current` / `--from-branch HEAD` preserved for power users who want chaining. Projects with explicit `from_branch` in their own `.aperant/config.json` are unaffected.
|
|
58
|
+
- **FRAMEWORK-BUG-038** — `/apt:spar` Round-1 `verdict=cede` terminated unilaterally, collapsing every multi-round session to one round. Two SKILL.md edits: partner prompt template now requires `NEXT_WEAKEST_POINT`; Step 8 splits cede semantics — `--rounds 1` explicit terminates, `--rounds >= 2` (default) emits `next-round` regardless and requires two consecutive same-disposition rounds for convergence. No new flags, no new skills.
|
|
59
|
+
|
|
60
|
+
### Version
|
|
61
|
+
|
|
62
|
+
- `packages/framework/package.json`: 0.7.4 → 0.8.0
|
|
63
|
+
- `cli-baseline-version.txt` + `cli-baseline-help.txt` fixtures bumped
|
|
64
|
+
|
|
65
|
+
### Commits
|
|
66
|
+
|
|
67
|
+
- feat(framework): cross-task fan-out + 4 lifecycle/identity fixes (#208) — bd099c8f
|
|
68
|
+
- fix(framework): apt:spar Round-1 collapse (#210) — 567a63d0
|
|
69
|
+
- fix(framework): validate-evidence + audit-fixer parsers (#211) — 0f28a1af
|
|
70
|
+
- fix(framework): lifecycle auto-advance + from-branch default (#214) — b1abcb65
|
|
71
|
+
- (this one) — chore(framework): 0.8.0 — cross-task fan-out + 5 framework defects (BUG-033..038)
|
|
72
|
+
|
|
8
73
|
## 0.7.4 — 2026-05-18 — apt-pr-review context-budget skip prohibition
|
|
9
74
|
|
|
10
75
|
Docs-only patch release hardening the `apt-pr-review` "Fix Everything" contract against a live failure pattern where an orchestrator dropped confirmed minor findings mid-Phase-6 because its own context window felt heavy ("my orchestrator window was getting heavy after 6 specialist rounds + Round 1 work"). Pre-existing rule 5 in §Context Budget Rules already forbade skipping *phases*; this release closes the per-finding gap inside Phase 6.
|
package/README.md
CHANGED
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
npx @aperant/framework init .
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
+
For non-interactive install or re-init across common runtimes:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx @aperant/framework init . --claude --codex --pi --yes
|
|
18
|
+
```
|
|
19
|
+
|
|
14
20
|
## Usage
|
|
15
21
|
|
|
16
22
|
Just type `/apt` and describe what you want in natural language. The router classifies your input and dispatches to the right skill.
|
|
@@ -25,6 +31,12 @@ Just type `/apt` and describe what you want in natural language. The router clas
|
|
|
25
31
|
|
|
26
32
|
You can also call any skill directly (e.g. `/apt:plan ...`, `/apt:debug ...`).
|
|
27
33
|
|
|
34
|
+
Runtime command surfaces differ slightly:
|
|
35
|
+
|
|
36
|
+
- Claude: `/apt:plan`
|
|
37
|
+
- Codex: `/apt-plan`
|
|
38
|
+
- Pi: `/apt`, `/apt:plan` via `.pi/prompts/`
|
|
39
|
+
|
|
28
40
|
## Available commands
|
|
29
41
|
|
|
30
42
|
| Stage | Command | Purpose |
|
package/agents/apt-executor.md
CHANGED
|
@@ -46,6 +46,18 @@ node packages/framework/bin/apt-tools.mjs gate check . --task-id {task-id} --ski
|
|
|
46
46
|
|
|
47
47
|
If `status == "fail"`, STOP. Report the failed gates verbatim and exit — do NOT auto-apply `--force`. Forcing is a human decision; the user can re-invoke with `--force --reason "<explanation>"` to bypass (the override is logged to `.aperant/events/{today}.jsonl`).
|
|
48
48
|
|
|
49
|
+
## 0a. Fan-out worker identity (FRAMEWORK-BUG-033 defect 3)
|
|
50
|
+
|
|
51
|
+
If your spawn prompt contains both `batch_id` and `task_id` (i.e. you are a fan-out worker subagent dispatched by `/apt:fan-out`), export `APT_AGENT_ID` in EVERY `Bash` invocation that runs `apt-tools ...`:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
APT_AGENT_ID=fanout-${batch_id}-${task_id} node packages/framework/bin/apt-tools.mjs <command> ...
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This pins your `team-status/{agentId}.json` file across short-lived CLI invocations. Without it, each `apt-tools` call gets a fresh `hostname-pid` agentId (per `agent-identity.mjs:86`), the previous pid dies, and `listTeamStatus({ includeStale: false })` filters healthy workers out between invocations — the team-status dashboard flickers into emptiness instead of showing 4 stable fan-out workers.
|
|
58
|
+
|
|
59
|
+
Non-fan-out invocations of this agent receive no `batch_id` and skip this export — the legacy `hostname-pid` path remains correct for single-task work.
|
|
60
|
+
|
|
49
61
|
## 1. Load Context
|
|
50
62
|
|
|
51
63
|
1. Read `CLAUDE.md` and `AGENTS.md` if they exist
|
|
@@ -72,6 +72,17 @@ If the parent spawned you without a mode you recognize, write an error line to `
|
|
|
72
72
|
rendered table. If present, REPLACE the content between anchors (never
|
|
73
73
|
append — this is how re-runs stay idempotent).
|
|
74
74
|
7. Call `apt-tools roadmap sync . --reason 'narrator:phase-ship:<phase_id>'`.
|
|
75
|
+
8. **Slice 5 / AC14 / ADR-0006 dual-write.** Write the rendered prose
|
|
76
|
+
block to a temp file (e.g. `mktemp -t narrator-prose-XXXXXX.md`), then
|
|
77
|
+
run
|
|
78
|
+
`apt-tools roadmap convex-mirror . --scope <scope> --phase <phase_id> --anchor-id phase-ship:<phase_id> --prose-path <tempfile>`
|
|
79
|
+
(add `--merged-pr <pr-number>` when known). The markdown write from
|
|
80
|
+
step 7 is canonical (ADR-0006); this step is the Convex mirror.
|
|
81
|
+
Fail-soft contract:
|
|
82
|
+
- exit 0 with `status:ok` or `status:queued` → continue normally
|
|
83
|
+
- exit non-zero with `status:error` → append the error message to
|
|
84
|
+
`.aperant/digests/errors.log` and continue (do NOT block on Convex
|
|
85
|
+
failures; the in-process cron drainer reconciles within 5 min)
|
|
75
86
|
|
|
76
87
|
## Mode 2: `decision-merge` — merge a recorded decision into the roadmap
|
|
77
88
|
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @typedef {Object} CheckRow
|
|
3
3
|
* @property {string} [name]
|
|
4
|
-
* @property {string} [
|
|
5
|
-
*
|
|
4
|
+
* @property {string} [state] Primary per-check status (gh-CLI uppercase enum):
|
|
5
|
+
* 'SUCCESS' | 'FAILURE' | 'CANCELLED' | 'TIMED_OUT' | 'SKIPPED' |
|
|
6
|
+
* 'IN_PROGRESS' | 'QUEUED' | 'PENDING' | 'NEUTRAL'.
|
|
7
|
+
* @property {string} [conclusion] Legacy lowercase per-check field
|
|
8
|
+
* (deprecated — gh dropped it from `pr checks --json` schema circa 2.65).
|
|
9
|
+
* Retained only as a soft fallback for in-memory test fixtures
|
|
10
|
+
* (FRAMEWORK-BUG-016).
|
|
6
11
|
* @property {string} [bucket]
|
|
7
12
|
* @property {string} [failure_class] — optional pre-classified hint (test-only seam)
|
|
8
13
|
* @property {string} [log_fingerprint] — optional digest for identical-log detection
|
|
@@ -25,10 +30,18 @@ export function isFailing(check: any): boolean;
|
|
|
25
30
|
export type CheckRow = {
|
|
26
31
|
name?: string | undefined;
|
|
27
32
|
/**
|
|
28
|
-
*
|
|
33
|
+
* Primary per-check status (gh-CLI uppercase enum):
|
|
34
|
+
* 'SUCCESS' | 'FAILURE' | 'CANCELLED' | 'TIMED_OUT' | 'SKIPPED' |
|
|
35
|
+
* 'IN_PROGRESS' | 'QUEUED' | 'PENDING' | 'NEUTRAL'.
|
|
29
36
|
*/
|
|
30
|
-
conclusion?: string | undefined;
|
|
31
37
|
state?: string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Legacy lowercase per-check field
|
|
40
|
+
* (deprecated — gh dropped it from `pr checks --json` schema circa 2.65).
|
|
41
|
+
* Retained only as a soft fallback for in-memory test fixtures
|
|
42
|
+
* (FRAMEWORK-BUG-016).
|
|
43
|
+
*/
|
|
44
|
+
conclusion?: string | undefined;
|
|
32
45
|
bucket?: string | undefined;
|
|
33
46
|
/**
|
|
34
47
|
* — optional pre-classified hint (test-only seam)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stop-matrix.d.mts","sourceRoot":"","sources":["../../../src/cli/ci-watch/stop-matrix.mjs"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"stop-matrix.d.mts","sourceRoot":"","sources":["../../../src/cli/ci-watch/stop-matrix.mjs"],"names":[],"mappings":"AAoCA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wDAHW,aAAa,GACX,cAAc,CAuJ1B;AAED,+CAuBC;;;;;;;;;;;;;;;;;;;;;;;;;;;YA1La,QAAQ,EAAE;;;;WACV,MAAM;;;;gBACN,MAAM;;;YAGN,MAAM;0BACN,OAAO;YACP,MAAM"}
|
|
@@ -5,11 +5,17 @@
|
|
|
5
5
|
* { action, counts_toward_budget, reason }
|
|
6
6
|
*
|
|
7
7
|
* No I/O, no fs, no gh CLI shell-outs — caller pre-fetches `checks` (the
|
|
8
|
-
* payload from `gh pr checks --json name,bucket,state,
|
|
8
|
+
* payload from `gh pr checks --json name,bucket,state,link,workflow,completedAt`)
|
|
9
9
|
* and `prMetadata` (`gh pr view --json state,reviewDecision`) and passes them
|
|
10
10
|
* in. The orchestrator in commands/ci-watch.mjs handles the side effects
|
|
11
11
|
* implied by the action.
|
|
12
12
|
*
|
|
13
|
+
* Primary per-check signal is `state` (uppercase per gh-CLI: SUCCESS,
|
|
14
|
+
* FAILURE, CANCELLED, TIMED_OUT, SKIPPED, IN_PROGRESS, QUEUED, PENDING,
|
|
15
|
+
* NEUTRAL). The legacy lowercase per-check field that gh dropped circa
|
|
16
|
+
* 2.65 is kept as a soft fallback for in-memory test fixtures only —
|
|
17
|
+
* production gh payloads no longer expose it (FRAMEWORK-BUG-016).
|
|
18
|
+
*
|
|
13
19
|
* Predicate order matters — short-circuits go first (merged/closed/green/cap
|
|
14
20
|
* fire before any per-check inspection). See spec.md §9 table for the full
|
|
15
21
|
* ordering.
|
|
@@ -28,8 +34,13 @@ const INFRA_FAILURE_CLASSES = new Set(['runner-oom', 'runner-cancelled', 'gh-5xx
|
|
|
28
34
|
/**
|
|
29
35
|
* @typedef {Object} CheckRow
|
|
30
36
|
* @property {string} [name]
|
|
31
|
-
* @property {string} [
|
|
32
|
-
*
|
|
37
|
+
* @property {string} [state] Primary per-check status (gh-CLI uppercase enum):
|
|
38
|
+
* 'SUCCESS' | 'FAILURE' | 'CANCELLED' | 'TIMED_OUT' | 'SKIPPED' |
|
|
39
|
+
* 'IN_PROGRESS' | 'QUEUED' | 'PENDING' | 'NEUTRAL'.
|
|
40
|
+
* @property {string} [conclusion] Legacy lowercase per-check field
|
|
41
|
+
* (deprecated — gh dropped it from `pr checks --json` schema circa 2.65).
|
|
42
|
+
* Retained only as a soft fallback for in-memory test fixtures
|
|
43
|
+
* (FRAMEWORK-BUG-016).
|
|
33
44
|
* @property {string} [bucket]
|
|
34
45
|
* @property {string} [failure_class] — optional pre-classified hint (test-only seam)
|
|
35
46
|
* @property {string} [log_fingerprint] — optional digest for identical-log detection
|
|
@@ -60,7 +71,15 @@ export function classify({ checks, state, prMetadata }) {
|
|
|
60
71
|
return { action: 'closed', counts_toward_budget: false, reason: 'pr is closed unmerged' };
|
|
61
72
|
}
|
|
62
73
|
const failed = rows.filter((c) => isFailing(c));
|
|
63
|
-
|
|
74
|
+
// FRAMEWORK-BUG-016: `state` is gh-CLI's primary per-check field post-2.65.
|
|
75
|
+
// SKIPPED rows (workflow `if:` guards that didn't trip) are
|
|
76
|
+
// success-equivalent — they intentionally did not run and that is OK.
|
|
77
|
+
// Soft fallback to the legacy lowercase field keeps the in-memory test
|
|
78
|
+
// fixtures green (production gh payloads never hit it).
|
|
79
|
+
const isGreenRow = (c) => c.state === 'SUCCESS' ||
|
|
80
|
+
c.state === 'SKIPPED' ||
|
|
81
|
+
(c.state == null && c.conclusion === 'success');
|
|
82
|
+
const allGreen = rows.length > 0 && rows.every(isGreenRow);
|
|
64
83
|
// 3. All checks green.
|
|
65
84
|
if (allGreen) {
|
|
66
85
|
return { action: 'green', counts_toward_budget: false, reason: 'all checks succeeded' };
|
|
@@ -174,6 +193,24 @@ export function classify({ checks, state, prMetadata }) {
|
|
|
174
193
|
};
|
|
175
194
|
}
|
|
176
195
|
export function isFailing(check) {
|
|
196
|
+
// FRAMEWORK-BUG-016 / BUG-025: prefer the uppercase `state` field that gh
|
|
197
|
+
// 2.65+ exposes. SKIPPED / NEUTRAL / IN_PROGRESS / QUEUED / PENDING /
|
|
198
|
+
// SUCCESS are explicitly NOT red — SKIPPED in particular must never
|
|
199
|
+
// burn a fix attempt (workflow `if:` guards routinely skip jobs on PRs
|
|
200
|
+
// that don't trip them). The legacy lowercase field is a soft fallback
|
|
201
|
+
// for in-memory test fixtures only.
|
|
202
|
+
const s = check.state;
|
|
203
|
+
if (s === 'SUCCESS' ||
|
|
204
|
+
s === 'SKIPPED' ||
|
|
205
|
+
s === 'NEUTRAL' ||
|
|
206
|
+
s === 'IN_PROGRESS' ||
|
|
207
|
+
s === 'QUEUED' ||
|
|
208
|
+
s === 'PENDING') {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
if (s === 'FAILURE' || s === 'CANCELLED' || s === 'TIMED_OUT') {
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
177
214
|
const c = check.conclusion;
|
|
178
215
|
return c === 'failure' || c === 'cancelled' || c === 'timed_out' || c === 'action_required';
|
|
179
216
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stop-matrix.mjs","sourceRoot":"","sources":["../../../src/cli/ci-watch/stop-matrix.mjs"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"stop-matrix.mjs","sourceRoot":"","sources":["../../../src/cli/ci-watch/stop-matrix.mjs"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fan-out.d.mts","sourceRoot":"","sources":["../../../src/cli/commands/fan-out.mjs"],"names":[],"mappings":"AAmEA,wHA6DC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* commands/fan-out.mjs — FRAMEWORK-BUG-033 capability gap (ID-04 / ID-05).
|
|
3
|
+
*
|
|
4
|
+
* Single resolver helper for the `/apt:fan-out` SKILL body. Three input
|
|
5
|
+
* forms accepted (`--tasks`, `--phases`, `--unblocked`); all resolve to
|
|
6
|
+
* the canonical `{task_ids, source, batch_id}` shape. The actual
|
|
7
|
+
* orchestration loop (worktree create, worker spawn, polling) lives in
|
|
8
|
+
* the SKILL body — this CLI just materializes the batch.
|
|
9
|
+
*
|
|
10
|
+
* Subcommands: `resolve`.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
13
|
+
import { join, resolve } from 'node:path';
|
|
14
|
+
import { parseFlags } from '../util/args.mjs';
|
|
15
|
+
import { err, ok } from '../util/result.mjs';
|
|
16
|
+
const ID_PATTERN = /^[a-z0-9_-]+$/i;
|
|
17
|
+
function generateBatchId() {
|
|
18
|
+
const d = new Date();
|
|
19
|
+
const yyyy = d.getUTCFullYear();
|
|
20
|
+
const mm = String(d.getUTCMonth() + 1).padStart(2, '0');
|
|
21
|
+
const dd = String(d.getUTCDate()).padStart(2, '0');
|
|
22
|
+
const hex = Math.random().toString(16).slice(2, 8);
|
|
23
|
+
return `fanout-${yyyy}${mm}${dd}-${hex}`;
|
|
24
|
+
}
|
|
25
|
+
function parseIdList(raw) {
|
|
26
|
+
if (typeof raw !== 'string')
|
|
27
|
+
return [];
|
|
28
|
+
return raw
|
|
29
|
+
.split(',')
|
|
30
|
+
.map((s) => s.trim())
|
|
31
|
+
.filter(Boolean);
|
|
32
|
+
}
|
|
33
|
+
function readState(targetDir) {
|
|
34
|
+
const statePath = join(targetDir, '.aperant', 'state.json');
|
|
35
|
+
if (!existsSync(statePath))
|
|
36
|
+
return null;
|
|
37
|
+
try {
|
|
38
|
+
return JSON.parse(readFileSync(statePath, 'utf-8'));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function resolveFromPhases(state, phases) {
|
|
45
|
+
const wanted = new Set(phases);
|
|
46
|
+
const ids = [];
|
|
47
|
+
for (const [id, task] of Object.entries(state?.active_tasks || {})) {
|
|
48
|
+
if (!task)
|
|
49
|
+
continue;
|
|
50
|
+
const key = `${task.milestone_id ?? ''}/${task.phase_id ?? ''}`;
|
|
51
|
+
if (wanted.has(key) && task.lifecycle_phase !== 'closed') {
|
|
52
|
+
ids.push(id);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return ids;
|
|
56
|
+
}
|
|
57
|
+
function resolveUnblocked(state) {
|
|
58
|
+
const ids = [];
|
|
59
|
+
for (const [id, task] of Object.entries(state?.active_tasks || {})) {
|
|
60
|
+
if (task?.lifecycle_phase === 'ready-for-agent')
|
|
61
|
+
ids.push(id);
|
|
62
|
+
}
|
|
63
|
+
return ids;
|
|
64
|
+
}
|
|
65
|
+
export function cmdFanOut(subcommand, projectDir, extraArgs) {
|
|
66
|
+
if (!subcommand) {
|
|
67
|
+
return err('Usage: apt-tools fan-out <resolve> <project-dir> [--tasks <ids> | --phases <m/p,m/p> | --unblocked]');
|
|
68
|
+
}
|
|
69
|
+
switch (subcommand) {
|
|
70
|
+
case 'resolve': {
|
|
71
|
+
if (!projectDir) {
|
|
72
|
+
return err('Usage: apt-tools fan-out resolve <project-dir> [--tasks <ids> | --phases <m/p,m/p> | --unblocked]');
|
|
73
|
+
}
|
|
74
|
+
const targetDir = resolve(projectDir);
|
|
75
|
+
const flags = parseFlags(extraArgs);
|
|
76
|
+
const hasTasks = flags.has('tasks');
|
|
77
|
+
const hasPhases = flags.has('phases');
|
|
78
|
+
const hasUnblocked = flags.has('unblocked');
|
|
79
|
+
const inputForms = [hasTasks, hasPhases, hasUnblocked].filter(Boolean).length;
|
|
80
|
+
if (inputForms === 0) {
|
|
81
|
+
return err('One of --tasks, --phases, or --unblocked is required');
|
|
82
|
+
}
|
|
83
|
+
if (inputForms > 1) {
|
|
84
|
+
return err('Only one of --tasks, --phases, or --unblocked may be passed at a time');
|
|
85
|
+
}
|
|
86
|
+
let taskIds = [];
|
|
87
|
+
let source = '';
|
|
88
|
+
if (hasTasks) {
|
|
89
|
+
taskIds = parseIdList(flags.get('tasks'));
|
|
90
|
+
source = 'tasks';
|
|
91
|
+
for (const id of taskIds) {
|
|
92
|
+
if (!ID_PATTERN.test(id)) {
|
|
93
|
+
return err(`Invalid task id in --tasks: "${id}" (must match /^[a-z0-9_-]+$/i)`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else if (hasPhases) {
|
|
98
|
+
const state = readState(targetDir);
|
|
99
|
+
if (!state)
|
|
100
|
+
return err('No state.json found — cannot resolve --phases');
|
|
101
|
+
taskIds = resolveFromPhases(state, parseIdList(flags.get('phases')));
|
|
102
|
+
source = 'phases';
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
const state = readState(targetDir);
|
|
106
|
+
if (!state)
|
|
107
|
+
return err('No state.json found — cannot resolve --unblocked');
|
|
108
|
+
taskIds = resolveUnblocked(state);
|
|
109
|
+
source = 'unblocked';
|
|
110
|
+
}
|
|
111
|
+
return ok({
|
|
112
|
+
status: 'ok',
|
|
113
|
+
command: 'fan-out-resolve',
|
|
114
|
+
source,
|
|
115
|
+
task_ids: taskIds,
|
|
116
|
+
batch_id: generateBatchId(),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
default:
|
|
120
|
+
return err(`Unknown fan-out subcommand: ${subcommand}. Available: resolve`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=fan-out.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fan-out.mjs","sourceRoot":"","sources":["../../../src/cli/commands/fan-out.mjs"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.mts","sourceRoot":"","sources":["../../../src/cli/commands/init.mjs"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.mts","sourceRoot":"","sources":["../../../src/cli/commands/init.mjs"],"names":[],"mappings":"AA4EA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wCAHW,MAAM,EAAE,GACN;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,GAAC,IAAI,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,GAAC,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,GAAC,CAAC,GAAC,CAAC,GAAC,CAAC,CAAC;IAAC,mBAAmB,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,OAAO,CAAC;IAAC,qBAAqB,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAmE1S;AAwzBD;;;;;;;GAOG;AACH,8CAHW,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,WACnB,cAAc,0BAoDxB;AAoED;;;;;;GAMG;AACH,oCAJW,MAAM,cACN,MAAM,EAAE,GACN,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA4L3D;;;;;cAnnCa,MAAM,EAAE;;;;qBACR,CAAC,GAAC,CAAC,GAAC,CAAC,GAAC,CAAC;;;;gBACP,MAAM,GAAC,MAAM;;;;4BACb,MAAM,EAAE;;;;aACR,OAAO;;;;mBACP,OAAO;eACP,OAAO,0BAA0B,EAAE,eAAe;;;;;;;;;aAErC,MAAM;eAAS,OAAO;cAAQ,MAAM;iBAAW,MAAM;;;;;;aAErD,MAAM;eAAS,OAAO;gBAAU,MAAM;;;;;;kBAEvC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;0BAAoB,OAAO,EAAE;2BAAqB,OAAO,EAAE;oBAAc,OAAO,EAAE"}
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* rewrite, 2026-04).
|
|
4
4
|
*
|
|
5
5
|
* Replaces the previous Claude-only `cp -r` installer with the per-runtime
|
|
6
|
-
* transform pipeline (src/cli/install/pipeline.mjs).
|
|
7
|
-
* supported via `--<runtime>` flags or `--all`. Default with no
|
|
6
|
+
* transform pipeline (src/cli/install/pipeline.mjs). Registered runtime
|
|
7
|
+
* targets are supported via `--<runtime>` flags or `--all`. Default with no
|
|
8
|
+
* flags in
|
|
8
9
|
* non-TTY mode → `--claude` (backward compat — existing skills invoke
|
|
9
10
|
* `apt-tools init <dir>` with no flags). Default in TTY → interactive prompt
|
|
10
11
|
* with auto-detection markers.
|
|
@@ -28,8 +29,9 @@ import { buildAperantGitignoreTemplate } from '../config/upgrade-gitignore.mjs';
|
|
|
28
29
|
import { detectPublicRemote } from '../git/remote.mjs';
|
|
29
30
|
import { detectArchetype } from '../install/archetype.mjs';
|
|
30
31
|
import { installKernel } from '../install/install-kernel.mjs';
|
|
32
|
+
import { MANIFEST_FILENAME } from '../install/manifest.mjs';
|
|
31
33
|
import { discoverCanonicalFiles, runInstall, writeLastInstallSummary, } from '../install/pipeline.mjs';
|
|
32
|
-
import { RUNTIMES, suggestRuntimes } from '../install/runtime-detect.mjs';
|
|
34
|
+
import { getRuntime, RUNTIMES, suggestRuntimes } from '../install/runtime-detect.mjs';
|
|
33
35
|
import { runLegacyCleanup } from '../install/runtime-migrate.mjs';
|
|
34
36
|
import { CLASS_A_SETTINGS, CLASS_B_SETTINGS, findClassDescriptor, parseClassFlags, } from '../install/setting-class.mjs';
|
|
35
37
|
import { detectAgentRuntime } from '../util/agent-runtime.mjs';
|
|
@@ -350,6 +352,44 @@ function selectRuntimes(targetDir, parsedFlags) {
|
|
|
350
352
|
}
|
|
351
353
|
return [...suggested];
|
|
352
354
|
}
|
|
355
|
+
/**
|
|
356
|
+
* Return the runtime ids that should be installed during a no-schema-drift
|
|
357
|
+
* init. A current config is not enough to prove runtime files exist on this
|
|
358
|
+
* machine: team repos often carry `.aperant/config.json` but not local
|
|
359
|
+
* runtime roots/manifests.
|
|
360
|
+
*
|
|
361
|
+
* @param {string} targetDir
|
|
362
|
+
* @param {string[]} runtimeIds
|
|
363
|
+
* @returns {string[]}
|
|
364
|
+
*/
|
|
365
|
+
function runtimesMissingManifest(targetDir, runtimeIds) {
|
|
366
|
+
const missing = [];
|
|
367
|
+
for (const id of runtimeIds) {
|
|
368
|
+
const runtime = getRuntime(id);
|
|
369
|
+
if (!runtime)
|
|
370
|
+
continue;
|
|
371
|
+
const manifestPath = join(targetDir, runtime.installRoot, MANIFEST_FILENAME);
|
|
372
|
+
if (!existsSync(manifestPath))
|
|
373
|
+
missing.push(id);
|
|
374
|
+
}
|
|
375
|
+
return missing;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Current-schema init should still run the runtime installer when the user
|
|
379
|
+
* explicitly requested runtimes, when --force-runtimes is present, or when
|
|
380
|
+
* local runtime roots are suggested but have no apt manifest.
|
|
381
|
+
*
|
|
382
|
+
* @param {string} targetDir
|
|
383
|
+
* @param {ReturnType<typeof parseInstallFlags>} parsedFlags
|
|
384
|
+
* @returns {string[]}
|
|
385
|
+
*/
|
|
386
|
+
function selectNoDriftRuntimeInstallIds(targetDir, parsedFlags) {
|
|
387
|
+
if (parsedFlags.forceRuntimes)
|
|
388
|
+
return selectRuntimes(targetDir, parsedFlags);
|
|
389
|
+
if (parsedFlags.runtimes_explicit)
|
|
390
|
+
return parsedFlags.runtimes;
|
|
391
|
+
return runtimesMissingManifest(targetDir, suggestRuntimes(targetDir));
|
|
392
|
+
}
|
|
353
393
|
/**
|
|
354
394
|
* Non-TTY / scripted path — derive answers from flags + sensible defaults,
|
|
355
395
|
* gated by the Class A/B classifier (spec R2 + R3).
|
|
@@ -600,11 +640,16 @@ async function interactiveInterview(targetDir, version, canonicalRoot, archetype
|
|
|
600
640
|
migration.applied_defaults.length === 0 &&
|
|
601
641
|
migration.auto_added.length === 0;
|
|
602
642
|
if (noDrift) {
|
|
603
|
-
|
|
604
|
-
// "Nothing to do." outro so the
|
|
605
|
-
//
|
|
606
|
-
if (
|
|
607
|
-
return {
|
|
643
|
+
const runtimeInstallIds = selectNoDriftRuntimeInstallIds(targetDir, parsedFlags);
|
|
644
|
+
// Runtime repair bypasses the TTY "Nothing to do." outro so the
|
|
645
|
+
// runtime walker can re-stamp missing manifests first.
|
|
646
|
+
if (runtimeInstallIds.length > 0) {
|
|
647
|
+
return {
|
|
648
|
+
upgrade_noop: true,
|
|
649
|
+
skipBootstrap,
|
|
650
|
+
migration,
|
|
651
|
+
runtime_reinstall_runtimes: runtimeInstallIds,
|
|
652
|
+
};
|
|
608
653
|
}
|
|
609
654
|
process.stdout.write(`\n${aperantBanner(version)}\n\n`);
|
|
610
655
|
clack.intro('install');
|
|
@@ -1058,20 +1103,19 @@ export async function cmdInit(projectDir, extraArgs = []) {
|
|
|
1058
1103
|
rerun_with: answers.rerun_with,
|
|
1059
1104
|
}, 2);
|
|
1060
1105
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1106
|
+
const noDriftRuntimeInstallIds = answers?.upgrade_noop
|
|
1107
|
+
? (answers.runtime_reinstall_runtimes ??
|
|
1108
|
+
selectNoDriftRuntimeInstallIds(installTarget, parsedFlags))
|
|
1109
|
+
: [];
|
|
1110
|
+
// Upgrade no-drift with no runtime work — short-circuit before
|
|
1111
|
+
// installRuntimes. /apt:update remains the right surface for refreshing
|
|
1112
|
+
// already-manifested skills; init only repairs selected or suggested
|
|
1113
|
+
// runtime roots that lack manifests.
|
|
1064
1114
|
// The bootstrap auto-chain still runs (it's deterministic and
|
|
1065
1115
|
// idempotent — preserves PROJECT.md, refreshes sidecar from it).
|
|
1066
1116
|
// In TTY mode clack already rendered "Nothing to do." to stdout,
|
|
1067
1117
|
// so suppress the JSON envelope (matches the cancelled path).
|
|
1068
|
-
|
|
1069
|
-
// 0.6.7 (Bug 2 fix) — `--force-runtimes` bypasses this short-circuit
|
|
1070
|
-
// so `/apt:update` can re-stamp every runtime manifest even when
|
|
1071
|
-
// `.aperant/config.json` is at the current schema. We synthesize a
|
|
1072
|
-
// real InstallAnswers shape from the existing config so
|
|
1073
|
-
// installRuntimes + finishInit run their normal upgrade path.
|
|
1074
|
-
if (answers?.upgrade_noop && !parsedFlags.forceRuntimes) {
|
|
1118
|
+
if (answers?.upgrade_noop && noDriftRuntimeInstallIds.length === 0) {
|
|
1075
1119
|
if (interactiveTty)
|
|
1076
1120
|
return rawText('', 0);
|
|
1077
1121
|
const bootstrap = answers.skipBootstrap
|
|
@@ -1087,18 +1131,14 @@ export async function cmdInit(projectDir, extraArgs = []) {
|
|
|
1087
1131
|
message: `Already up to date — v${version}`,
|
|
1088
1132
|
});
|
|
1089
1133
|
}
|
|
1090
|
-
//
|
|
1091
|
-
//
|
|
1092
|
-
//
|
|
1093
|
-
// cross-verification are read from answers.migration.migrated (already
|
|
1094
|
-
// in memory from nonInteractiveAnswers — avoids a second config read);
|
|
1095
|
-
// runtimes resolved via selectRuntimes helper shared with the upgrade path.
|
|
1134
|
+
// Current-schema runtime install — synthesize a real InstallAnswers
|
|
1135
|
+
// shape from the existing config so installRuntimes + finishInit run
|
|
1136
|
+
// their normal upgrade path.
|
|
1096
1137
|
let effectiveAnswers = answers;
|
|
1097
|
-
if (answers?.upgrade_noop &&
|
|
1138
|
+
if (answers?.upgrade_noop && noDriftRuntimeInstallIds.length > 0) {
|
|
1098
1139
|
const existing = answers.migration?.migrated || {};
|
|
1099
|
-
const runtimes = selectRuntimes(installTarget, parsedFlags);
|
|
1100
1140
|
effectiveAnswers = {
|
|
1101
|
-
runtimes,
|
|
1141
|
+
runtimes: noDriftRuntimeInstallIds,
|
|
1102
1142
|
autonomyDefault: existing?.autonomy?.default ?? 1,
|
|
1103
1143
|
visibility: existing?.share?.visibility === 'team' ? 'team' : 'solo',
|
|
1104
1144
|
crossVerificationTools: existing?.multi_model?.cross_verification?.tools ?? [],
|