@orchestrator-claude/definitions 3.32.1 → 3.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +113 -0
  2. package/agents/debug-sidecar.md +1 -1
  3. package/agents/doc-sidecar.md +1 -1
  4. package/agents/test-sidecar.md +1 -1
  5. package/dist/cli.js +78 -0
  6. package/dist/cli.js.map +1 -1
  7. package/dist/commands/DiffCommand.js +1 -1
  8. package/dist/commands/DiffCommand.js.map +1 -1
  9. package/dist/commands/InstallCommand.d.ts +41 -0
  10. package/dist/commands/InstallCommand.d.ts.map +1 -0
  11. package/dist/commands/InstallCommand.js +253 -0
  12. package/dist/commands/InstallCommand.js.map +1 -0
  13. package/dist/http/ApiClient.d.ts +5 -0
  14. package/dist/http/ApiClient.d.ts.map +1 -1
  15. package/dist/http/ApiClient.js.map +1 -1
  16. package/dist/install/DevCheckoutDetector.d.ts +66 -0
  17. package/dist/install/DevCheckoutDetector.d.ts.map +1 -0
  18. package/dist/install/DevCheckoutDetector.js +150 -0
  19. package/dist/install/DevCheckoutDetector.js.map +1 -0
  20. package/dist/install/HooksWirer.d.ts +29 -0
  21. package/dist/install/HooksWirer.d.ts.map +1 -0
  22. package/dist/install/HooksWirer.js +80 -0
  23. package/dist/install/HooksWirer.js.map +1 -0
  24. package/dist/install/LocalDiffReporter.d.ts +25 -0
  25. package/dist/install/LocalDiffReporter.d.ts.map +1 -0
  26. package/dist/install/LocalDiffReporter.js +50 -0
  27. package/dist/install/LocalDiffReporter.js.map +1 -0
  28. package/dist/install/Materializer.d.ts +67 -0
  29. package/dist/install/Materializer.d.ts.map +1 -0
  30. package/dist/install/Materializer.js +196 -0
  31. package/dist/install/Materializer.js.map +1 -0
  32. package/dist/install/McpRegistrar.d.ts +63 -0
  33. package/dist/install/McpRegistrar.d.ts.map +1 -0
  34. package/dist/install/McpRegistrar.js +114 -0
  35. package/dist/install/McpRegistrar.js.map +1 -0
  36. package/dist/install/ProcessRunner.d.ts +25 -0
  37. package/dist/install/ProcessRunner.d.ts.map +1 -0
  38. package/dist/install/ProcessRunner.js +41 -0
  39. package/dist/install/ProcessRunner.js.map +1 -0
  40. package/dist/install/ProjectSettingsNeutralizer.d.ts +39 -0
  41. package/dist/install/ProjectSettingsNeutralizer.d.ts.map +1 -0
  42. package/dist/install/ProjectSettingsNeutralizer.js +100 -0
  43. package/dist/install/ProjectSettingsNeutralizer.js.map +1 -0
  44. package/dist/install/types.d.ts +52 -0
  45. package/dist/install/types.d.ts.map +1 -0
  46. package/dist/install/types.js +8 -0
  47. package/dist/install/types.js.map +1 -0
  48. package/dist/manifest/ManifestLoader.d.ts.map +1 -1
  49. package/dist/manifest/ManifestLoader.js +3 -2
  50. package/dist/manifest/ManifestLoader.js.map +1 -1
  51. package/dist/manifest/types.d.ts +3 -0
  52. package/dist/manifest/types.d.ts.map +1 -1
  53. package/dist/scripts/bundle-hooks.d.ts +39 -0
  54. package/dist/scripts/bundle-hooks.d.ts.map +1 -0
  55. package/dist/scripts/bundle-hooks.js +165 -0
  56. package/dist/scripts/bundle-hooks.js.map +1 -0
  57. package/dist/scripts/generate-manifest.d.ts +22 -3
  58. package/dist/scripts/generate-manifest.d.ts.map +1 -1
  59. package/dist/scripts/generate-manifest.js +78 -35
  60. package/dist/scripts/generate-manifest.js.map +1 -1
  61. package/hooks/dangling-guard.mjs +7426 -0
  62. package/hooks/dangling-guard.ts +223 -6
  63. package/hooks/gate-guardian.mjs +463 -0
  64. package/hooks/lib/additional-directories-sync.ts +295 -0
  65. package/hooks/lib/api-client.ts +388 -7
  66. package/hooks/lib/session-selection.ts +81 -0
  67. package/hooks/mailbox-listener.mjs +259 -0
  68. package/hooks/post-compact.mjs +7931 -0
  69. package/hooks/post-implement.mjs +238 -0
  70. package/hooks/session-start.mjs +8234 -0
  71. package/hooks/session-start.ts +264 -23
  72. package/hooks/sprint-registry.mjs +59 -0
  73. package/hooks/subagent-start.mjs +289 -0
  74. package/hooks/subagent-stop.mjs +7793 -0
  75. package/hooks/subagent-stop.ts +4 -2
  76. package/hooks/user-prompt.mjs +329 -0
  77. package/hooks/workflow-guard.mjs +7805 -0
  78. package/hooks/workflow-guard.ts +360 -119
  79. package/hooks-settings-template.json +63 -0
  80. package/manifest.json +54 -68
  81. package/mcp-servers.json +48 -0
  82. package/package.json +10 -4
  83. package/personas/auditor-compliance.md +104 -0
  84. package/personas/cfo-conservador.md +88 -0
  85. package/personas/designer-perfeccionista.md +104 -0
  86. package/personas/diretor-cetico-fmcg.md +80 -0
  87. package/personas/engenheiro-cetico-construcao.md +107 -0
@@ -0,0 +1,295 @@
1
+ /**
2
+ * additional-directories-sync.ts — RFC-040 TD-204 ⑤-B.
3
+ *
4
+ * Drives (never enforces) a settings.json's
5
+ * `.permissions.additionalDirectories` from the Postgres SoT (registered
6
+ * projects — read via `listRegisteredProjects()` in api-client.ts, the SAME
7
+ * `ProjectRegistryService` domain path C2 `/resolve` reads from).
8
+ *
9
+ * ★ Union-merge law (THE #1 care, TD-204 §3a):
10
+ *
11
+ * result = existingManualEntries ∪ registeredProjectRoots
12
+ *
13
+ * NEVER a replace. De-duped. Existing order preserved; new entries
14
+ * appended. The real machine's `~/.claude/settings.json` already carries
15
+ * manual entries (`trc`, `red-bull`) that a blind write would wipe — this
16
+ * module exists specifically so that never happens.
17
+ *
18
+ * Prune policy v1 = ADDITIVE-ONLY: a project that is later unregistered
19
+ * does not have its dir revoked by this sync. `readManagedSidecar` /
20
+ * `writeManagedSidecarAtomic` persist the union of every root path this
21
+ * sync has ever added, as a design-for-it primitive a future prune-capable
22
+ * version can diff against (`manualEntries = additionalDirectories \
23
+ * managedSidecar`) — NOT wired to any pruning behaviour in v1.
24
+ *
25
+ * Honest limit (TD-204 §39): `additionalDirectories` is the operator's own
26
+ * Claude Code trust control (user settings), not a Postgres-enforced
27
+ * boundary. This module DRIVES (auto-populates) it; Class-A hooks
28
+ * (workflow-guard.ts) are the actual backstop. Never described as
29
+ * "enforcement".
30
+ *
31
+ * Installer-compatible (TD-204 §75-77): every function is pure/injectable
32
+ * — `settingsPath`/`sidecarPath` are always explicit parameters, never a
33
+ * hardcoded `~/.claude` path or a RUN-02 dev-checkout symlink assumption.
34
+ * Mirrored into packages/definitions/hooks/lib/ via
35
+ * scripts/sync-hook-mirrors.ts (DISTRIBUTABLE_LIBS) so the future
36
+ * `orch-defs install` can import this exact module.
37
+ *
38
+ * Write safety: read-modify-write via a pure JSON-preserving merge, then
39
+ * `writeSettingsAtomic` — back up the prior file, write a temp file in the
40
+ * SAME directory, validate it re-parses as JSON, atomic-rename over the
41
+ * target. Any failure before the rename leaves the real file byte-for-byte
42
+ * untouched (never a partial write of the settings file the operator's
43
+ * Claude Code process reads).
44
+ */
45
+
46
+ import {
47
+ existsSync,
48
+ readFileSync,
49
+ writeFileSync,
50
+ renameSync,
51
+ copyFileSync,
52
+ unlinkSync,
53
+ mkdirSync,
54
+ } from 'node:fs';
55
+ import { dirname, join } from 'node:path';
56
+
57
+ // ─── Types ───────────────────────────────────────────────────────────────
58
+
59
+ export interface MergeResult {
60
+ /** Final additionalDirectories array (existing ∪ registered), de-duped, order-stable. */
61
+ merged: string[];
62
+ /** Entries newly appended this run (registered roots not already present). */
63
+ added: string[];
64
+ }
65
+
66
+ export interface ManagedSidecar {
67
+ /** Every root path this sync has ever added — additive-only union across runs. */
68
+ managedPaths: string[];
69
+ updatedAt: string;
70
+ }
71
+
72
+ export type SyncOutcome =
73
+ | { ok: true; dryRun: boolean; merged: string[]; added: string[]; backupPath?: string }
74
+ | {
75
+ ok: false;
76
+ reason: 'settings-file-not-found' | 'invalid-json' | 'write-failed';
77
+ error?: string;
78
+ };
79
+
80
+ export interface SyncOptions {
81
+ settingsPath: string;
82
+ registeredRoots: readonly string[];
83
+ dryRun?: boolean;
84
+ /** Sidecar path override (tests / callers). Defaults to a file alongside settingsPath. */
85
+ sidecarPath?: string;
86
+ }
87
+
88
+ // ─── Pure merge (no I/O) ─────────────────────────────────────────────────
89
+
90
+ /**
91
+ * Union-merge law (THE #1 care): result = existingManualEntries ∪
92
+ * registeredProjectRoots. Never a replace. De-dupe. Preserve existing
93
+ * order; append new entries at the end. Defensive: filters out any
94
+ * non-string / empty-string entry from either side without throwing.
95
+ */
96
+ export function mergeAdditionalDirectories(
97
+ existing: readonly string[] | undefined,
98
+ registeredRoots: readonly string[]
99
+ ): MergeResult {
100
+ const normalizedExisting = Array.isArray(existing)
101
+ ? existing.filter((entry): entry is string => typeof entry === 'string' && entry !== '')
102
+ : [];
103
+ const seen = new Set(normalizedExisting);
104
+ const added: string[] = [];
105
+
106
+ for (const root of registeredRoots) {
107
+ if (typeof root !== 'string' || root === '' || seen.has(root)) continue;
108
+ seen.add(root);
109
+ added.push(root);
110
+ }
111
+
112
+ return { merged: [...normalizedExisting, ...added], added };
113
+ }
114
+
115
+ /**
116
+ * Applies the union-merge to a full settings object, preserving EVERY other
117
+ * key (top-level and inside `.permissions`) untouched. Never mutates the
118
+ * input object.
119
+ */
120
+ export function applyAdditionalDirectoriesToSettings(
121
+ settings: Record<string, unknown>,
122
+ registeredRoots: readonly string[]
123
+ ): { settings: Record<string, unknown>; added: string[] } {
124
+ const permissions =
125
+ settings.permissions && typeof settings.permissions === 'object'
126
+ ? (settings.permissions as Record<string, unknown>)
127
+ : {};
128
+
129
+ const existing = Array.isArray(permissions.additionalDirectories)
130
+ ? (permissions.additionalDirectories as unknown[]).filter(
131
+ (e): e is string => typeof e === 'string'
132
+ )
133
+ : undefined;
134
+
135
+ const { merged, added } = mergeAdditionalDirectories(existing, registeredRoots);
136
+
137
+ return {
138
+ settings: {
139
+ ...settings,
140
+ permissions: {
141
+ ...permissions,
142
+ additionalDirectories: merged,
143
+ },
144
+ },
145
+ added,
146
+ };
147
+ }
148
+
149
+ // ─── Atomic write (backup -> temp -> validate -> rename) ─────────────────
150
+
151
+ /**
152
+ * Read-modify-write safety: back up the prior file first (timestamped,
153
+ * same directory), write to a temp file in the SAME directory (same-
154
+ * filesystem rename is atomic on POSIX), validate the temp file re-parses
155
+ * as JSON, then rename over the target. On any failure BEFORE the rename,
156
+ * the original file is untouched — never a partial write of the real
157
+ * settings file. The temp file is best-effort cleaned up on any failure.
158
+ *
159
+ * Returns the backup path, or `undefined` when no prior file existed (a
160
+ * fresh file was created — nothing to back up).
161
+ */
162
+ export function writeSettingsAtomic(
163
+ settingsPath: string,
164
+ settings: Record<string, unknown>
165
+ ): string | undefined {
166
+ let backupPath: string | undefined;
167
+ if (existsSync(settingsPath)) {
168
+ backupPath = `${settingsPath}.bak.${String(Date.now())}`;
169
+ copyFileSync(settingsPath, backupPath);
170
+ }
171
+
172
+ const tempPath = `${settingsPath}.tmp.${String(process.pid)}.${String(Date.now())}`;
173
+ const content = JSON.stringify(settings, null, 2);
174
+
175
+ try {
176
+ writeFileSync(tempPath, content, 'utf-8');
177
+ // Validate before ever touching the real file.
178
+ JSON.parse(readFileSync(tempPath, 'utf-8'));
179
+ renameSync(tempPath, settingsPath);
180
+ } catch (err) {
181
+ if (existsSync(tempPath)) {
182
+ try {
183
+ unlinkSync(tempPath);
184
+ } catch {
185
+ // best-effort cleanup — the original file is already safe either way
186
+ }
187
+ }
188
+ throw err;
189
+ }
190
+
191
+ return backupPath;
192
+ }
193
+
194
+ // ─── Managed-paths sidecar (design-for-it, v1 additive-only) ─────────────
195
+
196
+ export function readManagedSidecar(sidecarPath: string): ManagedSidecar {
197
+ try {
198
+ if (!existsSync(sidecarPath)) return { managedPaths: [], updatedAt: '' };
199
+ const raw = JSON.parse(readFileSync(sidecarPath, 'utf-8')) as Partial<ManagedSidecar>;
200
+ return {
201
+ managedPaths: Array.isArray(raw.managedPaths)
202
+ ? raw.managedPaths.filter((p): p is string => typeof p === 'string')
203
+ : [],
204
+ updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt : '',
205
+ };
206
+ } catch {
207
+ return { managedPaths: [], updatedAt: '' };
208
+ }
209
+ }
210
+
211
+ export function writeManagedSidecarAtomic(
212
+ sidecarPath: string,
213
+ managedPaths: readonly string[]
214
+ ): void {
215
+ mkdirSync(dirname(sidecarPath), { recursive: true });
216
+ const tempPath = `${sidecarPath}.tmp.${String(process.pid)}.${String(Date.now())}`;
217
+ const record: ManagedSidecar = {
218
+ managedPaths: [...managedPaths],
219
+ updatedAt: new Date().toISOString(),
220
+ };
221
+
222
+ try {
223
+ writeFileSync(tempPath, JSON.stringify(record, null, 2), 'utf-8');
224
+ JSON.parse(readFileSync(tempPath, 'utf-8'));
225
+ renameSync(tempPath, sidecarPath);
226
+ } catch (err) {
227
+ if (existsSync(tempPath)) {
228
+ try {
229
+ unlinkSync(tempPath);
230
+ } catch {
231
+ // best-effort cleanup
232
+ }
233
+ }
234
+ throw err;
235
+ }
236
+ }
237
+
238
+ // ─── Orchestration ─────────────────────────────────────────────────────────
239
+
240
+ /**
241
+ * Reads `settingsPath`, union-merges `registeredRoots` into
242
+ * `.permissions.additionalDirectories`, and (unless `dryRun`) writes the
243
+ * result back atomically plus updates the managed-paths sidecar.
244
+ *
245
+ * Fail-SAFE, not fail-open: a missing or unparseable settings file returns
246
+ * `ok: false` and touches NOTHING — this module never creates a brand-new
247
+ * settings.json (the real file always pre-exists per TD-204 §0) and never
248
+ * risks writing on top of content it could not fully understand.
249
+ */
250
+ export function syncAdditionalDirectories(options: SyncOptions): SyncOutcome {
251
+ const { settingsPath, registeredRoots, dryRun = false } = options;
252
+ const sidecarPath =
253
+ options.sidecarPath ?? join(dirname(settingsPath), '.orchestrator-managed-directories.json');
254
+
255
+ if (!existsSync(settingsPath)) {
256
+ return { ok: false, reason: 'settings-file-not-found' };
257
+ }
258
+
259
+ let parsed: Record<string, unknown>;
260
+ try {
261
+ const raw = readFileSync(settingsPath, 'utf-8');
262
+ parsed = JSON.parse(raw) as Record<string, unknown>;
263
+ } catch (err) {
264
+ return {
265
+ ok: false,
266
+ reason: 'invalid-json',
267
+ error: err instanceof Error ? err.message : String(err),
268
+ };
269
+ }
270
+
271
+ const { settings: nextSettings, added } = applyAdditionalDirectoriesToSettings(
272
+ parsed,
273
+ registeredRoots
274
+ );
275
+ const permissions = nextSettings.permissions as Record<string, unknown>;
276
+ const merged = permissions.additionalDirectories as string[];
277
+
278
+ if (dryRun) {
279
+ return { ok: true, dryRun: true, merged, added };
280
+ }
281
+
282
+ try {
283
+ const backupPath = writeSettingsAtomic(settingsPath, nextSettings);
284
+ const sidecar = readManagedSidecar(sidecarPath);
285
+ const managedUnion = Array.from(new Set([...sidecar.managedPaths, ...registeredRoots]));
286
+ writeManagedSidecarAtomic(sidecarPath, managedUnion);
287
+ return { ok: true, dryRun: false, merged, added, ...(backupPath ? { backupPath } : {}) };
288
+ } catch (err) {
289
+ return {
290
+ ok: false,
291
+ reason: 'write-failed',
292
+ error: err instanceof Error ? err.message : String(err),
293
+ };
294
+ }
295
+ }