zora-agent 0.9.3 → 0.9.5
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/CHANGELOG.md +1 -1
- package/README.md +103 -92
- package/dist/cli/audit-commands.d.ts.map +1 -1
- package/dist/cli/audit-commands.js +3 -1
- package/dist/cli/audit-commands.js.map +1 -1
- package/dist/cli/daemon.js +86 -28
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/edit-commands.d.ts.map +1 -1
- package/dist/cli/edit-commands.js +3 -1
- package/dist/cli/edit-commands.js.map +1 -1
- package/dist/cli/hook-commands.d.ts +9 -0
- package/dist/cli/hook-commands.d.ts.map +1 -0
- package/dist/cli/hook-commands.js +106 -0
- package/dist/cli/hook-commands.js.map +1 -0
- package/dist/cli/index.js +91 -36
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init-command.d.ts.map +1 -1
- package/dist/cli/init-command.js +107 -8
- package/dist/cli/init-command.js.map +1 -1
- package/dist/cli/memory-commands.d.ts +1 -1
- package/dist/cli/memory-commands.d.ts.map +1 -1
- package/dist/cli/memory-commands.js +213 -1
- package/dist/cli/memory-commands.js.map +1 -1
- package/dist/cli/presets.d.ts.map +1 -1
- package/dist/cli/presets.js +2 -1
- package/dist/cli/presets.js.map +1 -1
- package/dist/cli/skill-commands.d.ts.map +1 -1
- package/dist/cli/skill-commands.js +4 -2
- package/dist/cli/skill-commands.js.map +1 -1
- package/dist/cli/steer-commands.d.ts.map +1 -1
- package/dist/cli/steer-commands.js +6 -4
- package/dist/cli/steer-commands.js.map +1 -1
- package/dist/cli/team-commands.d.ts.map +1 -1
- package/dist/cli/team-commands.js +3 -1
- package/dist/cli/team-commands.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +12 -2
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/loader.d.ts +23 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +64 -3
- package/dist/config/loader.js.map +1 -1
- package/dist/config/policy-loader.d.ts +14 -0
- package/dist/config/policy-loader.d.ts.map +1 -1
- package/dist/config/policy-loader.js +33 -0
- package/dist/config/policy-loader.js.map +1 -1
- package/dist/dashboard/frontend/dist/assets/index-BcOGj1EF.css +1 -0
- package/dist/dashboard/frontend/dist/assets/index-BtiFO9YN.js +261 -0
- package/dist/dashboard/frontend/dist/assets/index-Cfjy5acU.css +1 -0
- package/dist/dashboard/frontend/dist/assets/index-D41hcjgc.js +253 -0
- package/dist/dashboard/frontend/dist/assets/index-D83BawFd.css +1 -0
- package/dist/dashboard/frontend/dist/assets/index-DAODjoxu.css +1 -0
- package/dist/dashboard/frontend/dist/assets/index-DB-Eu5oV.js +253 -0
- package/dist/dashboard/frontend/dist/assets/index-W0VVEDu6.js +253 -0
- package/dist/dashboard/frontend/dist/index.html +17 -0
- package/dist/dashboard/server.d.ts +19 -2
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +121 -20
- package/dist/dashboard/server.js.map +1 -1
- package/dist/hooks/hook-runner.d.ts +55 -0
- package/dist/hooks/hook-runner.d.ts.map +1 -0
- package/dist/hooks/hook-runner.js +120 -0
- package/dist/hooks/hook-runner.js.map +1 -0
- package/dist/hooks/hook-types.d.ts +82 -0
- package/dist/hooks/hook-types.d.ts.map +1 -0
- package/dist/hooks/hook-types.js +20 -0
- package/dist/hooks/hook-types.js.map +1 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/memory/context-compressor.d.ts +108 -0
- package/dist/memory/context-compressor.d.ts.map +1 -0
- package/dist/memory/context-compressor.js +307 -0
- package/dist/memory/context-compressor.js.map +1 -0
- package/dist/memory/index.d.ts +1 -0
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +1 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/memory-manager.d.ts +88 -4
- package/dist/memory/memory-manager.d.ts.map +1 -1
- package/dist/memory/memory-manager.js +299 -7
- package/dist/memory/memory-manager.js.map +1 -1
- package/dist/memory/observation-store.d.ts +75 -0
- package/dist/memory/observation-store.d.ts.map +1 -0
- package/dist/memory/observation-store.js +162 -0
- package/dist/memory/observation-store.js.map +1 -0
- package/dist/memory/observer-worker.d.ts +34 -0
- package/dist/memory/observer-worker.d.ts.map +1 -0
- package/dist/memory/observer-worker.js +161 -0
- package/dist/memory/observer-worker.js.map +1 -0
- package/dist/memory/reflector-worker.d.ts +40 -0
- package/dist/memory/reflector-worker.d.ts.map +1 -0
- package/dist/memory/reflector-worker.js +185 -0
- package/dist/memory/reflector-worker.js.map +1 -0
- package/dist/memory/salience-scorer.d.ts +16 -6
- package/dist/memory/salience-scorer.d.ts.map +1 -1
- package/dist/memory/salience-scorer.js +42 -22
- package/dist/memory/salience-scorer.js.map +1 -1
- package/dist/memory/structured-memory.d.ts +36 -1
- package/dist/memory/structured-memory.d.ts.map +1 -1
- package/dist/memory/structured-memory.js +207 -8
- package/dist/memory/structured-memory.js.map +1 -1
- package/dist/memory/token-estimator.d.ts +31 -0
- package/dist/memory/token-estimator.d.ts.map +1 -0
- package/dist/memory/token-estimator.js +77 -0
- package/dist/memory/token-estimator.js.map +1 -0
- package/dist/memory/validation-pipeline.d.ts +37 -0
- package/dist/memory/validation-pipeline.d.ts.map +1 -0
- package/dist/memory/validation-pipeline.js +106 -0
- package/dist/memory/validation-pipeline.js.map +1 -0
- package/dist/orchestrator/auth-monitor.d.ts.map +1 -1
- package/dist/orchestrator/auth-monitor.js +3 -1
- package/dist/orchestrator/auth-monitor.js.map +1 -1
- package/dist/orchestrator/execution-loop.d.ts +23 -0
- package/dist/orchestrator/execution-loop.d.ts.map +1 -1
- package/dist/orchestrator/execution-loop.js +60 -19
- package/dist/orchestrator/execution-loop.js.map +1 -1
- package/dist/orchestrator/failover-controller.d.ts +26 -2
- package/dist/orchestrator/failover-controller.d.ts.map +1 -1
- package/dist/orchestrator/failover-controller.js +143 -23
- package/dist/orchestrator/failover-controller.js.map +1 -1
- package/dist/orchestrator/orchestrator.d.ts +70 -7
- package/dist/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/orchestrator.js +417 -92
- package/dist/orchestrator/orchestrator.js.map +1 -1
- package/dist/orchestrator/retry-queue.d.ts.map +1 -1
- package/dist/orchestrator/retry-queue.js +24 -9
- package/dist/orchestrator/retry-queue.js.map +1 -1
- package/dist/orchestrator/router.d.ts +16 -1
- package/dist/orchestrator/router.d.ts.map +1 -1
- package/dist/orchestrator/router.js +79 -20
- package/dist/orchestrator/router.js.map +1 -1
- package/dist/orchestrator/session-manager.d.ts +26 -1
- package/dist/orchestrator/session-manager.d.ts.map +1 -1
- package/dist/orchestrator/session-manager.js +88 -4
- package/dist/orchestrator/session-manager.js.map +1 -1
- package/dist/providers/circuit-breaker.d.ts +78 -0
- package/dist/providers/circuit-breaker.d.ts.map +1 -0
- package/dist/providers/circuit-breaker.js +129 -0
- package/dist/providers/circuit-breaker.js.map +1 -0
- package/dist/providers/claude-provider.d.ts +27 -11
- package/dist/providers/claude-provider.d.ts.map +1 -1
- package/dist/providers/claude-provider.js +164 -45
- package/dist/providers/claude-provider.js.map +1 -1
- package/dist/providers/gemini-provider.d.ts +9 -1
- package/dist/providers/gemini-provider.d.ts.map +1 -1
- package/dist/providers/gemini-provider.js +97 -48
- package/dist/providers/gemini-provider.js.map +1 -1
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +1 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/ollama-provider.d.ts +7 -0
- package/dist/providers/ollama-provider.d.ts.map +1 -1
- package/dist/providers/ollama-provider.js +89 -18
- package/dist/providers/ollama-provider.js.map +1 -1
- package/dist/routines/heartbeat.d.ts +10 -2
- package/dist/routines/heartbeat.d.ts.map +1 -1
- package/dist/routines/heartbeat.js +42 -5
- package/dist/routines/heartbeat.js.map +1 -1
- package/dist/routines/routine-manager.d.ts.map +1 -1
- package/dist/routines/routine-manager.js +22 -15
- package/dist/routines/routine-manager.js.map +1 -1
- package/dist/security/audit-logger.d.ts.map +1 -1
- package/dist/security/audit-logger.js +5 -7
- package/dist/security/audit-logger.js.map +1 -1
- package/dist/security/policy-engine.d.ts +33 -17
- package/dist/security/policy-engine.d.ts.map +1 -1
- package/dist/security/policy-engine.js +68 -181
- package/dist/security/policy-engine.js.map +1 -1
- package/dist/security/policy-serializer.d.ts +19 -0
- package/dist/security/policy-serializer.d.ts.map +1 -0
- package/dist/security/policy-serializer.js +100 -0
- package/dist/security/policy-serializer.js.map +1 -0
- package/dist/security/shell-validator.d.ts +42 -0
- package/dist/security/shell-validator.d.ts.map +1 -0
- package/dist/security/shell-validator.js +231 -0
- package/dist/security/shell-validator.js.map +1 -0
- package/dist/skills/index.d.ts +1 -0
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +1 -0
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/skill-loader.d.ts +38 -2
- package/dist/skills/skill-loader.d.ts.map +1 -1
- package/dist/skills/skill-loader.js +83 -2
- package/dist/skills/skill-loader.js.map +1 -1
- package/dist/skills/subagent-loader.d.ts +66 -0
- package/dist/skills/subagent-loader.d.ts.map +1 -0
- package/dist/skills/subagent-loader.js +143 -0
- package/dist/skills/subagent-loader.js.map +1 -0
- package/dist/steering/flag-manager.d.ts +20 -0
- package/dist/steering/flag-manager.d.ts.map +1 -1
- package/dist/steering/flag-manager.js +94 -11
- package/dist/steering/flag-manager.js.map +1 -1
- package/dist/steering/steering-manager.d.ts +11 -0
- package/dist/steering/steering-manager.d.ts.map +1 -1
- package/dist/steering/steering-manager.js +23 -0
- package/dist/steering/steering-manager.js.map +1 -1
- package/dist/steering/telegram-gateway.d.ts +4 -1
- package/dist/steering/telegram-gateway.d.ts.map +1 -1
- package/dist/steering/telegram-gateway.js +49 -10
- package/dist/steering/telegram-gateway.js.map +1 -1
- package/dist/teams/bridge-watchdog.d.ts.map +1 -1
- package/dist/teams/bridge-watchdog.js +5 -3
- package/dist/teams/bridge-watchdog.js.map +1 -1
- package/dist/teams/gemini-bridge.d.ts.map +1 -1
- package/dist/teams/gemini-bridge.js +9 -4
- package/dist/teams/gemini-bridge.js.map +1 -1
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/memory-tools.d.ts +16 -0
- package/dist/tools/memory-tools.d.ts.map +1 -0
- package/dist/tools/memory-tools.js +207 -0
- package/dist/tools/memory-tools.js.map +1 -0
- package/dist/tools/notifications.d.ts.map +1 -1
- package/dist/tools/notifications.js +3 -1
- package/dist/tools/notifications.js.map +1 -1
- package/dist/tools/tool-factory.d.ts +36 -0
- package/dist/tools/tool-factory.d.ts.map +1 -0
- package/dist/tools/tool-factory.js +55 -0
- package/dist/tools/tool-factory.js.map +1 -0
- package/dist/types.d.ts +213 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +47 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/errors.d.ts +21 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +29 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/event-filter.d.ts +25 -0
- package/dist/utils/event-filter.d.ts.map +1 -0
- package/dist/utils/event-filter.js +61 -0
- package/dist/utils/event-filter.js.map +1 -0
- package/dist/utils/logger.d.ts +33 -36
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +60 -130
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/validate-job-id.d.ts +6 -0
- package/dist/utils/validate-job-id.d.ts.map +1 -0
- package/dist/utils/validate-job-id.js +10 -0
- package/dist/utils/validate-job-id.js.map +1 -0
- package/package.json +12 -3
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubagentLoader — Discovers and loads subagent definitions from filesystem.
|
|
3
|
+
*
|
|
4
|
+
* TYPE-10: Subagents are defined in SUBAGENT.md files within directory hierarchies:
|
|
5
|
+
* 1. Project — `.zora/subagents/<name>/SUBAGENT.md`
|
|
6
|
+
* 2. Global — `~/.zora/subagents/<name>/SUBAGENT.md`
|
|
7
|
+
*
|
|
8
|
+
* Each subagent definition specifies:
|
|
9
|
+
* - name: unique identifier
|
|
10
|
+
* - description: what the subagent does
|
|
11
|
+
* - allowedTools: subset of tools the subagent can use
|
|
12
|
+
* - systemPrompt: optional system prompt override
|
|
13
|
+
*
|
|
14
|
+
* Subagent isolation rules (from ia-agents pattern):
|
|
15
|
+
* - Each subagent gets its own execution context
|
|
16
|
+
* - Declared tool subset (not the full tool set)
|
|
17
|
+
* - No access to parent conversation history
|
|
18
|
+
* - Cannot spawn nested subagents (delegate_to_subagent is excluded)
|
|
19
|
+
*/
|
|
20
|
+
import type { SkillLayer } from './skill-loader.js';
|
|
21
|
+
export interface SubagentInfo {
|
|
22
|
+
name: string;
|
|
23
|
+
description: string;
|
|
24
|
+
allowedTools: string[];
|
|
25
|
+
systemPrompt: string;
|
|
26
|
+
path: string;
|
|
27
|
+
layer: SkillLayer;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parses YAML frontmatter from a SUBAGENT.md file.
|
|
31
|
+
* Extracts: description, allowed_tools (comma-separated), system_prompt.
|
|
32
|
+
* The body of the markdown (after frontmatter) becomes the system prompt
|
|
33
|
+
* if no explicit system_prompt frontmatter field is present.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseSubagentFrontmatter(content: string): {
|
|
36
|
+
description: string;
|
|
37
|
+
allowedTools: string[];
|
|
38
|
+
systemPrompt: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Returns subagent layer directories in precedence order.
|
|
42
|
+
* Only project and global layers — no built-in subagents.
|
|
43
|
+
*/
|
|
44
|
+
export declare function getSubagentLayers(cwd?: string): Array<{
|
|
45
|
+
dir: string;
|
|
46
|
+
layer: SkillLayer;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Loads subagent definitions from project and global layers.
|
|
50
|
+
* First-match-wins deduplication (project overrides global).
|
|
51
|
+
*
|
|
52
|
+
* Subagent isolation is enforced:
|
|
53
|
+
* - Tools like 'delegate_to_subagent' are always stripped from allowedTools
|
|
54
|
+
* - Each subagent should be spawned with its own execution context
|
|
55
|
+
*
|
|
56
|
+
* @param options.cwd Override for project directory
|
|
57
|
+
* @param options.layers Override layer directories (useful for testing)
|
|
58
|
+
*/
|
|
59
|
+
export declare function loadSubagents(options?: {
|
|
60
|
+
cwd?: string;
|
|
61
|
+
layers?: Array<{
|
|
62
|
+
dir: string;
|
|
63
|
+
layer: SkillLayer;
|
|
64
|
+
}>;
|
|
65
|
+
}): Promise<SubagentInfo[]>;
|
|
66
|
+
//# sourceMappingURL=subagent-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-loader.d.ts","sourceRoot":"","sources":["../../src/skills/subagent-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,CAAC;CACnB;AAID;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,CAsCA;AAID;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC,CAQzF;AAkDD;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,OAAO,CAAC,EAAE;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC,CAAC;CACpD,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAgB1B"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubagentLoader — Discovers and loads subagent definitions from filesystem.
|
|
3
|
+
*
|
|
4
|
+
* TYPE-10: Subagents are defined in SUBAGENT.md files within directory hierarchies:
|
|
5
|
+
* 1. Project — `.zora/subagents/<name>/SUBAGENT.md`
|
|
6
|
+
* 2. Global — `~/.zora/subagents/<name>/SUBAGENT.md`
|
|
7
|
+
*
|
|
8
|
+
* Each subagent definition specifies:
|
|
9
|
+
* - name: unique identifier
|
|
10
|
+
* - description: what the subagent does
|
|
11
|
+
* - allowedTools: subset of tools the subagent can use
|
|
12
|
+
* - systemPrompt: optional system prompt override
|
|
13
|
+
*
|
|
14
|
+
* Subagent isolation rules (from ia-agents pattern):
|
|
15
|
+
* - Each subagent gets its own execution context
|
|
16
|
+
* - Declared tool subset (not the full tool set)
|
|
17
|
+
* - No access to parent conversation history
|
|
18
|
+
* - Cannot spawn nested subagents (delegate_to_subagent is excluded)
|
|
19
|
+
*/
|
|
20
|
+
import fs from 'node:fs/promises';
|
|
21
|
+
import path from 'node:path';
|
|
22
|
+
import os from 'node:os';
|
|
23
|
+
// ─── Frontmatter Parser ─────────────────────────────────────────────
|
|
24
|
+
/**
|
|
25
|
+
* Parses YAML frontmatter from a SUBAGENT.md file.
|
|
26
|
+
* Extracts: description, allowed_tools (comma-separated), system_prompt.
|
|
27
|
+
* The body of the markdown (after frontmatter) becomes the system prompt
|
|
28
|
+
* if no explicit system_prompt frontmatter field is present.
|
|
29
|
+
*/
|
|
30
|
+
export function parseSubagentFrontmatter(content) {
|
|
31
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)/);
|
|
32
|
+
if (!match) {
|
|
33
|
+
return { description: '', allowedTools: [], systemPrompt: content.trim() };
|
|
34
|
+
}
|
|
35
|
+
const frontmatter = match[1];
|
|
36
|
+
const body = match[2]?.trim() ?? '';
|
|
37
|
+
let description = '';
|
|
38
|
+
let allowedTools = [];
|
|
39
|
+
let systemPrompt = '';
|
|
40
|
+
for (const line of frontmatter.split('\n')) {
|
|
41
|
+
const colonIdx = line.indexOf(':');
|
|
42
|
+
if (colonIdx <= 0)
|
|
43
|
+
continue;
|
|
44
|
+
const key = line.slice(0, colonIdx).trim();
|
|
45
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
46
|
+
switch (key) {
|
|
47
|
+
case 'description':
|
|
48
|
+
description = value;
|
|
49
|
+
break;
|
|
50
|
+
case 'allowed_tools':
|
|
51
|
+
allowedTools = value.split(',').map(t => t.trim()).filter(Boolean);
|
|
52
|
+
break;
|
|
53
|
+
case 'system_prompt':
|
|
54
|
+
systemPrompt = value;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Body becomes system prompt if no explicit system_prompt in frontmatter
|
|
59
|
+
if (!systemPrompt && body) {
|
|
60
|
+
systemPrompt = body;
|
|
61
|
+
}
|
|
62
|
+
return { description, allowedTools, systemPrompt };
|
|
63
|
+
}
|
|
64
|
+
// ─── Layer Directories ──────────────────────────────────────────────
|
|
65
|
+
/**
|
|
66
|
+
* Returns subagent layer directories in precedence order.
|
|
67
|
+
* Only project and global layers — no built-in subagents.
|
|
68
|
+
*/
|
|
69
|
+
export function getSubagentLayers(cwd) {
|
|
70
|
+
const projectDir = path.join(cwd ?? process.cwd(), '.zora', 'subagents');
|
|
71
|
+
const globalDir = path.join(os.homedir(), '.zora', 'subagents');
|
|
72
|
+
return [
|
|
73
|
+
{ dir: projectDir, layer: 'project' },
|
|
74
|
+
{ dir: globalDir, layer: 'global' },
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
// ─── Subagent Scanner ───────────────────────────────────────────────
|
|
78
|
+
/** Blocked tools that subagents can never use (nesting prevention). */
|
|
79
|
+
const BLOCKED_SUBAGENT_TOOLS = ['delegate_to_subagent', 'spawn_subagent'];
|
|
80
|
+
/**
|
|
81
|
+
* Scans a single directory for SUBAGENT.md files.
|
|
82
|
+
*/
|
|
83
|
+
async function scanSubagentLayer(dir, layer) {
|
|
84
|
+
const subagents = [];
|
|
85
|
+
let entries;
|
|
86
|
+
try {
|
|
87
|
+
entries = await fs.readdir(dir);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return subagents;
|
|
91
|
+
}
|
|
92
|
+
for (const entry of entries) {
|
|
93
|
+
const subagentPath = path.join(dir, entry, 'SUBAGENT.md');
|
|
94
|
+
try {
|
|
95
|
+
const stat = await fs.stat(path.join(dir, entry));
|
|
96
|
+
if (!stat.isDirectory())
|
|
97
|
+
continue;
|
|
98
|
+
const content = await fs.readFile(subagentPath, 'utf-8');
|
|
99
|
+
const parsed = parseSubagentFrontmatter(content);
|
|
100
|
+
// Filter out blocked tools (nesting prevention)
|
|
101
|
+
const allowedTools = parsed.allowedTools.filter(t => !BLOCKED_SUBAGENT_TOOLS.includes(t));
|
|
102
|
+
subagents.push({
|
|
103
|
+
name: entry,
|
|
104
|
+
description: parsed.description || `Subagent: ${entry}`,
|
|
105
|
+
allowedTools,
|
|
106
|
+
systemPrompt: parsed.systemPrompt,
|
|
107
|
+
path: subagentPath,
|
|
108
|
+
layer,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Skip directories without SUBAGENT.md
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return subagents;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Loads subagent definitions from project and global layers.
|
|
119
|
+
* First-match-wins deduplication (project overrides global).
|
|
120
|
+
*
|
|
121
|
+
* Subagent isolation is enforced:
|
|
122
|
+
* - Tools like 'delegate_to_subagent' are always stripped from allowedTools
|
|
123
|
+
* - Each subagent should be spawned with its own execution context
|
|
124
|
+
*
|
|
125
|
+
* @param options.cwd Override for project directory
|
|
126
|
+
* @param options.layers Override layer directories (useful for testing)
|
|
127
|
+
*/
|
|
128
|
+
export async function loadSubagents(options) {
|
|
129
|
+
const layers = options?.layers ?? getSubagentLayers(options?.cwd);
|
|
130
|
+
const seen = new Set();
|
|
131
|
+
const result = [];
|
|
132
|
+
for (const { dir, layer } of layers) {
|
|
133
|
+
const subagents = await scanSubagentLayer(dir, layer);
|
|
134
|
+
for (const subagent of subagents) {
|
|
135
|
+
if (!seen.has(subagent.name)) {
|
|
136
|
+
seen.add(subagent.name);
|
|
137
|
+
result.push(subagent);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return result.sort((a, b) => a.name.localeCompare(b.name));
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=subagent-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-loader.js","sourceRoot":"","sources":["../../src/skills/subagent-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAczB,uEAAuE;AAEvE;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAe;IAKtD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACjE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,YAAY,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;IAC7E,CAAC;IAED,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACpC,IAAI,WAAW,GAAG,EAAE,CAAC;IACrB,IAAI,YAAY,GAAa,EAAE,CAAC;IAChC,IAAI,YAAY,GAAG,EAAE,CAAC;IAEtB,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,QAAQ,IAAI,CAAC;YAAE,SAAS;QAE5B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAE9C,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,aAAa;gBAChB,WAAW,GAAG,KAAK,CAAC;gBACpB,MAAM;YACR,KAAK,eAAe;gBAClB,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACnE,MAAM;YACR,KAAK,eAAe;gBAClB,YAAY,GAAG,KAAK,CAAC;gBACrB,MAAM;QACV,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,IAAI,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;QAC1B,YAAY,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;AACrD,CAAC;AAED,uEAAuE;AAEvE;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAY;IAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IAEhE,OAAO;QACL,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,SAAuB,EAAE;QACnD,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,QAAsB,EAAE;KAClD,CAAC;AACJ,CAAC;AAED,uEAAuE;AAEvE,uEAAuE;AACvE,MAAM,sBAAsB,GAAG,CAAC,sBAAsB,EAAE,gBAAgB,CAAC,CAAC;AAE1E;;GAEG;AACH,KAAK,UAAU,iBAAiB,CAAC,GAAW,EAAE,KAAiB;IAC7D,MAAM,SAAS,GAAmB,EAAE,CAAC;IAErC,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;QAC1D,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;YAClD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;gBAAE,SAAS;YAElC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YACzD,MAAM,MAAM,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAC;YAEjD,gDAAgD;YAChD,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAC7C,CAAC,CAAC,EAAE,CAAC,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC,CACzC,CAAC;YAEF,SAAS,CAAC,IAAI,CAAC;gBACb,IAAI,EAAE,KAAK;gBACX,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,aAAa,KAAK,EAAE;gBACvD,YAAY;gBACZ,YAAY,EAAE,MAAM,CAAC,YAAY;gBACjC,IAAI,EAAE,YAAY;gBAClB,KAAK;aACN,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,uCAAuC;QACzC,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAGnC;IACC,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,iBAAiB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAClE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,KAAK,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,MAAM,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,MAAM,iBAAiB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACtD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACxB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -16,6 +16,19 @@ export interface FlagEntry {
|
|
|
16
16
|
timestamp: string;
|
|
17
17
|
resolvedAt?: string;
|
|
18
18
|
}
|
|
19
|
+
export interface FlagFileDiagnostic {
|
|
20
|
+
file: string;
|
|
21
|
+
status: 'loaded' | 'failed';
|
|
22
|
+
errorType?: 'not_found' | 'permission' | 'parse_error' | 'read_error';
|
|
23
|
+
reason?: string;
|
|
24
|
+
timestamp: number;
|
|
25
|
+
}
|
|
26
|
+
export interface FlagConfigStatus {
|
|
27
|
+
filesLoaded: number;
|
|
28
|
+
filesFailed: number;
|
|
29
|
+
failedFiles: FlagFileDiagnostic[];
|
|
30
|
+
timestamp: number;
|
|
31
|
+
}
|
|
19
32
|
export interface FlagManagerOptions {
|
|
20
33
|
timeoutMs: number;
|
|
21
34
|
notifyFn?: (msg: string) => void;
|
|
@@ -25,7 +38,14 @@ export declare class FlagManager {
|
|
|
25
38
|
private readonly _timeoutMs;
|
|
26
39
|
private readonly _notifyFn?;
|
|
27
40
|
private readonly _timers;
|
|
41
|
+
private readonly _diagnostics;
|
|
42
|
+
private _filesLoaded;
|
|
43
|
+
private _filesFailed;
|
|
28
44
|
constructor(flagsDir: string, options: FlagManagerOptions);
|
|
45
|
+
/**
|
|
46
|
+
* Returns diagnostic status of flag file loading operations.
|
|
47
|
+
*/
|
|
48
|
+
getConfigStatus(): FlagConfigStatus;
|
|
29
49
|
/**
|
|
30
50
|
* Creates a new flag for a decision. Starts the timeout clock.
|
|
31
51
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flag-manager.d.ts","sourceRoot":"","sources":["../../src/steering/flag-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"flag-manager.d.ts","sourceRoot":"","sources":["../../src/steering/flag-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,gBAAgB,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,CAAC;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,SAAS,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,aAAa,GAAG,YAAY,CAAC;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAwB;IACnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyD;IACjF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA4B;IACzD,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,YAAY,CAAK;gBAEb,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB;IAMzD;;OAEG;IACH,eAAe,IAAI,gBAAgB;IASnC;;OAEG;IACG,IAAI,CACR,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC;IAgClB;;OAEG;IACG,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAmEpD;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D;;OAEG;IACG,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;YAgCrE,QAAQ;YA2CR,YAAY;CAgC3B"}
|
|
@@ -9,20 +9,37 @@
|
|
|
9
9
|
import fs from 'node:fs/promises';
|
|
10
10
|
import path from 'node:path';
|
|
11
11
|
import { writeAtomic } from '../utils/fs.js';
|
|
12
|
+
import { getLogger } from '../utils/logger.js';
|
|
13
|
+
import { validateJobId } from '../utils/validate-job-id.js';
|
|
12
14
|
export class FlagManager {
|
|
13
15
|
_flagsDir;
|
|
14
16
|
_timeoutMs;
|
|
15
17
|
_notifyFn;
|
|
16
18
|
_timers = new Map();
|
|
19
|
+
_diagnostics = [];
|
|
20
|
+
_filesLoaded = 0;
|
|
21
|
+
_filesFailed = 0;
|
|
17
22
|
constructor(flagsDir, options) {
|
|
18
23
|
this._flagsDir = flagsDir;
|
|
19
24
|
this._timeoutMs = options.timeoutMs;
|
|
20
25
|
this._notifyFn = options.notifyFn;
|
|
21
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Returns diagnostic status of flag file loading operations.
|
|
29
|
+
*/
|
|
30
|
+
getConfigStatus() {
|
|
31
|
+
return {
|
|
32
|
+
filesLoaded: this._filesLoaded,
|
|
33
|
+
filesFailed: this._filesFailed,
|
|
34
|
+
failedFiles: this._diagnostics.filter(d => d.status === 'failed'),
|
|
35
|
+
timestamp: Date.now(),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
22
38
|
/**
|
|
23
39
|
* Creates a new flag for a decision. Starts the timeout clock.
|
|
24
40
|
*/
|
|
25
41
|
async flag(jobId, question, defaultAction) {
|
|
42
|
+
validateJobId(jobId);
|
|
26
43
|
await fs.mkdir(this._flagsDir, { recursive: true });
|
|
27
44
|
const flagId = `flag_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
28
45
|
const entry = {
|
|
@@ -50,30 +67,64 @@ export class FlagManager {
|
|
|
50
67
|
* Lists all flags, optionally filtered by job ID.
|
|
51
68
|
*/
|
|
52
69
|
async getFlags(jobId) {
|
|
70
|
+
const logger = getLogger();
|
|
53
71
|
try {
|
|
54
72
|
const files = await fs.readdir(this._flagsDir);
|
|
55
73
|
const flags = [];
|
|
56
74
|
for (const file of files) {
|
|
57
75
|
if (!file.endsWith('.json'))
|
|
58
76
|
continue;
|
|
77
|
+
const filePath = path.join(this._flagsDir, file);
|
|
59
78
|
try {
|
|
60
|
-
const content = await fs.readFile(
|
|
79
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
61
80
|
const entry = JSON.parse(content);
|
|
62
81
|
if (!jobId || entry.jobId === jobId) {
|
|
63
82
|
flags.push(entry);
|
|
64
83
|
}
|
|
84
|
+
this._filesLoaded++;
|
|
85
|
+
this._diagnostics.push({ file, status: 'loaded', timestamp: Date.now() });
|
|
65
86
|
}
|
|
66
87
|
catch (err) {
|
|
67
|
-
|
|
68
|
-
|
|
88
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
89
|
+
const code = err.code;
|
|
90
|
+
const errorType = err instanceof SyntaxError
|
|
91
|
+
? 'parse_error'
|
|
92
|
+
: code === 'ENOENT'
|
|
93
|
+
? 'not_found'
|
|
94
|
+
: code === 'EACCES'
|
|
95
|
+
? 'permission'
|
|
96
|
+
: 'read_error';
|
|
97
|
+
logger.warn({ path: filePath, errorType, error: errMsg }, 'Failed to load flag file');
|
|
98
|
+
this._filesFailed++;
|
|
99
|
+
this._diagnostics.push({
|
|
100
|
+
file,
|
|
101
|
+
status: 'failed',
|
|
102
|
+
errorType,
|
|
103
|
+
reason: errMsg,
|
|
104
|
+
timestamp: Date.now(),
|
|
105
|
+
});
|
|
69
106
|
}
|
|
70
107
|
}
|
|
71
108
|
return flags;
|
|
72
109
|
}
|
|
73
110
|
catch (err) {
|
|
74
|
-
|
|
75
|
-
if (
|
|
76
|
-
|
|
111
|
+
const code = err.code;
|
|
112
|
+
if (code !== 'ENOENT') {
|
|
113
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
114
|
+
const errorType = code === 'ENOENT'
|
|
115
|
+
? 'not_found'
|
|
116
|
+
: code === 'EACCES'
|
|
117
|
+
? 'permission'
|
|
118
|
+
: 'read_error';
|
|
119
|
+
logger.warn({ path: this._flagsDir, errorType, error: errMsg }, 'Failed to read flags directory');
|
|
120
|
+
this._filesFailed++;
|
|
121
|
+
this._diagnostics.push({
|
|
122
|
+
file: this._flagsDir,
|
|
123
|
+
status: 'failed',
|
|
124
|
+
errorType,
|
|
125
|
+
reason: errMsg,
|
|
126
|
+
timestamp: Date.now(),
|
|
127
|
+
});
|
|
77
128
|
}
|
|
78
129
|
return [];
|
|
79
130
|
}
|
|
@@ -94,6 +145,7 @@ export class FlagManager {
|
|
|
94
145
|
* Returns the current decision status for a flag.
|
|
95
146
|
*/
|
|
96
147
|
async getFlagDecision(flagId) {
|
|
148
|
+
const logger = getLogger();
|
|
97
149
|
const flagPath = path.join(this._flagsDir, `${flagId}.json`);
|
|
98
150
|
try {
|
|
99
151
|
const content = await fs.readFile(flagPath, 'utf8');
|
|
@@ -105,8 +157,21 @@ export class FlagManager {
|
|
|
105
157
|
return 'rejected';
|
|
106
158
|
}
|
|
107
159
|
catch (err) {
|
|
108
|
-
|
|
109
|
-
|
|
160
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
161
|
+
const code = err.code;
|
|
162
|
+
const errorType = err instanceof SyntaxError
|
|
163
|
+
? 'parse_error'
|
|
164
|
+
: code === 'ENOENT'
|
|
165
|
+
? 'not_found'
|
|
166
|
+
: 'read_error';
|
|
167
|
+
logger.warn({ flagId, path: flagPath, errorType, error: errMsg }, 'Failed to read flag decision');
|
|
168
|
+
this._diagnostics.push({
|
|
169
|
+
file: `${flagId}.json`,
|
|
170
|
+
status: 'failed',
|
|
171
|
+
errorType,
|
|
172
|
+
reason: errMsg,
|
|
173
|
+
timestamp: Date.now(),
|
|
174
|
+
});
|
|
110
175
|
return 'pending';
|
|
111
176
|
}
|
|
112
177
|
}
|
|
@@ -117,6 +182,7 @@ export class FlagManager {
|
|
|
117
182
|
clearTimeout(timer);
|
|
118
183
|
this._timers.delete(flagId);
|
|
119
184
|
}
|
|
185
|
+
const logger = getLogger();
|
|
120
186
|
const flagPath = path.join(this._flagsDir, `${flagId}.json`);
|
|
121
187
|
let content;
|
|
122
188
|
try {
|
|
@@ -125,7 +191,15 @@ export class FlagManager {
|
|
|
125
191
|
catch {
|
|
126
192
|
throw new Error(`Flag not found: ${flagId}`);
|
|
127
193
|
}
|
|
128
|
-
|
|
194
|
+
let entry;
|
|
195
|
+
try {
|
|
196
|
+
entry = JSON.parse(content);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
200
|
+
logger.warn({ flagId, path: flagPath, errorType: 'parse_error', error: errMsg }, 'Corrupted flag file during resolve');
|
|
201
|
+
throw new Error(`Corrupted flag file: ${flagId}`);
|
|
202
|
+
}
|
|
129
203
|
// Only resolve if still pending to avoid TOCTOU race
|
|
130
204
|
if (entry.status !== 'pending_review') {
|
|
131
205
|
return; // Already resolved
|
|
@@ -138,6 +212,7 @@ export class FlagManager {
|
|
|
138
212
|
await writeAtomic(flagPath, JSON.stringify(entry, null, 2));
|
|
139
213
|
}
|
|
140
214
|
async _autoResolve(flagId, defaultAction) {
|
|
215
|
+
const logger = getLogger();
|
|
141
216
|
this._timers.delete(flagId);
|
|
142
217
|
const flagPath = path.join(this._flagsDir, `${flagId}.json`);
|
|
143
218
|
try {
|
|
@@ -152,8 +227,16 @@ export class FlagManager {
|
|
|
152
227
|
await writeAtomic(flagPath, JSON.stringify(entry, null, 2));
|
|
153
228
|
}
|
|
154
229
|
catch (err) {
|
|
155
|
-
|
|
156
|
-
|
|
230
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
231
|
+
const errorType = err instanceof SyntaxError ? 'parse_error' : 'read_error';
|
|
232
|
+
logger.warn({ flagId, path: flagPath, errorType, error: errMsg }, 'Failed to auto-resolve flag');
|
|
233
|
+
this._diagnostics.push({
|
|
234
|
+
file: `${flagId}.json`,
|
|
235
|
+
status: 'failed',
|
|
236
|
+
errorType,
|
|
237
|
+
reason: errMsg,
|
|
238
|
+
timestamp: Date.now(),
|
|
239
|
+
});
|
|
157
240
|
}
|
|
158
241
|
}
|
|
159
242
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flag-manager.js","sourceRoot":"","sources":["../../src/steering/flag-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"flag-manager.js","sourceRoot":"","sources":["../../src/steering/flag-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
import type { SteeringMessage } from './types.js';
|
|
10
10
|
export declare class SteeringManager {
|
|
11
11
|
private readonly _steeringDir;
|
|
12
|
+
/** Debounce cache for getPendingMessages — avoids per-event readdir calls. */
|
|
13
|
+
private _pendingCache;
|
|
12
14
|
constructor(baseDir?: string);
|
|
13
15
|
/**
|
|
14
16
|
* Initializes the steering directory.
|
|
@@ -24,6 +26,15 @@ export declare class SteeringManager {
|
|
|
24
26
|
getPendingMessages(jobId: string): Promise<(SteeringMessage & {
|
|
25
27
|
id: string;
|
|
26
28
|
})[]>;
|
|
29
|
+
/**
|
|
30
|
+
* Returns cached pending messages if the last poll was within maxAgeMs.
|
|
31
|
+
* Avoids per-event readdir + file read during streaming.
|
|
32
|
+
*/
|
|
33
|
+
cachedGetPendingMessages(jobId: string, maxAgeMs?: number): Promise<(SteeringMessage & {
|
|
34
|
+
id: string;
|
|
35
|
+
})[]>;
|
|
36
|
+
/** Invalidate the pending messages cache for a job (call after archiving). */
|
|
37
|
+
invalidatePendingCache(jobId: string): void;
|
|
27
38
|
/**
|
|
28
39
|
* Acknowledges or archives a steering message.
|
|
29
40
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"steering-manager.d.ts","sourceRoot":"","sources":["../../src/steering/steering-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"steering-manager.d.ts","sourceRoot":"","sources":["../../src/steering/steering-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EACV,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,8EAA8E;IAC9E,OAAO,CAAC,aAAa,CAAiG;gBAE1G,OAAO,GAAE,MAAyC;IAI9D;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IAe9D;;OAEG;IACG,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,eAAe,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAoBtF;;;OAGG;IACG,wBAAwB,CAC5B,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,MAAa,GACtB,OAAO,CAAC,CAAC,eAAe,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAWhD,8EAA8E;IAC9E,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI3C;;OAEG;IACG,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAcvD,OAAO;CAQtB"}
|
|
@@ -10,8 +10,11 @@ import path from 'node:path';
|
|
|
10
10
|
import os from 'node:os';
|
|
11
11
|
import fs from 'node:fs/promises';
|
|
12
12
|
import { writeAtomic } from '../utils/fs.js';
|
|
13
|
+
import { validateJobId } from '../utils/validate-job-id.js';
|
|
13
14
|
export class SteeringManager {
|
|
14
15
|
_steeringDir;
|
|
16
|
+
/** Debounce cache for getPendingMessages — avoids per-event readdir calls. */
|
|
17
|
+
_pendingCache = new Map();
|
|
15
18
|
constructor(baseDir = path.join(os.homedir(), '.zora')) {
|
|
16
19
|
this._steeringDir = path.join(baseDir, 'steering');
|
|
17
20
|
}
|
|
@@ -27,6 +30,7 @@ export class SteeringManager {
|
|
|
27
30
|
* Injects a steering message for a specific job.
|
|
28
31
|
*/
|
|
29
32
|
async injectMessage(message) {
|
|
33
|
+
validateJobId(message.jobId);
|
|
30
34
|
const messageId = `steer_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
31
35
|
const jobDir = path.join(this._steeringDir, message.jobId);
|
|
32
36
|
if (!(await this._exists(jobDir))) {
|
|
@@ -40,6 +44,7 @@ export class SteeringManager {
|
|
|
40
44
|
* Retrieves all unread/pending steering messages for a job.
|
|
41
45
|
*/
|
|
42
46
|
async getPendingMessages(jobId) {
|
|
47
|
+
validateJobId(jobId);
|
|
43
48
|
const jobDir = path.join(this._steeringDir, jobId);
|
|
44
49
|
if (!(await this._exists(jobDir)))
|
|
45
50
|
return [];
|
|
@@ -53,10 +58,28 @@ export class SteeringManager {
|
|
|
53
58
|
}
|
|
54
59
|
return messages.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
55
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Returns cached pending messages if the last poll was within maxAgeMs.
|
|
63
|
+
* Avoids per-event readdir + file read during streaming.
|
|
64
|
+
*/
|
|
65
|
+
async cachedGetPendingMessages(jobId, maxAgeMs = 2000) {
|
|
66
|
+
const cached = this._pendingCache.get(jobId);
|
|
67
|
+
if (cached && (Date.now() - cached.timestamp) < maxAgeMs) {
|
|
68
|
+
return cached.messages;
|
|
69
|
+
}
|
|
70
|
+
const messages = await this.getPendingMessages(jobId);
|
|
71
|
+
this._pendingCache.set(jobId, { messages, timestamp: Date.now() });
|
|
72
|
+
return messages;
|
|
73
|
+
}
|
|
74
|
+
/** Invalidate the pending messages cache for a job (call after archiving). */
|
|
75
|
+
invalidatePendingCache(jobId) {
|
|
76
|
+
this._pendingCache.delete(jobId);
|
|
77
|
+
}
|
|
56
78
|
/**
|
|
57
79
|
* Acknowledges or archives a steering message.
|
|
58
80
|
*/
|
|
59
81
|
async archiveMessage(jobId, messageId) {
|
|
82
|
+
validateJobId(jobId);
|
|
60
83
|
const messagePath = path.join(this._steeringDir, jobId, `${messageId}.json`);
|
|
61
84
|
const archiveDir = path.join(this._steeringDir, jobId, 'archive');
|
|
62
85
|
if (!(await this._exists(archiveDir))) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"steering-manager.js","sourceRoot":"","sources":["../../src/steering/steering-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"steering-manager.js","sourceRoot":"","sources":["../../src/steering/steering-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,22 +7,25 @@
|
|
|
7
7
|
* - Injects steer messages into SteeringManager.
|
|
8
8
|
*/
|
|
9
9
|
import type { SteeringManager } from './steering-manager.js';
|
|
10
|
+
import type { SessionManager } from '../orchestrator/session-manager.js';
|
|
10
11
|
import type { SteeringConfig } from '../types.js';
|
|
11
12
|
export interface TelegramConfig extends SteeringConfig {
|
|
12
13
|
bot_token?: string;
|
|
13
14
|
allowed_users: string[];
|
|
14
15
|
enabled: boolean;
|
|
16
|
+
mode?: 'polling' | 'webhook';
|
|
15
17
|
}
|
|
16
18
|
export declare class TelegramGateway {
|
|
17
19
|
private readonly _bot;
|
|
18
20
|
private readonly _steeringManager;
|
|
21
|
+
private readonly _sessionManager?;
|
|
19
22
|
private readonly _allowedUsers;
|
|
20
23
|
private constructor();
|
|
21
24
|
/**
|
|
22
25
|
* Factory method — loads node-telegram-bot-api dynamically.
|
|
23
26
|
* Throws a clear error if the optional dep isn't installed.
|
|
24
27
|
*/
|
|
25
|
-
static create(config: TelegramConfig, steeringManager: SteeringManager): Promise<TelegramGateway>;
|
|
28
|
+
static create(config: TelegramConfig, steeringManager: SteeringManager, sessionManager?: SessionManager): Promise<TelegramGateway>;
|
|
26
29
|
private _setupHandlers;
|
|
27
30
|
/**
|
|
28
31
|
* Stops the bot.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telegram-gateway.d.ts","sourceRoot":"","sources":["../../src/steering/telegram-gateway.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"telegram-gateway.d.ts","sourceRoot":"","sources":["../../src/steering/telegram-gateway.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQlD,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CAC9B;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IACnD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAiB;IAClD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAc;IAE5C,OAAO;IASP;;;OAGG;WACU,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAgCxI,OAAO,CAAC,cAAc;IAyFtB;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAG5B"}
|