@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
@@ -7324,38 +7324,68 @@ var require_dist = __commonJS({
7324
7324
  var import_yaml2 = __toESM(require_dist(), 1);
7325
7325
  import { readFileSync as readFileSync4, readdirSync as readdirSync3, existsSync as existsSync4 } from "node:fs";
7326
7326
  import { join as join5, dirname as dirname3 } from "node:path";
7327
- import { fileURLToPath as fileURLToPath2 } from "node:url";
7327
+ import { fileURLToPath } from "node:url";
7328
7328
 
7329
7329
  // hooks/lib/api-client.ts
7330
7330
  import { readFileSync, writeFileSync, mkdirSync, statSync, unlinkSync, readdirSync } from "node:fs";
7331
- import { join as join2, dirname as dirname2 } from "node:path";
7332
- import { fileURLToPath } from "node:url";
7331
+ import { join as join2 } from "node:path";
7332
+ import { tmpdir } from "node:os";
7333
+ import { createHash } from "node:crypto";
7333
7334
 
7334
7335
  // ../project-root-resolver/dist/index.js
7335
7336
  import { existsSync } from "node:fs";
7336
7337
  import { dirname, join } from "node:path";
7338
+ function hasProjectRootMarker(candidate, sentinel) {
7339
+ return existsSync(join(candidate, ".git")) || existsSync(join(candidate, "package.json")) || existsSync(join(candidate, sentinel, ".root"));
7340
+ }
7337
7341
  function resolveProjectRoot(cwd, sentinel = ".orchestrator") {
7342
+ const candidates = [];
7338
7343
  let currentDir = cwd;
7339
7344
  for (; ; ) {
7340
7345
  if (existsSync(join(currentDir, sentinel))) {
7341
- return currentDir;
7346
+ candidates.push(currentDir);
7342
7347
  }
7343
7348
  const parentDir = dirname(currentDir);
7344
7349
  if (parentDir === currentDir) {
7345
- return null;
7350
+ break;
7346
7351
  }
7347
7352
  currentDir = parentDir;
7348
7353
  }
7354
+ const [innermost] = candidates;
7355
+ if (innermost === void 0) {
7356
+ return null;
7357
+ }
7358
+ for (const candidate of candidates) {
7359
+ if (hasProjectRootMarker(candidate, sentinel)) {
7360
+ return candidate;
7361
+ }
7362
+ }
7363
+ return innermost;
7349
7364
  }
7350
7365
 
7351
7366
  // hooks/lib/api-client.ts
7352
- var __filename = fileURLToPath(import.meta.url);
7353
- var __dirname = dirname2(__filename);
7354
- var PROJECT_ROOT = join2(__dirname, "..", "..", "..");
7355
- var STATE_DIR = join2(PROJECT_ROOT, ".orchestrator", ".state");
7367
+ function resolveFallbackStateDir(cwd) {
7368
+ const cwdHash = createHash("sha256").update(cwd).digest("hex").slice(0, 16);
7369
+ return join2(tmpdir(), "orchestrator-hook-fallback", cwdHash);
7370
+ }
7371
+ var PROJECT_ROOT = (() => {
7372
+ const resolved = resolveHookProjectRoot(process.cwd());
7373
+ if (resolved !== null && hasProjectRootMarker(resolved, ".orchestrator")) {
7374
+ return resolved;
7375
+ }
7376
+ return null;
7377
+ })();
7378
+ var STATE_DIR_OVERRIDE = process.env.ORCHESTRATOR_STATE_DIR;
7379
+ 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());
7356
7380
  var JWT_CACHE = join2(STATE_DIR, "jwt-token");
7357
7381
  var DEBUG_LOG = join2(STATE_DIR, "hook-debug.log");
7358
7382
  mkdirSync(STATE_DIR, { recursive: true });
7383
+ if ((STATE_DIR_OVERRIDE === void 0 || STATE_DIR_OVERRIDE === "") && PROJECT_ROOT === null) {
7384
+ log(
7385
+ "API-CLIENT",
7386
+ `PROJECT_ROOT: no marker-verified ".orchestrator" project root found above ${process.cwd()} \u2014 falling back to isolated state dir ${STATE_DIR} (RF-003)`
7387
+ );
7388
+ }
7359
7389
  var API_URL = process.env.ORCHESTRATOR_API_URL || "http://localhost:3001";
7360
7390
  var AUTH_EMAIL = process.env.ORCHESTRATOR_ADMIN_EMAIL || process.env.ORCHESTRATOR_AUTH_EMAIL || "system@orchestrator.local";
7361
7391
  var AUTH_PASSWORD = process.env.ORCHESTRATOR_ADMIN_PASSWORD || process.env.ORCHESTRATOR_AUTH_PASSWORD || "system123";
@@ -7533,6 +7563,19 @@ async function allocateSessionNumber(projectId) {
7533
7563
  projectId
7534
7564
  });
7535
7565
  }
7566
+ async function readStdin() {
7567
+ const chunks = [];
7568
+ for await (const chunk of process.stdin) {
7569
+ chunks.push(chunk);
7570
+ }
7571
+ const raw = Buffer.concat(chunks).toString("utf-8").trim();
7572
+ if (!raw) return {};
7573
+ try {
7574
+ return JSON.parse(raw);
7575
+ } catch {
7576
+ return {};
7577
+ }
7578
+ }
7536
7579
  function outputContext(hookEvent, context) {
7537
7580
  console.log(
7538
7581
  JSON.stringify({
@@ -7546,8 +7589,8 @@ function outputContext(hookEvent, context) {
7546
7589
 
7547
7590
  // hooks/lib/capability-scanner.ts
7548
7591
  var import_yaml = __toESM(require_dist(), 1);
7549
- import { readFileSync as readFileSync2, readdirSync as readdirSync2, existsSync as existsSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
7550
- import { join as join3 } from "node:path";
7592
+ import { readFileSync as readFileSync2, readdirSync as readdirSync2, existsSync as existsSync2, statSync as statSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
7593
+ import { join as join3, dirname as dirname2 } from "node:path";
7551
7594
  function pluginNameFromKey(key) {
7552
7595
  return key.split("@")[0] ?? "";
7553
7596
  }
@@ -7728,13 +7771,14 @@ function buildCapabilityIndex(opts) {
7728
7771
  gaps
7729
7772
  };
7730
7773
  }
7731
- function writeCapabilitiesToVault(vaultConfigPath, index) {
7774
+ var CAPABILITY_CACHE_FILENAME = "capability-cache.yaml";
7775
+ function resolveCapabilityCachePath(projectRoot, env = process.env) {
7776
+ const override = env.ORCHESTRATOR_STATE_DIR;
7777
+ const stateDir = override !== void 0 && override !== "" ? override : join3(projectRoot, ".orchestrator", ".state");
7778
+ return join3(stateDir, CAPABILITY_CACHE_FILENAME);
7779
+ }
7780
+ function writeCapabilityCache(cachePath, index) {
7732
7781
  try {
7733
- let config = {};
7734
- if (existsSync2(vaultConfigPath)) {
7735
- const raw = readFileSync2(vaultConfigPath, "utf-8");
7736
- config = (0, import_yaml.parse)(raw) ?? {};
7737
- }
7738
7782
  const pluginEntries = index.plugins.map((p) => {
7739
7783
  const entry = { name: p.name };
7740
7784
  if (p.version !== "unknown") entry.version = p.version;
@@ -7745,25 +7789,27 @@ function writeCapabilitiesToVault(vaultConfigPath, index) {
7745
7789
  if (p.hasHooks) entry.hooks = true;
7746
7790
  return entry;
7747
7791
  });
7748
- config.capabilities = {
7792
+ const payload = {
7793
+ schema: "capability-cache/v1",
7749
7794
  last_scanned: index.lastScanned,
7750
7795
  installed_plugins_mtime: index.installedPluginsMtime,
7751
7796
  plugins: pluginEntries,
7752
7797
  routing: index.routing,
7753
7798
  gaps: index.gaps
7754
7799
  };
7755
- writeFileSync2(vaultConfigPath, (0, import_yaml.stringify)(config, { lineWidth: 120 }));
7800
+ mkdirSync2(dirname2(cachePath), { recursive: true });
7801
+ writeFileSync2(cachePath, (0, import_yaml.stringify)(payload, { lineWidth: 120 }));
7756
7802
  } catch {
7757
7803
  }
7758
7804
  }
7759
- function readCapabilitiesFromVault(vaultConfigPath) {
7805
+ function readCapabilityCache(cachePath, vaultConfigPath) {
7760
7806
  try {
7761
- if (!existsSync2(vaultConfigPath)) return null;
7762
- const raw = readFileSync2(vaultConfigPath, "utf-8");
7763
- const config = (0, import_yaml.parse)(raw);
7764
- const caps = config?.capabilities;
7765
- if (!caps) return null;
7766
- const rawPlugins = Array.isArray(caps.plugins) ? caps.plugins : [];
7807
+ if (!existsSync2(cachePath)) return null;
7808
+ const raw = readFileSync2(cachePath, "utf-8");
7809
+ const cache = (0, import_yaml.parse)(raw);
7810
+ if (!cache || typeof cache !== "object") return null;
7811
+ if (cache.last_scanned === void 0 && cache.plugins === void 0) return null;
7812
+ const rawPlugins = Array.isArray(cache.plugins) ? cache.plugins : [];
7767
7813
  const plugins = rawPlugins.map((p) => ({
7768
7814
  name: p.name ?? "",
7769
7815
  version: p.version ?? "unknown",
@@ -7774,14 +7820,14 @@ function readCapabilitiesFromVault(vaultConfigPath) {
7774
7820
  hasHooks: p.hooks ?? false
7775
7821
  }));
7776
7822
  return {
7777
- lastScanned: caps.last_scanned ?? "",
7778
- installedPluginsMtime: caps.installed_plugins_mtime ?? "",
7823
+ lastScanned: cache.last_scanned ?? "",
7824
+ installedPluginsMtime: cache.installed_plugins_mtime ?? "",
7779
7825
  plugins,
7780
7826
  agents: [],
7781
7827
  // agents are always scanned fresh (fast, <10ms)
7782
7828
  vault: readVaultSummary(vaultConfigPath),
7783
- routing: caps.routing ?? {},
7784
- gaps: caps.gaps ?? []
7829
+ routing: cache.routing ?? {},
7830
+ gaps: cache.gaps ?? []
7785
7831
  };
7786
7832
  } catch {
7787
7833
  return null;
@@ -7809,32 +7855,102 @@ function formatCapabilityMatrix(index) {
7809
7855
  `gaps: ${gapsLine}`
7810
7856
  ].join("\n");
7811
7857
  }
7812
- function formatMemoryContext(entries) {
7813
- if (entries.length === 0) return "";
7814
- const byType = {};
7815
- for (const e of entries) {
7816
- byType[e.type] = (byType[e.type] ?? 0) + 1;
7858
+ var PER_ENTRY_SUMMARY_CHAR_CAP = 300;
7859
+ var AGGREGATE_CHAR_BUDGET = 8e3;
7860
+ var SUFFIX_RESERVE = 64;
7861
+ var MEMORY_TYPES = ["feedback", "project", "reference", "user"];
7862
+ function truncateSummary(summary, cap) {
7863
+ return summary.length > cap ? `${summary.slice(0, cap)}\u2026` : summary;
7864
+ }
7865
+ function hasRenderableSummary(entry) {
7866
+ return typeof entry.summary === "string";
7867
+ }
7868
+ var MEMORY_SKIPPED_WARNING_PREFIX = "- [AVISO] ";
7869
+ function countByType(list) {
7870
+ const counts = {};
7871
+ for (const e of list) {
7872
+ counts[e.type] = (counts[e.type] ?? 0) + 1;
7817
7873
  }
7818
- const typeSummary = Object.entries(byType).map(([t, n]) => `${n} ${t}`).join(", ");
7819
- const recentNames = entries.slice(0, 5).map((e) => e.file.replace(/\.md$/, "").replace(/^(feedback|project|reference|user)_/, "")).join(", ");
7820
- return [
7821
- `[MEMORY-CONTEXT] ${entries.length} entries: ${typeSummary}`,
7822
- `recent: ${recentNames}`
7823
- ].join("\n");
7874
+ return counts;
7824
7875
  }
7825
- function readMemoryIndex(indexPath) {
7876
+ function formatMemoryContext(selected, allEntries) {
7877
+ const renderable = selected.filter(hasRenderableSummary);
7878
+ const skipped = selected.filter((e) => !hasRenderableSummary(e));
7879
+ const warning = skipped.length > 0 ? `${MEMORY_SKIPPED_WARNING_PREFIX}${String(skipped.length)} entrada(s) sem 'summary:' pulada(s) \u2014 conserte o \xEDndice: ${skipped.map((e) => e.file).join(", ")}` : "";
7880
+ if (renderable.length === 0) return warning ? `[MEMORY-CONTEXT] 0 mem\xF3rias
7881
+ ${warning}` : "";
7882
+ const selectedCounts = countByType(renderable);
7883
+ const totalCounts = countByType(allEntries);
7884
+ const perTypeSummary = MEMORY_TYPES.map(
7885
+ (t) => `${t}: ${selectedCounts[t] ?? 0}/${totalCounts[t] ?? 0}`
7886
+ ).join(", ");
7887
+ const headerBase = `[MEMORY-CONTEXT] ${renderable.length} de ${allEntries.length} mem\xF3rias (${perTypeSummary}); crit\xE9rio: cota m\xEDnima de 2 por tipo n\xE3o-feedback + prioridade feedback\u2192rec\xEAncia no restante`;
7888
+ const availableForLines = AGGREGATE_CHAR_BUDGET - headerBase.length - SUFFIX_RESERVE - (warning ? warning.length + 1 : 0);
7889
+ const lines = [];
7890
+ let used = 0;
7891
+ let droppedByBudget = 0;
7892
+ for (let i = 0; i < renderable.length; i++) {
7893
+ const entry = renderable[i];
7894
+ const name = entry.file.replace(/\.md$/, "");
7895
+ const truncated = truncateSummary(entry.summary, PER_ENTRY_SUMMARY_CHAR_CAP);
7896
+ const line = `- [${entry.type}] ${name}: ${truncated}`;
7897
+ if (used + line.length + 1 > availableForLines) {
7898
+ droppedByBudget = renderable.length - i;
7899
+ break;
7900
+ }
7901
+ lines.push(line);
7902
+ used += line.length + 1;
7903
+ }
7904
+ const header = droppedByBudget > 0 ? `${headerBase}; +${droppedByBudget} truncadas por or\xE7amento de caracteres` : headerBase;
7905
+ return [header, ...lines, warning].filter(Boolean).join("\n");
7906
+ }
7907
+ function isWellFormedMemoryEntry(value) {
7908
+ return typeof value === "object" && value !== null && typeof value.file === "string";
7909
+ }
7910
+ function readMemoryIndex(indexPath, diag) {
7826
7911
  try {
7827
7912
  if (!existsSync2(indexPath)) return null;
7828
7913
  const raw = readFileSync2(indexPath, "utf-8");
7829
- const parsed = (0, import_yaml.parse)(raw);
7830
- return parsed?.entries ?? null;
7831
- } catch {
7914
+ let parsed;
7915
+ try {
7916
+ parsed = (0, import_yaml.parse)(raw);
7917
+ } catch (err) {
7918
+ if (diag) diag.reason = `YAML inv\xE1lido em ${indexPath}: ${String(err).split("\n")[0]}`;
7919
+ return null;
7920
+ }
7921
+ let candidate = null;
7922
+ if (Array.isArray(parsed)) {
7923
+ candidate = parsed;
7924
+ } else if (typeof parsed === "object" && parsed !== null && Array.isArray(parsed.entries)) {
7925
+ candidate = parsed.entries;
7926
+ }
7927
+ if (candidate === null) {
7928
+ const chaves = typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? Object.keys(parsed).join(", ") : typeof parsed;
7929
+ if (diag) {
7930
+ diag.reason = `formato n\xE3o reconhecido em ${indexPath} \u2014 topo tem [${chaves}]; esperado uma lista no topo ou a chave 'entries:'`;
7931
+ }
7932
+ return null;
7933
+ }
7934
+ const bemFormadas = candidate.filter(isWellFormedMemoryEntry);
7935
+ if (diag && candidate.length > 0) {
7936
+ const descartadas = candidate.length - bemFormadas.length;
7937
+ if (bemFormadas.length === 0) {
7938
+ diag.reason = `${candidate.length} entrada(s) lidas e NENHUMA bem-formada em ${indexPath} \u2014 toda entrada precisa da chave 'file:'`;
7939
+ } else if (descartadas > 0) {
7940
+ diag.reason = `${descartadas} de ${candidate.length} entrada(s) descartadas em ${indexPath} (falta a chave 'file:')`;
7941
+ }
7942
+ }
7943
+ return bemFormadas;
7944
+ } catch (err) {
7945
+ if (diag) diag.reason = `falha ao ler ${indexPath}: ${String(err).split("\n")[0]}`;
7832
7946
  return null;
7833
7947
  }
7834
7948
  }
7835
7949
  function filterRelevantMemories(entries, contextTags = []) {
7836
7950
  const now = Date.now();
7837
7951
  const fourteenDays = 14 * 24 * 60 * 60 * 1e3;
7952
+ const MAX_TOTAL = 20;
7953
+ const RESERVED_SLOTS_PER_TYPE = 2;
7838
7954
  const relevant = entries.filter((e) => {
7839
7955
  if (e.type === "feedback") return true;
7840
7956
  const accessed = new Date(e.last_accessed).getTime();
@@ -7848,17 +7964,32 @@ function filterRelevantMemories(entries, contextTags = []) {
7848
7964
  reference: 2,
7849
7965
  user: 3
7850
7966
  };
7851
- relevant.sort((a, b) => {
7967
+ const byPriorityThenRecency = (a, b) => {
7852
7968
  const pa = typePriority[a.type] ?? 9;
7853
7969
  const pb = typePriority[b.type] ?? 9;
7854
7970
  if (pa !== pb) return pa - pb;
7855
7971
  return b.last_accessed.localeCompare(a.last_accessed);
7856
- });
7857
- return relevant.slice(0, 20);
7972
+ };
7973
+ relevant.sort(byPriorityThenRecency);
7974
+ const reserved = /* @__PURE__ */ new Set();
7975
+ const nonFeedbackTypes = new Set(entries.filter((e) => e.type !== "feedback").map((e) => e.type));
7976
+ for (const type of nonFeedbackTypes) {
7977
+ const ofType = entries.filter((e) => e.type === type).sort((a, b) => b.last_accessed.localeCompare(a.last_accessed));
7978
+ for (const entry of ofType.slice(0, RESERVED_SLOTS_PER_TYPE)) {
7979
+ reserved.add(entry);
7980
+ }
7981
+ }
7982
+ const selected = new Set(reserved);
7983
+ for (const entry of relevant) {
7984
+ if (selected.size >= MAX_TOTAL) break;
7985
+ if (reserved.has(entry)) continue;
7986
+ selected.add(entry);
7987
+ }
7988
+ return [...selected].sort(byPriorityThenRecency);
7858
7989
  }
7859
7990
 
7860
7991
  // hooks/lib/session-selection.ts
7861
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "node:fs";
7992
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "node:fs";
7862
7993
  import { join as join4 } from "node:path";
7863
7994
  function selectionFilePath(stateDir, sessionId) {
7864
7995
  const safeId = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
@@ -7879,8 +8010,8 @@ function readSessionSelection(stateDir, sessionId) {
7879
8010
 
7880
8011
  // hooks/session-start.ts
7881
8012
  var HOOK = "SESSION-START";
7882
- var __filename2 = fileURLToPath2(import.meta.url);
7883
- var __dirname2 = dirname3(__filename2);
8013
+ var __filename = fileURLToPath(import.meta.url);
8014
+ var __dirname = dirname3(__filename);
7884
8015
  var PROJECT_ROOT2 = resolveHookProjectRoot(process.cwd());
7885
8016
  var PROJECT_ID2 = process.env.ORCHESTRATOR_PROJECT_ID ?? "";
7886
8017
  var HOME = process.env.HOME ?? process.env.USERPROFILE ?? "/home/user";
@@ -7889,18 +8020,35 @@ var PROJECT_SELECTION_ENABLED = process.env.ORCHESTRATOR_ENABLE_PROJECT_SELECTIO
7889
8020
  var SESSION_SELECTION_STATE_DIR = join5(HOME, ".orchestrator", "session-selection");
7890
8021
  var AGENTS_DIR = PROJECT_ROOT2 ? join5(PROJECT_ROOT2, ".claude", "agents") : null;
7891
8022
  var VAULT_CONFIG_PATH = PROJECT_ROOT2 ? join5(PROJECT_ROOT2, "project-guidelines", ".vault-config.yaml") : null;
8023
+ var CAPABILITY_CACHE_PATH = PROJECT_ROOT2 ? resolveCapabilityCachePath(PROJECT_ROOT2) : null;
7892
8024
  var PROFILES_PATH = PROJECT_ROOT2 ? join5(PROJECT_ROOT2, ".claude", "plugin-profiles.yaml") : null;
7893
8025
  var MEMORY_INDEX_PATH = PROJECT_ROOT2 ? join5(PROJECT_ROOT2, ".claude", "agent-memory", "orchestrator", "memory-index.yaml") : null;
7894
- function readSessionId() {
8026
+ async function readSessionStartPayload() {
7895
8027
  try {
7896
- const raw = readFileSync4("/dev/stdin", "utf-8").trim();
7897
- if (!raw) return null;
7898
- const payload = JSON.parse(raw);
7899
- return payload.session_id ?? null;
7900
- } catch {
7901
- return null;
8028
+ const payload = await readStdin();
8029
+ log(HOOK, `stdin keys: [${Object.keys(payload).join(", ")}]`);
8030
+ if (!payload.session_id && !payload.source) {
8031
+ log(
8032
+ HOOK,
8033
+ `[WARN] stdin payload has neither session_id nor source \u2014 read likely empty or unparseable (readStdin() collapses both cases to {}); raw keys=[${Object.keys(payload).join(", ")}]`
8034
+ );
8035
+ }
8036
+ return {
8037
+ sessionId: payload.session_id ?? null,
8038
+ source: payload.source ?? null
8039
+ };
8040
+ } catch (err) {
8041
+ log(HOOK, `[WARN] readStdin() itself threw (not just empty/malformed stdin) \u2014 ${String(err)}`);
8042
+ return { sessionId: null, source: null };
7902
8043
  }
7903
8044
  }
8045
+ function isRecoverySource(source) {
8046
+ return source === "compact";
8047
+ }
8048
+ var RECOVERY_DIRECTIVE = [
8049
+ "[ORCHESTRATOR] Context was compacted mid-session. This is NOT a session start.",
8050
+ "Do NOT greet. Do NOT call AskUserQuestion. Resume the in-flight task."
8051
+ ];
7904
8052
  var PROJECT_STATE_PATH = PROJECT_ROOT2 ? join5(PROJECT_ROOT2, "project-guidelines", "project-state.yaml") : null;
7905
8053
  function synthesizeStatus(pending) {
7906
8054
  const { critical, high, medium, ci_gating: ciGating } = pending;
@@ -8057,43 +8205,76 @@ async function buildProjectSelectionPrompt() {
8057
8205
  return "";
8058
8206
  }
8059
8207
  }
8060
- function buildCapabilityMatrixContext() {
8208
+ function buildMatrixLine(vaultConfigPath, agentsDir, profilesPath, cachePath) {
8209
+ let index = readCapabilityCache(cachePath, vaultConfigPath);
8210
+ const cachedMtime = index?.installedPluginsMtime ?? "";
8211
+ if (!index || needsRescan(INSTALLED_PLUGINS_PATH, cachedMtime)) {
8212
+ log(HOOK, "Capability rescan triggered");
8213
+ index = buildCapabilityIndex({
8214
+ installedPluginsPath: INSTALLED_PLUGINS_PATH,
8215
+ agentsDir,
8216
+ vaultConfigPath,
8217
+ profilesPath
8218
+ });
8219
+ writeCapabilityCache(cachePath, index);
8220
+ } else {
8221
+ index.agents = scanAgentDefinitions(agentsDir);
8222
+ log(HOOK, "Using cached capability index");
8223
+ }
8224
+ return formatCapabilityMatrix(index);
8225
+ }
8226
+ function buildMemoryLine(memoryIndexPath) {
8227
+ const diag = {};
8228
+ const memoryEntries = readMemoryIndex(memoryIndexPath, diag);
8229
+ if (diag.reason) log(HOOK, `Memory index: ${diag.reason}`);
8230
+ if (diag.reason && (!memoryEntries || memoryEntries.length === 0)) {
8231
+ return `[MEMORY-CONTEXT] INDISPON\xCDVEL \u2014 nenhuma mem\xF3ria injetada. ${diag.reason}`;
8232
+ }
8233
+ if (!memoryEntries) return "";
8234
+ const filtered = filterRelevantMemories(memoryEntries);
8235
+ return formatMemoryContext(filtered, memoryEntries);
8236
+ }
8237
+ function resolveVaultPaths(caller) {
8238
+ if (VAULT_CONFIG_PATH === null || AGENTS_DIR === null || PROFILES_PATH === null || MEMORY_INDEX_PATH === null || CAPABILITY_CACHE_PATH === null) {
8239
+ log(HOOK, `${caller}: PROJECT_ROOT unresolved (unregistered cwd) \u2014 skipping`);
8240
+ return null;
8241
+ }
8242
+ return {
8243
+ vaultConfigPath: VAULT_CONFIG_PATH,
8244
+ agentsDir: AGENTS_DIR,
8245
+ profilesPath: PROFILES_PATH,
8246
+ memoryIndexPath: MEMORY_INDEX_PATH,
8247
+ capabilityCachePath: CAPABILITY_CACHE_PATH
8248
+ };
8249
+ }
8250
+ function buildMatrixContext() {
8251
+ const paths = resolveVaultPaths("buildMatrixContext");
8252
+ if (!paths) return "";
8061
8253
  try {
8062
- if (VAULT_CONFIG_PATH === null || AGENTS_DIR === null || PROFILES_PATH === null || MEMORY_INDEX_PATH === null) {
8063
- log(
8064
- HOOK,
8065
- "buildCapabilityMatrixContext: PROJECT_ROOT unresolved (unregistered cwd) \u2014 skipping"
8066
- );
8067
- return "";
8068
- }
8069
- let index = readCapabilitiesFromVault(VAULT_CONFIG_PATH);
8070
- const cachedMtime = index?.installedPluginsMtime ?? "";
8071
- if (!index || needsRescan(INSTALLED_PLUGINS_PATH, cachedMtime)) {
8072
- log(HOOK, "Capability rescan triggered");
8073
- index = buildCapabilityIndex({
8074
- installedPluginsPath: INSTALLED_PLUGINS_PATH,
8075
- agentsDir: AGENTS_DIR,
8076
- vaultConfigPath: VAULT_CONFIG_PATH,
8077
- profilesPath: PROFILES_PATH
8078
- });
8079
- writeCapabilitiesToVault(VAULT_CONFIG_PATH, index);
8080
- } else {
8081
- index.agents = scanAgentDefinitions(AGENTS_DIR);
8082
- log(HOOK, "Using cached capability index");
8083
- }
8084
- const matrixLine = formatCapabilityMatrix(index);
8085
- const memoryEntries = readMemoryIndex(MEMORY_INDEX_PATH);
8086
- let memoryLine = "";
8087
- if (memoryEntries) {
8088
- const filtered = filterRelevantMemories(memoryEntries);
8089
- memoryLine = formatMemoryContext(filtered);
8090
- }
8091
- return [matrixLine, memoryLine].filter(Boolean).join("\n");
8254
+ return buildMatrixLine(
8255
+ paths.vaultConfigPath,
8256
+ paths.agentsDir,
8257
+ paths.profilesPath,
8258
+ paths.capabilityCachePath
8259
+ );
8092
8260
  } catch (err) {
8093
8261
  log(HOOK, `Capability matrix failed: ${err}`);
8094
8262
  return "";
8095
8263
  }
8096
8264
  }
8265
+ function buildMemoryContext() {
8266
+ const paths = resolveVaultPaths("buildMemoryContext");
8267
+ if (!paths) return "";
8268
+ try {
8269
+ return buildMemoryLine(paths.memoryIndexPath);
8270
+ } catch (err) {
8271
+ log(HOOK, `Memory context failed: ${err}`);
8272
+ return "";
8273
+ }
8274
+ }
8275
+ function buildCapabilityMatrixContext() {
8276
+ return [buildMatrixContext(), buildMemoryContext()].filter(Boolean).join("\n");
8277
+ }
8097
8278
  function checkSprintInbox() {
8098
8279
  const sprintId = process.env.SPRINT_ID;
8099
8280
  const paneRole = process.env.PANE_ROLE;
@@ -8140,13 +8321,16 @@ async function main() {
8140
8321
  "PROJECT_ROOT unresolved: cwd has no .orchestrator sentinel up to the filesystem root \u2014 vault-dependent sections (tier, capability matrix, BACKLOG fallback) will be skipped this session (RFC-040 C5, AC-C5-2)."
8141
8322
  );
8142
8323
  }
8143
- const sessionId = readSessionId();
8324
+ const { sessionId, source } = await readSessionStartPayload();
8325
+ const isRecovery = isRecoverySource(source);
8144
8326
  const sessionSegment = sessionId ? ` | session=${sessionId}` : "";
8145
8327
  if (sessionId) log(HOOK, `Claude session: ${sessionId}`);
8328
+ log(HOOK, `source=${source ?? "unknown"} mode=${isRecovery ? "recovery" : "boot"}`);
8146
8329
  const backlog = getBacklogSummary();
8147
8330
  const tierInfo = await checkTier();
8148
8331
  const tierSegment = formatTierSegment(tierInfo);
8149
- const capabilityContext = buildCapabilityMatrixContext();
8332
+ const memoryContext = buildMemoryContext();
8333
+ const matrixContext = buildMatrixContext();
8150
8334
  const sprintInboxContext = checkSprintInbox();
8151
8335
  await getToken();
8152
8336
  const selection = PROJECT_SELECTION_ENABLED && sessionId ? readSessionSelection(SESSION_SELECTION_STATE_DIR, sessionId) : void 0;
@@ -8157,22 +8341,26 @@ async function main() {
8157
8341
  });
8158
8342
  const projectBindingSegment = formatProjectBindingSegment(projectBinding);
8159
8343
  setEffectiveProjectId(projectBinding.projectId);
8160
- const projectSelectionPrompt = PROJECT_SELECTION_ENABLED && projectBinding.source === "none" ? await buildProjectSelectionPrompt() : "";
8344
+ const projectSelectionPrompt = PROJECT_SELECTION_ENABLED && !isRecovery && projectBinding.source === "none" ? await buildProjectSelectionPrompt() : "";
8161
8345
  const sessionAllocation = await allocateSessionNumber(projectBinding.projectId);
8162
8346
  const sessionNumberSegment = formatSessionNumberSegment(sessionAllocation);
8163
8347
  const workflow = await getActiveWorkflow();
8164
8348
  if (!workflow) {
8165
- log(HOOK, "No active workflow, injecting greeting data");
8349
+ log(HOOK, `No active workflow, injecting ${isRecovery ? "recovery" : "greeting"} data`);
8350
+ const stateLine2 = `version=${backlog.version}${sessionSegment} | workflow=none${tierSegment}${sessionNumberSegment}${projectBindingSegment} | next=${backlog.next}`;
8166
8351
  outputContext(
8167
8352
  "SessionStart",
8168
8353
  [
8169
- `[ORCHESTRATOR-DATA] version=${backlog.version}${sessionSegment} | workflow=none${tierSegment}${sessionNumberSegment}${projectBindingSegment} | next=${backlog.next}`,
8170
- backlog.lastSession ? `[LAST-SESSION] ${backlog.lastSession}` : "",
8171
- backlog.status ? `[PENDENTE] ${backlog.status}` : "",
8172
- `[ORCHESTRATOR] Greet the user via AskUserQuestion using the data above (CLAUDE.md Rule #1).`,
8173
- "Do NOT invoke /orchestrator skill for the greeting \u2014 use AskUserQuestion directly.",
8174
- "Invoke /orchestrator skill only when the user chooses to start a workflow.",
8175
- capabilityContext,
8354
+ `${isRecovery ? "[ORCHESTRATOR-RECOVERY]" : "[ORCHESTRATOR-DATA]"} ${stateLine2}`,
8355
+ memoryContext,
8356
+ ...isRecovery ? RECOVERY_DIRECTIVE : [
8357
+ backlog.lastSession ? `[LAST-SESSION] ${backlog.lastSession}` : "",
8358
+ backlog.status ? `[PENDENTE] ${backlog.status}` : "",
8359
+ `[ORCHESTRATOR] Greet the user via AskUserQuestion using the data above (orchestrator identity, MUST rule #1).`,
8360
+ "Do NOT invoke /orchestrator skill for the greeting \u2014 use AskUserQuestion directly.",
8361
+ "Invoke /orchestrator skill only when the user chooses to start a workflow."
8362
+ ],
8363
+ matrixContext,
8176
8364
  sprintInboxContext,
8177
8365
  projectSelectionPrompt
8178
8366
  ].filter(Boolean).join("\n")
@@ -8181,21 +8369,31 @@ async function main() {
8181
8369
  }
8182
8370
  const action = await getNextAction(workflow.id);
8183
8371
  const actionHint = action?.hasAction && action.pendingAction ? ` | pending=${action.pendingAction.agent} (${action.pendingAction.status})` : "";
8184
- log(HOOK, `Injecting workflow context (wf=${workflow.id} phase=${workflow.currentPhase})`);
8372
+ log(
8373
+ HOOK,
8374
+ `Injecting workflow ${isRecovery ? "recovery" : "context"} (wf=${workflow.id} phase=${workflow.currentPhase})`
8375
+ );
8376
+ const stateLine = `version=${backlog.version}${sessionSegment} | workflow=${workflow.id} | type=${workflow.type} | phase=${workflow.currentPhase} | status=${workflow.status}${actionHint}${tierSegment}${sessionNumberSegment}${projectBindingSegment}`;
8185
8377
  outputContext(
8186
8378
  "SessionStart",
8187
8379
  [
8188
- `[ORCHESTRATOR-DATA] version=${backlog.version}${sessionSegment} | workflow=${workflow.id} | type=${workflow.type} | phase=${workflow.currentPhase} | status=${workflow.status}${actionHint}${tierSegment}${sessionNumberSegment}${projectBindingSegment}`,
8189
- `[ORCHESTRATOR] Active workflow detected. Greet the user via AskUserQuestion showing workflow state (CLAUDE.md Rule #1).`,
8190
- "Do NOT invoke /orchestrator skill for the greeting \u2014 use AskUserQuestion directly.",
8191
- "Invoke /orchestrator skill when the user chooses to continue the workflow.",
8192
- capabilityContext,
8380
+ `${isRecovery ? "[ORCHESTRATOR-RECOVERY]" : "[ORCHESTRATOR-DATA]"} ${stateLine}`,
8381
+ memoryContext,
8382
+ ...isRecovery ? RECOVERY_DIRECTIVE : [
8383
+ `[ORCHESTRATOR] Active workflow detected. Greet the user via AskUserQuestion showing workflow state (orchestrator identity, MUST rule #1).`,
8384
+ "Do NOT invoke /orchestrator skill for the greeting \u2014 use AskUserQuestion directly.",
8385
+ "Invoke /orchestrator skill when the user chooses to continue the workflow."
8386
+ ],
8387
+ matrixContext,
8193
8388
  projectSelectionPrompt
8194
8389
  ].filter(Boolean).join("\n")
8195
8390
  );
8196
8391
  }
8197
8392
  main().catch(() => process.exit(0));
8198
8393
  export {
8394
+ buildCapabilityMatrixContext,
8395
+ buildMatrixContext,
8396
+ buildMemoryContext,
8199
8397
  buildProjectSelectionPrompt,
8200
8398
  formatProjectBindingSegment,
8201
8399
  formatSessionNumberSegment,