axstack 0.20.30 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +24 -23
  2. package/bin/axstack.js +18 -5
  3. package/docs/installation.md +101 -46
  4. package/docs/workflows.md +179 -117
  5. package/package.json +3 -3
  6. package/profiles/presets/claude-only.json +46 -46
  7. package/profiles/presets/codex-only.json +50 -50
  8. package/profiles/presets/mixed.json +59 -59
  9. package/skills/axstack/references/automations.md +127 -137
  10. package/skills/axstack/references/autopilot.md +121 -0
  11. package/skills/axstack/references/candidate-publication.md +13 -8
  12. package/skills/axstack/references/contracts.md +10 -4
  13. package/skills/axstack/references/diligence.md +3 -1
  14. package/skills/axstack/references/evidence-archive.md +38 -33
  15. package/skills/axstack/references/lifecycle.md +64 -50
  16. package/skills/axstack/references/review-manager-prompt.md +13 -11
  17. package/skills/axstack/references/role-roster.md +19 -9
  18. package/skills/axstack/references/routing.md +33 -18
  19. package/skills/axstack/references/run-record.md +36 -15
  20. package/skills/axstack/references/t3-runtime.md +234 -0
  21. package/skills/axstack/references/test-audit-weekly.md +62 -0
  22. package/skills/axstack/references/test-value.md +120 -0
  23. package/skills/axstack/references/ui-verification.md +5 -1
  24. package/skills/axstack/references/workspace-hygiene.md +102 -156
  25. package/skills/axstack/scripts/pr-digest.js +120 -0
  26. package/skills/axstack/scripts/resolve-models.js +102 -0
  27. package/skills/axstack-align/SKILL.md +25 -11
  28. package/skills/axstack-audit/SKILL.md +22 -5
  29. package/skills/axstack-audit/references/record.md +1 -1
  30. package/skills/axstack-cleanup/SKILL.md +69 -87
  31. package/skills/axstack-debug/SKILL.md +1 -1
  32. package/skills/axstack-explain/SKILL.md +1 -1
  33. package/skills/axstack-explain/references/visual-qa.md +2 -0
  34. package/skills/axstack-implement/SKILL.md +76 -26
  35. package/skills/axstack-improve/SKILL.md +24 -4
  36. package/skills/axstack-relay/SKILL.md +16 -7
  37. package/skills/axstack-research/SKILL.md +11 -4
  38. package/skills/axstack-review/SKILL.md +42 -32
  39. package/skills/axstack-spec/SKILL.md +23 -14
  40. package/skills/axstack-tickets/SKILL.md +13 -11
  41. package/skills/axstack-watch/SKILL.md +117 -34
  42. package/skills/axstack-watch/references/watch-runtime.md +61 -69
  43. package/src/capabilities.js +33 -69
  44. package/src/installer.js +9 -1
  45. package/src/instructions.js +9 -4
  46. package/src/roles.js +38 -10
  47. package/skills/axstack/references/orca-runtime.md +0 -183
  48. package/skills/axstack/scripts/trust-path.js +0 -123
@@ -1,183 +0,0 @@
1
- # Orca runtime boundary
2
-
3
- Read this immediately before using Orca for a role dispatch, handoff, delivery,
4
- settlement, or recovery. Ordinary local reading and writing do not load it.
5
- Axstack owns policy, role selection, and evidence; Orca owns Run, Task,
6
- Dispatch, session, worktree, messaging, settlement, and scheduling state.
7
-
8
- ## Discover the runtime-owned guides
9
-
10
- Resolve one Orca executable for the session and reuse it. Prefer
11
- `ORCA_CLI_COMMAND` when set, then the checkout's `orca-dev` when
12
- `ORCA_DEV_REPO_ROOT` is set, the Linux-safe `orca-ide` outside managed
13
- terminals, and otherwise `orca`. If the selected executable fails, report that
14
- exact gap; never switch binaries silently.
15
-
16
- Load only the selected executable's version-matched guides needed by the
17
- operation through `skills get orchestration --json`,
18
- `skills get orca-cli --json`, and `skills get orca-linear --json`.
19
- `orchestration` owns Run, Task,
20
- Dispatch, messaging, supervision,
21
- settlement, and recovery. `orca-cli` owns worktrees, terminals, automations,
22
- handoffs, and artifact publication; load its named conditional reference at
23
- the matching action gate. `orca-linear` owns Linear issue reads and writes.
24
- Follow returned schemas and current command help rather than copying their
25
- procedures into Axstack. Guide discovery does not prove runtime support for a
26
- particular operation: preflight that operation and report an advertised gap.
27
- Missing discovery never authorizes legacy runtime use, a silent integration or
28
- store fallback, or an Axstack dispatcher, daemon, scheduler, database, or
29
- escalation engine.
30
-
31
- Orca artifacts publish public-by-link output. They are not private evidence
32
- storage and must never receive private evidence by default; sharing requires
33
- explicit publication authority and the `orca-cli` publishing reference.
34
-
35
- ## Bind the configured role
36
-
37
- Read `roles.json` from the installed shared root `skills/axstack/`. The installed
38
- shape is `{ "version": 1, "preset": "<name>", "roles": [...] }`. Bundled
39
- profiles are setup inputs shaped as
40
- `{ "version": 1, "roles": [...] }`. A new run records the selected preset and
41
- all 32 role rows once. An active run keeps the exact snapshot until the user
42
- explicitly changes it.
43
-
44
- Select the requested role by stable ID. A missing or null model holds only that role;
45
- never launch a provider default. Launch-by-agent-id routes for which Orca exposes no
46
- `--model` override (today: `grok`, `antigravity`) record `model: null` with an explicit note and are
47
- launchable; the run record snapshots the model the TUI reports. Validate provider, model, and effort
48
- against the guide and actual launch capability. Stored `modeId` and other
49
- permission fields are conservative intent, not proof of effective permission
50
- parity or a security boundary. Requested settings, input acceptance, effective
51
- settings, and completed work are separate evidence. An unsupported or
52
- unavailable value holds affected work for the user's decision without fallback.
53
- The single-provider preset's null adviser and round-2 seat are intentional installation data, not
54
- readiness failure; because Align and Spec require both adviser receipts, either
55
- null adviser still holds those phases. The current chat is the driver and has
56
- no role row in any preset.
57
-
58
- ## Materialize checkouts as worktrees of the registered repo
59
-
60
- Every reviewer, release, or worker checkout is `ORCA worktree create --repo
61
- id:<repoId> ...` under the repo Orca already registers. `ORCA repo add` is a
62
- one-time import of a new repository; running it on a clone of a registered
63
- repo creates a second top-level repo record, so it never materializes a
64
- checkout. See [Candidate publication](candidate-publication.md) for the
65
- detached immutable review checkout.
66
-
67
- ## Supervise one authoritative attempt
68
-
69
- For supervised work, use the orchestration guide's native Run, Task, and
70
- Dispatch flow. Reconcile existing attempts first. Bind the approved spec or
71
- small-change intent, brief, authority, role snapshot, worktree, base, and
72
- candidate to the Task; preserve the returned
73
- Task, Dispatch, terminal, agent, and worktree identities. Exactly one Dispatch
74
- may write a candidate at a time.
75
- Put the [Safe deletion](workspace-hygiene.md#safe-deletion) rule in every
76
- worker brief.
77
-
78
- Create a worker worktree with `--parent-worktree` naming the candidate's
79
- worktree when both are in the same repository; see
80
- [Readable sidebar](workspace-hygiene.md#readable-sidebar) for naming, status,
81
- and parentage at dispatch. `--no-parent` is for unrelated work with no parent
82
- context. Where supported, correct wrong lineage in place with
83
- `worktree set --parent-worktree`. Lineage is presentation, never authority: it
84
- grants nothing and cannot replace Task, Dispatch, and receipt evidence.
85
- `--no-parent` is never used for a review or repair checkout.
86
-
87
- Every reviewer gets a separate Orca child worktree parented to the candidate.
88
- Keep that reviewer's probes and private evidence in its separate private
89
- per-Dispatch run folder under [Workspace hygiene](workspace-hygiene.md), with no
90
- first-pass cross-read. Untracked files never prove a worktree disposable.
91
-
92
- Before launching a Claude worker in a checkout, from the installed `axstack` skill directory
93
- run `bun scripts/trust-path.js --path <exact checkout path>` for that
94
- exact checkout path. It trusts only Orca-registered repository roots and their
95
- worktrees. A failed preflight holds launch; workers never answer trust or
96
- permission dialogs. A trust dialog that still appears is a hold.
97
-
98
- An `input_accepted` stage proves only that input reached the terminal. Require
99
- `turn_started` plus runtime/session inspection before treating the agent as
100
- started, and verify the requested role independently before trusting its work.
101
- If a worker asks to confirm its own dispatch brief, the dispatching owner
102
- confirms once by typed terminal input restating the brief's authority, then
103
- re-verifies `turn_started`. That confirmation never answers a trust or permission prompt;
104
- it answers only the agent's own model-turn question about its brief, never a
105
- harness or tool dialog, and adds no authority. A second ask is a hold.
106
- A workspace trust, hook review, permission, authentication, or model prompt is
107
- a visible hold. Never answer a trust or permission prompt on the worker's
108
- behalf. A permission prompt or provider safety refusal is a held, incomplete
109
- outcome, never consent or completion. Never bypass or retry it through another
110
- model. Preserve the attempt and its evidence, then use only
111
- the runtime guide's inspection and recovery procedure; reconcile before any
112
- authorized retry so no duplicate writer starts.
113
-
114
- ## Reviewer workspaces and evidence
115
-
116
- Give each reviewer a separate Orca-managed child worktree under the candidate's
117
- worktree, including report-only reviews and rechecks; never share the author's
118
- checkout or another reviewer's checkout. A later review gets a fresh Orca-managed
119
- child worktree after the prior settled review's evidence and cleanup are
120
- reconciled. Use the runtime-owned worktree guide,
121
- not a raw Git worktree or temporary clone. Before dispatch, verify a detached
122
- checkout of the exact candidate SHA and the pinned base in that child.
123
-
124
- Name the private `<run dir>/evidence/<dispatch>/` folder in the brief and
125
- completion receipt. Keep tracked candidate files read-only and peer folders
126
- isolated. Scope `TMPDIR` to that 0700 folder for owned commands where supported.
127
- Before use or temporary-file cleanup, validate that its real path equals or
128
- is inside the recorded run evidence folder, is not a symbolic link, and matches the recorded
129
- Dispatch owner. Worktree-local temporary paths use the same guards against
130
- their recorded worktree and owner. Remove only an exact validated owned
131
- path, with no glob or parent-root deletion; never wipe a general cache.
132
- Uncertain temporary paths are preserved for reconciliation.
133
- Before removing a reviewer worktree, read back its report and supporting
134
- evidence from the private run evidence folder and record their paths. Files
135
- already there need no archive step; the private evidence archive applies only
136
- to legacy in-worktree evidence. Incidental caches are not evidence.
137
- A settled reviewer Dispatch can be
138
- cleaned before PR merge through [axstack-cleanup](../../axstack-cleanup/SKILL.md)
139
- only after its classification, readback, and removal guards pass. Preserve
140
- active or unknown review evidence and unique evidence whose bytes must survive;
141
- uncertain ownership or evidence holds. Terminal release alone is not permission
142
- to discard evidence or remove the worktree.
143
-
144
- ## Consume, settle, and recover
145
-
146
- Process a whole delivery before acknowledgment. Accept `worker_done` only when
147
- its sender, Task, and Dispatch match the expected active attempt; then verify
148
- the candidate revision and evidence before advancing Axstack's derived record.
149
- A valid completion for an older Dispatch never completes a newer Dispatch.
150
- Duplicate messages are deduplicated by their runtime identity.
151
-
152
- On `consumer_fenced`, stop consuming under that identity. Reconcile the active
153
- coordinator and delivery through the runtime guide; never bypass the fence,
154
- forge a sender, borrow a terminal identity, or partially acknowledge the
155
- delivery. Settlement is also runtime-owned: reuse, retain, or release a settled
156
- terminal only through the guide. A genuine `user_takeover` result requires
157
- retention; do not close, release, reuse, or send commands to that terminal as
158
- cleanup. Apply only the recorded
159
- repair Dispatch ID exception in [Workspace hygiene](workspace-hygiene.md).
160
-
161
- Contact loss, silence, idle state, or an absent status never proves exit or
162
- transfers authority. Ordinary restart and resume reconcile the same owner,
163
- author, Task, Dispatch, worktree, revisions, and pending receipts. Authorized
164
- repairs return to the same author when its session and evidence remain usable;
165
- uncertainty holds replacement rather than creating a second writer.
166
-
167
- ## Transfer ownership explicitly
168
-
169
- Distinguish supervised workers from a full ownership handoff. Only the user's
170
- explicit transfer request enters this branch. Record the intended recipient,
171
- exact scope, revisions, authority, and pending request before following the
172
- runtime-owned `orca-cli` handoff procedure.
173
-
174
- Input acceptance or turn start is launch evidence, not ownership. Validate an
175
- explicit recipient acceptance against the intended request, session, scope,
176
- candidate/base, and authority before changing ownership. Until then the current
177
- owner remains accountable. After a valid acceptance, record it, transfer only
178
- the accepted authority, and have the prior owner stop. Ordinary resume keeps
179
- the current owner and never launches a handoff.
180
-
181
- The runtime step is complete only when its real receipts are recorded with
182
- their limitations. Those receipts grant no merge, release, publication, model
183
- substitution, host-configuration, or scope authority.
@@ -1,123 +0,0 @@
1
- #!/usr/bin/env bun
2
- import { chmod, lstat, readFile, rename, unlink, writeFile } from 'node:fs/promises';
3
-
4
- function fail(message) { throw new Error(message); }
5
-
6
- function args(argv) {
7
- const values = {};
8
- for (let i = 0; i < argv.length; i += 2) {
9
- const key = argv[i];
10
- if (!['--path', '--repo-list-file', '--worktree-list-file'].includes(key) || !argv[i + 1] || values[key]) {
11
- fail(`invalid argument: ${key ?? '(end)'}`);
12
- }
13
- values[key] = argv[i + 1];
14
- }
15
- const path = values['--path'];
16
- if (!path || !path.startsWith('/') || path.includes('\0') || path.split('/').some((part) => part === '.' || part === '..') ||
17
- (path !== '/' && (path.endsWith('/') || path.includes('//')))) fail('path must be an exact absolute path');
18
- if (Boolean(values['--repo-list-file']) !== Boolean(values['--worktree-list-file'])) {
19
- fail('both Orca inventory files are required together');
20
- }
21
- return values;
22
- }
23
-
24
- async function inventory(file, command, key) {
25
- let raw;
26
- if (file) raw = await readFile(file, 'utf8');
27
- else {
28
- const result = Bun.spawnSync(['orca', ...command, '--json'], { stdout: 'pipe', stderr: 'pipe' });
29
- if (result.exitCode !== 0) fail(`Orca ${command.join(' ')} failed: ${result.stderr.toString().trim()}`);
30
- raw = result.stdout.toString();
31
- }
32
- const response = JSON.parse(raw);
33
- if (response.ok !== true || !Array.isArray(response.result?.[key])) fail(`invalid Orca ${key} inventory`);
34
- if (response.result.truncated === true) fail(`truncated Orca ${key} inventory`);
35
- return response.result[key];
36
- }
37
-
38
- async function configStat(path) {
39
- const stat = await lstat(path).catch((err) => err?.code === 'ENOENT' ? null : Promise.reject(err));
40
- if (stat?.isSymbolicLink()) fail(`refusing symlinked Claude config: ${path}`);
41
- if (stat && !stat.isFile()) fail(`Claude config is not a regular file: ${path}`);
42
- return stat;
43
- }
44
-
45
- async function snapshot(path) {
46
- const stat = await configStat(path);
47
- return { stat, raw: stat ? await readFile(path, 'utf8') : null };
48
- }
49
-
50
- async function withLock(path, action) {
51
- // The lock serializes this helper's writers; byte checks also catch other writers.
52
- const lock = `${path}.axstack-lock`;
53
- for (let attempt = 0; attempt < 100; attempt += 1) {
54
- try {
55
- await writeFile(lock, `${process.pid}\n`, { flag: 'wx', mode: 0o600 });
56
- try { return await action(); }
57
- finally { await unlink(lock); }
58
- } catch (err) {
59
- if (err?.code !== 'EEXIST') throw err;
60
- await Bun.sleep(5 + Math.floor(Math.random() * 10));
61
- }
62
- }
63
- fail('Claude config is busy; trust preflight held');
64
- }
65
-
66
- async function trust(configPath, path) {
67
- for (let attempt = 0; attempt < 5; attempt += 1) {
68
- const { stat, raw } = await snapshot(configPath);
69
- const current = raw === null ? {} : JSON.parse(raw);
70
- if (!current || typeof current !== 'object' || Array.isArray(current) ||
71
- (current.projects !== undefined && (!current.projects || typeof current.projects !== 'object' || Array.isArray(current.projects)))) {
72
- fail('invalid Claude config shape');
73
- }
74
- if (current.projects?.[path]?.hasTrustDialogAccepted === true) {
75
- console.log(JSON.stringify({ status: 'already-trusted', path }));
76
- return;
77
- }
78
- current.projects ??= {};
79
- if (current.projects[path] !== undefined && (!current.projects[path] || typeof current.projects[path] !== 'object' || Array.isArray(current.projects[path]))) {
80
- fail('invalid Claude project entry');
81
- }
82
- current.projects[path] ??= {};
83
- current.projects[path].hasTrustDialogAccepted = true;
84
-
85
- const temp = `${configPath}.${crypto.randomUUID()}.tmp`;
86
- try {
87
- await writeFile(temp, `${JSON.stringify(current, null, 2)}\n`, { flag: 'wx', mode: stat ? stat.mode & 0o777 : 0o600 });
88
- if (stat) await chmod(temp, stat.mode & 0o777);
89
- if ((await snapshot(configPath)).raw !== raw) {
90
- await Bun.sleep(5 + Math.floor(Math.random() * 10));
91
- continue;
92
- }
93
- await rename(temp, configPath);
94
- const after = await snapshot(configPath);
95
- if (JSON.parse(after.raw).projects?.[path]?.hasTrustDialogAccepted === true) {
96
- console.log(JSON.stringify({ status: 'trusted', path }));
97
- return;
98
- }
99
- } finally {
100
- await unlink(temp).catch((err) => { if (err?.code !== 'ENOENT') throw err; });
101
- }
102
- await Bun.sleep(5 + Math.floor(Math.random() * 10));
103
- }
104
- fail('Claude config changed during trust preflight');
105
- }
106
-
107
- async function main() {
108
- const options = args(process.argv.slice(2));
109
- const path = options['--path'];
110
- const repos = await inventory(options['--repo-list-file'], ['repo', 'list'], 'repos');
111
- const worktrees = await inventory(options['--worktree-list-file'], ['worktree', 'list'], 'worktrees');
112
- const repoIds = new Set(repos.filter((repo) => repo.kind === 'git').map((repo) => repo.id));
113
- const registered = repos.some((repo) => repo.kind === 'git' && repo.path === path) ||
114
- worktrees.some((worktree) => repoIds.has(worktree.repoId) && worktree.hostId === 'local' && worktree.path === path);
115
- if (!registered) fail(`path is not an Orca-registered repository or worktree: ${path}`);
116
-
117
- const home = process.env.HOME;
118
- if (!home?.startsWith('/')) fail('HOME must be absolute');
119
- const configPath = `${home.replace(/\/$/, '')}/.claude.json`;
120
- await withLock(configPath, () => trust(configPath, path));
121
- }
122
-
123
- main().catch((err) => { console.error(err.message); process.exitCode = 1; });