@rubytech/create-maxy-code 0.1.568 → 0.1.569
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 +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +4 -2
- package/payload/platform/plugins/admin/hooks/__tests__/quote-path-write-gate.test.sh +152 -0
- package/payload/platform/plugins/admin/hooks/__tests__/quote-pdf-bash-gate.test.sh +95 -0
- package/payload/platform/plugins/admin/hooks/__tests__/quote-render-gate.test.sh +141 -45
- package/payload/platform/plugins/admin/hooks/__tests__/quote-render-pdf-conformance.test.sh +114 -0
- package/payload/platform/plugins/admin/hooks/quote-path-write-gate.sh +137 -0
- package/payload/platform/plugins/admin/hooks/quote-pdf-bash-gate.sh +70 -0
- package/payload/platform/plugins/admin/hooks/quote-render-gate.sh +105 -37
- package/payload/platform/plugins/admin/hooks/quote-render-pdf-conformance.sh +178 -0
- package/payload/platform/plugins/admin/mcp/dist/lib/roster-census.d.ts.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/lib/roster-census.js +50 -4
- package/payload/platform/plugins/admin/mcp/dist/lib/roster-census.js.map +1 -1
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +8 -0
- package/payload/platform/scripts/__tests__/mailbox-inject-registered.test.sh +5 -5
- package/payload/platform/scripts/__tests__/preference-hooks-registered.test.sh +3 -1
- package/payload/platform/scripts/__tests__/public-surface-registered.test.sh +5 -5
- package/payload/platform/scripts/__tests__/quote-ownership-contract.test.sh +86 -0
- package/payload/platform/scripts/lib/__tests__/account-settings-reconcile.test.sh +73 -0
- package/payload/platform/scripts/lib/account-settings-reconcile.sh +88 -0
- package/payload/platform/scripts/lib/provision-account-dir.sh +11 -144
- package/payload/platform/scripts/setup-account.sh +13 -0
- package/payload/platform/services/claude-session-manager/dist/account-agent-registry.d.ts +20 -0
- package/payload/platform/services/claude-session-manager/dist/account-agent-registry.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/account-agent-registry.js +78 -1
- package/payload/platform/services/claude-session-manager/dist/account-agent-registry.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +87 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.d.ts +42 -0
- package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.js +215 -0
- package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-preference-audit.d.ts +108 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-preference-audit.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-preference-audit.js +299 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-preference-audit.js.map +1 -0
- package/payload/platform/templates/account-settings.json +153 -0
|
@@ -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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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"
|
|
@@ -119,3 +119,16 @@ reconcile_all_accounts_mailbox_inject "$ACCOUNTS_DIR"
|
|
|
119
119
|
# under a one-tool allowlist. Reconcile every account on every install.
|
|
120
120
|
# Idempotent; logs one [backfill-2339] line per account.
|
|
121
121
|
reconcile_all_accounts_public_surface "$ACCOUNTS_DIR"
|
|
122
|
+
|
|
123
|
+
# ------------------------------------------------------------------
|
|
124
|
+
# 8. Converge the whole hook set on every account
|
|
125
|
+
# ------------------------------------------------------------------
|
|
126
|
+
# Steps 3 to 7 each retrofit one hook, and each was written after that hook was
|
|
127
|
+
# found missing on a live account. provision_account_dir writes the full set,
|
|
128
|
+
# but only at provision time, and this script re-provisions the house account
|
|
129
|
+
# and no other — so every future hook repeats the same fault. This step
|
|
130
|
+
# converges each account's settings against the shipped template instead, and
|
|
131
|
+
# states the divergence count on every run including zero. A hook added to
|
|
132
|
+
# platform/templates/account-settings.json needs no backfill of its own.
|
|
133
|
+
. "$SCRIPT_DIR/lib/account-settings-reconcile.sh"
|
|
134
|
+
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:
|
package/payload/platform/services/claude-session-manager/dist/account-agent-registry.d.ts.map
CHANGED
|
@@ -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,
|
|
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":"AAAA,kDAAkD;AAClD,EAAE;AACF,0EAA0E;AAC1E,2EAA2E;AAC3E,0EAA0E;AAC1E,uEAAuE;AACvE,gFAAgF;AAChF,0EAA0E;AAC1E,6EAA6E;AAC7E,EAAE;AACF,+DAA+D;AAC/D,6EAA6E;AAC7E,gFAAgF;AAChF,sDAAsD;AACtD,EAAE;AACF,gFAAgF;AAChF,sEAAsE;AACtE,EAAE;AACF,4EAA4E;AAC5E,2EAA2E;AAC3E,uDAAuD;AACvD,EAAE;AACF,0EAA0E;AAC1E,+EAA+E;AAC/E,uCAAuC;AAEvC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"account-agent-registry.js","sourceRoot":"","sources":["../src/account-agent-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,9 +48,11 @@ import { createPassiveIntakeAudit } from './passive-intake-audit.js';
|
|
|
48
48
|
import { createPassiveDispatchPrune } from './passive-dispatch-prune.js';
|
|
49
49
|
import { createXacctCensus } from './cross-account-census.js';
|
|
50
50
|
import { createAccountDirSchemaReconcile } from './account-dir-schema-reconcile.js';
|
|
51
|
+
import { createQuoteDeliveryReconcile } from './quote-delivery-reconcile.js';
|
|
51
52
|
import { createSessionCapAudit } from './session-cap-audit.js';
|
|
52
53
|
import { createSkillStalenessAudit, collectPlatformSkillMtimes, collectPremiumSkillMtimes, resolveEnabledPlugins, buildLiveSessionRefs, parseProcStartMs, } from './skill-staleness-audit.js';
|
|
53
54
|
import { createPublicSurfaceAudit, parseMcpLogServerName } from './public-surface-audit.js';
|
|
55
|
+
import { createSpecialistPreferenceAudit, readLinesSync } from './specialist-preference-audit.js';
|
|
54
56
|
import { projectsDirForCwd, sessionsDir, jsonlPathForSessionId, slugForExistingJsonl, jsonlPathForSlug, sidecarPathForSlug } from './jsonl-path.js';
|
|
55
57
|
import { readSidecar } from './session-sidecar.js';
|
|
56
58
|
import { runSystemPromptSelfTest, runIdentityDriftAssertion, runIdentityForbiddenTokenCheck } from './system-prompt.js';
|
|
@@ -885,6 +887,76 @@ async function main() {
|
|
|
885
887
|
},
|
|
886
888
|
});
|
|
887
889
|
publicSurfaceAudit.start();
|
|
890
|
+
// Task 2469 — the second question about a specialist. The registry reconcile
|
|
891
|
+
// beside the spawn answers whether one CAN be reached; this answers whether
|
|
892
|
+
// it WAS. Both were needed: four authored clerks owned the works orders,
|
|
893
|
+
// invoices and client emails on a live account while content-producer
|
|
894
|
+
// produced all of them, and every reachability signal read green throughout.
|
|
895
|
+
//
|
|
896
|
+
// `<projectDir>/<sessionId>/subagents/` is the only surface that ties a write
|
|
897
|
+
// to a specialist — the parent transcript carries none of a subagent's tool
|
|
898
|
+
// calls — so the walk is over that directory across every account on the
|
|
899
|
+
// install. 300s rather than the 60s beside it: this reads transcripts, and
|
|
900
|
+
// the mtime guard means a steady state costs one stat per file.
|
|
901
|
+
const preferenceProjectsRoot = dirname(projectsDirForCwd(config.spawnCwd));
|
|
902
|
+
/** sessionId -> its `subagents/` directory, rebuilt by `listSessions` at the
|
|
903
|
+
* top of every tick. Held here rather than in the audit because resolving a
|
|
904
|
+
* session id to a path is install layout, which is this file's business. */
|
|
905
|
+
const subagentDirs = new Map();
|
|
906
|
+
const specialistPreferenceAudit = createSpecialistPreferenceAudit({
|
|
907
|
+
intervalMs: 300_000,
|
|
908
|
+
logger: log,
|
|
909
|
+
listSessions: () => {
|
|
910
|
+
subagentDirs.clear();
|
|
911
|
+
let accountProjectDirs;
|
|
912
|
+
try {
|
|
913
|
+
accountProjectDirs = readdirSync(preferenceProjectsRoot);
|
|
914
|
+
}
|
|
915
|
+
catch {
|
|
916
|
+
return [];
|
|
917
|
+
}
|
|
918
|
+
for (const projectDir of accountProjectDirs) {
|
|
919
|
+
const abs = join(preferenceProjectsRoot, projectDir);
|
|
920
|
+
let sessions;
|
|
921
|
+
try {
|
|
922
|
+
sessions = readdirSync(abs);
|
|
923
|
+
}
|
|
924
|
+
catch {
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
for (const sessionId of sessions) {
|
|
928
|
+
const dir = join(abs, sessionId, 'subagents');
|
|
929
|
+
if (existsSync(dir))
|
|
930
|
+
subagentDirs.set(sessionId, dir);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
return Array.from(subagentDirs.keys());
|
|
934
|
+
},
|
|
935
|
+
listTranscripts: (sessionId) => {
|
|
936
|
+
const dir = subagentDirs.get(sessionId);
|
|
937
|
+
if (!dir)
|
|
938
|
+
return [];
|
|
939
|
+
// A throw here is caught by the audit, which names the session rather
|
|
940
|
+
// than losing the whole run to one unreadable directory.
|
|
941
|
+
return readdirSync(dir)
|
|
942
|
+
.filter((f) => f.startsWith('agent-') && f.endsWith('.jsonl'))
|
|
943
|
+
.map((f) => ({
|
|
944
|
+
jsonl: join(dir, f),
|
|
945
|
+
meta: join(dir, `${f.slice(0, -'.jsonl'.length)}.meta.json`),
|
|
946
|
+
mtimeMs: statSync(join(dir, f)).mtimeMs,
|
|
947
|
+
}));
|
|
948
|
+
},
|
|
949
|
+
readMeta: (path) => {
|
|
950
|
+
try {
|
|
951
|
+
return readFileSync(path, 'utf8');
|
|
952
|
+
}
|
|
953
|
+
catch {
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
},
|
|
957
|
+
readLines: (path) => readLinesSync(path),
|
|
958
|
+
});
|
|
959
|
+
specialistPreferenceAudit.start();
|
|
888
960
|
// Task 2285 — standing audit for public-agent knowledge curation. A
|
|
889
961
|
// `knowledgeKeywords` subscription nobody asked for is dormant until matching
|
|
890
962
|
// content lands, and a KNOWLEDGE.md that grows after deployment emits nothing
|
|
@@ -1053,6 +1125,21 @@ async function main() {
|
|
|
1053
1125
|
intervalMs: 300_000,
|
|
1054
1126
|
});
|
|
1055
1127
|
schemaReconcile.start();
|
|
1128
|
+
// Task 2467 — standing reconcile of delivered client quotes against their
|
|
1129
|
+
// render receipts. The three PreToolUse quote gates refuse the print, the
|
|
1130
|
+
// Bash conversion and the write, but all three fail open on an uninspectable
|
|
1131
|
+
// envelope and none can see a delivery route nobody enumerated. This pass is
|
|
1132
|
+
// the backstop, and it is the only instrument that can see the failure at
|
|
1133
|
+
// all: on 2026-08-05 a hand-authored client quote was printed and emailed
|
|
1134
|
+
// while the bypass counter for that day sat at zero, so no transition log
|
|
1135
|
+
// could have shown it. Emits one line per unreconciled document plus one
|
|
1136
|
+
// summary per run, zero count included. Purely filesystem — no Neo4j.
|
|
1137
|
+
const quoteReconcile = createQuoteDeliveryReconcile({
|
|
1138
|
+
accountsDir: dirname(config.accountDir),
|
|
1139
|
+
logger: log,
|
|
1140
|
+
intervalMs: 900_000,
|
|
1141
|
+
});
|
|
1142
|
+
quoteReconcile.start();
|
|
1056
1143
|
// Task 183 — recorder JSONL tail. Posts [recorder-session-init] and
|
|
1057
1144
|
// [recorder-turn] lines for every database-operator specialist spawn,
|
|
1058
1145
|
// routed through the platform UI's /api/admin/log-ingest loopback
|