@rubytech/create-sitedesk-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 (57) 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/premium-plugins/sitedesk/agents/sitedesk--quoter.md +2 -2
  49. package/payload/server/server.js +750 -656
  50. package/payload/platform/scripts/lib/__tests__/account-settings-askgate.test.sh +0 -144
  51. package/payload/platform/scripts/lib/__tests__/account-settings-mailbox-inject.test.sh +0 -166
  52. package/payload/platform/scripts/lib/__tests__/account-settings-pdf-conformance.test.sh +0 -151
  53. package/payload/platform/scripts/lib/__tests__/account-settings-public-surface.test.sh +0 -109
  54. package/payload/platform/scripts/lib/account-settings-askgate.sh +0 -98
  55. package/payload/platform/scripts/lib/account-settings-mailbox-inject.sh +0 -91
  56. package/payload/platform/scripts/lib/account-settings-pdf-conformance.sh +0 -98
  57. package/payload/platform/scripts/lib/account-settings-public-surface.sh +0 -109
@@ -0,0 +1 @@
1
+ {"version":3,"file":"specialist-preference-audit.d.ts","sourceRoot":"","sources":["../src/specialist-preference-audit.ts"],"names":[],"mappings":"AA8BA,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;AAE3C;;;;;;;0BAO0B;AAC1B,wBAAiB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,SAAU,GAAG,SAAS,CAAC,MAAM,CAAC,CAkBpF;AAID;;;;;;;;;;;kCAWkC;AAClC,eAAO,MAAM,WAAW,EAAE,aAAa,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAKzE,CAAA;AAED;;;mEAGmE;AACnE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS5D;AAED;;yCAEyC;AACzC,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CASrE;AAED;;iEAEiE;AACjE,wBAAgB,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,CAmB7D;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,MAAM,CAAA;IACvB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,QAAQ,EAAE,CAAA;CACtB;AAED;;;;;;eAMe;AACf,wBAAgB,eAAe,CAAC,CAAC,EAAE;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;CACxB,GAAG,eAAe,CAmBlB;AAED;sDACsD;AACtD,wBAAgB,uBAAuB,CAAC,CAAC,EAAE;IACzC,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,eAAe,EAAE,MAAM,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;CACrB,GAAG,MAAM,CAKT;AAED;;;;;;;0DAO0D;AAC1D,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAGlD;AAED,MAAM,WAAW,aAAa;IAC5B,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAA;IACb,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,8EAA8E;IAC9E,YAAY,IAAI,SAAS,MAAM,EAAE,CAAA;IACjC;oFACgF;IAChF,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,aAAa,EAAE,CAAA;IAC5D,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACrC;sCACkC;IAClC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;CAC1C;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,IAAI,CAAA;IACZ,QAAQ,IAAI,IAAI,CAAA;CACjB;AAED,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,6BAA6B,GAClC,yBAAyB,CAyG3B"}
@@ -0,0 +1,299 @@
1
+ // Task 2469 — a specialist that CAN be reached is not a specialist that WAS.
2
+ //
3
+ // The registry reconcile in account-agent-registry.ts answers the first
4
+ // question and emits `op=agent-registry-resolution`. It was green on the
5
+ // account that filed this, and would have stayed green through the whole
6
+ // incident, because every clerk was reachable and none was reached: four
7
+ // authored clerks owned the works orders, invoices and client emails while
8
+ // content-producer produced all of them. The two questions are deliberately
9
+ // separate signals, because one cannot answer the other.
10
+ //
11
+ // Keyed on the written path rather than on the dispatch prose. A dispatch
12
+ // description is the model's own account of what it is doing, and the incident
13
+ // this closes had twelve descriptions that each read as reasonable. A path is
14
+ // a fact, and it is the same fact a write gate enforces on, so enforcement and
15
+ // audit cannot drift apart.
16
+ //
17
+ // The input is `<projectDir>/<sessionId>/subagents/agent-<agentId>.jsonl` with
18
+ // its sibling `.meta.json`. That directory is the ONLY surface that ties a
19
+ // write to a specialist: the parent transcript records every record as
20
+ // `isSidechain: false`, carries none of the subagent's tool calls, and its
21
+ // `toolUseResult.toolStats` gives aggregate counts with no paths.
22
+ //
23
+ // Shape mirrors public-surface-audit.ts: PURE parsers, selector and formatters
24
+ // plus an impure factory whose setInterval is unref'd and whose readers are
25
+ // injected.
26
+ import { closeSync, openSync, readSync } from 'node:fs';
27
+ import { StringDecoder } from 'node:string_decoder';
28
+ const TAG = '[specialist-preference]';
29
+ /** Lines of a file, read in bounded chunks rather than into one string.
30
+ *
31
+ * One session's `subagents/` directory measured 473 MB, so reading a
32
+ * transcript with `readFileSync` would put the whole thing on the heap to look
33
+ * at one field per line. A `StringDecoder` carries partial multi-byte
34
+ * characters across chunk boundaries: splitting one would corrupt the line,
35
+ * `JSON.parse` would reject it, and the write it carried would vanish from
36
+ * the audit silently. */
37
+ export function* readLinesSync(path, chunkBytes = 1 << 20) {
38
+ const fd = openSync(path, 'r');
39
+ try {
40
+ const buf = Buffer.allocUnsafe(chunkBytes);
41
+ const decoder = new StringDecoder('utf8');
42
+ let carry = '';
43
+ for (;;) {
44
+ const n = readSync(fd, buf, 0, chunkBytes, null);
45
+ if (n === 0)
46
+ break;
47
+ const parts = (carry + decoder.write(buf.subarray(0, n))).split('\n');
48
+ carry = parts.pop() ?? '';
49
+ for (const p of parts)
50
+ if (p.length > 0)
51
+ yield p;
52
+ }
53
+ carry += decoder.end();
54
+ if (carry.length > 0)
55
+ yield carry;
56
+ }
57
+ finally {
58
+ closeSync(fd);
59
+ }
60
+ }
61
+ const WRITE_TOOLS = new Set(['Write', 'Edit', 'MultiEdit', 'NotebookEdit']);
62
+ /** Artefact directory to the specialist that owns it.
63
+ *
64
+ * Every entry is a directory measured in the live job tree: `quote` (17 jobs),
65
+ * `Quotations` (5), `orders` (8), `invoices` (1). There is no valuation
66
+ * directory anywhere in that tree, so valuation-clerk deliberately has no
67
+ * entry — a guessed owner produces misroute lines nobody can act on.
68
+ *
69
+ * Two exclusions are deliberate. `pricing/` holds the internal priced
70
+ * breakdown rather than a client-facing artefact. `Suppliers Invoices` is the
71
+ * supplier's invoice to the business, not the client invoice the
72
+ * invoice-clerk issues, and the match is exact-segment so it cannot be swept
73
+ * in by the `invoices` entry. */
74
+ export const OWNED_PATHS = [
75
+ { segment: 'quote', owner: 'sitedesk:quoter' },
76
+ { segment: 'Quotations', owner: 'sitedesk:quoter' },
77
+ { segment: 'orders', owner: 'order-clerk' },
78
+ { segment: 'invoices', owner: 'invoice-clerk' },
79
+ ];
80
+ /** The specialist that owns a written path, or null when the path is not an
81
+ * owned artefact. Anchored on `jobs/<jobId>/<segment>/`, so a same-named
82
+ * directory elsewhere in the account is not swept in and a file sitting
83
+ * directly in a job directory belongs to nobody in particular. */
84
+ export function ownerForPath(filePath) {
85
+ const seg = filePath.split('/');
86
+ for (let i = 0; i + 3 < seg.length; i++) {
87
+ if (seg[i] !== 'jobs')
88
+ continue;
89
+ const bucket = seg[i + 2];
90
+ const hit = OWNED_PATHS.find((o) => o.segment === bucket);
91
+ if (hit)
92
+ return hit.owner;
93
+ }
94
+ return null;
95
+ }
96
+ /** `agentType` from a subagent's sibling meta file, or null when the file is
97
+ * unreadable, unparseable, or carries no type. Null is never read as
98
+ * compliance: see `auditTranscript`. */
99
+ export function parseAgentType(metaJson) {
100
+ if (metaJson === null)
101
+ return null;
102
+ try {
103
+ const d = JSON.parse(metaJson);
104
+ const t = d?.agentType;
105
+ return typeof t === 'string' && t.length > 0 ? t : null;
106
+ }
107
+ catch {
108
+ return null;
109
+ }
110
+ }
111
+ /** Written paths in one transcript line. A line that will not parse yields
112
+ * nothing rather than throwing: the corpus carries partial trailing writes,
113
+ * and one bad line must not abort the transcript it sits in. */
114
+ export function selectWrites(transcriptLine) {
115
+ let d;
116
+ try {
117
+ d = JSON.parse(transcriptLine);
118
+ }
119
+ catch {
120
+ return [];
121
+ }
122
+ const content = d?.message?.content;
123
+ if (!Array.isArray(content))
124
+ return [];
125
+ const out = [];
126
+ for (const b of content) {
127
+ if (!b || typeof b !== 'object')
128
+ continue;
129
+ const blk = b;
130
+ if (blk.type !== 'tool_use')
131
+ continue;
132
+ if (typeof blk.name !== 'string' || !WRITE_TOOLS.has(blk.name))
133
+ continue;
134
+ const fp = blk.input?.file_path;
135
+ if (typeof fp === 'string' && fp.length > 0)
136
+ out.push(fp);
137
+ }
138
+ return out;
139
+ }
140
+ /** One subagent run.
141
+ *
142
+ * `agentType` null means the meta file was missing or unreadable. Its
143
+ * owned-path writes are counted as unattributed rather than as compliant:
144
+ * "we could not tell who wrote this" is not "the right specialist wrote it",
145
+ * and folding the two together is how a broken reader reads as a clean
146
+ * account. */
147
+ export function auditTranscript(p) {
148
+ let ownedPathWrites = 0;
149
+ let unattributed = 0;
150
+ const misroutes = [];
151
+ for (const line of p.lines) {
152
+ for (const path of selectWrites(line)) {
153
+ const owner = ownerForPath(path);
154
+ if (owner === null)
155
+ continue;
156
+ ownedPathWrites++;
157
+ if (p.agentType === null) {
158
+ unattributed++;
159
+ continue;
160
+ }
161
+ if (p.agentType !== owner) {
162
+ misroutes.push({ session: p.session, agent: p.agentType, owner, path });
163
+ }
164
+ }
165
+ }
166
+ return { ownedPathWrites, unattributed, misroutes };
167
+ }
168
+ /** The every-tick line. Emitted including zero, so a run that found nothing is
169
+ * distinguishable from a run that did not happen. */
170
+ export function formatPreferenceSummary(p) {
171
+ return `${TAG} op=audit sessionsScanned=${p.sessionsScanned}` +
172
+ ` transcriptsScanned=${p.transcriptsScanned}` +
173
+ ` ownedPathWrites=${p.ownedPathWrites}` +
174
+ ` misrouted=${p.misrouted} unattributed=${p.unattributed}`;
175
+ }
176
+ /** One line per misroute, naming the subagent, the owner it displaced and the
177
+ * path. The displaced owner is the actionable half: "content-producer wrote
178
+ * this" says less than "content-producer wrote this instead of the quoter".
179
+ *
180
+ * The path is JSON-quoted because these paths contain spaces — the document
181
+ * that prompted this task is `Q 1879 - Woolgrove School - Yellow Class
182
+ * Kitchenette.html` — and a bare value would split into four tokens under any
183
+ * `key=value` reader, including `grep -o 'path=\S*'`. */
184
+ export function formatMisroute(p) {
185
+ return `${TAG} op=misroute session=${p.session} agent=${p.agent}` +
186
+ ` owner=${p.owner} path=${JSON.stringify(p.path)}`;
187
+ }
188
+ export function createSpecialistPreferenceAudit(deps) {
189
+ /** jsonl path -> the result of reading it at `mtimeMs`.
190
+ *
191
+ * The emitted counts are a STATE — the totals across every transcript
192
+ * currently known — not a per-tick delta. A transcript still being appended
193
+ * to is re-read when its mtime moves and its entry is REPLACED, so its
194
+ * earlier writes are counted once, not once per tick. A delta counter over
195
+ * a growing file would inflate every total it reported. */
196
+ const seen = new Map();
197
+ /** Misroutes already named, so a steady state does not re-log every tick. */
198
+ const logged = new Set();
199
+ let timer = null;
200
+ function tickOnce() {
201
+ let sessionsScanned = 0;
202
+ const live = new Set();
203
+ for (const session of deps.listSessions()) {
204
+ sessionsScanned++;
205
+ let transcripts;
206
+ try {
207
+ transcripts = deps.listTranscripts(session);
208
+ }
209
+ catch (err) {
210
+ // A directory that cannot be listed is named and skipped. Silence here
211
+ // would read as a session with no subagent activity, which is the one
212
+ // reading this audit must never produce by accident.
213
+ deps.logger(`${TAG} op=session-unreadable session=${session}` +
214
+ ` reason=${err instanceof Error ? err.message : String(err)}`);
215
+ continue;
216
+ }
217
+ for (const t of transcripts) {
218
+ live.add(t.jsonl);
219
+ const prior = seen.get(t.jsonl);
220
+ if (prior && prior.mtimeMs === t.mtimeMs)
221
+ continue;
222
+ const agentType = parseAgentType(deps.readMeta(t.meta));
223
+ let audit;
224
+ try {
225
+ audit = auditTranscript({ session, agentType, lines: deps.readLines(t.jsonl) });
226
+ }
227
+ catch (err) {
228
+ deps.logger(`${TAG} op=transcript-unreadable path=${t.jsonl}` +
229
+ ` reason=${err instanceof Error ? err.message : String(err)}`);
230
+ continue;
231
+ }
232
+ seen.set(t.jsonl, { mtimeMs: t.mtimeMs, audit });
233
+ for (const m of audit.misroutes) {
234
+ const key = `${m.session}|${m.agent}|${m.path}`;
235
+ if (logged.has(key))
236
+ continue;
237
+ deps.logger(formatMisroute(m));
238
+ logged.add(key);
239
+ }
240
+ }
241
+ }
242
+ // Drop transcripts that have gone, so the totals describe what is on disk
243
+ // now rather than accumulating across the process's whole lifetime. The
244
+ // logged-misroute keys go with them: this process runs for weeks, and a set
245
+ // that only ever grew would hold every path of every session the install
246
+ // has ever archived.
247
+ for (const path of Array.from(seen.keys()))
248
+ if (!live.has(path))
249
+ seen.delete(path);
250
+ const liveKeys = new Set();
251
+ for (const { audit } of seen.values()) {
252
+ for (const m of audit.misroutes)
253
+ liveKeys.add(`${m.session}|${m.agent}|${m.path}`);
254
+ }
255
+ for (const key of Array.from(logged))
256
+ if (!liveKeys.has(key))
257
+ logged.delete(key);
258
+ let ownedPathWrites = 0;
259
+ let misrouted = 0;
260
+ let unattributed = 0;
261
+ for (const { audit } of seen.values()) {
262
+ ownedPathWrites += audit.ownedPathWrites;
263
+ misrouted += audit.misroutes.length;
264
+ unattributed += audit.unattributed;
265
+ }
266
+ deps.logger(formatPreferenceSummary({
267
+ sessionsScanned,
268
+ transcriptsScanned: seen.size,
269
+ ownedPathWrites,
270
+ misrouted,
271
+ unattributed,
272
+ }));
273
+ }
274
+ return {
275
+ tickOnce,
276
+ start() {
277
+ if (timer)
278
+ return;
279
+ timer = setInterval(() => {
280
+ try {
281
+ tickOnce();
282
+ }
283
+ catch (err) {
284
+ deps.logger(`${TAG} op=audit-tick-failed message=${err instanceof Error ? err.message : String(err)}`);
285
+ }
286
+ }, deps.intervalMs);
287
+ if (typeof timer.unref === 'function')
288
+ timer.unref();
289
+ deps.logger(`${TAG} op=audit-started intervalMs=${deps.intervalMs}`);
290
+ },
291
+ stop() {
292
+ if (timer) {
293
+ clearInterval(timer);
294
+ timer = null;
295
+ }
296
+ },
297
+ };
298
+ }
299
+ //# sourceMappingURL=specialist-preference-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"specialist-preference-audit.js","sourceRoot":"","sources":["../src/specialist-preference-audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ {
2
+ "permissions": {
3
+ "defaultMode": "bypassPermissions",
4
+ "allow": [],
5
+ "deny": []
6
+ },
7
+ "hooks": {
8
+ "PreToolUse": [
9
+ {
10
+ "matcher": "Write",
11
+ "hooks": [
12
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/archive-ingest-surface-gate.sh" },
13
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/fs-schema-guard.sh" },
14
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/quote-path-write-gate.sh" }
15
+ ]
16
+ },
17
+ {
18
+ "matcher": "Edit",
19
+ "hooks": [
20
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/archive-ingest-surface-gate.sh" },
21
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/fs-schema-guard.sh" },
22
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/quote-path-write-gate.sh" }
23
+ ]
24
+ },
25
+ {
26
+ "matcher": "MultiEdit",
27
+ "hooks": [
28
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/archive-ingest-surface-gate.sh" },
29
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/fs-schema-guard.sh" },
30
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/quote-path-write-gate.sh" }
31
+ ]
32
+ },
33
+ {
34
+ "matcher": "NotebookEdit",
35
+ "hooks": [
36
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/archive-ingest-surface-gate.sh" },
37
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/fs-schema-guard.sh" },
38
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/quote-path-write-gate.sh" }
39
+ ]
40
+ },
41
+ {
42
+ "matcher": "Bash",
43
+ "hooks": [
44
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/archive-ingest-surface-gate.sh" },
45
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/fs-schema-guard-bash-pre.sh" },
46
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/quote-engine-gate.sh" },
47
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/quote-pdf-bash-gate.sh" }
48
+ ]
49
+ },
50
+ {
51
+ "hooks": [
52
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/archive-ingest-surface-gate.sh" },
53
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/public-tool-surface.sh" }
54
+ ]
55
+ },
56
+ {
57
+ "matcher": "WebFetch",
58
+ "hooks": [
59
+ { "type": "command", "command": "node $PLATFORM_ROOT/plugins/admin/hooks/webfetch-preflight.mjs" }
60
+ ]
61
+ },
62
+ {
63
+ "matcher": "AskUserQuestion",
64
+ "hooks": [
65
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/askuserquestion-investigate-gate.sh" },
66
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/askuserquestion-channel-carrier-gate.sh" }
67
+ ]
68
+ },
69
+ {
70
+ "matcher": "mcp__plugin_browser_browser__browser-pdf-save",
71
+ "hooks": [
72
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/quote-render-gate.sh" }
73
+ ]
74
+ },
75
+ {
76
+ "matcher": "mcp__plugin_browser_browser__browser-pdf-save",
77
+ "hooks": [
78
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/preference-consult-gate.sh" }
79
+ ]
80
+ },
81
+ {
82
+ "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",
83
+ "hooks": [
84
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/preference-consult-gate.sh" }
85
+ ]
86
+ }
87
+ ],
88
+ "PostToolUse": [
89
+ {
90
+ "matcher": "Bash",
91
+ "hooks": [
92
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/fs-schema-guard-bash-post.sh" }
93
+ ]
94
+ },
95
+ {
96
+ "matcher": "Agent",
97
+ "hooks": [
98
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/post-tool-use-agent.sh" }
99
+ ]
100
+ },
101
+ {
102
+ "matcher": "mcp__plugin_browser_browser__browser-pdf-save",
103
+ "hooks": [
104
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/quote-render-pdf-conformance.sh" }
105
+ ]
106
+ },
107
+ {
108
+ "matcher": "mcp__.*__.*-(export|import)-parse$",
109
+ "hooks": [
110
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/archive-ingest-surface-gate.sh" }
111
+ ]
112
+ },
113
+ {
114
+ "matcher": "mcp__.*",
115
+ "hooks": [
116
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/mcp-tool-missing.sh" }
117
+ ]
118
+ },
119
+ {
120
+ "matcher": "Write",
121
+ "hooks": [
122
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/admin-authoring-observer.sh" }
123
+ ]
124
+ },
125
+ {
126
+ "matcher": "Edit",
127
+ "hooks": [
128
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/admin-authoring-observer.sh" }
129
+ ]
130
+ },
131
+ {
132
+ "matcher": "Read",
133
+ "hooks": [
134
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/pdf-text-layer-inject.sh" }
135
+ ]
136
+ }
137
+ ],
138
+ "UserPromptSubmit": [
139
+ {
140
+ "hooks": [
141
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/archive-ingest-surface-gate.sh" },
142
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/prompt-optimiser-directive.sh" },
143
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/datetime-inject.sh" },
144
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/mailbox-inject.sh" },
145
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/preference-consult-directive.sh" },
146
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/public-tool-surface.sh" }
147
+ ]
148
+ }
149
+ ],
150
+ "Stop": [
151
+ {
152
+ "hooks": [
153
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/prompt-optimiser-compliance.sh" },
154
+ { "type": "command", "command": "bash $PLATFORM_ROOT/plugins/admin/hooks/public-tool-surface.sh" }
155
+ ]
156
+ }
157
+ ]
158
+ }
159
+ }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: quoter
3
- description: "SiteDesk quoter. Delegate when the operator wants a priced quote for a job or enquiry, whether a new quote or a reprice/revision of an existing one — measuring quantities off a supplied drawing (PDF, photo, or scan) when one is given, then capturing or applying their own pricing and quotation method (items, quantity rules, pricing rules, roll-up, documents) to produce the live quote and its A4 PDF. Not for an interim valuation on a running job (that is the valuer) or a worker timesheet (that is the payroll-clerk)."
3
+ description: "SiteDesk quoter. Delegate when the operator wants a priced quote for a job or enquiry, whether a new quote or a reprice/revision of an existing one — measuring quantities off a supplied drawing (PDF, photo, or scan) when one is given, then capturing or applying their own pricing and quotation method (items, quantity rules, pricing rules, roll-up, documents) to produce the live quote and its A4 PDF. Not for an interim valuation on a running job (that is the valuer) or a worker timesheet (that is the payroll-clerk). The quoter owns the client quote document entire, figures and presentation alike, including layout, cover pages, photographs, the running header, and every later correction to an issued quote."
4
4
  summary: "Your quoter — measures a drawing into quantities, then turns the operator's own pricing method into a live priced quote and its PDF, for a new quote or a reprice."
5
5
  model: claude-sonnet-5
6
6
  tools: Skill, Read, Write, Edit, Bash, Glob, Grep, mcp__plugin_sitedesk-job_sitedesk-job__quote-engine-run, mcp__plugin_sitedesk-job_sitedesk-job__quote-render, mcp__plugin_browser_browser__browser-navigate, mcp__plugin_browser_browser__browser-pdf-save, mcp__plugin_email_email__email-send
@@ -15,7 +15,7 @@ Never run uncommanded git writes. `git init`, `git commit`, `git add`, `git stas
15
15
 
16
16
  A message from the agent that dispatched you arrives on the platform's own dispatcher channel, and it carries the same authority as the brief that dispatched you. Verify a figure or a fact against its source on disk, never against the messenger. If you still refuse, name the refusal and its reason in what you return, so the dispatcher relays it rather than guessing.
17
17
 
18
- You are the SiteDesk quoter — the owner of quote work for an independent service business (a building contractor and the like): a new priced quote, and repricing or revising an existing one. You own one deliverable: a priced quote built from the operator's own method, rendered to an A4 PDF. A reprice re-runs the same method against the job's updated payload; it is your work, not a document edit for another agent. When the operator hands over a drawing rather than finished measurements, you measure it first with the `takeoff` skill, then price the quantities with `quotation`. The admin agent dispatches a brief to you; you run the skills and return the result.
18
+ You are the SiteDesk quoter — the owner of quote work for an independent service business (a building contractor and the like): a new priced quote, and repricing or revising an existing one. You own one deliverable: a priced quote built from the operator's own method, rendered to an A4 PDF. A reprice re-runs the same method against the job's updated payload. You own the client quote document entire, its figures and its presentation alike: layout, cover pages, photographs, the running header, and every later correction to any of them. No part of a client quote document is another agent's work, and a correction to an issued quote comes back to you. When the operator hands over a drawing rather than finished measurements, you measure it first with the `takeoff` skill, then price the quantities with `quotation`. The admin agent dispatches a brief to you; you run the skills and return the result.
19
19
 
20
20
  The engine and render scripts run only through their tools. Price a job with the `quote-engine-run` tool, which runs the operator's persisted `quoting/engine.mjs` and files the figures; produce the documents with the `quote-render` tool, which runs the persisted `quoting/render.mjs` behind the reconcile, margin-leak and link-liveness gates. Never run `quoting/engine.mjs` or `quoting/render.mjs` directly with `Bash`; that skips the gates and files no receipt.
21
21