@orchestrator-claude/definitions 3.37.0 → 3.37.1
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/agents/adversarial-reviewer.md +6 -1
- package/agents/api-extractor.md +6 -0
- package/agents/azure-devops-engineer.md +1 -2
- package/agents/business-rule-miner.md +6 -0
- package/agents/cicd-platform-engineer.md +1 -2
- package/agents/ciclo-engineer.md +15 -2
- package/agents/code-archaeologist.md +6 -0
- package/agents/debug-sidecar.md +6 -0
- package/agents/doc-sidecar.md +6 -0
- package/agents/docs-guardian.md +9 -3
- package/agents/frontend-engineer.md +1 -2
- package/agents/{ai-architect.md → harness-architect.md} +8 -3
- package/agents/implementer.md +6 -1
- package/agents/legacy-discoverer.md +6 -0
- package/agents/legacy-synthesizer.md +6 -0
- package/agents/methodology-researcher.md +6 -1
- package/agents/operational-artifact-builder.md +6 -1
- package/agents/orchestrator.md +27 -87
- package/agents/planner.md +6 -1
- package/agents/presentation-engineer.md +5 -4
- package/agents/python-data-engineer.md +0 -1
- package/agents/researcher.md +6 -0
- package/agents/reviewer.md +6 -1
- package/agents/schema-extractor.md +6 -0
- package/agents/software-architect.md +10 -5
- package/agents/specifier.md +6 -1
- package/agents/task-generator.md +6 -1
- package/agents/test-sidecar.md +6 -0
- package/dist/scripts/generate-hooks-matcher.d.ts +106 -0
- package/dist/scripts/generate-hooks-matcher.d.ts.map +1 -0
- package/dist/scripts/generate-hooks-matcher.js +153 -0
- package/dist/scripts/generate-hooks-matcher.js.map +1 -0
- package/dist/scripts/generate-manifest.d.ts +22 -0
- package/dist/scripts/generate-manifest.d.ts.map +1 -1
- package/dist/scripts/generate-manifest.js +67 -2
- package/dist/scripts/generate-manifest.js.map +1 -1
- package/hooks/agent-git-guard.mjs +63 -11
- package/hooks/dangling-guard.mjs +42 -12
- package/hooks/gate-guardian.mjs +38 -8
- package/hooks/hooks.json +3 -9
- package/hooks/lib/api-client.ts +128 -9
- package/hooks/lib/capability-scanner.ts +391 -55
- package/hooks/lib/dispatch-marker.ts +214 -0
- package/hooks/lib/git-checkpoint.ts +34 -37
- package/hooks/lib/observations-helper.ts +14 -1
- package/hooks/mailbox-listener.mjs +69 -17
- package/hooks/playwright-output-guard.mjs +40 -10
- package/hooks/post-implement.mjs +38 -8
- package/hooks/pre-agent-dispatch.mjs +137 -16
- package/hooks/pre-agent-dispatch.ts +82 -15
- package/hooks/session-start.mjs +274 -103
- package/hooks/session-start.ts +250 -69
- package/hooks/subagent-start.mjs +7665 -22
- package/hooks/subagent-start.ts +367 -16
- package/hooks/subagent-stop.mjs +102 -62
- package/hooks/subagent-stop.ts +124 -28
- package/hooks/user-prompt.mjs +43 -13
- package/hooks/verification-before-completion.mjs +63 -11
- package/hooks/workflow-guard.mjs +45 -11
- package/hooks-settings-template.json +1 -7
- package/manifest.json +62 -62
- package/package.json +4 -2
- package/skills/checkpoint-protocol/SKILL.md +19 -4
- package/skills/ciclo-lane-dispatch/SKILL.md +24 -0
- package/skills/fase-1b-projecao/SKILL.md +146 -0
- package/skills/orchestrator/SKILL.md +11 -3
- package/skills/workflow-coordination/SKILL.md +3 -3
- package/hooks/post-compact.mjs +0 -7931
- package/hooks/post-compact.ts +0 -170
package/hooks/session-start.mjs
CHANGED
|
@@ -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
|
|
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
|
|
7332
|
-
import {
|
|
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
|
-
|
|
7346
|
+
candidates.push(currentDir);
|
|
7342
7347
|
}
|
|
7343
7348
|
const parentDir = dirname(currentDir);
|
|
7344
7349
|
if (parentDir === currentDir) {
|
|
7345
|
-
|
|
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
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
7805
|
+
function readCapabilityCache(cachePath, vaultConfigPath) {
|
|
7760
7806
|
try {
|
|
7761
|
-
if (!existsSync2(
|
|
7762
|
-
const raw = readFileSync2(
|
|
7763
|
-
const
|
|
7764
|
-
|
|
7765
|
-
if (
|
|
7766
|
-
const rawPlugins = Array.isArray(
|
|
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:
|
|
7778
|
-
installedPluginsMtime:
|
|
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:
|
|
7784
|
-
gaps:
|
|
7829
|
+
routing: cache.routing ?? {},
|
|
7830
|
+
gaps: cache.gaps ?? []
|
|
7785
7831
|
};
|
|
7786
7832
|
} catch {
|
|
7787
7833
|
return null;
|
|
@@ -7809,32 +7855,94 @@ function formatCapabilityMatrix(index) {
|
|
|
7809
7855
|
`gaps: ${gapsLine}`
|
|
7810
7856
|
].join("\n");
|
|
7811
7857
|
}
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
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 countByType(list) {
|
|
7866
|
+
const counts = {};
|
|
7867
|
+
for (const e of list) {
|
|
7868
|
+
counts[e.type] = (counts[e.type] ?? 0) + 1;
|
|
7817
7869
|
}
|
|
7818
|
-
|
|
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");
|
|
7870
|
+
return counts;
|
|
7824
7871
|
}
|
|
7825
|
-
function
|
|
7872
|
+
function formatMemoryContext(selected, allEntries) {
|
|
7873
|
+
if (selected.length === 0) return "";
|
|
7874
|
+
const selectedCounts = countByType(selected);
|
|
7875
|
+
const totalCounts = countByType(allEntries);
|
|
7876
|
+
const perTypeSummary = MEMORY_TYPES.map(
|
|
7877
|
+
(t) => `${t}: ${selectedCounts[t] ?? 0}/${totalCounts[t] ?? 0}`
|
|
7878
|
+
).join(", ");
|
|
7879
|
+
const headerBase = `[MEMORY-CONTEXT] ${selected.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`;
|
|
7880
|
+
const availableForLines = AGGREGATE_CHAR_BUDGET - headerBase.length - SUFFIX_RESERVE;
|
|
7881
|
+
const lines = [];
|
|
7882
|
+
let used = 0;
|
|
7883
|
+
let droppedByBudget = 0;
|
|
7884
|
+
for (let i = 0; i < selected.length; i++) {
|
|
7885
|
+
const entry = selected[i];
|
|
7886
|
+
const name = entry.file.replace(/\.md$/, "");
|
|
7887
|
+
const truncated = truncateSummary(entry.summary, PER_ENTRY_SUMMARY_CHAR_CAP);
|
|
7888
|
+
const line = `- [${entry.type}] ${name}: ${truncated}`;
|
|
7889
|
+
if (used + line.length + 1 > availableForLines) {
|
|
7890
|
+
droppedByBudget = selected.length - i;
|
|
7891
|
+
break;
|
|
7892
|
+
}
|
|
7893
|
+
lines.push(line);
|
|
7894
|
+
used += line.length + 1;
|
|
7895
|
+
}
|
|
7896
|
+
const header = droppedByBudget > 0 ? `${headerBase}; +${droppedByBudget} truncadas por or\xE7amento de caracteres` : headerBase;
|
|
7897
|
+
return [header, ...lines].join("\n");
|
|
7898
|
+
}
|
|
7899
|
+
function isWellFormedMemoryEntry(value) {
|
|
7900
|
+
return typeof value === "object" && value !== null && typeof value.file === "string";
|
|
7901
|
+
}
|
|
7902
|
+
function readMemoryIndex(indexPath, diag) {
|
|
7826
7903
|
try {
|
|
7827
7904
|
if (!existsSync2(indexPath)) return null;
|
|
7828
7905
|
const raw = readFileSync2(indexPath, "utf-8");
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7906
|
+
let parsed;
|
|
7907
|
+
try {
|
|
7908
|
+
parsed = (0, import_yaml.parse)(raw);
|
|
7909
|
+
} catch (err) {
|
|
7910
|
+
if (diag) diag.reason = `YAML inv\xE1lido em ${indexPath}: ${String(err).split("\n")[0]}`;
|
|
7911
|
+
return null;
|
|
7912
|
+
}
|
|
7913
|
+
let candidate = null;
|
|
7914
|
+
if (Array.isArray(parsed)) {
|
|
7915
|
+
candidate = parsed;
|
|
7916
|
+
} else if (typeof parsed === "object" && parsed !== null && Array.isArray(parsed.entries)) {
|
|
7917
|
+
candidate = parsed.entries;
|
|
7918
|
+
}
|
|
7919
|
+
if (candidate === null) {
|
|
7920
|
+
const chaves = typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? Object.keys(parsed).join(", ") : typeof parsed;
|
|
7921
|
+
if (diag) {
|
|
7922
|
+
diag.reason = `formato n\xE3o reconhecido em ${indexPath} \u2014 topo tem [${chaves}]; esperado uma lista no topo ou a chave 'entries:'`;
|
|
7923
|
+
}
|
|
7924
|
+
return null;
|
|
7925
|
+
}
|
|
7926
|
+
const bemFormadas = candidate.filter(isWellFormedMemoryEntry);
|
|
7927
|
+
if (diag && candidate.length > 0) {
|
|
7928
|
+
const descartadas = candidate.length - bemFormadas.length;
|
|
7929
|
+
if (bemFormadas.length === 0) {
|
|
7930
|
+
diag.reason = `${candidate.length} entrada(s) lidas e NENHUMA bem-formada em ${indexPath} \u2014 toda entrada precisa da chave 'file:'`;
|
|
7931
|
+
} else if (descartadas > 0) {
|
|
7932
|
+
diag.reason = `${descartadas} de ${candidate.length} entrada(s) descartadas em ${indexPath} (falta a chave 'file:')`;
|
|
7933
|
+
}
|
|
7934
|
+
}
|
|
7935
|
+
return bemFormadas;
|
|
7936
|
+
} catch (err) {
|
|
7937
|
+
if (diag) diag.reason = `falha ao ler ${indexPath}: ${String(err).split("\n")[0]}`;
|
|
7832
7938
|
return null;
|
|
7833
7939
|
}
|
|
7834
7940
|
}
|
|
7835
7941
|
function filterRelevantMemories(entries, contextTags = []) {
|
|
7836
7942
|
const now = Date.now();
|
|
7837
7943
|
const fourteenDays = 14 * 24 * 60 * 60 * 1e3;
|
|
7944
|
+
const MAX_TOTAL = 20;
|
|
7945
|
+
const RESERVED_SLOTS_PER_TYPE = 2;
|
|
7838
7946
|
const relevant = entries.filter((e) => {
|
|
7839
7947
|
if (e.type === "feedback") return true;
|
|
7840
7948
|
const accessed = new Date(e.last_accessed).getTime();
|
|
@@ -7848,17 +7956,32 @@ function filterRelevantMemories(entries, contextTags = []) {
|
|
|
7848
7956
|
reference: 2,
|
|
7849
7957
|
user: 3
|
|
7850
7958
|
};
|
|
7851
|
-
|
|
7959
|
+
const byPriorityThenRecency = (a, b) => {
|
|
7852
7960
|
const pa = typePriority[a.type] ?? 9;
|
|
7853
7961
|
const pb = typePriority[b.type] ?? 9;
|
|
7854
7962
|
if (pa !== pb) return pa - pb;
|
|
7855
7963
|
return b.last_accessed.localeCompare(a.last_accessed);
|
|
7856
|
-
}
|
|
7857
|
-
|
|
7964
|
+
};
|
|
7965
|
+
relevant.sort(byPriorityThenRecency);
|
|
7966
|
+
const reserved = /* @__PURE__ */ new Set();
|
|
7967
|
+
const nonFeedbackTypes = new Set(entries.filter((e) => e.type !== "feedback").map((e) => e.type));
|
|
7968
|
+
for (const type of nonFeedbackTypes) {
|
|
7969
|
+
const ofType = entries.filter((e) => e.type === type).sort((a, b) => b.last_accessed.localeCompare(a.last_accessed));
|
|
7970
|
+
for (const entry of ofType.slice(0, RESERVED_SLOTS_PER_TYPE)) {
|
|
7971
|
+
reserved.add(entry);
|
|
7972
|
+
}
|
|
7973
|
+
}
|
|
7974
|
+
const selected = new Set(reserved);
|
|
7975
|
+
for (const entry of relevant) {
|
|
7976
|
+
if (selected.size >= MAX_TOTAL) break;
|
|
7977
|
+
if (reserved.has(entry)) continue;
|
|
7978
|
+
selected.add(entry);
|
|
7979
|
+
}
|
|
7980
|
+
return [...selected].sort(byPriorityThenRecency);
|
|
7858
7981
|
}
|
|
7859
7982
|
|
|
7860
7983
|
// hooks/lib/session-selection.ts
|
|
7861
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as
|
|
7984
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "node:fs";
|
|
7862
7985
|
import { join as join4 } from "node:path";
|
|
7863
7986
|
function selectionFilePath(stateDir, sessionId) {
|
|
7864
7987
|
const safeId = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
@@ -7879,8 +8002,8 @@ function readSessionSelection(stateDir, sessionId) {
|
|
|
7879
8002
|
|
|
7880
8003
|
// hooks/session-start.ts
|
|
7881
8004
|
var HOOK = "SESSION-START";
|
|
7882
|
-
var
|
|
7883
|
-
var
|
|
8005
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
8006
|
+
var __dirname = dirname3(__filename);
|
|
7884
8007
|
var PROJECT_ROOT2 = resolveHookProjectRoot(process.cwd());
|
|
7885
8008
|
var PROJECT_ID2 = process.env.ORCHESTRATOR_PROJECT_ID ?? "";
|
|
7886
8009
|
var HOME = process.env.HOME ?? process.env.USERPROFILE ?? "/home/user";
|
|
@@ -7889,18 +8012,35 @@ var PROJECT_SELECTION_ENABLED = process.env.ORCHESTRATOR_ENABLE_PROJECT_SELECTIO
|
|
|
7889
8012
|
var SESSION_SELECTION_STATE_DIR = join5(HOME, ".orchestrator", "session-selection");
|
|
7890
8013
|
var AGENTS_DIR = PROJECT_ROOT2 ? join5(PROJECT_ROOT2, ".claude", "agents") : null;
|
|
7891
8014
|
var VAULT_CONFIG_PATH = PROJECT_ROOT2 ? join5(PROJECT_ROOT2, "project-guidelines", ".vault-config.yaml") : null;
|
|
8015
|
+
var CAPABILITY_CACHE_PATH = PROJECT_ROOT2 ? resolveCapabilityCachePath(PROJECT_ROOT2) : null;
|
|
7892
8016
|
var PROFILES_PATH = PROJECT_ROOT2 ? join5(PROJECT_ROOT2, ".claude", "plugin-profiles.yaml") : null;
|
|
7893
8017
|
var MEMORY_INDEX_PATH = PROJECT_ROOT2 ? join5(PROJECT_ROOT2, ".claude", "agent-memory", "orchestrator", "memory-index.yaml") : null;
|
|
7894
|
-
function
|
|
8018
|
+
async function readSessionStartPayload() {
|
|
7895
8019
|
try {
|
|
7896
|
-
const
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
8020
|
+
const payload = await readStdin();
|
|
8021
|
+
log(HOOK, `stdin keys: [${Object.keys(payload).join(", ")}]`);
|
|
8022
|
+
if (!payload.session_id && !payload.source) {
|
|
8023
|
+
log(
|
|
8024
|
+
HOOK,
|
|
8025
|
+
`[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(", ")}]`
|
|
8026
|
+
);
|
|
8027
|
+
}
|
|
8028
|
+
return {
|
|
8029
|
+
sessionId: payload.session_id ?? null,
|
|
8030
|
+
source: payload.source ?? null
|
|
8031
|
+
};
|
|
8032
|
+
} catch (err) {
|
|
8033
|
+
log(HOOK, `[WARN] readStdin() itself threw (not just empty/malformed stdin) \u2014 ${String(err)}`);
|
|
8034
|
+
return { sessionId: null, source: null };
|
|
7902
8035
|
}
|
|
7903
8036
|
}
|
|
8037
|
+
function isRecoverySource(source) {
|
|
8038
|
+
return source === "compact";
|
|
8039
|
+
}
|
|
8040
|
+
var RECOVERY_DIRECTIVE = [
|
|
8041
|
+
"[ORCHESTRATOR] Context was compacted mid-session. This is NOT a session start.",
|
|
8042
|
+
"Do NOT greet. Do NOT call AskUserQuestion. Resume the in-flight task."
|
|
8043
|
+
];
|
|
7904
8044
|
var PROJECT_STATE_PATH = PROJECT_ROOT2 ? join5(PROJECT_ROOT2, "project-guidelines", "project-state.yaml") : null;
|
|
7905
8045
|
function synthesizeStatus(pending) {
|
|
7906
8046
|
const { critical, high, medium, ci_gating: ciGating } = pending;
|
|
@@ -8057,42 +8197,61 @@ async function buildProjectSelectionPrompt() {
|
|
|
8057
8197
|
return "";
|
|
8058
8198
|
}
|
|
8059
8199
|
}
|
|
8200
|
+
function buildMatrixLine(vaultConfigPath, agentsDir, profilesPath, cachePath) {
|
|
8201
|
+
let index = readCapabilityCache(cachePath, vaultConfigPath);
|
|
8202
|
+
const cachedMtime = index?.installedPluginsMtime ?? "";
|
|
8203
|
+
if (!index || needsRescan(INSTALLED_PLUGINS_PATH, cachedMtime)) {
|
|
8204
|
+
log(HOOK, "Capability rescan triggered");
|
|
8205
|
+
index = buildCapabilityIndex({
|
|
8206
|
+
installedPluginsPath: INSTALLED_PLUGINS_PATH,
|
|
8207
|
+
agentsDir,
|
|
8208
|
+
vaultConfigPath,
|
|
8209
|
+
profilesPath
|
|
8210
|
+
});
|
|
8211
|
+
writeCapabilityCache(cachePath, index);
|
|
8212
|
+
} else {
|
|
8213
|
+
index.agents = scanAgentDefinitions(agentsDir);
|
|
8214
|
+
log(HOOK, "Using cached capability index");
|
|
8215
|
+
}
|
|
8216
|
+
return formatCapabilityMatrix(index);
|
|
8217
|
+
}
|
|
8218
|
+
function buildMemoryLine(memoryIndexPath) {
|
|
8219
|
+
const diag = {};
|
|
8220
|
+
const memoryEntries = readMemoryIndex(memoryIndexPath, diag);
|
|
8221
|
+
if (diag.reason) log(HOOK, `Memory index: ${diag.reason}`);
|
|
8222
|
+
if (diag.reason && (!memoryEntries || memoryEntries.length === 0)) {
|
|
8223
|
+
return `[MEMORY-CONTEXT] INDISPON\xCDVEL \u2014 nenhuma mem\xF3ria injetada. ${diag.reason}`;
|
|
8224
|
+
}
|
|
8225
|
+
if (!memoryEntries) return "";
|
|
8226
|
+
const filtered = filterRelevantMemories(memoryEntries);
|
|
8227
|
+
return formatMemoryContext(filtered, memoryEntries);
|
|
8228
|
+
}
|
|
8060
8229
|
function buildCapabilityMatrixContext() {
|
|
8230
|
+
if (VAULT_CONFIG_PATH === null || AGENTS_DIR === null || PROFILES_PATH === null || MEMORY_INDEX_PATH === null || CAPABILITY_CACHE_PATH === null) {
|
|
8231
|
+
log(
|
|
8232
|
+
HOOK,
|
|
8233
|
+
"buildCapabilityMatrixContext: PROJECT_ROOT unresolved (unregistered cwd) \u2014 skipping"
|
|
8234
|
+
);
|
|
8235
|
+
return "";
|
|
8236
|
+
}
|
|
8237
|
+
let matrixLine = "";
|
|
8061
8238
|
try {
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
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");
|
|
8239
|
+
matrixLine = buildMatrixLine(
|
|
8240
|
+
VAULT_CONFIG_PATH,
|
|
8241
|
+
AGENTS_DIR,
|
|
8242
|
+
PROFILES_PATH,
|
|
8243
|
+
CAPABILITY_CACHE_PATH
|
|
8244
|
+
);
|
|
8092
8245
|
} catch (err) {
|
|
8093
8246
|
log(HOOK, `Capability matrix failed: ${err}`);
|
|
8094
|
-
return "";
|
|
8095
8247
|
}
|
|
8248
|
+
let memoryLine = "";
|
|
8249
|
+
try {
|
|
8250
|
+
memoryLine = buildMemoryLine(MEMORY_INDEX_PATH);
|
|
8251
|
+
} catch (err) {
|
|
8252
|
+
log(HOOK, `Memory context failed: ${err}`);
|
|
8253
|
+
}
|
|
8254
|
+
return [matrixLine, memoryLine].filter(Boolean).join("\n");
|
|
8096
8255
|
}
|
|
8097
8256
|
function checkSprintInbox() {
|
|
8098
8257
|
const sprintId = process.env.SPRINT_ID;
|
|
@@ -8140,9 +8299,11 @@ async function main() {
|
|
|
8140
8299
|
"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
8300
|
);
|
|
8142
8301
|
}
|
|
8143
|
-
const sessionId =
|
|
8302
|
+
const { sessionId, source } = await readSessionStartPayload();
|
|
8303
|
+
const isRecovery = isRecoverySource(source);
|
|
8144
8304
|
const sessionSegment = sessionId ? ` | session=${sessionId}` : "";
|
|
8145
8305
|
if (sessionId) log(HOOK, `Claude session: ${sessionId}`);
|
|
8306
|
+
log(HOOK, `source=${source ?? "unknown"} mode=${isRecovery ? "recovery" : "boot"}`);
|
|
8146
8307
|
const backlog = getBacklogSummary();
|
|
8147
8308
|
const tierInfo = await checkTier();
|
|
8148
8309
|
const tierSegment = formatTierSegment(tierInfo);
|
|
@@ -8157,21 +8318,24 @@ async function main() {
|
|
|
8157
8318
|
});
|
|
8158
8319
|
const projectBindingSegment = formatProjectBindingSegment(projectBinding);
|
|
8159
8320
|
setEffectiveProjectId(projectBinding.projectId);
|
|
8160
|
-
const projectSelectionPrompt = PROJECT_SELECTION_ENABLED && projectBinding.source === "none" ? await buildProjectSelectionPrompt() : "";
|
|
8321
|
+
const projectSelectionPrompt = PROJECT_SELECTION_ENABLED && !isRecovery && projectBinding.source === "none" ? await buildProjectSelectionPrompt() : "";
|
|
8161
8322
|
const sessionAllocation = await allocateSessionNumber(projectBinding.projectId);
|
|
8162
8323
|
const sessionNumberSegment = formatSessionNumberSegment(sessionAllocation);
|
|
8163
8324
|
const workflow = await getActiveWorkflow();
|
|
8164
8325
|
if (!workflow) {
|
|
8165
|
-
log(HOOK,
|
|
8326
|
+
log(HOOK, `No active workflow, injecting ${isRecovery ? "recovery" : "greeting"} data`);
|
|
8327
|
+
const stateLine2 = `version=${backlog.version}${sessionSegment} | workflow=none${tierSegment}${sessionNumberSegment}${projectBindingSegment} | next=${backlog.next}`;
|
|
8166
8328
|
outputContext(
|
|
8167
8329
|
"SessionStart",
|
|
8168
8330
|
[
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8331
|
+
`${isRecovery ? "[ORCHESTRATOR-RECOVERY]" : "[ORCHESTRATOR-DATA]"} ${stateLine2}`,
|
|
8332
|
+
...isRecovery ? RECOVERY_DIRECTIVE : [
|
|
8333
|
+
backlog.lastSession ? `[LAST-SESSION] ${backlog.lastSession}` : "",
|
|
8334
|
+
backlog.status ? `[PENDENTE] ${backlog.status}` : "",
|
|
8335
|
+
`[ORCHESTRATOR] Greet the user via AskUserQuestion using the data above (orchestrator identity, MUST rule #1).`,
|
|
8336
|
+
"Do NOT invoke /orchestrator skill for the greeting \u2014 use AskUserQuestion directly.",
|
|
8337
|
+
"Invoke /orchestrator skill only when the user chooses to start a workflow."
|
|
8338
|
+
],
|
|
8175
8339
|
capabilityContext,
|
|
8176
8340
|
sprintInboxContext,
|
|
8177
8341
|
projectSelectionPrompt
|
|
@@ -8181,14 +8345,20 @@ async function main() {
|
|
|
8181
8345
|
}
|
|
8182
8346
|
const action = await getNextAction(workflow.id);
|
|
8183
8347
|
const actionHint = action?.hasAction && action.pendingAction ? ` | pending=${action.pendingAction.agent} (${action.pendingAction.status})` : "";
|
|
8184
|
-
log(
|
|
8348
|
+
log(
|
|
8349
|
+
HOOK,
|
|
8350
|
+
`Injecting workflow ${isRecovery ? "recovery" : "context"} (wf=${workflow.id} phase=${workflow.currentPhase})`
|
|
8351
|
+
);
|
|
8352
|
+
const stateLine = `version=${backlog.version}${sessionSegment} | workflow=${workflow.id} | type=${workflow.type} | phase=${workflow.currentPhase} | status=${workflow.status}${actionHint}${tierSegment}${sessionNumberSegment}${projectBindingSegment}`;
|
|
8185
8353
|
outputContext(
|
|
8186
8354
|
"SessionStart",
|
|
8187
8355
|
[
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8356
|
+
`${isRecovery ? "[ORCHESTRATOR-RECOVERY]" : "[ORCHESTRATOR-DATA]"} ${stateLine}`,
|
|
8357
|
+
...isRecovery ? RECOVERY_DIRECTIVE : [
|
|
8358
|
+
`[ORCHESTRATOR] Active workflow detected. Greet the user via AskUserQuestion showing workflow state (orchestrator identity, MUST rule #1).`,
|
|
8359
|
+
"Do NOT invoke /orchestrator skill for the greeting \u2014 use AskUserQuestion directly.",
|
|
8360
|
+
"Invoke /orchestrator skill when the user chooses to continue the workflow."
|
|
8361
|
+
],
|
|
8192
8362
|
capabilityContext,
|
|
8193
8363
|
projectSelectionPrompt
|
|
8194
8364
|
].filter(Boolean).join("\n")
|
|
@@ -8196,6 +8366,7 @@ async function main() {
|
|
|
8196
8366
|
}
|
|
8197
8367
|
main().catch(() => process.exit(0));
|
|
8198
8368
|
export {
|
|
8369
|
+
buildCapabilityMatrixContext,
|
|
8199
8370
|
buildProjectSelectionPrompt,
|
|
8200
8371
|
formatProjectBindingSegment,
|
|
8201
8372
|
formatSessionNumberSegment,
|