@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.
- package/README.md +113 -0
- package/agents/debug-sidecar.md +1 -1
- package/agents/doc-sidecar.md +1 -1
- package/agents/test-sidecar.md +1 -1
- package/dist/cli.js +78 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/DiffCommand.js +1 -1
- package/dist/commands/DiffCommand.js.map +1 -1
- package/dist/commands/InstallCommand.d.ts +41 -0
- package/dist/commands/InstallCommand.d.ts.map +1 -0
- package/dist/commands/InstallCommand.js +253 -0
- package/dist/commands/InstallCommand.js.map +1 -0
- package/dist/http/ApiClient.d.ts +5 -0
- package/dist/http/ApiClient.d.ts.map +1 -1
- package/dist/http/ApiClient.js.map +1 -1
- package/dist/install/DevCheckoutDetector.d.ts +66 -0
- package/dist/install/DevCheckoutDetector.d.ts.map +1 -0
- package/dist/install/DevCheckoutDetector.js +150 -0
- package/dist/install/DevCheckoutDetector.js.map +1 -0
- package/dist/install/HooksWirer.d.ts +29 -0
- package/dist/install/HooksWirer.d.ts.map +1 -0
- package/dist/install/HooksWirer.js +80 -0
- package/dist/install/HooksWirer.js.map +1 -0
- package/dist/install/LocalDiffReporter.d.ts +25 -0
- package/dist/install/LocalDiffReporter.d.ts.map +1 -0
- package/dist/install/LocalDiffReporter.js +50 -0
- package/dist/install/LocalDiffReporter.js.map +1 -0
- package/dist/install/Materializer.d.ts +67 -0
- package/dist/install/Materializer.d.ts.map +1 -0
- package/dist/install/Materializer.js +196 -0
- package/dist/install/Materializer.js.map +1 -0
- package/dist/install/McpRegistrar.d.ts +63 -0
- package/dist/install/McpRegistrar.d.ts.map +1 -0
- package/dist/install/McpRegistrar.js +114 -0
- package/dist/install/McpRegistrar.js.map +1 -0
- package/dist/install/ProcessRunner.d.ts +25 -0
- package/dist/install/ProcessRunner.d.ts.map +1 -0
- package/dist/install/ProcessRunner.js +41 -0
- package/dist/install/ProcessRunner.js.map +1 -0
- package/dist/install/ProjectSettingsNeutralizer.d.ts +39 -0
- package/dist/install/ProjectSettingsNeutralizer.d.ts.map +1 -0
- package/dist/install/ProjectSettingsNeutralizer.js +100 -0
- package/dist/install/ProjectSettingsNeutralizer.js.map +1 -0
- package/dist/install/types.d.ts +52 -0
- package/dist/install/types.d.ts.map +1 -0
- package/dist/install/types.js +8 -0
- package/dist/install/types.js.map +1 -0
- package/dist/manifest/ManifestLoader.d.ts.map +1 -1
- package/dist/manifest/ManifestLoader.js +3 -2
- package/dist/manifest/ManifestLoader.js.map +1 -1
- package/dist/manifest/types.d.ts +3 -0
- package/dist/manifest/types.d.ts.map +1 -1
- package/dist/scripts/bundle-hooks.d.ts +39 -0
- package/dist/scripts/bundle-hooks.d.ts.map +1 -0
- package/dist/scripts/bundle-hooks.js +165 -0
- package/dist/scripts/bundle-hooks.js.map +1 -0
- package/dist/scripts/generate-manifest.d.ts +22 -3
- package/dist/scripts/generate-manifest.d.ts.map +1 -1
- package/dist/scripts/generate-manifest.js +78 -35
- package/dist/scripts/generate-manifest.js.map +1 -1
- package/hooks/dangling-guard.mjs +7426 -0
- package/hooks/dangling-guard.ts +223 -6
- package/hooks/gate-guardian.mjs +463 -0
- package/hooks/lib/additional-directories-sync.ts +295 -0
- package/hooks/lib/api-client.ts +388 -7
- package/hooks/lib/session-selection.ts +81 -0
- package/hooks/mailbox-listener.mjs +259 -0
- package/hooks/post-compact.mjs +7931 -0
- package/hooks/post-implement.mjs +238 -0
- package/hooks/session-start.mjs +8234 -0
- package/hooks/session-start.ts +264 -23
- package/hooks/sprint-registry.mjs +59 -0
- package/hooks/subagent-start.mjs +289 -0
- package/hooks/subagent-stop.mjs +7793 -0
- package/hooks/subagent-stop.ts +4 -2
- package/hooks/user-prompt.mjs +329 -0
- package/hooks/workflow-guard.mjs +7805 -0
- package/hooks/workflow-guard.ts +360 -119
- package/hooks-settings-template.json +63 -0
- package/manifest.json +54 -68
- package/mcp-servers.json +48 -0
- package/package.json +10 -4
- package/personas/auditor-compliance.md +104 -0
- package/personas/cfo-conservador.md +88 -0
- package/personas/designer-perfeccionista.md +104 -0
- package/personas/diretor-cetico-fmcg.md +80 -0
- 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
|
+
}
|