axstack 0.11.6 → 0.11.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "axstack",
3
- "version": "0.11.6",
3
+ "version": "0.11.7",
4
4
  "description": "Axstack installer and setup CLI: installs owned chat skills and role data, configures supported harness settings, and checks Orca capabilities.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -124,6 +124,66 @@ The driver performs this order and exits:
124
124
 
125
125
  ## Dispatch and repair selection
126
126
 
127
+ Claude Code trusts a folder per git toplevel and stops at its "Quick safety
128
+ check" dialog otherwise; every per-PR child worktree is a new toplevel, and
129
+ the driver must never answer that dialog for a worker. The user decided on
130
+ 2026-09-17 that a worktree the driver itself creates from an allowlisted
131
+ clone at the pinned head is trusted by policy: immediately after creating
132
+ it and before `worker-start`, the driver runs the trust helper
133
+ (`docs/plans/pr-automations-trust.js`, deployed beside the precheck and run
134
+ with Bun), which
135
+ owns the only write the automation makes to `~/.claude.json`. It writes the path's `hasTrustDialogAccepted` entry — what a
136
+ manual acceptance writes. The helper
137
+ enforces the scope mechanically before it writes anything: the path must be
138
+ a git worktree whose common dir is the named allowlisted clone's, must not
139
+ be the clone itself, and must sit at exactly the pinned head — anything
140
+ else exits 3 and is never seeded. It is one process on purpose: lock, refresher,
141
+ render and rename all happen in the same process, so nothing can outlive the
142
+ owner and commit after it dies. It writes under Claude Code's own config
143
+ lock — the `mkdir`-based `~/.claude.json.lock` directory its sessions take —
144
+ following Claude's own lease rules, with a bounded retry. Only a successful
145
+ `mkdir` counts as holding it; a fresh foreign lock is never broken, and the only lock it will
146
+ reclaim is one whose mtime is past Claude's 10 s stale threshold, which is
147
+ exactly what Claude itself treats as abandoned. It keeps the lease alive the
148
+ way Claude does: a refresher touches the lock's mtime every second for as
149
+ long as it is held, so the lock cannot age into staleness under it even if a
150
+ rename stalls. The refresher runs with the owner and dies with it, exits the
151
+ moment the lock is no longer ours, and treats a failed refresh as a
152
+ compromised lease by terminating the owner before it can commit. The helper
153
+ re-reads under the lock, refuses a store that does not parse, writes a
154
+ unique temp file, preserves the store's mode, re-verifies at commit that the
155
+ lease is healthy — unchanged inode, refresher alive, refreshed within the
156
+ last few seconds — and otherwise discards the temp and commits nothing,
157
+ treats a failed chmod or rename as failure with the temp removed, and
158
+ releases only a lock it still owns, stopping the refresher first. A busy or unreadable
159
+ store exits 2: the worktree is retained and nothing is dispatched. The
160
+ worktree cleanup removes the entry through the same helper; if that
161
+ removal fails after the worktree is gone, the marker stays in
162
+ `pending_settlement[]` as `untrust-pending` — which keeps the PR
163
+ undispatchable, so the reused path can never inherit a dead trust entry —
164
+ and the removal is retried next tick. A retained worktree keeps its entry
165
+ while retained; it is the same driver-created path. This is scoped
166
+ exactly there — never for any other path, never for a worktree it did not
167
+ create — because that dialog is the last guard between PR content and a
168
+ worker running with permissions bypassed. Trusting a folder activates the
169
+ full project surface: its `.claude/settings.json` and the hooks it defines,
170
+ its `.mcp.json` servers, marketplace plugin auto-install, and `CLAUDE.md`;
171
+ a hostile branch's hooks or MCP servers would run the moment the folder
172
+ opens. So the worker is launched in Claude Code's own isolation mode,
173
+ `--safe-mode`, through `terminal create` and `worker-start --terminal`,
174
+ since `worker-start` cannot pass argv. Safe mode is the binary's sanctioned
175
+ "all customizations disabled" path: no `CLAUDE.md`, skills, plugins, hooks,
176
+ MCP servers, custom commands or agents load from anywhere, project or user;
177
+ built-in tools and authentication are untouched, and the brief loads the
178
+ skill files it needs by path. The driver confirms readiness from the
179
+ rendered frame — `wait.satisfied`, the prompt marker present, the dialog
180
+ absent — before dispatching. What remains live is the repository's files as
181
+ data the worker reads and the commands the worker itself chooses to run,
182
+ which it already runs today; nothing from the branch loads, executes, or is
183
+ offered for invocation on its own. The allowlist,
184
+ the pinned head, and that reduced surface are what make pre-trust
185
+ acceptable, and nothing else does.
186
+
127
187
  Every selected PR receives one dispatch marker with task id, dispatch id,
128
188
  worktree, head, `started_at`, reservation (`verdict` or `repair`), and trigger:
129
189
  `{kind: check, name, app_id}` or `{kind: review, review_id, digest}`. There is at
@@ -329,7 +389,8 @@ shared clone can fake durability, a failed fetch retaining the worktree — or h
329
389
  abandon path, the worktree has no uncommitted changes.
330
390
  Only then it closes any terminal tab still listed, clears untracked
331
391
  artefacts, removes the child worktree and its directory, deletes the branch
332
- the worktree created, and verifies the directory is gone. On the settled path
392
+ the worktree created, removes the Claude Code trust entry it seeded for that
393
+ path, and verifies the directory is gone. On the settled path
333
394
  the worker has finished, so untracked files are artefacts by definition and
334
395
  are cleared; a candidate there is already pushed or token-held. An abandoned
335
396
  worktree that is dirty or holds an unproven candidate is **retained**, named
@@ -349,6 +410,7 @@ its dispatch without such a retention record is a health finding. The run direct
349
410
  `runtime_refusal{code, first_seen, last_seen}` (absent when no runtime
350
411
  hold is open);
351
412
  - `pending.json`, `precheck.log` — driver precheck only;
413
+ - `trust.js` — the trust transaction helper, run by the driver only;
352
414
  - `decisions/<token>.json` — writers assigned by the lifecycle table;
353
415
  - `watchdog.log` and `watchdog-state.json` (occurrence `first_observed` values
354
416
  and send receipts) — watchdog only;