@rubytech/create-maxy-code 0.1.568 → 0.1.570

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 (56) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/PLUGIN.md +7 -5
  3. package/payload/platform/plugins/admin/hooks/__tests__/pdf-text-layer-inject.test.sh +177 -0
  4. package/payload/platform/plugins/admin/hooks/__tests__/quote-path-write-gate.test.sh +152 -0
  5. package/payload/platform/plugins/admin/hooks/__tests__/quote-pdf-bash-gate.test.sh +95 -0
  6. package/payload/platform/plugins/admin/hooks/__tests__/quote-render-gate.test.sh +141 -45
  7. package/payload/platform/plugins/admin/hooks/__tests__/quote-render-pdf-conformance.test.sh +114 -0
  8. package/payload/platform/plugins/admin/hooks/pdf-text-layer-inject.sh +137 -0
  9. package/payload/platform/plugins/admin/hooks/quote-path-write-gate.sh +137 -0
  10. package/payload/platform/plugins/admin/hooks/quote-pdf-bash-gate.sh +70 -0
  11. package/payload/platform/plugins/admin/hooks/quote-render-gate.sh +105 -37
  12. package/payload/platform/plugins/admin/hooks/quote-render-pdf-conformance.sh +178 -0
  13. package/payload/platform/plugins/admin/mcp/dist/lib/roster-census.d.ts.map +1 -1
  14. package/payload/platform/plugins/admin/mcp/dist/lib/roster-census.js +50 -4
  15. package/payload/platform/plugins/admin/mcp/dist/lib/roster-census.js.map +1 -1
  16. package/payload/platform/plugins/admin/skills/a4-print-documents/SKILL.md +12 -1
  17. package/payload/platform/plugins/admin/skills/a4-print-documents/pdf-inspect.mjs +113 -0
  18. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +14 -0
  19. package/payload/platform/plugins/docs/references/admin-session.md +15 -0
  20. package/payload/platform/scripts/__tests__/mailbox-inject-registered.test.sh +19 -43
  21. package/payload/platform/scripts/__tests__/preference-hooks-registered.test.sh +3 -1
  22. package/payload/platform/scripts/__tests__/public-prompt-gate-registered.test.sh +22 -37
  23. package/payload/platform/scripts/__tests__/public-surface-registered.test.sh +12 -35
  24. package/payload/platform/scripts/__tests__/quote-ownership-contract.test.sh +86 -0
  25. package/payload/platform/scripts/lib/__tests__/account-settings-reconcile.test.sh +73 -0
  26. package/payload/platform/scripts/lib/account-settings-reconcile.sh +88 -0
  27. package/payload/platform/scripts/lib/provision-account-dir.sh +11 -144
  28. package/payload/platform/scripts/setup-account.sh +11 -53
  29. package/payload/platform/services/claude-session-manager/dist/account-agent-registry.d.ts +20 -0
  30. package/payload/platform/services/claude-session-manager/dist/account-agent-registry.d.ts.map +1 -1
  31. package/payload/platform/services/claude-session-manager/dist/account-agent-registry.js +78 -1
  32. package/payload/platform/services/claude-session-manager/dist/account-agent-registry.js.map +1 -1
  33. package/payload/platform/services/claude-session-manager/dist/blocked-tool-census.d.ts +129 -0
  34. package/payload/platform/services/claude-session-manager/dist/blocked-tool-census.d.ts.map +1 -0
  35. package/payload/platform/services/claude-session-manager/dist/blocked-tool-census.js +344 -0
  36. package/payload/platform/services/claude-session-manager/dist/blocked-tool-census.js.map +1 -0
  37. package/payload/platform/services/claude-session-manager/dist/index.js +107 -0
  38. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  39. package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.d.ts +42 -0
  40. package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.d.ts.map +1 -0
  41. package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.js +215 -0
  42. package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.js.map +1 -0
  43. package/payload/platform/services/claude-session-manager/dist/specialist-preference-audit.d.ts +108 -0
  44. package/payload/platform/services/claude-session-manager/dist/specialist-preference-audit.d.ts.map +1 -0
  45. package/payload/platform/services/claude-session-manager/dist/specialist-preference-audit.js +299 -0
  46. package/payload/platform/services/claude-session-manager/dist/specialist-preference-audit.js.map +1 -0
  47. package/payload/platform/templates/account-settings.json +159 -0
  48. package/payload/server/server.js +750 -656
  49. package/payload/platform/scripts/lib/__tests__/account-settings-askgate.test.sh +0 -144
  50. package/payload/platform/scripts/lib/__tests__/account-settings-mailbox-inject.test.sh +0 -166
  51. package/payload/platform/scripts/lib/__tests__/account-settings-pdf-conformance.test.sh +0 -151
  52. package/payload/platform/scripts/lib/__tests__/account-settings-public-surface.test.sh +0 -109
  53. package/payload/platform/scripts/lib/account-settings-askgate.sh +0 -98
  54. package/payload/platform/scripts/lib/account-settings-mailbox-inject.sh +0 -91
  55. package/payload/platform/scripts/lib/account-settings-pdf-conformance.sh +0 -98
  56. package/payload/platform/scripts/lib/account-settings-public-surface.sh +0 -109
@@ -70,151 +70,18 @@ provision_account_dir() {
70
70
  [ -d "$ACCOUNT_DIR/.git" ] || git init -q "$ACCOUNT_DIR"
71
71
 
72
72
  # --- project-level .claude/settings.json (hooks; no allowlist) -------------
73
+ # The hook set is data, not a heredoc: platform/templates/account-settings.json
74
+ # is copied verbatim (every $PLATFORM_ROOT in it is a literal Claude Code
75
+ # resolves at hook-run time, so no substitution is needed). Keeping it as a
76
+ # file is what lets account-settings-reconcile.sh converge accounts that
77
+ # already exist, which this writer alone never could — it runs at provision
78
+ # time, and the upgrade path re-provisions the house account and no other.
73
79
  local ACCOUNT_SETTINGS="$ACCOUNT_DIR/.claude/settings.json"
74
- local HOOKS_PATH="\$PLATFORM_ROOT/plugins/admin/hooks"
75
- cat > "$ACCOUNT_SETTINGS" << SETTINGS_EOF
76
- {
77
- "permissions": {
78
- "defaultMode": "bypassPermissions",
79
- "allow": [],
80
- "deny": []
81
- },
82
- "hooks": {
83
- "PreToolUse": [
84
- {
85
- "matcher": "Write",
86
- "hooks": [
87
- { "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" },
88
- { "type": "command", "command": "bash $HOOKS_PATH/fs-schema-guard.sh" }
89
- ]
90
- },
91
- {
92
- "matcher": "Edit",
93
- "hooks": [
94
- { "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" },
95
- { "type": "command", "command": "bash $HOOKS_PATH/fs-schema-guard.sh" }
96
- ]
97
- },
98
- {
99
- "matcher": "NotebookEdit",
100
- "hooks": [
101
- { "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" },
102
- { "type": "command", "command": "bash $HOOKS_PATH/fs-schema-guard.sh" }
103
- ]
104
- },
105
- {
106
- "matcher": "Bash",
107
- "hooks": [
108
- { "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" },
109
- { "type": "command", "command": "bash $HOOKS_PATH/fs-schema-guard-bash-pre.sh" },
110
- { "type": "command", "command": "bash $HOOKS_PATH/quote-engine-gate.sh" }
111
- ]
112
- },
113
- {
114
- "hooks": [
115
- { "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" },
116
- { "type": "command", "command": "bash $HOOKS_PATH/public-tool-surface.sh" }
117
- ]
118
- },
119
- {
120
- "matcher": "WebFetch",
121
- "hooks": [
122
- { "type": "command", "command": "node $HOOKS_PATH/webfetch-preflight.mjs" }
123
- ]
124
- },
125
- {
126
- "matcher": "AskUserQuestion",
127
- "hooks": [
128
- { "type": "command", "command": "bash $HOOKS_PATH/askuserquestion-investigate-gate.sh" },
129
- { "type": "command", "command": "bash $HOOKS_PATH/askuserquestion-channel-carrier-gate.sh" }
130
- ]
131
- },
132
- {
133
- "matcher": "mcp__plugin_browser_browser__browser-pdf-save",
134
- "hooks": [
135
- { "type": "command", "command": "bash $HOOKS_PATH/quote-render-gate.sh" }
136
- ]
137
- },
138
- {
139
- "matcher": "mcp__plugin_browser_browser__browser-pdf-save",
140
- "hooks": [
141
- { "type": "command", "command": "bash $HOOKS_PATH/preference-consult-gate.sh" }
142
- ]
143
- },
144
- {
145
- "matcher": "mcp__plugin_email_email__email-send|mcp__plugin_email_email__email-reply|mcp__plugin_email_email__email-draft-send|mcp__plugin_outlook_outlook__outlook-mail-send|mcp__plugin_outlook_outlook__outlook-mail-reply|mcp__plugin_outlook_outlook__outlook-draft-send|SendUserFile",
146
- "hooks": [
147
- { "type": "command", "command": "bash $HOOKS_PATH/preference-consult-gate.sh" }
148
- ]
149
- }
150
- ],
151
- "PostToolUse": [
152
- {
153
- "matcher": "Bash",
154
- "hooks": [
155
- { "type": "command", "command": "bash $HOOKS_PATH/fs-schema-guard-bash-post.sh" }
156
- ]
157
- },
158
- {
159
- "matcher": "Agent",
160
- "hooks": [
161
- { "type": "command", "command": "bash $HOOKS_PATH/post-tool-use-agent.sh" }
162
- ]
163
- },
164
- {
165
- "matcher": "mcp__plugin_browser_browser__browser-pdf-save",
166
- "hooks": [
167
- { "type": "command", "command": "bash $HOOKS_PATH/quote-render-pdf-conformance.sh" }
168
- ]
169
- },
170
- {
171
- "matcher": "mcp__.*__.*-(export|import)-parse$",
172
- "hooks": [
173
- { "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" }
174
- ]
175
- },
176
- {
177
- "matcher": "mcp__.*",
178
- "hooks": [
179
- { "type": "command", "command": "bash $HOOKS_PATH/mcp-tool-missing.sh" }
180
- ]
181
- },
182
- {
183
- "matcher": "Write",
184
- "hooks": [
185
- { "type": "command", "command": "bash $HOOKS_PATH/admin-authoring-observer.sh" }
186
- ]
187
- },
188
- {
189
- "matcher": "Edit",
190
- "hooks": [
191
- { "type": "command", "command": "bash $HOOKS_PATH/admin-authoring-observer.sh" }
192
- ]
193
- }
194
- ],
195
- "UserPromptSubmit": [
196
- {
197
- "hooks": [
198
- { "type": "command", "command": "bash $HOOKS_PATH/archive-ingest-surface-gate.sh" },
199
- { "type": "command", "command": "bash $HOOKS_PATH/prompt-optimiser-directive.sh" },
200
- { "type": "command", "command": "bash $HOOKS_PATH/datetime-inject.sh" },
201
- { "type": "command", "command": "bash $HOOKS_PATH/mailbox-inject.sh" },
202
- { "type": "command", "command": "bash $HOOKS_PATH/preference-consult-directive.sh" },
203
- { "type": "command", "command": "bash $HOOKS_PATH/public-tool-surface.sh" }
204
- ]
205
- }
206
- ],
207
- "Stop": [
208
- {
209
- "hooks": [
210
- { "type": "command", "command": "bash $HOOKS_PATH/prompt-optimiser-compliance.sh" },
211
- { "type": "command", "command": "bash $HOOKS_PATH/public-tool-surface.sh" }
212
- ]
213
- }
214
- ]
215
- }
216
- }
217
- SETTINGS_EOF
80
+ if [ -f "$TEMPLATES_DIR/account-settings.json" ]; then
81
+ cp "$TEMPLATES_DIR/account-settings.json" "$ACCOUNT_SETTINGS"
82
+ else
83
+ echo " [acct-settings] WARNING: template missing at $TEMPLATES_DIR/account-settings.json — settings.json not written" >&2
84
+ fi
218
85
 
219
86
  # --- agent identities + specialist plugin templates ------------------------
220
87
  cp "$TEMPLATES_DIR/agents/admin/IDENTITY.md" "$ACCOUNT_DIR/agents/admin/IDENTITY.md"
@@ -34,14 +34,6 @@ ACCOUNTS_DIR="$INSTALL_DIR/data/accounts"
34
34
  . "$SCRIPT_DIR/lib/resolve-account-dir.sh"
35
35
  # shellcheck source=lib/provision-account-dir.sh
36
36
  . "$SCRIPT_DIR/lib/provision-account-dir.sh"
37
- # shellcheck source=lib/account-settings-askgate.sh
38
- . "$SCRIPT_DIR/lib/account-settings-askgate.sh"
39
- # shellcheck source=lib/account-settings-pdf-conformance.sh
40
- . "$SCRIPT_DIR/lib/account-settings-pdf-conformance.sh"
41
- # shellcheck source=lib/account-settings-mailbox-inject.sh
42
- . "$SCRIPT_DIR/lib/account-settings-mailbox-inject.sh"
43
- # shellcheck source=lib/account-settings-public-surface.sh
44
- . "$SCRIPT_DIR/lib/account-settings-public-surface.sh"
45
37
  # shellcheck source=lib/read-brand-json.sh
46
38
  . "$SCRIPT_DIR/lib/read-brand-json.sh"
47
39
  # Resolve brand-aware persistent users.json path before the resolver runs.
@@ -73,49 +65,15 @@ provision_account_dir "$ACCOUNT_DIR" "$ACCOUNT_ID" "house"
73
65
  reconcile_all_accounts_owned_dirs "$ACCOUNTS_DIR"
74
66
 
75
67
  # ------------------------------------------------------------------
76
- # 4. Retrofit the AskUserQuestion carrier gate onto every existing account
68
+ # 4. Converge the whole hook set on every account
77
69
  # ------------------------------------------------------------------
78
- # Standing check + durable backfill (Task 1683): provision_account_dir writes the
79
- # AskUserQuestion PreToolUse matcher (both gates) only at provision time, and this
80
- # script re-provisions only the house account so a client sub-account created
81
- # before Task 1552 keeps a stale matcher with no channel-carrier gate and
82
- # re-wedges on a channel AskUserQuestion. Reconcile every account on every install
83
- # so the gate reaches pre-1552 accounts. Idempotent; logs one [backfill-1683] line
84
- # per account.
85
- reconcile_all_accounts_askgate "$ACCOUNTS_DIR"
86
-
87
- # ------------------------------------------------------------------
88
- # 5. Retrofit the quote-render PDF-conformance matcher onto every account
89
- # ------------------------------------------------------------------
90
- # Standing check + durable backfill (Task 1929): provision_account_dir writes the
91
- # PostToolUse browser-pdf-save matcher (quote-render-pdf-conformance.sh) only at
92
- # provision time, and this script re-provisions only the house account. An
93
- # account created before Task 1922 keeps a settings.json without the matcher and
94
- # never runs the PDF gate. Reconcile every account on every install so the gate
95
- # reaches pre-1922 accounts. Idempotent; logs one [backfill-1929] line per account.
96
- reconcile_all_accounts_pdf_conformance "$ACCOUNTS_DIR"
97
-
98
- # ------------------------------------------------------------------
99
- # 6. Retrofit the per-turn <mailboxes> injection hook onto every account
100
- # ------------------------------------------------------------------
101
- # Standing check + durable backfill (Task 2157): provision_account_dir writes the
102
- # UserPromptSubmit array only at provision time, and this script re-provisions
103
- # only the house account. A client sub-account created by the account-lifecycle
104
- # tool keeps a settings.json without mailbox-inject.sh and never gets the
105
- # standing mailbox list, so its sessions go on learning attachment state by
106
- # polling one mail plugin and reading that plugin's miss as an account-wide fact.
107
- # Reconcile every account on every install. Idempotent; logs one [backfill-2157]
108
- # line per account.
109
- reconcile_all_accounts_mailbox_inject "$ACCOUNTS_DIR"
110
-
111
- # ------------------------------------------------------------------
112
- # 7. Retrofit the realised-public-tool-surface hook onto every account
113
- # ------------------------------------------------------------------
114
- # Standing check + durable backfill (Task 2339): provision_account_dir writes the
115
- # matcher-less PreToolUse entry and the Stop entry only at provision time, and
116
- # this script re-provisions only the house account. Without this, the hook that
117
- # records what a public spawn's tools actually did would reach house accounts
118
- # only — including not reaching the account where five tools were seen running
119
- # under a one-tool allowlist. Reconcile every account on every install.
120
- # Idempotent; logs one [backfill-2339] line per account.
121
- reconcile_all_accounts_public_surface "$ACCOUNTS_DIR"
70
+ # provision_account_dir writes the full hook set, but only at provision time,
71
+ # and this script re-provisions the house account and no other — so an account
72
+ # created before a hook landed would run a stale set indefinitely. This step
73
+ # converges each account's settings against the shipped template instead, and
74
+ # states the divergence count on every run including zero. It is the single
75
+ # writer of account settings: a hook added to
76
+ # platform/templates/account-settings.json needs no backfill of its own.
77
+ # (Task 2475 retired the four one-hook backfill libs this replaced.)
78
+ . "$SCRIPT_DIR/lib/account-settings-reconcile.sh"
79
+ reconcile_all_accounts_settings "$ACCOUNTS_DIR"
@@ -10,6 +10,26 @@
10
10
  * into `op=account-agent-registry error`. Exported for its own unit test: the
11
11
  * propagation half cannot be provoked through the filesystem from outside. */
12
12
  export declare function ignoringRaceWith(code: 'EEXIST' | 'ENOENT', act: () => void): void;
13
+ /** What the CLI will be able to dispatch from the registry we just wrote.
14
+ *
15
+ * Task 2469 — the mirror is keyed on filename and dispatch is keyed on the
16
+ * frontmatter `name`, so `synced=<N>` cannot answer "can this be reached?".
17
+ * A card with no name, and two cards claiming one name, both mirror cleanly
18
+ * and neither dispatches; a specialist that is never dispatched never fails,
19
+ * so no transition log anywhere carries it. Only a state reconcile sees it.
20
+ *
21
+ * Measured over the registry rather than the source directory, because the
22
+ * registry is the directory the CLI reads: where an operator's own regular
23
+ * file sits at a card's name, that file is what resolves, and it is that file
24
+ * this must report on.
25
+ *
26
+ * Exported for its own unit test and for callers that want the state without
27
+ * re-running a sync. */
28
+ export declare function resolveRegistryNames(registryDir: string): {
29
+ resolvable: number;
30
+ unnamed: string[];
31
+ dupeNames: string[];
32
+ };
13
33
  /** Mirror `<accountDir>/specialists/agents/*.md` into
14
34
  * `<accountDir>/.claude/agents/` as symlinks, and remove every registry
15
35
  * symlink the source no longer has. Emits exactly one line:
@@ -1 +1 @@
1
- {"version":3,"file":"account-agent-registry.d.ts","sourceRoot":"","sources":["../src/account-agent-registry.ts"],"names":[],"mappings":"AA6BA;;;;;;;;;;+EAU+E;AAC/E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,EAAE,GAAG,EAAE,MAAM,IAAI,GAAG,IAAI,CAOjF;AAED;;;;+EAI+E;AAC/E,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAmF9F"}
1
+ {"version":3,"file":"account-agent-registry.d.ts","sourceRoot":"","sources":["../src/account-agent-registry.ts"],"names":[],"mappings":"AA6BA;;;;;;;;;;+EAU+E;AAC/E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,EAAE,GAAG,EAAE,MAAM,IAAI,GAAG,IAAI,CAOjF;AA6BD;;;;;;;;;;;;;;yBAcyB;AACzB,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG;IACzD,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB,CAsBA;AAED;;;;+EAI+E;AAC/E,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAgG9F"}
@@ -23,7 +23,7 @@
23
23
  // It never throws. A registry that cannot be written is a specialist that
24
24
  // cannot be dispatched, which is the state before this module existed; a spawn
25
25
  // that dies instead is strictly worse.
26
- import { existsSync, lstatSync, mkdirSync, readdirSync, readlinkSync, symlinkSync, unlinkSync } from 'node:fs';
26
+ import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, readlinkSync, symlinkSync, unlinkSync } from 'node:fs';
27
27
  import { dirname, join, resolve } from 'node:path';
28
28
  /** Two spawns in the same account sync concurrently — an admin session and a
29
29
  * channel session are routine — and they write identical content. Whoever
@@ -46,6 +46,72 @@ export function ignoringRaceWith(code, act) {
46
46
  throw err;
47
47
  }
48
48
  }
49
+ /** The `name:` value from a card's frontmatter, or null. CRLF-tolerant and
50
+ * quote-stripping, matching the reader in `specialist-roster.ts` and the one
51
+ * in the roster census, so every surface agrees on what a card is called. A
52
+ * card that cannot be read — a dangling link, a directory at a `.md` path,
53
+ * EACCES — yields null rather than throwing, because "we could not tell" and
54
+ * "it does not resolve" are the same answer to the dispatcher. */
55
+ function readFrontmatterName(file) {
56
+ let raw;
57
+ try {
58
+ raw = readFileSync(file, 'utf8');
59
+ }
60
+ catch {
61
+ return null;
62
+ }
63
+ const fm = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
64
+ if (!fm)
65
+ return null;
66
+ const m = fm[1].match(/^name:\s*(.*?)\r?$/m);
67
+ if (!m)
68
+ return null;
69
+ let value = m[1].trim();
70
+ if ((value.startsWith('"') && value.endsWith('"')) ||
71
+ (value.startsWith("'") && value.endsWith("'"))) {
72
+ value = value.slice(1, -1);
73
+ }
74
+ return value || null;
75
+ }
76
+ /** What the CLI will be able to dispatch from the registry we just wrote.
77
+ *
78
+ * Task 2469 — the mirror is keyed on filename and dispatch is keyed on the
79
+ * frontmatter `name`, so `synced=<N>` cannot answer "can this be reached?".
80
+ * A card with no name, and two cards claiming one name, both mirror cleanly
81
+ * and neither dispatches; a specialist that is never dispatched never fails,
82
+ * so no transition log anywhere carries it. Only a state reconcile sees it.
83
+ *
84
+ * Measured over the registry rather than the source directory, because the
85
+ * registry is the directory the CLI reads: where an operator's own regular
86
+ * file sits at a card's name, that file is what resolves, and it is that file
87
+ * this must report on.
88
+ *
89
+ * Exported for its own unit test and for callers that want the state without
90
+ * re-running a sync. */
91
+ export function resolveRegistryNames(registryDir) {
92
+ let entries;
93
+ try {
94
+ entries = readdirSync(registryDir).filter((n) => n.endsWith('.md')).sort();
95
+ }
96
+ catch {
97
+ return { resolvable: 0, unnamed: [], dupeNames: [] };
98
+ }
99
+ const claims = new Map();
100
+ const unnamed = [];
101
+ for (const file of entries) {
102
+ const name = readFrontmatterName(join(registryDir, file));
103
+ if (name === null) {
104
+ unnamed.push(file);
105
+ continue;
106
+ }
107
+ claims.set(name, (claims.get(name) ?? 0) + 1);
108
+ }
109
+ const dupeNames = Array.from(claims.entries())
110
+ .filter(([, n]) => n > 1)
111
+ .map(([name]) => name)
112
+ .sort();
113
+ return { resolvable: claims.size, unnamed, dupeNames };
114
+ }
49
115
  /** Mirror `<accountDir>/specialists/agents/*.md` into
50
116
  * `<accountDir>/.claude/agents/` as symlinks, and remove every registry
51
117
  * symlink the source no longer has. Emits exactly one line:
@@ -138,6 +204,17 @@ export function syncAccountAgentRegistry(accountDir, log) {
138
204
  pruned++;
139
205
  }
140
206
  log(`op=account-agent-registry synced=${synced} pruned=${pruned} collisions=${collisions.join(',')}`);
207
+ // Task 2469 — a second line, not three more fields on the first. That one
208
+ // is a transition record: what this spawn changed. This is a state
209
+ // reconcile: what is reachable now. Emitted every spawn including zero, so
210
+ // an account with no specialists is distinguishable from a reconcile that
211
+ // did not run. On the error path below it is deliberately absent — after a
212
+ // failed sync the reachable set is unknown, and reporting zero would assert
213
+ // something this never measured.
214
+ const resolution = resolveRegistryNames(registryDir);
215
+ log(`op=agent-registry-resolution resolvable=${resolution.resolvable}` +
216
+ ` unnamed=${resolution.unnamed.join(',')}` +
217
+ ` dupeNames=${resolution.dupeNames.join(',')}`);
141
218
  }
142
219
  catch (err) {
143
220
  log(`op=account-agent-registry error reason=${err instanceof Error ? err.message : String(err)}`);
@@ -1 +1 @@
1
- {"version":3,"file":"account-agent-registry.js","sourceRoot":"","sources":["../src/account-agent-registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-agent-registry.js","sourceRoot":"","sources":["../src/account-agent-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ import type { Logger } from './types.js';
2
+ export declare const TAG = "[blocked-tool]";
3
+ export interface ToolUseRecord {
4
+ id: string;
5
+ name: string;
6
+ }
7
+ /** One transcript's scan result. `agentId` is `—` for the session's own
8
+ * transcript and `agent-<id>` for a subagent's — the field that distinguishes
9
+ * a card the operator CAN see in the session UI from one they cannot. */
10
+ export interface TranscriptScan {
11
+ agentId: string;
12
+ path: string;
13
+ mtimeMs: number;
14
+ unmatched: ToolUseRecord[];
15
+ }
16
+ export interface BlockedCall {
17
+ sessionId: string;
18
+ agentId: string;
19
+ toolUseId: string;
20
+ tool: string;
21
+ blockedForMs: number;
22
+ }
23
+ export interface BlockedCensusSnapshot {
24
+ /** Transcripts read this tick, across every live session. */
25
+ scanned: number;
26
+ blocked: BlockedCall[];
27
+ /** The session ids that were live this tick. A previously-blocked call whose
28
+ * session is no longer here did not resolve — the session went away — and
29
+ * reporting that as `op=cleared` would tell the operator the block lifted. */
30
+ liveSessionIds: string[];
31
+ }
32
+ /** PURE. Every `tool_use` id in these lines with no matching `tool_result`.
33
+ * Order is first-sighting order. Malformed lines are skipped, not thrown on:
34
+ * a JSONL read can land mid-append. A `tool_use` carrying no `name` is
35
+ * reported as `unknown` rather than dropped — an unnamed blocked call is
36
+ * still a blocked call. */
37
+ export declare function unmatchedToolUses(lines: readonly string[]): ToolUseRecord[];
38
+ /** PURE. Which unmatched calls are blocked. Blocked means unmatched AND the
39
+ * transcript has not advanced for `staleMs`. Without the staleness term every
40
+ * in-flight call would be reported, which would make the signal useless. */
41
+ export declare function blockedFromScans(sessionId: string, scans: readonly TranscriptScan[], nowMs: number, staleMs: number): BlockedCall[];
42
+ /** PURE. Emitted every tick INCLUDING zero, so a census that stopped ticking is
43
+ * distinguishable from one that found nothing. `sessions` is separate from
44
+ * `scanned` on purpose: `sessions=3 scanned=0` is a census that could not
45
+ * resolve a transcript for any live session, which without the first field
46
+ * reads exactly like a quiet box. */
47
+ export declare function formatBlockedCensus(s: BlockedCensusSnapshot): string;
48
+ /** PURE. */
49
+ export declare function formatBlocked(c: BlockedCall): string;
50
+ /** PURE. Same ids as its `op=blocked` twin, so the pair is greppable. Emitted
51
+ * ONLY when the session is still live and the result landed. */
52
+ export declare function formatCleared(c: BlockedCall): string;
53
+ /** PURE. The other way a blocked call leaves the reported set: its session
54
+ * stopped being live. The call did NOT resolve, and saying `op=cleared` here
55
+ * would tell the operator the block lifted when the session actually went
56
+ * away with the card still unanswered. */
57
+ export declare function formatSessionGone(c: BlockedCall): string;
58
+ export declare const DEFAULT_STALE_MS = 120000;
59
+ export declare const DEFAULT_NOTIFY_AFTER_MS = 180000;
60
+ /** A `tool_result` always follows its `tool_use` in the same file, so a
61
+ * contiguous tail containing the use contains its result too — unless one
62
+ * result exceeds this window, in which case that one call reads as unmatched.
63
+ * 1 MB is a chosen bound, not a measured one; the failure mode it admits is a
64
+ * false `op=blocked` on a call whose result was larger than the window. */
65
+ export declare const TAIL_BYTES: number;
66
+ export interface BlockedCensusIo {
67
+ listSessionIds(): string[];
68
+ /** The session's own transcript (`agentId: '—'`) followed by every
69
+ * `<sessionId>/subagents/agent-*.jsonl`. */
70
+ listTranscripts(sessionId: string): Array<{
71
+ agentId: string;
72
+ path: string;
73
+ }>;
74
+ /** Last `maxBytes` of the file split into lines, plus its mtime. Null when
75
+ * the file cannot be read. The first line is dropped when the read started
76
+ * mid-record. */
77
+ readTail(path: string, maxBytes: number): {
78
+ lines: string[];
79
+ mtimeMs: number;
80
+ } | null;
81
+ now(): number;
82
+ }
83
+ /** IMPURE. `scanned` counts transcripts actually READ, so a session whose
84
+ * files vanished does not inflate the count into looking like coverage. */
85
+ export declare function collectBlockedCensus(io: BlockedCensusIo, staleMs: number, tailBytes: number): BlockedCensusSnapshot;
86
+ /** `claudeConfigDir` is the state root (`CLAUDE_CONFIG_DIR`), NOT a spawn cwd.
87
+ * Task 1490 re-points the manager's `spawnCwd` per sub-account spawn, so a
88
+ * client session's transcript is filed under a slug derived from the
89
+ * sub-account directory rather than the house cwd (http-server.ts:815 states
90
+ * this: reading `deps.spawnCwd` "would always miss the file"). Keying this
91
+ * census on one cwd would make it blind to exactly the sub-account sessions it
92
+ * was written for, so it resolves each session through the all-slug scan
93
+ * instead. */
94
+ export declare function defaultBlockedCensusIo(claudeConfigDir: string): BlockedCensusIo;
95
+ export interface BlockedToolCensusDeps {
96
+ /** State root (`CLAUDE_CONFIG_DIR`), not a spawn cwd. See
97
+ * defaultBlockedCensusIo for why a cwd cannot be used here. */
98
+ claudeConfigDir: string;
99
+ intervalMs: number;
100
+ staleMs?: number;
101
+ notifyAfterMs?: number;
102
+ logger: Logger;
103
+ /** Injected in tests; production uses defaultBlockedCensusIo(claudeConfigDir). */
104
+ io?: BlockedCensusIo;
105
+ /** The loopback POST to the UI's notification route. Absent means log-only. */
106
+ notify?: (c: BlockedCall) => Promise<{
107
+ delivered: boolean;
108
+ channel: string;
109
+ }>;
110
+ }
111
+ export interface BlockedToolCensus {
112
+ tickOnce(): BlockedCensusSnapshot;
113
+ latest(): BlockedCensusSnapshot | null;
114
+ start(): void;
115
+ stop(): void;
116
+ }
117
+ export declare function createBlockedToolCensus(deps: BlockedToolCensusDeps): BlockedToolCensus;
118
+ /** Production notifier. POSTs to the brand UI's loopback route, the same
119
+ * transport `postLogLineViaFetch` uses. A throw or a non-200 resolves to
120
+ * `delivered:false` rather than rejecting: the census logs the outcome either
121
+ * way, and a send that failed silently is the blind spot this task closes. */
122
+ export declare function postBlockedNotifyViaFetch(opts: {
123
+ uiPort: string;
124
+ logger: Logger;
125
+ }): (c: BlockedCall) => Promise<{
126
+ delivered: boolean;
127
+ channel: string;
128
+ }>;
129
+ //# sourceMappingURL=blocked-tool-census.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocked-tool-census.d.ts","sourceRoot":"","sources":["../src/blocked-tool-census.ts"],"names":[],"mappings":"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"}