@yunhozz/arc 0.2.0 → 0.2.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/MANIFEST.sha256 +44 -43
- package/README.md +16 -32
- package/claude/agents/arc-implementer.md +9 -7
- package/claude/agents/arc-planner.md +10 -12
- package/claude/agents/arc-qa.md +8 -8
- package/claude/agents/arc-reviewer.md +7 -7
- package/claude/agents/arc-scouter.md +7 -7
- package/claude/skill/SKILL.md +17 -16
- package/claude/skill/references/commit.md +1 -1
- package/claude/skill/references/coordination.md +23 -35
- package/claude/skill/references/handoff-prep.md +6 -2
- package/claude/skill/references/handoff.md +18 -6
- package/claude/skill/references/limits.md +3 -4
- package/claude/skill/references/planning.md +54 -48
- package/claude/skill/references/verification.md +11 -5
- package/claude/skill/references/visual-companion.md +6 -0
- package/codex/agents/arc-implementer.toml +9 -6
- package/codex/agents/arc-planner.toml +11 -13
- package/codex/agents/arc-qa.toml +8 -8
- package/codex/agents/arc-reviewer.toml +7 -7
- package/codex/agents/arc-scouter.toml +7 -7
- package/codex/skill/SKILL.md +17 -19
- package/codex/skill/references/commit.md +4 -6
- package/codex/skill/references/coordination.md +26 -41
- package/codex/skill/references/git-recovery.md +2 -3
- package/codex/skill/references/handoff-prep.md +7 -3
- package/codex/skill/references/handoff-worktree.md +5 -9
- package/codex/skill/references/handoff.md +22 -15
- package/codex/skill/references/limits.md +3 -4
- package/codex/skill/references/planning.md +57 -52
- package/codex/skill/references/verification.md +16 -12
- package/codex/skill/references/visual-companion.md +7 -1
- package/lib/installer/manifest.mjs +1 -1
- package/lib/management/operations.mjs +15 -2
- package/lib/management/update.mjs +19 -10
- package/lib/npm/context.mjs +22 -0
- package/lib/npm/uninstall.mjs +17 -0
- package/lib/npm/upgrade.mjs +25 -0
- package/lib/policy/role-policy.json +10 -10
- package/lib/tui/app.mjs +51 -27
- package/lib/tui/render.mjs +29 -9
- package/lib/tui/setup.mjs +12 -9
- package/lib/tui/terminal.mjs +22 -12
- package/package.json +1 -1
- package/scripts/update-superpowers-local.sh +4 -0
- package/lib/tui/workflow.mjs +0 -12
|
@@ -4,28 +4,23 @@ Read before design/plan-depth decisions, spec/plan drafting and approval, and th
|
|
|
4
4
|
|
|
5
5
|
## Authorization and scope
|
|
6
6
|
|
|
7
|
-
An explicit execution request
|
|
7
|
+
An explicit execution request authorizes only its sufficiently specified scope. Confirm execution intent,
|
|
8
8
|
expected outcome, constraints, document depth, and verification risk, with no unresolved material behavior, method,
|
|
9
|
-
or risk decision requiring the user.
|
|
10
|
-
|
|
11
|
-
canonical record. Routine execution and check choices may be recorded by Orchestrator; added product behavior or
|
|
12
|
-
material scope cannot be claimed as already approved. A restatement, role handoff, or restart does not create an
|
|
13
|
-
approval requirement for the same scope.
|
|
9
|
+
or risk decision requiring the user. That scope must come from the request or a description the user explicitly references. Record authorization evidence, scope, acceptance criteria, constraints, and depth in the brief or
|
|
10
|
+
canonical record. Orchestrator may record routine execution and check choices; added product behavior or material scope is not already approved. Restating or handing off the same scope, or restarting, requires no new approval.
|
|
14
11
|
|
|
15
12
|
Silence, ambiguous assent, approval of other work, and unspecified blanket improvement requests are not authorization.
|
|
16
13
|
Planner's new material choices are not automatically approved. Ask for the missing material decision; roles route
|
|
17
14
|
questions to Orchestrator. Required written specs and plans still require their individual approval in the order below.
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
remaining work. Target changes, unclear ownership, unexpected state, unresolved failures, or missing required inputs
|
|
16
|
+
Material scope, method, or risk changes hold affected work; explain the missing decision or evidence and remaining work. Target changes, unclear ownership, unexpected state, unresolved failures, or missing required inputs
|
|
21
17
|
also hold affected work under [handoff](handoff.md) and [git-recovery](git-recovery.md). Distinguish new authorization
|
|
22
18
|
needs from execution issues within existing scope: ordinary corrections and reverification do not require duplicate
|
|
23
19
|
approval after failure. Revalidate affected gates after resolution.
|
|
24
20
|
|
|
25
21
|
### Probe scope
|
|
26
22
|
|
|
27
|
-
A probe-only scope completes with findings, evidence, limits, and remaining uncertainty
|
|
28
|
-
a well-supported infeasibility result can complete it. Probe-only authorization does not authorize product retention
|
|
23
|
+
A probe-only scope completes by answering the approved question with findings, evidence, limits, and remaining uncertainty; well-supported infeasibility can complete it. Probe-only authorization does not authorize product retention
|
|
29
24
|
or subsequent implementation. Record question, method/scope, criteria, and constraints; a sufficiently specific probe
|
|
30
25
|
request can supply that approval. Match checks to probe purpose/risk and do not report probe evidence as product proof.
|
|
31
26
|
|
|
@@ -38,41 +33,53 @@ remains separate.
|
|
|
38
33
|
|
|
39
34
|
## Formal drafting boundary
|
|
40
35
|
|
|
41
|
-
Initial design proposals and brainstorming may precede execution-target choice. Formal spec or plan drafting includes a
|
|
42
|
-
complete draft before saving, even when returned only in chat. Before formal drafting and saving, Orchestrator supplies
|
|
36
|
+
Initial design proposals and brainstorming may precede execution-target choice. Formal spec or plan drafting includes a complete draft before saving, even when returned only in chat. Before formal drafting and saving, Orchestrator supplies
|
|
43
37
|
and records the actual absolute workspace/repository, branch or detached HEAD, HEAD, changes and ownership,
|
|
44
38
|
explicit choice and preparation evidence, and absolute document paths inside that target. Planner drafts for that
|
|
45
39
|
verified workspace; Orchestrator saves directly in the selected target. Missing or mismatched evidence stops the
|
|
46
|
-
affected drafting or save and is reported to Orchestrator. Planned scope and paths do not
|
|
40
|
+
affected drafting or save and is reported to Orchestrator. Planned scope and paths do not prove actual preparation.
|
|
47
41
|
Initial target preparation does not authorize Implementer; the complete handoff gate still applies.
|
|
48
42
|
|
|
49
43
|
|
|
50
44
|
## Planner drafting preparation and consolidated feedback
|
|
51
45
|
|
|
52
|
-
Before formal drafting, Orchestrator performs a preflight of relevant policy, reference, profile, test, parity
|
|
53
|
-
manifest surfaces and conflicts.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
46
|
+
1. Before formal drafting, Orchestrator performs a preflight of relevant policy, reference, profile, test, parity
|
|
47
|
+
and manifest surfaces and conflicts. Apply the Formal drafting boundary above and coordination's instruction
|
|
48
|
+
provenance, input-state and local-skill rules, including required reference paths, authorized bounded read
|
|
49
|
+
alternatives and return conditions. Missing required inputs or unresolved conflicts hold dependent drafting;
|
|
50
|
+
Planner returns them to Orchestrator. Optional read recovery grants no preparation, verification, writing or
|
|
51
|
+
approval authority.
|
|
52
|
+
|
|
53
|
+
2. Maintain a compact ledger of original requirements/criteria IDs, approved and open decisions, exclusions and
|
|
54
|
+
scope deltas; merge intervening user changes into one next-brief delta. Distinguish user-approved decisions,
|
|
55
|
+
verified source facts with exact paths and lines, assumptions and open decisions.
|
|
56
|
+
|
|
57
|
+
3. Send one complete brief for the initial call of each stage, using coordination's shared fields and evidence-link
|
|
58
|
+
rules. Include the prepared workspace, branch or detached HEAD, HEAD and ownership; scope, exclusions, depth,
|
|
59
|
+
dependencies, shared contracts, acceptance criteria, required QA/focused checks, evidence and holds. Identify
|
|
60
|
+
preceding approved versions, document/output paths, current behavior and connected source, generated, runtime,
|
|
61
|
+
installer and documentation surfaces, policy conflicts and resolution direction, open decisions and the exact
|
|
62
|
+
stage deliverable. For visual work, include approved sources/versions, criteria and unresolved interpretations.
|
|
63
|
+
|
|
64
|
+
4. Planner returns a complete proportional draft and self-review. Orchestrator integrates, saves, reviews and
|
|
65
|
+
obtains approval; never authors missing content. Review the complete draft once with this fixed checklist:
|
|
66
|
+
scope and evidence; targets, ownership and paths; policy surfaces and conflicts; task boundaries, dependencies
|
|
67
|
+
and acceptance criteria; checks, evidence and holds; roles, approval and commit boundaries; draft completeness.
|
|
68
|
+
Finish the checklist before sending all substantive omissions in one consolidated follow-up request.
|
|
69
|
+
Identify each criterion, defect, evidence and expected correction. Follow coordination's changed-fields-only
|
|
70
|
+
and `unchanged` rules. Do not split requests by omission.
|
|
71
|
+
|
|
72
|
+
5. After that correction, additional Planner calls require user-approved material scope/evidence changes or
|
|
73
|
+
concrete unmet checklist items, plus meaningful new input or criterion-state progress. Identify changed input,
|
|
74
|
+
target criterion, expected artifact and expected progress. Distinguish approved scope changes from ordinary
|
|
75
|
+
omissions within existing scope; omissions require no renewed scope approval. If the same criterion remains
|
|
76
|
+
unmet without meaningful new input, evidence or progress, hold the stage and report the criterion, observed
|
|
77
|
+
evidence and exact unblock input or decision. Do not repeat resolved questions, reword the same request, or
|
|
78
|
+
count rewording or agent replacement as meaningful input or progress.
|
|
79
|
+
|
|
80
|
+
Initial design, required spec approval, and formal plan drafting/approval remain separate ordered stages;
|
|
81
|
+
written-spec approval precedes dependent plan drafting. No fixed call cap applies; never accept an incomplete draft
|
|
82
|
+
to reduce calls or add call-count conditions to Planner profiles.
|
|
76
83
|
|
|
77
84
|
## Design and planning
|
|
78
85
|
|
|
@@ -127,7 +134,7 @@ approved obligations separately.
|
|
|
127
134
|
When a Bounded written spec is required by Orchestrator's recorded plan-depth judgment, record that necessity and scope
|
|
128
135
|
and use the approved short design as its basis. Planner returns a proportional complete spec draft and self-review;
|
|
129
136
|
Orchestrator integrates, saves, self-reviews, and obtains individual written-spec approval before dependent plan
|
|
130
|
-
drafting and execution preparation. This applies that judgment
|
|
137
|
+
drafting and execution preparation. This applies that judgment without adding a spec-necessity rule.
|
|
131
138
|
|
|
132
139
|
Design, spec, plan, and brainstorming drafts are authored only by Planner.
|
|
133
140
|
Orchestrator must not substitute an independently authored spec or plan for Planner's complete draft.
|
|
@@ -200,11 +207,9 @@ If evidence is missing or mismatched in either gate, stop the affected save and
|
|
|
200
207
|
|
|
201
208
|
### Complete planning-document set
|
|
202
209
|
|
|
203
|
-
The applicable document set
|
|
204
|
-
project work. Orchestrator records scope, design/plan depth, absolute document paths and coverage, approved
|
|
210
|
+
The applicable document set covers all specs and plans required for the current approved execution scope, excluding future project work. Orchestrator records scope, design/plan depth, absolute document paths and coverage, approved
|
|
205
211
|
versions/status, plan dependencies and execution order, skipped stages with rationale, and documents still awaiting writing or approval
|
|
206
|
-
in the shared brief. The set is complete only when every required document is written and individually approved
|
|
207
|
-
no unresolved scope or dependency decision requires another document. Do not omit required documents from the list.
|
|
212
|
+
in the shared brief. The set is complete only when every required document is written and individually approved, with no unresolved scope or dependency decision requiring another document. Do not omit required documents from the list.
|
|
208
213
|
|
|
209
214
|
A required plan does not itself require a written spec. Bounded uses Orchestrator's recorded plan-depth judgment to
|
|
210
215
|
determine whether a written spec is required; do not infer one from plan necessity. Spec steps apply only to Architectural and
|
|
@@ -219,9 +224,7 @@ Written-spec approval precedes dependent plan drafting. On document-omission pat
|
|
|
219
224
|
steps; preserve target choice, preparation, state/ownership checks and Implementer gates.
|
|
220
225
|
|
|
221
226
|
While documents are being written, reviewed, or approved, do not stage documents or commit planning documents.
|
|
222
|
-
|
|
223
|
-
not an initial preparation gate. An incomplete set or missing applicable approval blocks document commit and Implementer,
|
|
224
|
-
not the initial choice request. No early Implementer work is authorized by approval of only some documents.
|
|
227
|
+
Select and initially prepare the target before formal drafting. Document completion gates staging/commit, not initial preparation. An incomplete set or missing applicable approval blocks document commit and Implementer, but not the initial choice request. No early Implementer work is authorized by approval of only some documents.
|
|
225
228
|
|
|
226
229
|
This ARC explicitly defers the local `brainstorming` instruction to commit the spec before written-spec review:
|
|
227
230
|
save and self-review the spec, obtain written-spec approval without committing it, then write and obtain approval for
|
|
@@ -254,8 +257,7 @@ lifetime and restart record in [handoff.md](handoff.md).
|
|
|
254
257
|
## Plan updates during execution
|
|
255
258
|
|
|
256
259
|
Mechanical execution records may be recorded without new user approval: checkbox completion, actual results, evidence
|
|
257
|
-
links and task completion state that preserve the approved execution contract. Record their classification, reason and
|
|
258
|
-
actual recording time in the canonical handoff record. Required checks' removal, invented success, unsupported acceptance
|
|
260
|
+
links and task completion state that preserve the approved execution contract. Record their classification, reason and actual recording time in the canonical handoff record. Required checks' removal, invented success, unsupported acceptance
|
|
259
261
|
or scope changes mixed with a completion mark are not mechanical records.
|
|
260
262
|
|
|
261
263
|
Changes to goals, task scope or boundaries, acceptance criteria, method, risk, dependencies or required verification
|
|
@@ -265,8 +267,7 @@ follow the document-version approval rules; classify typos, paths, commands and
|
|
|
265
267
|
|
|
266
268
|
Both mechanical records and approved contract revisions amend the original planning-document commit at a safe checkpoint.
|
|
267
269
|
Make no separate document commit or fixup commit, including for newly approved scope. Preserve implementation task commits.
|
|
268
|
-
This history update does not
|
|
269
|
-
that its contents were approved from the outset. Never use rewritten history to justify work started before approval.
|
|
270
|
+
This history update does not backdate approval: the latest plan in the original commit does not prove its contents were approved from the outset. Never use rewritten history to justify work started before approval.
|
|
270
271
|
|
|
271
272
|
In the canonical handoff record preserve plan absolute/Git paths; before and after content hashes and versions; prior and
|
|
272
273
|
revised approval references and actual times; change reason and classification; affected tasks and hold/preparation/resume
|
|
@@ -306,14 +307,18 @@ skill. Missing files stop the stage; report paths without global fallback. Keep
|
|
|
306
307
|
|
|
307
308
|
|
|
308
309
|
|
|
310
|
+
## Instruction and Input Provenance
|
|
311
|
+
|
|
312
|
+
Give the Planner the exact paths and access state for required skills and references, distinguish user-provided instructions from discovered files, and identify approved input versions and open questions. Criteria that use visual materials must link the approved source, version, access state, criterion IDs, and comparison method. Missing required inputs and unapproved interpretations hold dependent parts of the draft. Optional read alternatives must meet the pre-authorized conditions in [handoff](handoff.md#instruction-sources-bounded-read-recovery-visual-evidence-and-resumption). The Planner remains draft-only during recovery.
|
|
313
|
+
|
|
309
314
|
[ARC role policy: contract begin]
|
|
310
315
|
Generated from lib/policy/role-policy.json; do not edit this managed section manually.
|
|
311
316
|
- [git.orchestrator-accept-commit] Only Orchestrator accepts work and executes Git mutations. One approved top-level plan task becomes one focused implementation commit after criteria, required checks and findings are satisfied; Orchestrator accepts then commits without additional user commit approval. Reports, passing checks and Reviewer opinions do not replace acceptance. Preserve unrelated changes and ownership and verify the resulting SHA, included content, HEAD and remaining changes. Existing small-task direct and plan-omission paths are unchanged.
|
|
312
|
-
- [review.significant-no-plan] For significant/high-risk work without a plan: Implementer → QA and required QA rechecks → Reviewer of the final full change → Orchestrator acceptance. MUST NOT omit Reviewer
|
|
313
|
-
- [review.significant-plan] For significant/high-risk plan work: each task uses Implementer → fresh QA as required → Orchestrator acceptance and focused commit.
|
|
317
|
+
- [review.significant-no-plan] For significant/high-risk work without a plan: Implementer → QA and required QA rechecks → Reviewer of the final full change → Orchestrator acceptance. MUST NOT omit Reviewer because no plan exists. This creates no new plan obligation.
|
|
318
|
+
- [review.significant-plan] For significant/high-risk plan work: each task uses Implementer → fresh QA as required → Orchestrator acceptance and focused commit. Reviewer reviews the final full change once after all tasks are accepted and required QA is complete. Reviewer is NOT a per-task or per-commit required gate. Preserve required checks and necessary finding rechecks.
|
|
314
319
|
- [review.final-plan-recheck] For final overall Reviewer findings on plan work, including behavior findings, use Implementer → Reviewer without QA reassignment; repeat until resolved. This exception applies only at the final plan stage. Preserve required QA and QA failure rechecks before initial final review and outside this exception.
|
|
315
320
|
- [planning.plan-amend] During approved task execution, mechanical plan progress records need no new user approval; changed goals, scope, criteria, method, risk, dependencies or required verification require revised-version approval and preparation before affected work. In both cases Orchestrator amends the original planning-document commit at a safe boundary, without a separate document or fixup commit. Preserve actual approval chronology, recoverable old/new contents, hashes, versions and SHA mappings; never retroactively authorize earlier work. Rewrite only unpublished, unshared local linear history with clear ownership and no merges; stop on unknown publication, ownership, unexpected state or replay conflicts, without force push or a fallback document commit. Preserve implementation task boundaries and revalidate affected evidence. See planning, handoff-prep, commit and verification for the full contract.
|
|
316
|
-
- [planning.planner-brief]
|
|
321
|
+
- [planning.planner-brief] Follow planning.md's Planner drafting preparation and consolidated feedback procedure, including preflight, ledger, evidence classification, target preparation, preceding approvals, provenance and reference gates. Send one complete stage-specific initial brief. Planner returns a complete proportional draft and self-review; Orchestrator reviews once with the fixed checklist and sends one consolidated correction using changed fields only. Additional Planner calls require user-approved material scope/evidence changes or concrete unmet checklist items after correction, plus meaningful new input or criterion-state progress; state changed input, target criterion, expected artifact and expected progress. Hold repeated unmet criteria without new input, evidence or progress and report the criterion, observed evidence and exact unblock input or decision. Do not split omissions, repeat resolved items, or count rewording or agent replacement as progress. Preserve separate sequential design/spec/plan approvals; no fixed call cap, Planner-profile call-count conditions or incomplete draft acceptance.
|
|
317
322
|
- [platform.codex] Role restrictions are prompt-level contracts, not a filesystem sandbox. No documented role-specific Git hook or generic per-agent tool allowlist is assumed. Existing shell capabilities are retained because static read access after shell reduction has not been verified; Implementer and QA need shell for approved checks.
|
|
318
323
|
[ARC role policy: contract end]
|
|
319
324
|
|
|
@@ -7,6 +7,12 @@ Visual companion design discussion is distinct from QA UI acceptance.
|
|
|
7
7
|
|
|
8
8
|
For Orchestrator, **Evidence verdict**: each criterion is proven, unmet, or unverified; passing runs, reports, or disposition never turn unverified into proven; reports keep unverified scope visible.
|
|
9
9
|
|
|
10
|
+
## Visual Evidence and Adjudication
|
|
11
|
+
|
|
12
|
+
Each visual criterion requires the exact location, version, approval, and access state of the approved visual source; criterion IDs, properties, and comparison method; and evidence linking the actual output to its revision. An Implementer report does not replace fresh QA's direct comparison. Record results as pass, mismatch, or unverified and connect them to the existing proven/unmet/unverified criterion verdicts. Use pass only when accessible evidence meets the visual criterion; keep unsupported claims unverified. Missing output-to-revision linkage is unverified; a visible difference is a mismatch. Record these separately; do not infer the current branch UI state. Hold the comparison if the approved source or actual output is inaccessible or interpretation approval is missing.
|
|
13
|
+
|
|
14
|
+
Static policy, generated-file, and manifest checks are structural evidence. They do not prove actual role behavior, an installed build, Claude Code CLI runtime compliance, or visual fidelity. Reports include actual changes, exclusion rationale, checks run and omitted, each criterion's evidence and limits, and platform availability. Keep baseline failures separate; progress on independent work does not relax required checks or acceptance criteria.
|
|
15
|
+
|
|
10
16
|
## Risk-scaled execution
|
|
11
17
|
|
|
12
18
|
Orchestrator assigns edits exclusively to Implementer except under the Orchestrator direct path in [handoff](handoff.md#orchestrator-direct-path-for-small-tasks), and determines affected
|
|
@@ -75,8 +81,7 @@ satisfies. For small, low-risk work with clear scope and acceptance evidence and
|
|
|
75
81
|
Orchestrator's focused checks suffice; do not call QA or Reviewer automatically. Significant/high-risk work requires
|
|
76
82
|
independent review of the full change at the final relevant state after the required QA/focused checks and any QA recheck.
|
|
77
83
|
|
|
78
|
-
|
|
79
|
-
rule may be. A vague request to delete unnecessary files does not establish low risk; reclassify when installer,
|
|
84
|
+
Metadata file count alone does not imply significant risk; a one-file permission or data-loss rule may. A vague request to delete unnecessary files does not establish low risk; reclassify when installer,
|
|
80
85
|
manifest, or other contracts are affected. For a verified ignore-pattern or metadata cleanup, confirm the targets are
|
|
81
86
|
unused, required project materials are unaffected, ignore patterns cover only intended paths, and the diff matches the
|
|
82
87
|
approved scope; Orchestrator's focused checks then suffice without automatically calling QA or Reviewer.
|
|
@@ -110,7 +115,7 @@ Structural checks establish written-contract alignment, not live agent complianc
|
|
|
110
115
|
|
|
111
116
|
Task-local acceptance is distinct from overall final plan verification and acceptance. Orchestrator connects each task's
|
|
112
117
|
acceptance criteria to actual evidence, currently required checks and findings before accepting it; checkbox
|
|
113
|
-
completion,
|
|
118
|
+
completion, an Implementer report or passing commands alone do not establish acceptance.
|
|
114
119
|
|
|
115
120
|
Task acceptance and its focused commit require only the task's risk-scaled evidence: a FRESH QA instance per task that
|
|
116
121
|
needs QA (default to the current QA for post-fix rechecks of the same task while the approved scope, workspace,
|
|
@@ -120,7 +125,7 @@ do not delay its acceptance/commit solely for later final plan verification. Cur
|
|
|
120
125
|
be deferred to final verification to accept early. State the scope and timing of final-only integration criteria in
|
|
121
126
|
the plan; with a plan, the required final whole-change review is final plan verification.
|
|
122
127
|
|
|
123
|
-
A task commit record does not
|
|
128
|
+
A task commit record does not prove unperformed final verification complete. Orchestrator still decides final plan
|
|
124
129
|
acceptance using final QA/Reviewer/integration evidence and findings, preserving unverified scope and explicit dispositions.
|
|
125
130
|
Valid evidence may cover both task and plan requirements only under the existing scope/state/independence/freshness/flow
|
|
126
131
|
rules. For final Reviewer findings on already committed plan work, Orchestrator defines a follow-up task and required
|
|
@@ -154,8 +159,7 @@ unmet, or unverified. Passing a check alone does not prove a criterion: evidence
|
|
|
154
159
|
expected result to actual observations. Preserve partial confirmation and out-of-scope, missing-check, or environment
|
|
155
160
|
blocked gaps as unverified; omit no criteria. PASS, if used, means only run status and cannot replace criterion
|
|
156
161
|
verdicts.
|
|
157
|
-
Structural checks prove structural criteria
|
|
158
|
-
compliance.
|
|
162
|
+
Structural checks prove only structural criteria, not actual behavior, installation, or live agent runtime compliance.
|
|
159
163
|
|
|
160
164
|
For QA execution failure or an unmet criterion within the current task, Orchestrator defaults to the current Implementer
|
|
161
165
|
for correction and the current QA for a post-fix recheck, subject to the context, task-boundary and amendment rules in
|
|
@@ -176,7 +180,7 @@ issues may require both QA verification and Reviewer source review.
|
|
|
176
180
|
|
|
177
181
|
Orchestrator accepts using criterion verdicts, findings, recheck evidence, and remaining gaps, rather than an overall
|
|
178
182
|
run result.
|
|
179
|
-
Explicit disposition does not
|
|
183
|
+
Explicit disposition does not turn unverified into proven; completion reports preserve remaining unverified scope.
|
|
180
184
|
For low-risk work without QA, Orchestrator's focused checks likewise connect each criterion to evidence.
|
|
181
185
|
|
|
182
186
|
|
|
@@ -188,8 +192,8 @@ Read brief-cited `references/superpowers/test-driven-development/SKILL.md`; reta
|
|
|
188
192
|
Once applicable authorization, document-depth, execution-target, and handoff conditions hold for the approved scope,
|
|
189
193
|
continue through execution, correction, reverification, required QA and Reviewer, findings disposition, Orchestrator
|
|
190
194
|
acceptance, and the result report. Apply risk-scaled timing above; this adds no per-task Reviewer or new QA obligation.
|
|
191
|
-
|
|
192
|
-
|
|
195
|
+
Role reports, probe findings, or passing commands do not establish overall completion while approved work remains.
|
|
196
|
+
Do not present remaining approved execution as an optional suggestion awaiting a user response. A probe-only scope
|
|
193
197
|
ends at its approved question's evidence and limits; a combined scope continues under planning's scope rules.
|
|
194
198
|
Document omission changes neither verification risk nor acceptance responsibility. Hold only affected work for an
|
|
195
199
|
actual unmet condition and report what is needed to resume. Structural evidence does not prove live agent compliance.
|
|
@@ -225,7 +229,7 @@ This is an operator verdict record; it does not replace semantic proof of a crit
|
|
|
225
229
|
Failures, unknown, mismatch and unverified outcomes are not passing evidence. Preserve previous results and failure records.
|
|
226
230
|
|
|
227
231
|
A failed check/review leaves an open finding. Link a separate finding to an existing check/review through `record` with
|
|
228
|
-
`data: {action: "open", id, checkId, message}`. After
|
|
232
|
+
`data: {action: "open", id, checkId, message}`. After an Implementer fix, record
|
|
229
233
|
`data: {action: "resolve", id, actor: {id, role: "implementer"}, changeFingerprint}` and the fix evidence messageRef.
|
|
230
234
|
The actor must be the Implementer assigned to that task, or a relevant task for an overall finding. This marks the finding resolved;
|
|
231
235
|
it becomes closed only when a subsequent prepare includes it in `findingIds` and revalidation passes for the same change version.
|
|
@@ -277,8 +281,8 @@ A changed runtimeHash follows the existing stale/hold rules; the stored version
|
|
|
277
281
|
[ARC role policy: contract begin]
|
|
278
282
|
Generated from lib/policy/role-policy.json; do not edit this managed section manually.
|
|
279
283
|
- [git.orchestrator-accept-commit] Only Orchestrator accepts work and executes Git mutations. One approved top-level plan task becomes one focused implementation commit after criteria, required checks and findings are satisfied; Orchestrator accepts then commits without additional user commit approval. Reports, passing checks and Reviewer opinions do not replace acceptance. Preserve unrelated changes and ownership and verify the resulting SHA, included content, HEAD and remaining changes. Existing small-task direct and plan-omission paths are unchanged.
|
|
280
|
-
- [review.significant-no-plan] For significant/high-risk work without a plan: Implementer → QA and required QA rechecks → Reviewer of the final full change → Orchestrator acceptance. MUST NOT omit Reviewer
|
|
281
|
-
- [review.significant-plan] For significant/high-risk plan work: each task uses Implementer → fresh QA as required → Orchestrator acceptance and focused commit.
|
|
284
|
+
- [review.significant-no-plan] For significant/high-risk work without a plan: Implementer → QA and required QA rechecks → Reviewer of the final full change → Orchestrator acceptance. MUST NOT omit Reviewer because no plan exists. This creates no new plan obligation.
|
|
285
|
+
- [review.significant-plan] For significant/high-risk plan work: each task uses Implementer → fresh QA as required → Orchestrator acceptance and focused commit. Reviewer reviews the final full change once after all tasks are accepted and required QA is complete. Reviewer is NOT a per-task or per-commit required gate. Preserve required checks and necessary finding rechecks.
|
|
282
286
|
- [review.final-plan-recheck] For final overall Reviewer findings on plan work, including behavior findings, use Implementer → Reviewer without QA reassignment; repeat until resolved. This exception applies only at the final plan stage. Preserve required QA and QA failure rechecks before initial final review and outside this exception.
|
|
283
287
|
- [planning.plan-amend] During approved task execution, mechanical plan progress records need no new user approval; changed goals, scope, criteria, method, risk, dependencies or required verification require revised-version approval and preparation before affected work. In both cases Orchestrator amends the original planning-document commit at a safe boundary, without a separate document or fixup commit. Preserve actual approval chronology, recoverable old/new contents, hashes, versions and SHA mappings; never retroactively authorize earlier work. Rewrite only unpublished, unshared local linear history with clear ownership and no merges; stop on unknown publication, ownership, unexpected state or replay conflicts, without force push or a fallback document commit. Preserve implementation task boundaries and revalidate affected evidence. See planning, handoff-prep, commit and verification for the full contract.
|
|
284
288
|
- [platform.codex] Role restrictions are prompt-level contracts, not a filesystem sandbox. No documented role-specific Git hook or generic per-agent tool allowlist is assumed. Existing shell capabilities are retained because static read access after shell reduction has not been verified; Implementer and QA need shell for approved checks.
|
|
@@ -13,9 +13,15 @@ acceptance. If declined, continue in text and do not offer again unless the user
|
|
|
13
13
|
question whether to use the companion. Orchestrator owns its guide, server/browser, workspace paths, live-session
|
|
14
14
|
checks, complete keyed URL, screens, session state, feedback/events, stale-screen clearing when returning to text, and
|
|
15
15
|
cleanup. Check the server before showing a screen; after the user's reply, treat terminal text as primary and events as
|
|
16
|
-
supplemental. A UI topic or
|
|
16
|
+
supplemental. A UI topic or companion acceptance alone does not route every question through a browser.
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
Upstream guide/scripts: `<installed ARC>/references/superpowers/brainstorming/visual-companion.md` and adjacent `scripts/`.
|
|
20
20
|
ARC guide: `references/visual-companion.md`; Orchestrator briefs absolute paths and retains approval/server/browser
|
|
21
21
|
ownership. Missing files stop dependent work. MUST NOT use a global fallback.
|
|
22
|
+
|
|
23
|
+
## Follow-up Verification of Approved Visual Sources
|
|
24
|
+
|
|
25
|
+
Each visual criterion requires the exact location, version, approval, and access state of the approved visual source; criterion IDs, properties, and comparison method; and evidence linking the actual output to its revision. An Implementer report does not replace fresh QA's direct comparison. Record results as pass, mismatch, or unverified and connect them to the existing proven/unmet/unverified criterion verdicts. Use pass only when accessible evidence meets the visual criterion; keep unsupported claims unverified. Missing output-to-revision linkage is unverified; a visible difference is a mismatch. Record these separately; do not infer the current branch UI state. Hold the comparison if the approved source or actual output is inaccessible or interpretation approval is missing.
|
|
26
|
+
|
|
27
|
+
Static policy, generated-file, and manifest checks are structural evidence. They do not prove actual role behavior, an installed build, Claude Code CLI runtime compliance, or visual fidelity. Reports include actual changes, exclusion rationale, checks run and omitted, each criterion's evidence and limits, and platform availability. Keep baseline failures separate; progress on independent work does not relax required checks or acceptance criteria.
|
|
@@ -25,7 +25,7 @@ export function verifyPayload({packageRoot,safeFs}){
|
|
|
25
25
|
for(const item of FIXED)select(item,false);for(const item of ROOTS)select(item,true);
|
|
26
26
|
for(const platform of ['codex','claude'])if(!referenceTrees[platform])throw Error('Required superpowers reference tree is missing');
|
|
27
27
|
for(const name of listed.keys())if(!files.has(name))throw Error(`Manifest entry is missing: ${name}`);
|
|
28
|
-
const required=['claude/skill/hooks/role-git-guard.mjs','claude/skill/hooks/git-policy.json','lib/policy/claude-hook.mjs','lib/policy/role-policy.json','lib/policy/render.mjs','scripts/update-role-policy.mjs','lib/limits.mjs','lib/installer/limits.mjs','lib/installer/runtime-config.mjs','README.md','install.command','package.json','bin/arc.mjs','lib/cli/root.mjs','lib/tui/app.mjs','lib/tui/terminal.mjs','lib/tui/render.mjs','lib/tui/setup.mjs','lib/
|
|
28
|
+
const required=['claude/skill/hooks/role-git-guard.mjs','claude/skill/hooks/git-policy.json','lib/policy/claude-hook.mjs','lib/policy/role-policy.json','lib/policy/render.mjs','scripts/update-role-policy.mjs','lib/limits.mjs','lib/installer/limits.mjs','lib/installer/runtime-config.mjs','README.md','install.command','package.json','bin/arc.mjs','lib/cli/root.mjs','lib/tui/app.mjs','lib/tui/terminal.mjs','lib/tui/render.mjs','lib/tui/setup.mjs','lib/management/operations.mjs','lib/management/status.mjs','lib/management/update.mjs','lib/management/workflow.mjs','lib/cli/postinstall.mjs','scripts/postinstall.mjs','lib/cli/upgrade.mjs','bin/arc-upgrade.mjs','lib/installer/shell-completion.mjs','lib/installer/manifest.mjs','lib/installer/targets.mjs','lib/installer/global-config.mjs','lib/installer/plan.mjs','lib/safe-fs/index.mjs','lib/safe-fs/native.mjs','lib/models/index.mjs','lib/models/config.mjs','lib/models/profiles.mjs','vendor/toml/LICENSE','vendor/toml/package.json','vendor/toml/provenance.json','vendor/toml/dist/index.js','prebuilds/index.json'];
|
|
29
29
|
required.push('lib/installer/runtime-assets.mjs',...RUNTIME_MODULE_PATHS);
|
|
30
30
|
for(const platform of ['codex','claude'])required.push(`${platform}/skill/runtime/role-policy.json`,...RUNTIME_MODULE_PATHS.map(name=>`${platform}/skill/runtime/${name.slice('lib/runtime/'.length)}`));
|
|
31
31
|
for(const tuple of ['darwin-arm64','darwin-x64','linux-arm64-gnu','linux-x64-gnu'])required.push(`prebuilds/${tuple}/arc_safe_fs.node`);
|
|
@@ -9,6 +9,8 @@ import {buildPresetPlan,switchPresetTargets} from '../installer/preset.mjs';
|
|
|
9
9
|
import {buildUninstallPlan,uninstallTargets} from '../installer/uninstall.mjs';
|
|
10
10
|
import {installTargets} from '../installer/install.mjs';
|
|
11
11
|
import {attachShellCompletionCleanup} from '../installer/shell-completion.mjs';
|
|
12
|
+
import {inspectGlobalArc} from '../npm/context.mjs';
|
|
13
|
+
import {uninstallGlobal,sameGlobalArc} from '../npm/uninstall.mjs';
|
|
12
14
|
import {acquireExternalSkills} from '../installer/acquisition.mjs';
|
|
13
15
|
/** @typedef {{packageRoot:string,userHome:string,cwd:string,env:object,safeFs:object,signal?:AbortSignal,acquisition?:Function}} ManagementContext */
|
|
14
16
|
/** @typedef {{kind:string,plans:object[],options:object}} PreparedOperation */
|
|
@@ -25,7 +27,8 @@ export async function prepareOperation(context,options,{selections=[]}={}){
|
|
|
25
27
|
if(options.kind==='install')attachShellCompletionCleanup(plans,context);
|
|
26
28
|
// Uninstall plans initially share the completion snapshot; its executor assigns one owner.
|
|
27
29
|
if(options.kind!=='uninstall')validatePlanSet(plans);
|
|
28
|
-
|
|
30
|
+
const globalArc=options.kind==='uninstall'?await(context.inspectGlobalArc??inspectGlobalArc)({env:context.env,cwd:context.cwd,runNpm:context.runNpm}):undefined;
|
|
31
|
+
return{kind:options.kind,plans,options:{...options},...(globalArc?{globalArc}:{})};
|
|
29
32
|
}
|
|
30
33
|
export function operationResult(result,successStatuses=['installed']){return{...result,code:result.interrupted?130:result.results.every(item=>successStatuses.includes(item.status)&&!item.error)?0:1,exitSession:false};}
|
|
31
34
|
export function acquisitionFor(context){return context.acquisition??(async()=>{const work=fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()),'arc-acquire-'));let acquired;try{acquired=await acquireExternalSkills({work,safeFs:context.safeFs,signal:context.signal});}catch(error){if(!error.residualPaths?.length)try{fs.rmdirSync(work);}catch(cleanup){throw Object.assign(new AggregateError([error,cleanup],'Cannot clean private acquisition work'),{code:'ARC_ACQUISITION_CLEANUP',residualPaths:[work]});}throw error;}return{...acquired,dispose:async()=>{await acquired.dispose();fs.rmdirSync(work);}};});}
|
|
@@ -34,6 +37,16 @@ export async function executeOperation(context,prepared){
|
|
|
34
37
|
const options={safeFs:context.safeFs,signal:context.signal,hooks:context.hooks};
|
|
35
38
|
if(prepared.kind==='install')return operationResult(await installTargets(prepared.plans,{...options,acquisition:acquisitionFor(context)}));
|
|
36
39
|
if(prepared.kind==='preset')return operationResult(await switchPresetTargets(prepared.plans,options),['updated','unchanged']);
|
|
37
|
-
if(prepared.kind==='uninstall')
|
|
40
|
+
if(prepared.kind==='uninstall'){
|
|
41
|
+
let result;
|
|
42
|
+
try{
|
|
43
|
+
const current=await(context.inspectGlobalArc??inspectGlobalArc)({context:prepared.globalArc,env:context.env,cwd:context.cwd,runNpm:context.runNpm});
|
|
44
|
+
if(!sameGlobalArc(prepared.globalArc,current))throw Error('Global ARC installation changed; prepare uninstall again');
|
|
45
|
+
result=operationResult(await uninstallTargets(prepared.plans,options),['uninstalled']);
|
|
46
|
+
if(result.code!==0||context.signal?.aborted)return{...result,code:context.signal?.aborted?130:result.code,cli:{status:'skipped'}};
|
|
47
|
+
const cli=await(context.uninstallGlobal??uninstallGlobal)({context:prepared.globalArc,env:context.env,cwd:context.cwd,signal:context.signal,runNpm:context.runNpm});
|
|
48
|
+
return{...result,code:cli.code??(cli.packageStatus==='failed'?1:0),interrupted:result.interrupted||Boolean(cli.interrupted),exitSession:Boolean(cli.started),cli:{...cli,status:cli.packageStatus},stdout:cli.stdout,stderr:cli.stderr};
|
|
49
|
+
}catch(error){return{...(result??{results:[],interrupted:false}),code:context.signal?.aborted?130:1,exitSession:false,cli:{status:'skipped'},error};}
|
|
50
|
+
}
|
|
38
51
|
throw Object.assign(Error('Unknown prepared operation'),{code:'ARC_CLI_INPUT'});
|
|
39
52
|
}
|
|
@@ -15,7 +15,7 @@ export function report(result,output,error){
|
|
|
15
15
|
for(const item of result.results){output.write(item.platform+': '+item.status+'; rollback: '+item.rollback+'\n');for(const filename of item.residualPaths??[])output.write('Residual path: '+filename+'\n');if(item.error)error.write('Error: '+item.error.message+'\n');}
|
|
16
16
|
if(result.interrupted)return 130;
|
|
17
17
|
if(result.results.every(item=>item.status==='installed'&&!item.error)){output.write('ARC version '+result.version+' harness upgraded! Previous harness version: not recorded.\n');return 0;}
|
|
18
|
-
error.write('Harness update did not complete. Run arc again and choose
|
|
18
|
+
error.write('Harness update did not complete. Run arc again and choose Install / Update to retry the harness update.\n');return 1;
|
|
19
19
|
}
|
|
20
20
|
export function failure(cause,error){error.write('Error: '+cause.message+'\n');return ['ARC_CANCELLED','ARC_NPM_CANCELLED'].includes(cause.code)?130:['ARC_CLI_INPUT','ARC_TARGET_CONFIGURATION','ARC_UNSUPPORTED_RUNTIME','ARC_NATIVE_UNAVAILABLE'].includes(cause.code)?2:1;}
|
|
21
21
|
export async function runChild(request,io={},deps={}){
|
|
@@ -36,23 +36,32 @@ export async function prepareUpdate(context){
|
|
|
36
36
|
const root=context.packageRoot??packageRoot,pkg=identity(root),api=await runtime(context),cwd=fs.realpathSync(context.cwd??process.cwd()),env=context.env??process.env;
|
|
37
37
|
const state=api.collectInstalledState({safeFs:api.safeFs,userHome:context.userHome??os.homedir(),env,cwd});
|
|
38
38
|
if(!state.targets.length)throw configurationError('No installed ARC harness found. Run npx --yes @yunhozz/arc to install it first');
|
|
39
|
-
|
|
40
|
-
if(!
|
|
41
|
-
|
|
39
|
+
const npmContext=await api.inspectNpmContext({packageRoot:root,entryPath:path.join(root,'bin/arc.mjs'),env,cwd});
|
|
40
|
+
if(!['global','npx'].includes(npmContext.kind))throw configurationError('Run arc from a verified global ARC installation or npx');
|
|
41
|
+
let latestVersion=null,latestError;
|
|
42
|
+
try{const latest=await api.resolveLatest({context:npmContext,env,cwd,signal:context.signal});if(!/^\d+\.\d+\.\d+$/.test(latest.version))throw Error('Invalid latest ARC version');latestVersion=latest.version;}catch(error){if(['ARC_CANCELLED','ARC_NPM_CANCELLED'].includes(error.code))throw error;latestError=error;}
|
|
43
|
+
return{kind:'update',root,pkg,cwd,env,state,npmContext,currentVersion:pkg.version,latestVersion,canUpgrade:latestVersion!==null&&newer(latestVersion,pkg.version),latestError};
|
|
42
44
|
}
|
|
45
|
+
function newer(left,right){const a=left.split('.').map(BigInt),b=right.split('.').map(BigInt);for(let i=0;i<3;i++){if(a[i]!==b[i])return a[i]>b[i];}return false;}
|
|
46
|
+
|
|
43
47
|
export async function executeUpdate(context,prepared){
|
|
44
48
|
let packageStarted=false;const messages=[];try{
|
|
45
49
|
const api=await runtime(context),{root,pkg,cwd,env,state}=prepared;
|
|
50
|
+
if(!prepared.canUpgrade||typeof prepared.latestVersion!=='string'||!/^\d+\.\d+\.\d+$/.test(prepared.latestVersion)||!newer(prepared.latestVersion,prepared.currentVersion))throw configurationError('No newer ARC version is available');
|
|
51
|
+
if(identity(root).version!==pkg.version||pkg.version!==prepared.currentVersion)throw configurationError('ARC package changed after checking its version');
|
|
46
52
|
const{assertPlanSnapshot}=await import('../installer/transaction.mjs');for(const entry of state.targets)assertPlanSnapshot(entry,{safeFs:api.safeFs});
|
|
53
|
+
const currentState=api.collectInstalledState({safeFs:api.safeFs,userHome:context.userHome??os.homedir(),env,cwd});if(currentState.stateToken!==state.stateToken)throw configurationError('Installed ARC settings changed; check the version again');
|
|
47
54
|
const npmContext=await api.inspectNpmContext({packageRoot:root,entryPath:path.join(root,'bin/arc.mjs'),env,cwd});
|
|
48
|
-
if(!['global','npx'].includes(npmContext.kind))throw configurationError('
|
|
55
|
+
if(!['global','npx'].includes(npmContext.kind)||['kind','packageRoot','entryPath','npmCli','prefix'].some(key=>npmContext[key]!==prepared.npmContext[key]))throw configurationError('ARC npm context changed; check the version again');
|
|
56
|
+
const expectedVersion=prepared.latestVersion;
|
|
49
57
|
if(npmContext.kind==='npx'){
|
|
50
|
-
|
|
58
|
+
const child=await api.runNpxUpgrade({context:npmContext,expectedVersion,expectedStateToken:state.stateToken,env,cwd,signal:context.signal});
|
|
59
|
+
return{...child,code:child.code===0&&!child.signal?0:child.code===130?130:1,exitSession:false,results:[],messages};
|
|
51
60
|
}
|
|
52
|
-
|
|
53
|
-
const replaced=await api.upgradeGlobal({context:npmContext,expectedVersion
|
|
54
|
-
messages.push('CLI: updated to '+
|
|
55
|
-
const child=await api.runUpgradeChild({entryPath:path.join(npmContext.packageRoot,'bin/arc-upgrade.mjs'),request:{protocol:1,expectedVersion
|
|
61
|
+
packageStarted=true;
|
|
62
|
+
const replaced=await api.upgradeGlobal({context:npmContext,expectedVersion,env,cwd,signal:context.signal});if(replaced.packageStatus!=='updated')throw replaced.error??Error('CLI replacement failed');
|
|
63
|
+
messages.push('CLI: updated to '+expectedVersion+' (previous '+pkg.version+').\n');
|
|
64
|
+
const child=await api.runUpgradeChild({entryPath:path.join(npmContext.packageRoot,'bin/arc-upgrade.mjs'),request:{protocol:1,expectedVersion,invocationCwd:cwd,expectedStateToken:state.stateToken},env,cwd,signal:context.signal});
|
|
56
65
|
return{...child,code:child.code===0&&!child.signal?0:child.code===130?130:1,exitSession:true,results:[],messages};
|
|
57
66
|
}catch(error){return{code:['ARC_CANCELLED','ARC_NPM_CANCELLED'].includes(error.code)?130:['ARC_CLI_INPUT','ARC_TARGET_CONFIGURATION','ARC_UNSUPPORTED_RUNTIME','ARC_NATIVE_UNAVAILABLE'].includes(error.code)?2:1,exitSession:packageStarted,results:[],error,messages};}
|
|
58
67
|
}
|
package/lib/npm/context.mjs
CHANGED
|
@@ -34,3 +34,25 @@ export async function inspectNpmContext({packageRoot,entryPath,env=process.env,c
|
|
|
34
34
|
return unsupported('ARC is not in a verified global or npm exec installation');
|
|
35
35
|
}catch{return unsupported('Cannot verify npm installation context');}
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
// Global absence is a filesystem fact. Identity and context failures must throw,
|
|
39
|
+
// because treating them as absence could allow harness removal before validation.
|
|
40
|
+
export async function inspectGlobalArc({context,env=process.env,cwd=process.cwd(),runNpm=defaultRunNpm}={}){
|
|
41
|
+
const fail=message=>Object.assign(Error(message),{code:'ARC_TARGET_CONFIGURATION'}),npmCli=npmExecutable(env);
|
|
42
|
+
if(context?.npmCli&&context.npmCli!==npmCli)throw fail('Global ARC npm context changed');
|
|
43
|
+
async function query(args){const result=await runNpm(npmCli,args,{env,cwd});if(result.code!==0||result.signal)throw fail('Cannot verify global npm context');const value=result.stdout.trim();if(!path.isAbsolute(value)||value.includes('\n'))throw fail('Invalid global npm context path');return path.resolve(value);}
|
|
44
|
+
const queriedPrefix=await query(['prefix','--global']),queriedRoot=await query(['root','--global']);
|
|
45
|
+
let prefix;try{prefix=realDirectory(queriedPrefix);}catch(error){if(error.code!=='ENOENT')throw error;prefix=queriedPrefix;}
|
|
46
|
+
if(![path.join(queriedPrefix,'lib/node_modules'),path.join(queriedPrefix,'node_modules')].includes(queriedRoot))throw fail('Unverified global npm root');
|
|
47
|
+
const root=path.join(prefix,path.relative(queriedPrefix,queriedRoot)),packageRoot=path.join(root,'@yunhozz/arc');
|
|
48
|
+
for(const relative of [path.relative(prefix,root),'@yunhozz','arc']){
|
|
49
|
+
// Check each component, including lib/node_modules, without following links.
|
|
50
|
+
const base=relative==='@yunhozz'?root:relative==='arc'?path.join(root,'@yunhozz'):prefix;
|
|
51
|
+
let current=base;for(const part of relative.split(path.sep)){current=path.join(current,part);let stat;try{stat=fs.lstatSync(current);}catch(error){if(error.code==='ENOENT')return{kind:'absent'};throw error;}if(stat.isSymbolicLink()||!stat.isDirectory())throw fail('Global ARC directory identity is invalid or symlinked');}
|
|
52
|
+
}
|
|
53
|
+
const filename=path.join(packageRoot,'package.json');if(!fs.lstatSync(filename).isFile()||fs.lstatSync(filename).isSymbolicLink())throw fail('Invalid global ARC package identity');
|
|
54
|
+
let pkg;try{pkg=JSON.parse(fs.readFileSync(filename,'utf8'));}catch{throw fail('Invalid global ARC package identity');}
|
|
55
|
+
if(pkg.name!=='@yunhozz/arc'||!/^\d+\.\d+\.\d+$/.test(pkg.version))throw fail('Invalid global ARC package identity');
|
|
56
|
+
const{createHash}=await import('node:crypto'),stat=fs.lstatSync(packageRoot),packageToken=createHash('sha256').update(fs.readFileSync(filename)).update(String(stat.dev)+':'+String(stat.ino)).digest('hex');
|
|
57
|
+
return{kind:'global',npmCli,prefix,packageRoot,version:pkg.version,packageToken};
|
|
58
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {inspectGlobalArc} from './context.mjs';
|
|
2
|
+
import {runNpm as defaultRunNpm} from './process.mjs';
|
|
3
|
+
export function sameGlobalArc(left,right){return['kind','npmCli','prefix','packageRoot','version','packageToken'].every(key=>left?.[key]===right?.[key]);}
|
|
4
|
+
export async function uninstallGlobal({context,env=process.env,cwd=process.cwd(),signal,runNpm=defaultRunNpm}){
|
|
5
|
+
let started=false,result;
|
|
6
|
+
try{
|
|
7
|
+
const current=await inspectGlobalArc({context,env,cwd,runNpm});
|
|
8
|
+
if(!sameGlobalArc(context,current))throw Object.assign(Error('Global ARC installation changed; prepare uninstall again'),{code:'ARC_TARGET_CONFIGURATION'});
|
|
9
|
+
if(signal?.aborted)throw Object.assign(Error('Uninstall interrupted'),{code:'ARC_NPM_CANCELLED'});
|
|
10
|
+
if(current.kind==='absent')return{packageStatus:'absent',code:0,started:false,stdout:'',stderr:''};
|
|
11
|
+
started=true;
|
|
12
|
+
result=await runNpm(current.npmCli,['uninstall','--global','@yunhozz/arc','--prefix',current.prefix,'--ignore-scripts'],{env,cwd,signal});
|
|
13
|
+
if(result.code!==0||result.signal)throw Error('Global CLI removal failed; the package may have changed');
|
|
14
|
+
if((await inspectGlobalArc({context:current,env,cwd,runNpm})).kind!=='absent')throw Error('Global ARC remains after npm uninstall');
|
|
15
|
+
return{...result,packageStatus:'removed',started};
|
|
16
|
+
}catch(error){const interrupted=['ARC_CANCELLED','ARC_NPM_CANCELLED'].includes(error.code)||Boolean(signal?.aborted);return{...result,packageStatus:'failed',code:interrupted?130:result?.code||1,interrupted,started,error};}
|
|
17
|
+
}
|
package/lib/npm/upgrade.mjs
CHANGED
|
@@ -27,3 +27,28 @@ export async function runUpgradeChild({entryPath,request,env,cwd,signal}){
|
|
|
27
27
|
child.stdin.end(JSON.stringify(request));
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
|
+
// Resolve the npm-exec payload from its own bin, then use only that payload's
|
|
31
|
+
// verified management runtime. The global-only private child is not reused.
|
|
32
|
+
export async function runNpxUpgrade({context,expectedVersion,expectedStateToken,env,cwd,signal,runNpm=defaultRunNpm}){
|
|
33
|
+
if(context.kind!=='npx'||!validVersion(expectedVersion)||typeof expectedStateToken!=='string'||!/^[a-f0-9]{64}$/.test(expectedStateToken))throw Error('Invalid pinned npx upgrade request');
|
|
34
|
+
if(signal?.aborted)throw cancelled();
|
|
35
|
+
const bootstrap=`import fs from 'node:fs';import path from 'node:path';import os from 'node:os';import {pathToFileURL} from 'node:url';
|
|
36
|
+
try{
|
|
37
|
+
const expectedVersion=${JSON.stringify(expectedVersion)},expectedStateToken=${JSON.stringify(expectedStateToken)},cwd=${JSON.stringify(cwd)};
|
|
38
|
+
const bin=process.env.PATH.split(path.delimiter).map(p=>path.join(p,'arc')).find(p=>fs.existsSync(p));
|
|
39
|
+
if(!bin)throw Error('Cannot locate pinned ARC payload');
|
|
40
|
+
const entry=fs.realpathSync(bin),root=path.dirname(path.dirname(entry)),pkg=JSON.parse(fs.readFileSync(path.join(root,'package.json'),'utf8'));
|
|
41
|
+
if(pkg.name!=='@yunhozz/arc'||pkg.version!==expectedVersion||entry!==path.join(root,'bin/arc.mjs'))throw Error('Pinned ARC package identity mismatch');
|
|
42
|
+
const management=await import(pathToFileURL(path.join(root,'lib/management/update.mjs')));
|
|
43
|
+
if(typeof management.runtime!=='function'||typeof management.report!=='function')throw Error('Pinned ARC management runtime is unavailable');
|
|
44
|
+
const api=await management.runtime({});
|
|
45
|
+
if(typeof api.inspectNpmContext!=='function'||typeof api.collectInstalledState!=='function'||typeof api.upgradeInstalledTargets!=='function')throw Error('Pinned ARC management API is unavailable');
|
|
46
|
+
const context=await api.inspectNpmContext({packageRoot:root,entryPath:entry,env:process.env,cwd});
|
|
47
|
+
if(context.kind!=='npx'||context.packageRoot!==root)throw Error('Cannot verify pinned npm exec context');
|
|
48
|
+
const state=api.collectInstalledState({safeFs:api.safeFs,userHome:os.homedir(),env:process.env,cwd});
|
|
49
|
+
if(state.stateToken!==expectedStateToken||!state.targets.length)throw Error('Installed ARC settings changed before pinned upgrade');
|
|
50
|
+
const controller=new AbortController(),abort=()=>controller.abort();process.once('SIGINT',abort);process.once('SIGTERM',abort);
|
|
51
|
+
try{process.exitCode=management.report(await api.upgradeInstalledTargets({packageRoot:root,state,safeFs:api.safeFs,signal:controller.signal}),process.stdout,process.stderr);}finally{process.removeListener('SIGINT',abort);process.removeListener('SIGTERM',abort);}
|
|
52
|
+
}catch(error){console.error('Error: '+error.message);process.exitCode=2;}`;
|
|
53
|
+
return runNpm(context.npmCli,['exec','--yes','--package','@yunhozz/arc@'+expectedVersion,'--',process.execPath,'--input-type=module','-e',bootstrap],{env,cwd,signal});
|
|
54
|
+
}
|