@orchestrator-claude/definitions 3.37.0 → 3.37.2

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 (73) hide show
  1. package/agents/adversarial-reviewer.md +6 -1
  2. package/agents/api-extractor.md +6 -0
  3. package/agents/azure-devops-engineer.md +1 -2
  4. package/agents/business-rule-miner.md +6 -0
  5. package/agents/cicd-platform-engineer.md +1 -2
  6. package/agents/ciclo-engineer.md +50 -21
  7. package/agents/code-archaeologist.md +6 -0
  8. package/agents/debug-sidecar.md +6 -0
  9. package/agents/doc-sidecar.md +6 -0
  10. package/agents/docs-guardian.md +9 -3
  11. package/agents/frontend-engineer.md +1 -2
  12. package/agents/{ai-architect.md → harness-architect.md} +8 -3
  13. package/agents/implementer.md +6 -1
  14. package/agents/legacy-discoverer.md +6 -0
  15. package/agents/legacy-synthesizer.md +6 -0
  16. package/agents/methodology-researcher.md +6 -1
  17. package/agents/operational-artifact-builder.md +6 -1
  18. package/agents/orchestrator.md +27 -87
  19. package/agents/planner.md +6 -1
  20. package/agents/presentation-engineer.md +29 -15
  21. package/agents/python-data-engineer.md +0 -1
  22. package/agents/researcher.md +6 -0
  23. package/agents/reviewer.md +6 -1
  24. package/agents/schema-extractor.md +6 -0
  25. package/agents/software-architect.md +10 -5
  26. package/agents/specifier.md +6 -1
  27. package/agents/task-generator.md +6 -1
  28. package/agents/test-sidecar.md +6 -0
  29. package/dist/scripts/generate-hooks-matcher.d.ts +106 -0
  30. package/dist/scripts/generate-hooks-matcher.d.ts.map +1 -0
  31. package/dist/scripts/generate-hooks-matcher.js +153 -0
  32. package/dist/scripts/generate-hooks-matcher.js.map +1 -0
  33. package/dist/scripts/generate-manifest.d.ts +22 -0
  34. package/dist/scripts/generate-manifest.d.ts.map +1 -1
  35. package/dist/scripts/generate-manifest.js +67 -2
  36. package/dist/scripts/generate-manifest.js.map +1 -1
  37. package/hooks/agent-git-guard.mjs +63 -11
  38. package/hooks/dangling-guard.mjs +42 -12
  39. package/hooks/gate-guardian.mjs +38 -8
  40. package/hooks/hooks.json +3 -9
  41. package/hooks/lib/api-client.ts +128 -9
  42. package/hooks/lib/capability-scanner.ts +462 -55
  43. package/hooks/lib/dispatch-marker.ts +214 -0
  44. package/hooks/lib/git-checkpoint.ts +34 -37
  45. package/hooks/lib/observations-helper.ts +14 -1
  46. package/hooks/lib/security-gate-core.ts +271 -0
  47. package/hooks/mailbox-listener.mjs +69 -17
  48. package/hooks/playwright-output-guard.mjs +40 -10
  49. package/hooks/post-implement.mjs +38 -8
  50. package/hooks/pre-agent-dispatch.mjs +137 -16
  51. package/hooks/pre-agent-dispatch.ts +82 -15
  52. package/hooks/security-gate-honest.mjs +302 -0
  53. package/hooks/security-gate-honest.ts +148 -0
  54. package/hooks/session-start.mjs +304 -106
  55. package/hooks/session-start.ts +317 -71
  56. package/hooks/subagent-start.mjs +7673 -22
  57. package/hooks/subagent-start.ts +367 -16
  58. package/hooks/subagent-stop.mjs +102 -62
  59. package/hooks/subagent-stop.ts +124 -28
  60. package/hooks/user-prompt.mjs +43 -13
  61. package/hooks/verification-before-completion.mjs +63 -11
  62. package/hooks/workflow-guard.mjs +45 -11
  63. package/hooks-settings-template.json +1 -7
  64. package/manifest.json +77 -61
  65. package/package.json +4 -2
  66. package/skills/checkpoint-protocol/SKILL.md +19 -4
  67. package/skills/ciclo-lane-dispatch/SKILL.md +117 -8
  68. package/skills/fase-1b-projecao/SKILL.md +150 -0
  69. package/skills/lane-1-entrevista/SKILL.md +173 -0
  70. package/skills/orchestrator/SKILL.md +11 -3
  71. package/skills/workflow-coordination/SKILL.md +3 -3
  72. package/hooks/post-compact.mjs +0 -7931
  73. package/hooks/post-compact.ts +0 -170
@@ -6,28 +6,80 @@ import {
6
6
  readFileSync as readFileSync2,
7
7
  unlinkSync as unlinkSync2,
8
8
  renameSync,
9
- existsSync,
9
+ existsSync as existsSync2,
10
10
  mkdirSync as mkdirSync2,
11
11
  writeFileSync as writeFileSync2
12
12
  } from "node:fs";
13
- import { join as join2 } from "node:path";
13
+ import { join as join3 } from "node:path";
14
14
  import { randomUUID } from "node:crypto";
15
15
 
16
16
  // hooks/lib/api-client.ts
17
17
  import { readFileSync, writeFileSync, mkdirSync, statSync, unlinkSync, readdirSync } from "node:fs";
18
- import { join, dirname } from "node:path";
19
- import { fileURLToPath } from "node:url";
20
- var __filename = fileURLToPath(import.meta.url);
21
- var __dirname = dirname(__filename);
22
- var PROJECT_ROOT = join(__dirname, "..", "..", "..");
23
- var STATE_DIR = join(PROJECT_ROOT, ".orchestrator", ".state");
24
- var JWT_CACHE = join(STATE_DIR, "jwt-token");
25
- var DEBUG_LOG = join(STATE_DIR, "hook-debug.log");
18
+ import { join as join2 } from "node:path";
19
+ import { tmpdir } from "node:os";
20
+ import { createHash } from "node:crypto";
21
+
22
+ // ../project-root-resolver/dist/index.js
23
+ import { existsSync } from "node:fs";
24
+ import { dirname, join } from "node:path";
25
+ function hasProjectRootMarker(candidate, sentinel) {
26
+ return existsSync(join(candidate, ".git")) || existsSync(join(candidate, "package.json")) || existsSync(join(candidate, sentinel, ".root"));
27
+ }
28
+ function resolveProjectRoot(cwd, sentinel = ".orchestrator") {
29
+ const candidates = [];
30
+ let currentDir = cwd;
31
+ for (; ; ) {
32
+ if (existsSync(join(currentDir, sentinel))) {
33
+ candidates.push(currentDir);
34
+ }
35
+ const parentDir = dirname(currentDir);
36
+ if (parentDir === currentDir) {
37
+ break;
38
+ }
39
+ currentDir = parentDir;
40
+ }
41
+ const [innermost] = candidates;
42
+ if (innermost === void 0) {
43
+ return null;
44
+ }
45
+ for (const candidate of candidates) {
46
+ if (hasProjectRootMarker(candidate, sentinel)) {
47
+ return candidate;
48
+ }
49
+ }
50
+ return innermost;
51
+ }
52
+
53
+ // hooks/lib/api-client.ts
54
+ function resolveFallbackStateDir(cwd) {
55
+ const cwdHash = createHash("sha256").update(cwd).digest("hex").slice(0, 16);
56
+ return join2(tmpdir(), "orchestrator-hook-fallback", cwdHash);
57
+ }
58
+ var PROJECT_ROOT = (() => {
59
+ const resolved = resolveHookProjectRoot(process.cwd());
60
+ if (resolved !== null && hasProjectRootMarker(resolved, ".orchestrator")) {
61
+ return resolved;
62
+ }
63
+ return null;
64
+ })();
65
+ var STATE_DIR_OVERRIDE = process.env.ORCHESTRATOR_STATE_DIR;
66
+ var STATE_DIR = STATE_DIR_OVERRIDE !== void 0 && STATE_DIR_OVERRIDE !== "" ? STATE_DIR_OVERRIDE : PROJECT_ROOT !== null ? join2(PROJECT_ROOT, ".orchestrator", ".state") : resolveFallbackStateDir(process.cwd());
67
+ var JWT_CACHE = join2(STATE_DIR, "jwt-token");
68
+ var DEBUG_LOG = join2(STATE_DIR, "hook-debug.log");
26
69
  mkdirSync(STATE_DIR, { recursive: true });
70
+ if ((STATE_DIR_OVERRIDE === void 0 || STATE_DIR_OVERRIDE === "") && PROJECT_ROOT === null) {
71
+ log(
72
+ "API-CLIENT",
73
+ `PROJECT_ROOT: no marker-verified ".orchestrator" project root found above ${process.cwd()} \u2014 falling back to isolated state dir ${STATE_DIR} (RF-003)`
74
+ );
75
+ }
27
76
  var API_URL = process.env.ORCHESTRATOR_API_URL || "http://localhost:3001";
28
77
  var AUTH_EMAIL = process.env.ORCHESTRATOR_ADMIN_EMAIL || process.env.ORCHESTRATOR_AUTH_EMAIL || "system@orchestrator.local";
29
78
  var AUTH_PASSWORD = process.env.ORCHESTRATOR_ADMIN_PASSWORD || process.env.ORCHESTRATOR_AUTH_PASSWORD || "system123";
30
79
  var PROJECT_ID = process.env.ORCHESTRATOR_PROJECT_ID || "";
80
+ function resolveHookProjectRoot(cwd) {
81
+ return resolveProjectRoot(cwd);
82
+ }
31
83
  function log(prefix, msg) {
32
84
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z");
33
85
  try {
@@ -37,11 +89,11 @@ function log(prefix, msg) {
37
89
  } catch {
38
90
  }
39
91
  }
40
- var LAST_COMPLETED_FILE = join(STATE_DIR, "last-completed-workflow.json");
92
+ var LAST_COMPLETED_FILE = join2(STATE_DIR, "last-completed-workflow.json");
41
93
  var LAST_COMPLETED_TTL_MS = 60 * 60 * 1e3;
42
- var INVOCATIONS_DIR = join(STATE_DIR, "invocations");
94
+ var INVOCATIONS_DIR = join2(STATE_DIR, "invocations");
43
95
  var INVOCATION_STATE_TTL_MS = 4 * 60 * 60 * 1e3;
44
- var DISPATCH_INTENT_DIR = join(STATE_DIR, "dispatch-intent");
96
+ var DISPATCH_INTENT_DIR = join2(STATE_DIR, "dispatch-intent");
45
97
  function outputContext(hookEvent, context) {
46
98
  console.log(
47
99
  JSON.stringify({
@@ -82,7 +134,7 @@ function consumeInbox(inboxPath, quarantinePath, paneRole) {
82
134
  const consumed = [];
83
135
  const errors = [];
84
136
  for (const file of files) {
85
- const filePath = join2(inboxPath, file);
137
+ const filePath = join3(inboxPath, file);
86
138
  try {
87
139
  const raw = readFileSync2(filePath, "utf-8");
88
140
  const parsed = JSON.parse(raw);
@@ -101,7 +153,7 @@ function consumeInbox(inboxPath, quarantinePath, paneRole) {
101
153
  log(HOOK, `Quarantine: ${file} \u2014 ${errMsg}`);
102
154
  try {
103
155
  mkdirSync2(quarantinePath, { recursive: true });
104
- renameSync(filePath, join2(quarantinePath, file));
156
+ renameSync(filePath, join3(quarantinePath, file));
105
157
  } catch {
106
158
  }
107
159
  }
@@ -211,7 +263,7 @@ function relaySidecarMessages(consumed, sprintId, paneRole, deps = { readdirSync
211
263
  };
212
264
  const sidecarAddr = `${sidecar.role}-${String(sidecar.index)}`;
213
265
  const targetInbox = `/tmp/${sprintId}/mailbox/${sidecarAddr}/inbox`;
214
- const targetPath = join2(targetInbox, `${envelope.id}.json`);
266
+ const targetPath = join3(targetInbox, `${envelope.id}.json`);
215
267
  deps.writeFileSync(targetPath, JSON.stringify(envelope), "utf-8");
216
268
  log(HOOK, `Relayed task_complete to ${sidecarAddr}: ${envelope.id}`);
217
269
  } catch (err) {
@@ -229,7 +281,7 @@ async function main() {
229
281
  }
230
282
  const inboxPath = `/tmp/${sprintId}/mailbox/${paneRole}/inbox`;
231
283
  const quarantinePath = `/tmp/${sprintId}/mailbox/${paneRole}/quarantine`;
232
- if (!existsSync(inboxPath)) {
284
+ if (!existsSync2(inboxPath)) {
233
285
  return;
234
286
  }
235
287
  let hookEventName;
@@ -1,38 +1,68 @@
1
1
  import { createRequire as __createRequireShim } from 'node:module'; const require = __createRequireShim(import.meta.url);
2
2
 
3
3
  // hooks/playwright-output-guard.ts
4
- import { dirname as dirname3, isAbsolute, normalize, resolve } from "node:path";
4
+ import { dirname as dirname2, isAbsolute, normalize, resolve } from "node:path";
5
5
 
6
6
  // hooks/lib/api-client.ts
7
7
  import { readFileSync, writeFileSync, mkdirSync, statSync, unlinkSync, readdirSync } from "node:fs";
8
- import { join as join2, dirname as dirname2 } from "node:path";
9
- import { fileURLToPath } from "node:url";
8
+ import { join as join2 } from "node:path";
9
+ import { tmpdir } from "node:os";
10
+ import { createHash } from "node:crypto";
10
11
 
11
12
  // ../project-root-resolver/dist/index.js
12
13
  import { existsSync } from "node:fs";
13
14
  import { dirname, join } from "node:path";
15
+ function hasProjectRootMarker(candidate, sentinel) {
16
+ return existsSync(join(candidate, ".git")) || existsSync(join(candidate, "package.json")) || existsSync(join(candidate, sentinel, ".root"));
17
+ }
14
18
  function resolveProjectRoot(cwd, sentinel = ".orchestrator") {
19
+ const candidates = [];
15
20
  let currentDir = cwd;
16
21
  for (; ; ) {
17
22
  if (existsSync(join(currentDir, sentinel))) {
18
- return currentDir;
23
+ candidates.push(currentDir);
19
24
  }
20
25
  const parentDir = dirname(currentDir);
21
26
  if (parentDir === currentDir) {
22
- return null;
27
+ break;
23
28
  }
24
29
  currentDir = parentDir;
25
30
  }
31
+ const [innermost] = candidates;
32
+ if (innermost === void 0) {
33
+ return null;
34
+ }
35
+ for (const candidate of candidates) {
36
+ if (hasProjectRootMarker(candidate, sentinel)) {
37
+ return candidate;
38
+ }
39
+ }
40
+ return innermost;
26
41
  }
27
42
 
28
43
  // hooks/lib/api-client.ts
29
- var __filename = fileURLToPath(import.meta.url);
30
- var __dirname = dirname2(__filename);
31
- var PROJECT_ROOT = join2(__dirname, "..", "..", "..");
32
- var STATE_DIR = join2(PROJECT_ROOT, ".orchestrator", ".state");
44
+ function resolveFallbackStateDir(cwd) {
45
+ const cwdHash = createHash("sha256").update(cwd).digest("hex").slice(0, 16);
46
+ return join2(tmpdir(), "orchestrator-hook-fallback", cwdHash);
47
+ }
48
+ var PROJECT_ROOT = (() => {
49
+ const resolved = resolveHookProjectRoot(process.cwd());
50
+ if (resolved !== null && hasProjectRootMarker(resolved, ".orchestrator")) {
51
+ return resolved;
52
+ }
53
+ return null;
54
+ })();
55
+ var STATE_DIR_OVERRIDE = process.env.ORCHESTRATOR_STATE_DIR;
56
+ var STATE_DIR = STATE_DIR_OVERRIDE !== void 0 && STATE_DIR_OVERRIDE !== "" ? STATE_DIR_OVERRIDE : PROJECT_ROOT !== null ? join2(PROJECT_ROOT, ".orchestrator", ".state") : resolveFallbackStateDir(process.cwd());
33
57
  var JWT_CACHE = join2(STATE_DIR, "jwt-token");
34
58
  var DEBUG_LOG = join2(STATE_DIR, "hook-debug.log");
35
59
  mkdirSync(STATE_DIR, { recursive: true });
60
+ if ((STATE_DIR_OVERRIDE === void 0 || STATE_DIR_OVERRIDE === "") && PROJECT_ROOT === null) {
61
+ log(
62
+ "API-CLIENT",
63
+ `PROJECT_ROOT: no marker-verified ".orchestrator" project root found above ${process.cwd()} \u2014 falling back to isolated state dir ${STATE_DIR} (RF-003)`
64
+ );
65
+ }
36
66
  var API_URL = process.env.ORCHESTRATOR_API_URL || "http://localhost:3001";
37
67
  var AUTH_EMAIL = process.env.ORCHESTRATOR_ADMIN_EMAIL || process.env.ORCHESTRATOR_AUTH_EMAIL || "system@orchestrator.local";
38
68
  var AUTH_PASSWORD = process.env.ORCHESTRATOR_ADMIN_PASSWORD || process.env.ORCHESTRATOR_AUTH_PASSWORD || "system123";
@@ -95,7 +125,7 @@ var GUIDANCE = 'Playwright Output Guard: screenshots n\xE3o podem cair na raiz d
95
125
  function evaluateFilename(filename) {
96
126
  if (!filename) return { decision: "allow" };
97
127
  const resolved = isAbsolute(filename) ? normalize(filename) : resolve(PROJECT_ROOT2, filename);
98
- const dir = dirname3(resolved);
128
+ const dir = dirname2(resolved);
99
129
  if (dir === PROJECT_ROOT2) {
100
130
  return { decision: "deny", reason: GUIDANCE };
101
131
  }
@@ -2,34 +2,64 @@ import { createRequire as __createRequireShim } from 'node:module'; const requir
2
2
 
3
3
  // hooks/lib/api-client.ts
4
4
  import { readFileSync, writeFileSync, mkdirSync, statSync, unlinkSync, readdirSync } from "node:fs";
5
- import { join as join2, dirname as dirname2 } from "node:path";
6
- import { fileURLToPath } from "node:url";
5
+ import { join as join2 } from "node:path";
6
+ import { tmpdir } from "node:os";
7
+ import { createHash } from "node:crypto";
7
8
 
8
9
  // ../project-root-resolver/dist/index.js
9
10
  import { existsSync } from "node:fs";
10
11
  import { dirname, join } from "node:path";
12
+ function hasProjectRootMarker(candidate, sentinel) {
13
+ return existsSync(join(candidate, ".git")) || existsSync(join(candidate, "package.json")) || existsSync(join(candidate, sentinel, ".root"));
14
+ }
11
15
  function resolveProjectRoot(cwd, sentinel = ".orchestrator") {
16
+ const candidates = [];
12
17
  let currentDir = cwd;
13
18
  for (; ; ) {
14
19
  if (existsSync(join(currentDir, sentinel))) {
15
- return currentDir;
20
+ candidates.push(currentDir);
16
21
  }
17
22
  const parentDir = dirname(currentDir);
18
23
  if (parentDir === currentDir) {
19
- return null;
24
+ break;
20
25
  }
21
26
  currentDir = parentDir;
22
27
  }
28
+ const [innermost] = candidates;
29
+ if (innermost === void 0) {
30
+ return null;
31
+ }
32
+ for (const candidate of candidates) {
33
+ if (hasProjectRootMarker(candidate, sentinel)) {
34
+ return candidate;
35
+ }
36
+ }
37
+ return innermost;
23
38
  }
24
39
 
25
40
  // hooks/lib/api-client.ts
26
- var __filename = fileURLToPath(import.meta.url);
27
- var __dirname = dirname2(__filename);
28
- var PROJECT_ROOT = join2(__dirname, "..", "..", "..");
29
- var STATE_DIR = join2(PROJECT_ROOT, ".orchestrator", ".state");
41
+ function resolveFallbackStateDir(cwd) {
42
+ const cwdHash = createHash("sha256").update(cwd).digest("hex").slice(0, 16);
43
+ return join2(tmpdir(), "orchestrator-hook-fallback", cwdHash);
44
+ }
45
+ var PROJECT_ROOT = (() => {
46
+ const resolved = resolveHookProjectRoot(process.cwd());
47
+ if (resolved !== null && hasProjectRootMarker(resolved, ".orchestrator")) {
48
+ return resolved;
49
+ }
50
+ return null;
51
+ })();
52
+ var STATE_DIR_OVERRIDE = process.env.ORCHESTRATOR_STATE_DIR;
53
+ var STATE_DIR = STATE_DIR_OVERRIDE !== void 0 && STATE_DIR_OVERRIDE !== "" ? STATE_DIR_OVERRIDE : PROJECT_ROOT !== null ? join2(PROJECT_ROOT, ".orchestrator", ".state") : resolveFallbackStateDir(process.cwd());
30
54
  var JWT_CACHE = join2(STATE_DIR, "jwt-token");
31
55
  var DEBUG_LOG = join2(STATE_DIR, "hook-debug.log");
32
56
  mkdirSync(STATE_DIR, { recursive: true });
57
+ if ((STATE_DIR_OVERRIDE === void 0 || STATE_DIR_OVERRIDE === "") && PROJECT_ROOT === null) {
58
+ log(
59
+ "API-CLIENT",
60
+ `PROJECT_ROOT: no marker-verified ".orchestrator" project root found above ${process.cwd()} \u2014 falling back to isolated state dir ${STATE_DIR} (RF-003)`
61
+ );
62
+ }
33
63
  var API_URL = process.env.ORCHESTRATOR_API_URL || "http://localhost:3001";
34
64
  var AUTH_EMAIL = process.env.ORCHESTRATOR_ADMIN_EMAIL || process.env.ORCHESTRATOR_AUTH_EMAIL || "system@orchestrator.local";
35
65
  var AUTH_PASSWORD = process.env.ORCHESTRATOR_ADMIN_PASSWORD || process.env.ORCHESTRATOR_AUTH_PASSWORD || "system123";
@@ -1,38 +1,68 @@
1
1
  import { createRequire as __createRequireShim } from 'node:module'; const require = __createRequireShim(import.meta.url);
2
2
 
3
3
  // hooks/pre-agent-dispatch.ts
4
- import { execFileSync } from "node:child_process";
4
+ import { execFileSync as execFileSync2 } from "node:child_process";
5
5
 
6
6
  // hooks/lib/api-client.ts
7
7
  import { readFileSync, writeFileSync, mkdirSync, statSync, unlinkSync, readdirSync } from "node:fs";
8
- import { join as join2, dirname as dirname2 } from "node:path";
9
- import { fileURLToPath } from "node:url";
8
+ import { join as join2 } from "node:path";
9
+ import { tmpdir } from "node:os";
10
+ import { createHash } from "node:crypto";
10
11
 
11
12
  // ../project-root-resolver/dist/index.js
12
13
  import { existsSync } from "node:fs";
13
14
  import { dirname, join } from "node:path";
15
+ function hasProjectRootMarker(candidate, sentinel) {
16
+ return existsSync(join(candidate, ".git")) || existsSync(join(candidate, "package.json")) || existsSync(join(candidate, sentinel, ".root"));
17
+ }
14
18
  function resolveProjectRoot(cwd, sentinel = ".orchestrator") {
19
+ const candidates = [];
15
20
  let currentDir = cwd;
16
21
  for (; ; ) {
17
22
  if (existsSync(join(currentDir, sentinel))) {
18
- return currentDir;
23
+ candidates.push(currentDir);
19
24
  }
20
25
  const parentDir = dirname(currentDir);
21
26
  if (parentDir === currentDir) {
22
- return null;
27
+ break;
23
28
  }
24
29
  currentDir = parentDir;
25
30
  }
31
+ const [innermost] = candidates;
32
+ if (innermost === void 0) {
33
+ return null;
34
+ }
35
+ for (const candidate of candidates) {
36
+ if (hasProjectRootMarker(candidate, sentinel)) {
37
+ return candidate;
38
+ }
39
+ }
40
+ return innermost;
26
41
  }
27
42
 
28
43
  // hooks/lib/api-client.ts
29
- var __filename = fileURLToPath(import.meta.url);
30
- var __dirname = dirname2(__filename);
31
- var PROJECT_ROOT = join2(__dirname, "..", "..", "..");
32
- var STATE_DIR = join2(PROJECT_ROOT, ".orchestrator", ".state");
44
+ function resolveFallbackStateDir(cwd) {
45
+ const cwdHash = createHash("sha256").update(cwd).digest("hex").slice(0, 16);
46
+ return join2(tmpdir(), "orchestrator-hook-fallback", cwdHash);
47
+ }
48
+ var PROJECT_ROOT = (() => {
49
+ const resolved = resolveHookProjectRoot(process.cwd());
50
+ if (resolved !== null && hasProjectRootMarker(resolved, ".orchestrator")) {
51
+ return resolved;
52
+ }
53
+ return null;
54
+ })();
55
+ var STATE_DIR_OVERRIDE = process.env.ORCHESTRATOR_STATE_DIR;
56
+ var STATE_DIR = STATE_DIR_OVERRIDE !== void 0 && STATE_DIR_OVERRIDE !== "" ? STATE_DIR_OVERRIDE : PROJECT_ROOT !== null ? join2(PROJECT_ROOT, ".orchestrator", ".state") : resolveFallbackStateDir(process.cwd());
33
57
  var JWT_CACHE = join2(STATE_DIR, "jwt-token");
34
58
  var DEBUG_LOG = join2(STATE_DIR, "hook-debug.log");
35
59
  mkdirSync(STATE_DIR, { recursive: true });
60
+ if ((STATE_DIR_OVERRIDE === void 0 || STATE_DIR_OVERRIDE === "") && PROJECT_ROOT === null) {
61
+ log(
62
+ "API-CLIENT",
63
+ `PROJECT_ROOT: no marker-verified ".orchestrator" project root found above ${process.cwd()} \u2014 falling back to isolated state dir ${STATE_DIR} (RF-003)`
64
+ );
65
+ }
36
66
  var API_URL = process.env.ORCHESTRATOR_API_URL || "http://localhost:3001";
37
67
  var AUTH_EMAIL = process.env.ORCHESTRATOR_ADMIN_EMAIL || process.env.ORCHESTRATOR_AUTH_EMAIL || "system@orchestrator.local";
38
68
  var AUTH_PASSWORD = process.env.ORCHESTRATOR_ADMIN_PASSWORD || process.env.ORCHESTRATOR_AUTH_PASSWORD || "system123";
@@ -73,6 +103,10 @@ async function ensureProjectIdResolved(token) {
73
103
  );
74
104
  }
75
105
  }
106
+ function normalizeAgentName(subagentType) {
107
+ const i = subagentType.lastIndexOf(":");
108
+ return i === -1 ? subagentType : subagentType.slice(i + 1);
109
+ }
76
110
  function log(prefix, msg) {
77
111
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z");
78
112
  try {
@@ -211,6 +245,72 @@ function outputContext(hookEvent, context) {
211
245
  );
212
246
  }
213
247
 
248
+ // hooks/lib/dispatch-marker.ts
249
+ import { execFileSync } from "node:child_process";
250
+ var DISPATCH_MARKER_REF_PREFIX = "refs/orchestrator/dispatch";
251
+ var MAX_DISPATCH_MARKERS_PER_KEY = 20;
252
+ var EMPTY_COMPONENT_PLACEHOLDER = "unknown";
253
+ function sanitizeRefComponent(raw) {
254
+ const cleaned = (raw || "").replace(/[^A-Za-z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
255
+ return cleaned || EMPTY_COMPONENT_PLACEHOLDER;
256
+ }
257
+ function formatMarkerStamp(d) {
258
+ return d.toISOString().replace(/[-:.]/g, "");
259
+ }
260
+ function buildMarkerRefName(branch, agent, stamp) {
261
+ const branchPart = sanitizeRefComponent(branch);
262
+ const agentPart = sanitizeRefComponent(agent);
263
+ const stampPart = sanitizeRefComponent(stamp);
264
+ return `${DISPATCH_MARKER_REF_PREFIX}/${branchPart}/${stampPart}-${agentPart}`;
265
+ }
266
+ function runGitDefault(args) {
267
+ return execFileSync("git", args, {
268
+ encoding: "utf-8",
269
+ stdio: ["ignore", "pipe", "ignore"]
270
+ });
271
+ }
272
+ function pruneOldestMarkers(prefix, cap, deps) {
273
+ const listed = deps.runGit(["for-each-ref", "--format=%(refname)", "--sort=refname", `${prefix}/`]).split("\n").map((l) => l.trim()).filter(Boolean);
274
+ const excess = listed.length - cap;
275
+ if (excess <= 0) return [];
276
+ const doomed = listed.slice(0, excess);
277
+ for (const ref of doomed) {
278
+ deps.runGit(["update-ref", "-d", ref]);
279
+ }
280
+ return doomed;
281
+ }
282
+ function writeDispatchBoundaryMarker(agentName, branch, deps) {
283
+ let ref = "";
284
+ try {
285
+ if (sanitizeRefComponent(agentName) === EMPTY_COMPONENT_PLACEHOLDER) {
286
+ return {
287
+ status: "failed",
288
+ reason: `refusing to write an unattributable marker (agent name "${agentName}")`
289
+ };
290
+ }
291
+ const sha = deps.runGit(["rev-parse", "HEAD"]).trim();
292
+ if (!/^[0-9a-f]{40}$/.test(sha)) {
293
+ return { status: "failed", reason: `HEAD did not resolve to a 40-hex sha (got "${sha}")` };
294
+ }
295
+ const stamp = formatMarkerStamp((deps.now ?? (() => /* @__PURE__ */ new Date()))());
296
+ ref = buildMarkerRefName(branch, agentName, stamp);
297
+ deps.runGit(["update-ref", ref, sha]);
298
+ let pruned = [];
299
+ try {
300
+ pruned = pruneOldestMarkers(
301
+ `${DISPATCH_MARKER_REF_PREFIX}/${sanitizeRefComponent(branch)}`,
302
+ MAX_DISPATCH_MARKERS_PER_KEY,
303
+ deps
304
+ );
305
+ } catch {
306
+ pruned = [];
307
+ }
308
+ return { status: "written", ref, sha, pruned };
309
+ } catch (err) {
310
+ return { status: "failed", reason: `${ref ? `ref="${ref}" ` : ""}${String(err)}` };
311
+ }
312
+ }
313
+
214
314
  // hooks/pre-agent-dispatch.ts
215
315
  var HOOK = "PRE-AGENT-DISPATCH";
216
316
  var KNOWN_AGENTS = [
@@ -232,10 +332,6 @@ var COMMITTING_AGENTS = [
232
332
  "frontend-engineer"
233
333
  ];
234
334
  var PROTECTED_BRANCHES = ["main", "master"];
235
- function normalizeAgentName(subagentType) {
236
- const i = subagentType.lastIndexOf(":");
237
- return i === -1 ? subagentType : subagentType.slice(i + 1);
238
- }
239
335
  function isCommittingAgent(subagentType) {
240
336
  if (!subagentType) return false;
241
337
  const t = normalizeAgentName(subagentType).toLowerCase();
@@ -274,7 +370,7 @@ function evaluateDispatch(ctx) {
274
370
  }
275
371
  function readBranchFromGit() {
276
372
  try {
277
- return execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
373
+ return execFileSync2("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
278
374
  encoding: "utf-8",
279
375
  stdio: ["ignore", "pipe", "ignore"]
280
376
  }).trim();
@@ -288,7 +384,8 @@ var defaultDeps = {
288
384
  log,
289
385
  readBranch: readBranchFromGit,
290
386
  getActiveWorkflow,
291
- writeDispatchIntent
387
+ writeDispatchIntent,
388
+ writeDispatchMarker: (agentName, branch) => writeDispatchBoundaryMarker(agentName, branch, { runGit: runGitDefault })
292
389
  };
293
390
  var DISPATCH_INTENT_RESOLVE_TIMEOUT_MS = 3e3;
294
391
  async function stampDispatchIntent(deps) {
@@ -310,6 +407,29 @@ async function stampDispatchIntent(deps) {
310
407
  deps.log(HOOK, `[TD-205] stampDispatchIntent failed (fail-open): ${String(err)}`);
311
408
  }
312
409
  }
410
+ function markDispatchBoundary(subagentType, branch, deps) {
411
+ if (!deps.writeDispatchMarker) return [];
412
+ if (!isCommittingAgent(subagentType)) return [];
413
+ try {
414
+ const outcome = deps.writeDispatchMarker(subagentType, branch);
415
+ if (outcome.status === "written") {
416
+ deps.log(HOOK, `[S445] boundary marker ${outcome.ref} -> ${outcome.sha}`);
417
+ if (outcome.pruned.length > 0) {
418
+ deps.log(HOOK, `[S445] pruned ${outcome.pruned.length} marker(s) over retention cap`);
419
+ }
420
+ return [];
421
+ }
422
+ deps.log(HOOK, `[S445] boundary marker FAILED: ${outcome.reason}`);
423
+ return [
424
+ `[BOUNDARY-MARKER][S445] Could not record the pre-dispatch git coordinate for '${subagentType}' on '${branch}': ${outcome.reason}. The dispatch proceeds (this never blocks), but there will be NO ref to 'git reset --hard' back to for this agent's work.`
425
+ ];
426
+ } catch (err) {
427
+ deps.log(HOOK, `[S445] boundary marker threw (fail-open): ${String(err)}`);
428
+ return [
429
+ `[BOUNDARY-MARKER][S445] Boundary-marker step threw for '${subagentType}': ${String(err)}. Dispatch proceeds; no rollback coordinate was recorded.`
430
+ ];
431
+ }
432
+ }
313
433
  async function mainWithDeps(deps) {
314
434
  const stdin = await deps.readStdin();
315
435
  const toolInput = getField(stdin, "tool_input") || "";
@@ -317,6 +437,7 @@ async function mainWithDeps(deps) {
317
437
  const prompt = getField(stdin, "tool_input.prompt") || getField(stdin, "tool_input.description") || (typeof toolInput === "string" ? toolInput : JSON.stringify(toolInput));
318
438
  const branch = deps.readBranch();
319
439
  const warnings = evaluateDispatch({ subagentType, prompt, branch });
440
+ warnings.push(...markDispatchBoundary(subagentType, branch, deps));
320
441
  await stampDispatchIntent(deps);
321
442
  if (warnings.length > 0) {
322
443
  deps.outputContext(HOOK, warnings.join("\n"));
@@ -340,7 +461,7 @@ export {
340
461
  isCommittingAgent,
341
462
  isProtectedBranch,
342
463
  mainWithDeps,
343
- normalizeAgentName,
464
+ markDispatchBoundary,
344
465
  parseBranchFromHead,
345
466
  stampDispatchIntent
346
467
  };