@renseiai/agentfactory 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +125 -0
- package/dist/src/config/index.d.ts +3 -0
- package/dist/src/config/index.d.ts.map +1 -0
- package/dist/src/config/index.js +1 -0
- package/dist/src/config/repository-config.d.ts +44 -0
- package/dist/src/config/repository-config.d.ts.map +1 -0
- package/dist/src/config/repository-config.js +88 -0
- package/dist/src/config/repository-config.test.d.ts +2 -0
- package/dist/src/config/repository-config.test.d.ts.map +1 -0
- package/dist/src/config/repository-config.test.js +249 -0
- package/dist/src/deployment/deployment-checker.d.ts +110 -0
- package/dist/src/deployment/deployment-checker.d.ts.map +1 -0
- package/dist/src/deployment/deployment-checker.js +242 -0
- package/dist/src/deployment/index.d.ts +3 -0
- package/dist/src/deployment/index.d.ts.map +1 -0
- package/dist/src/deployment/index.js +2 -0
- package/dist/src/frontend/index.d.ts +2 -0
- package/dist/src/frontend/index.d.ts.map +1 -0
- package/dist/src/frontend/index.js +1 -0
- package/dist/src/frontend/types.d.ts +106 -0
- package/dist/src/frontend/types.d.ts.map +1 -0
- package/dist/src/frontend/types.js +11 -0
- package/dist/src/governor/decision-engine.d.ts +52 -0
- package/dist/src/governor/decision-engine.d.ts.map +1 -0
- package/dist/src/governor/decision-engine.js +220 -0
- package/dist/src/governor/decision-engine.test.d.ts +2 -0
- package/dist/src/governor/decision-engine.test.d.ts.map +1 -0
- package/dist/src/governor/decision-engine.test.js +629 -0
- package/dist/src/governor/event-bus.d.ts +43 -0
- package/dist/src/governor/event-bus.d.ts.map +1 -0
- package/dist/src/governor/event-bus.js +8 -0
- package/dist/src/governor/event-deduplicator.d.ts +43 -0
- package/dist/src/governor/event-deduplicator.d.ts.map +1 -0
- package/dist/src/governor/event-deduplicator.js +53 -0
- package/dist/src/governor/event-driven-governor.d.ts +131 -0
- package/dist/src/governor/event-driven-governor.d.ts.map +1 -0
- package/dist/src/governor/event-driven-governor.js +379 -0
- package/dist/src/governor/event-driven-governor.test.d.ts +2 -0
- package/dist/src/governor/event-driven-governor.test.d.ts.map +1 -0
- package/dist/src/governor/event-driven-governor.test.js +673 -0
- package/dist/src/governor/event-types.d.ts +78 -0
- package/dist/src/governor/event-types.d.ts.map +1 -0
- package/dist/src/governor/event-types.js +32 -0
- package/dist/src/governor/governor-types.d.ts +82 -0
- package/dist/src/governor/governor-types.d.ts.map +1 -0
- package/dist/src/governor/governor-types.js +21 -0
- package/dist/src/governor/governor.d.ts +100 -0
- package/dist/src/governor/governor.d.ts.map +1 -0
- package/dist/src/governor/governor.js +262 -0
- package/dist/src/governor/governor.test.d.ts +2 -0
- package/dist/src/governor/governor.test.d.ts.map +1 -0
- package/dist/src/governor/governor.test.js +514 -0
- package/dist/src/governor/human-touchpoints.d.ts +131 -0
- package/dist/src/governor/human-touchpoints.d.ts.map +1 -0
- package/dist/src/governor/human-touchpoints.js +251 -0
- package/dist/src/governor/human-touchpoints.test.d.ts +2 -0
- package/dist/src/governor/human-touchpoints.test.d.ts.map +1 -0
- package/dist/src/governor/human-touchpoints.test.js +366 -0
- package/dist/src/governor/in-memory-event-bus.d.ts +29 -0
- package/dist/src/governor/in-memory-event-bus.d.ts.map +1 -0
- package/dist/src/governor/in-memory-event-bus.js +79 -0
- package/dist/src/governor/index.d.ts +14 -0
- package/dist/src/governor/index.d.ts.map +1 -0
- package/dist/src/governor/index.js +13 -0
- package/dist/src/governor/override-parser.d.ts +60 -0
- package/dist/src/governor/override-parser.d.ts.map +1 -0
- package/dist/src/governor/override-parser.js +98 -0
- package/dist/src/governor/override-parser.test.d.ts +2 -0
- package/dist/src/governor/override-parser.test.d.ts.map +1 -0
- package/dist/src/governor/override-parser.test.js +312 -0
- package/dist/src/governor/platform-adapter.d.ts +69 -0
- package/dist/src/governor/platform-adapter.d.ts.map +1 -0
- package/dist/src/governor/platform-adapter.js +11 -0
- package/dist/src/governor/processing-state.d.ts +66 -0
- package/dist/src/governor/processing-state.d.ts.map +1 -0
- package/dist/src/governor/processing-state.js +43 -0
- package/dist/src/governor/processing-state.test.d.ts +2 -0
- package/dist/src/governor/processing-state.test.d.ts.map +1 -0
- package/dist/src/governor/processing-state.test.js +96 -0
- package/dist/src/governor/top-of-funnel.d.ts +118 -0
- package/dist/src/governor/top-of-funnel.d.ts.map +1 -0
- package/dist/src/governor/top-of-funnel.js +168 -0
- package/dist/src/governor/top-of-funnel.test.d.ts +2 -0
- package/dist/src/governor/top-of-funnel.test.d.ts.map +1 -0
- package/dist/src/governor/top-of-funnel.test.js +331 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +10 -0
- package/dist/src/linear-cli.d.ts +38 -0
- package/dist/src/linear-cli.d.ts.map +1 -0
- package/dist/src/linear-cli.js +674 -0
- package/dist/src/logger.d.ts +117 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +430 -0
- package/dist/src/manifest/generate.d.ts +20 -0
- package/dist/src/manifest/generate.d.ts.map +1 -0
- package/dist/src/manifest/generate.js +65 -0
- package/dist/src/manifest/index.d.ts +4 -0
- package/dist/src/manifest/index.d.ts.map +1 -0
- package/dist/src/manifest/index.js +2 -0
- package/dist/src/manifest/route-manifest.d.ts +34 -0
- package/dist/src/manifest/route-manifest.d.ts.map +1 -0
- package/dist/src/manifest/route-manifest.js +148 -0
- package/dist/src/orchestrator/activity-emitter.d.ts +119 -0
- package/dist/src/orchestrator/activity-emitter.d.ts.map +1 -0
- package/dist/src/orchestrator/activity-emitter.js +306 -0
- package/dist/src/orchestrator/api-activity-emitter.d.ts +167 -0
- package/dist/src/orchestrator/api-activity-emitter.d.ts.map +1 -0
- package/dist/src/orchestrator/api-activity-emitter.js +417 -0
- package/dist/src/orchestrator/heartbeat-writer.d.ts +57 -0
- package/dist/src/orchestrator/heartbeat-writer.d.ts.map +1 -0
- package/dist/src/orchestrator/heartbeat-writer.js +137 -0
- package/dist/src/orchestrator/index.d.ts +20 -0
- package/dist/src/orchestrator/index.d.ts.map +1 -0
- package/dist/src/orchestrator/index.js +22 -0
- package/dist/src/orchestrator/log-analyzer.d.ts +160 -0
- package/dist/src/orchestrator/log-analyzer.d.ts.map +1 -0
- package/dist/src/orchestrator/log-analyzer.js +572 -0
- package/dist/src/orchestrator/log-config.d.ts +39 -0
- package/dist/src/orchestrator/log-config.d.ts.map +1 -0
- package/dist/src/orchestrator/log-config.js +45 -0
- package/dist/src/orchestrator/orchestrator.d.ts +316 -0
- package/dist/src/orchestrator/orchestrator.d.ts.map +1 -0
- package/dist/src/orchestrator/orchestrator.js +3290 -0
- package/dist/src/orchestrator/parse-work-result.d.ts +16 -0
- package/dist/src/orchestrator/parse-work-result.d.ts.map +1 -0
- package/dist/src/orchestrator/parse-work-result.js +135 -0
- package/dist/src/orchestrator/parse-work-result.test.d.ts +2 -0
- package/dist/src/orchestrator/parse-work-result.test.d.ts.map +1 -0
- package/dist/src/orchestrator/parse-work-result.test.js +234 -0
- package/dist/src/orchestrator/progress-logger.d.ts +72 -0
- package/dist/src/orchestrator/progress-logger.d.ts.map +1 -0
- package/dist/src/orchestrator/progress-logger.js +135 -0
- package/dist/src/orchestrator/session-logger.d.ts +159 -0
- package/dist/src/orchestrator/session-logger.d.ts.map +1 -0
- package/dist/src/orchestrator/session-logger.js +275 -0
- package/dist/src/orchestrator/state-recovery.d.ts +96 -0
- package/dist/src/orchestrator/state-recovery.d.ts.map +1 -0
- package/dist/src/orchestrator/state-recovery.js +302 -0
- package/dist/src/orchestrator/state-types.d.ts +165 -0
- package/dist/src/orchestrator/state-types.d.ts.map +1 -0
- package/dist/src/orchestrator/state-types.js +7 -0
- package/dist/src/orchestrator/stream-parser.d.ts +151 -0
- package/dist/src/orchestrator/stream-parser.d.ts.map +1 -0
- package/dist/src/orchestrator/stream-parser.js +137 -0
- package/dist/src/orchestrator/types.d.ts +232 -0
- package/dist/src/orchestrator/types.d.ts.map +1 -0
- package/dist/src/orchestrator/types.js +4 -0
- package/dist/src/orchestrator/validate-git-remote.test.d.ts +2 -0
- package/dist/src/orchestrator/validate-git-remote.test.d.ts.map +1 -0
- package/dist/src/orchestrator/validate-git-remote.test.js +61 -0
- package/dist/src/providers/a2a-auth.d.ts +81 -0
- package/dist/src/providers/a2a-auth.d.ts.map +1 -0
- package/dist/src/providers/a2a-auth.js +188 -0
- package/dist/src/providers/a2a-auth.test.d.ts +2 -0
- package/dist/src/providers/a2a-auth.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-auth.test.js +232 -0
- package/dist/src/providers/a2a-provider.d.ts +254 -0
- package/dist/src/providers/a2a-provider.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.integration.test.d.ts +9 -0
- package/dist/src/providers/a2a-provider.integration.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.integration.test.js +665 -0
- package/dist/src/providers/a2a-provider.js +811 -0
- package/dist/src/providers/a2a-provider.test.d.ts +2 -0
- package/dist/src/providers/a2a-provider.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.test.js +681 -0
- package/dist/src/providers/amp-provider.d.ts +20 -0
- package/dist/src/providers/amp-provider.d.ts.map +1 -0
- package/dist/src/providers/amp-provider.js +24 -0
- package/dist/src/providers/claude-provider.d.ts +18 -0
- package/dist/src/providers/claude-provider.d.ts.map +1 -0
- package/dist/src/providers/claude-provider.js +437 -0
- package/dist/src/providers/codex-provider.d.ts +133 -0
- package/dist/src/providers/codex-provider.d.ts.map +1 -0
- package/dist/src/providers/codex-provider.js +381 -0
- package/dist/src/providers/codex-provider.test.d.ts +2 -0
- package/dist/src/providers/codex-provider.test.d.ts.map +1 -0
- package/dist/src/providers/codex-provider.test.js +387 -0
- package/dist/src/providers/index.d.ts +44 -0
- package/dist/src/providers/index.d.ts.map +1 -0
- package/dist/src/providers/index.js +85 -0
- package/dist/src/providers/spring-ai-provider.d.ts +90 -0
- package/dist/src/providers/spring-ai-provider.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.integration.test.d.ts +13 -0
- package/dist/src/providers/spring-ai-provider.integration.test.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.integration.test.js +351 -0
- package/dist/src/providers/spring-ai-provider.js +317 -0
- package/dist/src/providers/spring-ai-provider.test.d.ts +2 -0
- package/dist/src/providers/spring-ai-provider.test.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.test.js +200 -0
- package/dist/src/providers/types.d.ts +165 -0
- package/dist/src/providers/types.d.ts.map +1 -0
- package/dist/src/providers/types.js +13 -0
- package/dist/src/templates/adapters.d.ts +51 -0
- package/dist/src/templates/adapters.d.ts.map +1 -0
- package/dist/src/templates/adapters.js +104 -0
- package/dist/src/templates/adapters.test.d.ts +2 -0
- package/dist/src/templates/adapters.test.d.ts.map +1 -0
- package/dist/src/templates/adapters.test.js +165 -0
- package/dist/src/templates/agent-definition.d.ts +85 -0
- package/dist/src/templates/agent-definition.d.ts.map +1 -0
- package/dist/src/templates/agent-definition.js +97 -0
- package/dist/src/templates/agent-definition.test.d.ts +2 -0
- package/dist/src/templates/agent-definition.test.d.ts.map +1 -0
- package/dist/src/templates/agent-definition.test.js +209 -0
- package/dist/src/templates/index.d.ts +14 -0
- package/dist/src/templates/index.d.ts.map +1 -0
- package/dist/src/templates/index.js +11 -0
- package/dist/src/templates/loader.d.ts +41 -0
- package/dist/src/templates/loader.d.ts.map +1 -0
- package/dist/src/templates/loader.js +114 -0
- package/dist/src/templates/registry.d.ts +80 -0
- package/dist/src/templates/registry.d.ts.map +1 -0
- package/dist/src/templates/registry.js +177 -0
- package/dist/src/templates/registry.test.d.ts +2 -0
- package/dist/src/templates/registry.test.d.ts.map +1 -0
- package/dist/src/templates/registry.test.js +198 -0
- package/dist/src/templates/renderer.d.ts +29 -0
- package/dist/src/templates/renderer.d.ts.map +1 -0
- package/dist/src/templates/renderer.js +35 -0
- package/dist/src/templates/strategy-templates.test.d.ts +2 -0
- package/dist/src/templates/strategy-templates.test.d.ts.map +1 -0
- package/dist/src/templates/strategy-templates.test.js +619 -0
- package/dist/src/templates/types.d.ts +233 -0
- package/dist/src/templates/types.d.ts.map +1 -0
- package/dist/src/templates/types.js +127 -0
- package/dist/src/templates/types.test.d.ts +2 -0
- package/dist/src/templates/types.test.d.ts.map +1 -0
- package/dist/src/templates/types.test.js +232 -0
- package/dist/src/tools/index.d.ts +6 -0
- package/dist/src/tools/index.d.ts.map +1 -0
- package/dist/src/tools/index.js +3 -0
- package/dist/src/tools/linear-runner.d.ts +34 -0
- package/dist/src/tools/linear-runner.d.ts.map +1 -0
- package/dist/src/tools/linear-runner.js +700 -0
- package/dist/src/tools/plugins/linear.d.ts +9 -0
- package/dist/src/tools/plugins/linear.d.ts.map +1 -0
- package/dist/src/tools/plugins/linear.js +138 -0
- package/dist/src/tools/registry.d.ts +9 -0
- package/dist/src/tools/registry.d.ts.map +1 -0
- package/dist/src/tools/registry.js +18 -0
- package/dist/src/tools/types.d.ts +18 -0
- package/dist/src/tools/types.d.ts.map +1 -0
- package/dist/src/tools/types.js +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AgentWorkType } from '@renseiai/agentfactory-linear';
|
|
2
|
+
import type { AgentWorkResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Parse the agent's result message to determine whether the work passed or failed.
|
|
5
|
+
*
|
|
6
|
+
* Detection priority:
|
|
7
|
+
* 1. Structured marker: `<!-- WORK_RESULT:passed/failed -->`
|
|
8
|
+
* 2. Heuristic heading/pattern matching scoped to the work type
|
|
9
|
+
* 3. Returns 'unknown' if nothing matches (safe default: no transition)
|
|
10
|
+
*
|
|
11
|
+
* @param resultMessage - The agent's final output message
|
|
12
|
+
* @param workType - The type of work performed (qa, acceptance, etc.)
|
|
13
|
+
* @returns 'passed', 'failed', or 'unknown'
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseWorkResult(resultMessage: string | undefined, workType: AgentWorkType): AgentWorkResult;
|
|
16
|
+
//# sourceMappingURL=parse-work-result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-work-result.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/parse-work-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AA+FjD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,QAAQ,EAAE,aAAa,GACtB,eAAe,CAyCjB"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured marker pattern embedded in agent output.
|
|
3
|
+
* Agents are instructed to include this marker in their final output.
|
|
4
|
+
*
|
|
5
|
+
* Format: <!-- WORK_RESULT:passed --> or <!-- WORK_RESULT:failed -->
|
|
6
|
+
*/
|
|
7
|
+
const STRUCTURED_MARKER_RE = /<!--\s*WORK_RESULT:(passed|failed)\s*-->/i;
|
|
8
|
+
/**
|
|
9
|
+
* Heuristic patterns for detecting QA pass/fail when structured marker is absent.
|
|
10
|
+
* Patterns are checked case-insensitively against the result message.
|
|
11
|
+
*/
|
|
12
|
+
const QA_PASS_PATTERNS = [
|
|
13
|
+
// Heading patterns
|
|
14
|
+
/##\s*QA\s+Passed/i,
|
|
15
|
+
/##\s*QA\s+Complete[^]*?\bPASS/i,
|
|
16
|
+
// Explicit label patterns (with optional "QA" prefix, word-bounded to avoid WORK_RESULT)
|
|
17
|
+
/\b(?:QA\s+)?Result:\s*\*{0,2}Pass(?:ed)?\*{0,2}/i,
|
|
18
|
+
/\b(?:QA\s+)?Status:\s*\*{0,2}Pass(?:ed)?\*{0,2}/i,
|
|
19
|
+
/\b(?:QA\s+)?Verdict:\s*\*{0,2}Pass(?:ed)?\*{0,2}/i,
|
|
20
|
+
/\b(?:QA\s+)?(?:Result|Status|Verdict):\s*✅/i,
|
|
21
|
+
/Overall\s+(?:QA\s+)?Result:\s*PASS/i,
|
|
22
|
+
/Roll-?Up\s+Verdict:\s*PASS/i,
|
|
23
|
+
// Bold standalone PASS (agents commonly output **PASS** or **PASS.**)
|
|
24
|
+
/\*\*PASS\.?\*\*/,
|
|
25
|
+
];
|
|
26
|
+
const QA_FAIL_PATTERNS = [
|
|
27
|
+
// Heading patterns
|
|
28
|
+
/##\s*QA\s+Failed/i,
|
|
29
|
+
/##\s*QA\s+Complete[^]*?\bFAIL/i,
|
|
30
|
+
// Explicit label patterns (with optional "QA" prefix, word-bounded to avoid WORK_RESULT)
|
|
31
|
+
/\b(?:QA\s+)?Result:\s*\*{0,2}Fail(?:ed)?\*{0,2}/i,
|
|
32
|
+
/\b(?:QA\s+)?Status:\s*\*{0,2}Fail(?:ed)?\*{0,2}/i,
|
|
33
|
+
/\b(?:QA\s+)?Verdict:\s*\*{0,2}Fail(?:ed)?\*{0,2}/i,
|
|
34
|
+
/\b(?:QA\s+)?(?:Result|Status|Verdict):\s*❌/i,
|
|
35
|
+
/Overall\s+(?:QA\s+)?Result:\s*FAIL/i,
|
|
36
|
+
/Roll-?Up\s+Verdict:\s*FAIL/i,
|
|
37
|
+
/Parent\s+QA\s+verdict:\s*FAIL/i,
|
|
38
|
+
// Bold standalone FAIL
|
|
39
|
+
/\*\*FAIL\.?\*\*/,
|
|
40
|
+
// QA coordination report with issues found (agents output "Status: N Issues Found")
|
|
41
|
+
/\bStatus:\s*\d+\s+Issues?\s+Found\b/i,
|
|
42
|
+
// "Must Fix Before Merge" — agents use this heading for blocking findings
|
|
43
|
+
/\bMust\s+Fix\s+Before\s+Merge\b/i,
|
|
44
|
+
// "N Critical Issues (Block Merge)" — coordination QA summary format
|
|
45
|
+
/\d+\s+Critical\s+Issues?\s*\(Block\s+Merge\)/i,
|
|
46
|
+
];
|
|
47
|
+
const ACCEPTANCE_PASS_PATTERNS = [
|
|
48
|
+
/##\s*Acceptance\s+Complete/i,
|
|
49
|
+
/Acceptance\s+Result:\s*Pass/i,
|
|
50
|
+
/PR\s+has\s+been\s+merged\s+successfully/i,
|
|
51
|
+
];
|
|
52
|
+
const ACCEPTANCE_FAIL_PATTERNS = [
|
|
53
|
+
/##\s*Acceptance\s+(?:Processing\s+)?Failed/i,
|
|
54
|
+
/Acceptance\s+(?:Processing\s+)?Blocked/i,
|
|
55
|
+
/Acceptance\s+Result:\s*Fail/i,
|
|
56
|
+
/Cannot\s+merge\s+PR/i,
|
|
57
|
+
// Coordination-style patterns (agents output reports with "Must Fix" / "Critical Issues")
|
|
58
|
+
/\bMust\s+Fix\s+Before\s+Merge\b/i,
|
|
59
|
+
/\d+\s+Critical\s+Issues?\s*\(Block\s+Merge\)/i,
|
|
60
|
+
];
|
|
61
|
+
/**
|
|
62
|
+
* Heuristic patterns for detecting coordination pass/fail.
|
|
63
|
+
* These apply to the 'coordination' work type (development coordination).
|
|
64
|
+
*/
|
|
65
|
+
const COORDINATION_PASS_PATTERNS = [
|
|
66
|
+
// "all 8/8 sub-issues completed" or "all sub-issues completed"
|
|
67
|
+
/\ball\s+(?:\d+\/\d+\s+)?sub-issues?\s+(?:completed|finished)/i,
|
|
68
|
+
// "8/8 sub-issues completed/finished" (without leading "all")
|
|
69
|
+
/\b(\d+)\/\1\b.*\bsub-issues?\s+(?:completed|finished)/i,
|
|
70
|
+
// Explicit result labels
|
|
71
|
+
/\bCoordination\s+(?:Result|Status|Verdict):\s*\*{0,2}Pass(?:ed)?\*{0,2}/i,
|
|
72
|
+
/\bCoordination\s+Complete/i,
|
|
73
|
+
// "Parent issue marked Finished" — coordinator confirms parent status update
|
|
74
|
+
/\bParent\s+issue\s+marked\s+Finished/i,
|
|
75
|
+
];
|
|
76
|
+
const COORDINATION_FAIL_PATTERNS = [
|
|
77
|
+
// "Must Fix Before Merge" — agents use this heading for blocking issues
|
|
78
|
+
/\bMust\s+Fix\s+Before\s+Merge\b/i,
|
|
79
|
+
// "N Critical Issues (Block Merge)"
|
|
80
|
+
/\d+\s+Critical\s+Issues?\s*\(Block\s+Merge\)/i,
|
|
81
|
+
// "sub-issues need work/attention/fixes"
|
|
82
|
+
/\bsub-issues?\s+(?:need|require)[s]?\s+(?:work|attention|fixes?)\b/i,
|
|
83
|
+
// Explicit result labels
|
|
84
|
+
/\bCoordination\s+(?:Result|Status|Verdict):\s*\*{0,2}Fail(?:ed)?\*{0,2}/i,
|
|
85
|
+
/\bCoordination\s+Failed/i,
|
|
86
|
+
];
|
|
87
|
+
/**
|
|
88
|
+
* Parse the agent's result message to determine whether the work passed or failed.
|
|
89
|
+
*
|
|
90
|
+
* Detection priority:
|
|
91
|
+
* 1. Structured marker: `<!-- WORK_RESULT:passed/failed -->`
|
|
92
|
+
* 2. Heuristic heading/pattern matching scoped to the work type
|
|
93
|
+
* 3. Returns 'unknown' if nothing matches (safe default: no transition)
|
|
94
|
+
*
|
|
95
|
+
* @param resultMessage - The agent's final output message
|
|
96
|
+
* @param workType - The type of work performed (qa, acceptance, etc.)
|
|
97
|
+
* @returns 'passed', 'failed', or 'unknown'
|
|
98
|
+
*/
|
|
99
|
+
export function parseWorkResult(resultMessage, workType) {
|
|
100
|
+
if (!resultMessage) {
|
|
101
|
+
return 'unknown';
|
|
102
|
+
}
|
|
103
|
+
// 1. Check for structured marker (highest priority, work-type agnostic)
|
|
104
|
+
const markerMatch = resultMessage.match(STRUCTURED_MARKER_RE);
|
|
105
|
+
if (markerMatch) {
|
|
106
|
+
return markerMatch[1].toLowerCase();
|
|
107
|
+
}
|
|
108
|
+
// 2. Fall back to heuristic patterns scoped by work type
|
|
109
|
+
if (workType === 'qa' || workType === 'qa-coordination') {
|
|
110
|
+
if (QA_FAIL_PATTERNS.some((p) => p.test(resultMessage))) {
|
|
111
|
+
return 'failed';
|
|
112
|
+
}
|
|
113
|
+
if (QA_PASS_PATTERNS.some((p) => p.test(resultMessage))) {
|
|
114
|
+
return 'passed';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (workType === 'acceptance' || workType === 'acceptance-coordination') {
|
|
118
|
+
if (ACCEPTANCE_FAIL_PATTERNS.some((p) => p.test(resultMessage))) {
|
|
119
|
+
return 'failed';
|
|
120
|
+
}
|
|
121
|
+
if (ACCEPTANCE_PASS_PATTERNS.some((p) => p.test(resultMessage))) {
|
|
122
|
+
return 'passed';
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (workType === 'coordination') {
|
|
126
|
+
if (COORDINATION_FAIL_PATTERNS.some((p) => p.test(resultMessage))) {
|
|
127
|
+
return 'failed';
|
|
128
|
+
}
|
|
129
|
+
if (COORDINATION_PASS_PATTERNS.some((p) => p.test(resultMessage))) {
|
|
130
|
+
return 'passed';
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// 3. Unknown — safe default
|
|
134
|
+
return 'unknown';
|
|
135
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-work-result.test.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/parse-work-result.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { parseWorkResult } from './parse-work-result.js';
|
|
3
|
+
describe('parseWorkResult', () => {
|
|
4
|
+
// Structured marker tests
|
|
5
|
+
describe('structured markers', () => {
|
|
6
|
+
it('detects <!-- WORK_RESULT:passed --> marker', () => {
|
|
7
|
+
expect(parseWorkResult('Some text <!-- WORK_RESULT:passed --> more text', 'qa')).toBe('passed');
|
|
8
|
+
});
|
|
9
|
+
it('detects <!-- WORK_RESULT:failed --> marker', () => {
|
|
10
|
+
expect(parseWorkResult('<!-- WORK_RESULT:failed -->', 'qa')).toBe('failed');
|
|
11
|
+
});
|
|
12
|
+
it('is case-insensitive for marker value', () => {
|
|
13
|
+
expect(parseWorkResult('<!-- WORK_RESULT:PASSED -->', 'qa')).toBe('passed');
|
|
14
|
+
expect(parseWorkResult('<!-- WORK_RESULT:Failed -->', 'acceptance')).toBe('failed');
|
|
15
|
+
});
|
|
16
|
+
it('handles extra whitespace in marker', () => {
|
|
17
|
+
expect(parseWorkResult('<!-- WORK_RESULT:passed -->', 'qa')).toBe('passed');
|
|
18
|
+
});
|
|
19
|
+
it('finds marker anywhere in the message', () => {
|
|
20
|
+
const msg = 'Here is my QA report\n\nEverything looks good\n\n<!-- WORK_RESULT:passed -->\n\nEnd of report';
|
|
21
|
+
expect(parseWorkResult(msg, 'qa')).toBe('passed');
|
|
22
|
+
});
|
|
23
|
+
it('works for any work type (not just qa/acceptance)', () => {
|
|
24
|
+
expect(parseWorkResult('<!-- WORK_RESULT:passed -->', 'development')).toBe('passed');
|
|
25
|
+
expect(parseWorkResult('<!-- WORK_RESULT:failed -->', 'coordination')).toBe('failed');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
// QA heuristic pattern tests
|
|
29
|
+
describe('QA heuristic patterns', () => {
|
|
30
|
+
it('detects "## QA Passed" heading', () => {
|
|
31
|
+
expect(parseWorkResult('## QA Passed\nAll tests pass.', 'qa')).toBe('passed');
|
|
32
|
+
});
|
|
33
|
+
it('detects "QA Result: Pass"', () => {
|
|
34
|
+
expect(parseWorkResult('QA Result: Pass', 'qa')).toBe('passed');
|
|
35
|
+
});
|
|
36
|
+
it('detects "QA Status: Passed"', () => {
|
|
37
|
+
expect(parseWorkResult('QA Status: Passed', 'qa')).toBe('passed');
|
|
38
|
+
});
|
|
39
|
+
it('detects "## QA Failed" heading', () => {
|
|
40
|
+
expect(parseWorkResult('## QA Failed\nTests are broken.', 'qa')).toBe('failed');
|
|
41
|
+
});
|
|
42
|
+
it('detects "QA Result: Fail"', () => {
|
|
43
|
+
expect(parseWorkResult('QA Result: Fail', 'qa')).toBe('failed');
|
|
44
|
+
});
|
|
45
|
+
it('does not match QA patterns for non-qa work types', () => {
|
|
46
|
+
expect(parseWorkResult('## QA Passed', 'development')).toBe('unknown');
|
|
47
|
+
expect(parseWorkResult('QA Result: Pass', 'acceptance')).toBe('unknown');
|
|
48
|
+
});
|
|
49
|
+
it('matches QA patterns for qa-coordination work type', () => {
|
|
50
|
+
expect(parseWorkResult('## QA Passed\nAll sub-issues pass.', 'qa-coordination')).toBe('passed');
|
|
51
|
+
expect(parseWorkResult('## QA Failed\nSUP-712 needs work.', 'qa-coordination')).toBe('failed');
|
|
52
|
+
expect(parseWorkResult('QA Result: Pass', 'qa-coordination')).toBe('passed');
|
|
53
|
+
expect(parseWorkResult('QA Result: Fail', 'qa-coordination')).toBe('failed');
|
|
54
|
+
});
|
|
55
|
+
it('checks fail patterns before pass patterns', () => {
|
|
56
|
+
// Both present - fail takes precedence since it's checked first
|
|
57
|
+
expect(parseWorkResult('## QA Failed\n## QA Passed', 'qa')).toBe('failed');
|
|
58
|
+
});
|
|
59
|
+
it('detects "Overall Result: FAIL" (coordination style)', () => {
|
|
60
|
+
expect(parseWorkResult('**Overall Result: FAIL** — 4 of 6 phases failed', 'qa-coordination')).toBe('failed');
|
|
61
|
+
});
|
|
62
|
+
it('detects "Overall QA Result: FAIL" (coordination style)', () => {
|
|
63
|
+
expect(parseWorkResult('**Overall QA Result: FAIL (0/6 sub-issues pass)**', 'qa-coordination')).toBe('failed');
|
|
64
|
+
});
|
|
65
|
+
it('detects "Roll-Up Verdict: FAIL"', () => {
|
|
66
|
+
expect(parseWorkResult('### Roll-Up Verdict: FAIL (0/6 sub-issues pass)', 'qa-coordination')).toBe('failed');
|
|
67
|
+
});
|
|
68
|
+
it('detects "Parent QA verdict: FAIL"', () => {
|
|
69
|
+
expect(parseWorkResult('**Parent QA verdict: FAIL — requires fixes**', 'qa-coordination')).toBe('failed');
|
|
70
|
+
});
|
|
71
|
+
it('detects "Overall Result: PASS" (coordination style)', () => {
|
|
72
|
+
expect(parseWorkResult('**Overall Result: PASS** — all phases passed', 'qa-coordination')).toBe('passed');
|
|
73
|
+
});
|
|
74
|
+
it('detects "Roll-Up Verdict: PASS"', () => {
|
|
75
|
+
expect(parseWorkResult('### Roll-Up Verdict: PASS (6/6 sub-issues pass)', 'qa-coordination')).toBe('passed');
|
|
76
|
+
});
|
|
77
|
+
// Real agent output patterns (SUP-867 regression)
|
|
78
|
+
it('detects bold **PASS**', () => {
|
|
79
|
+
expect(parseWorkResult('Branch unchanged — `4383c3e`. **PASS.** No new findings.', 'qa')).toBe('passed');
|
|
80
|
+
});
|
|
81
|
+
it('detects bold **PASS** without period', () => {
|
|
82
|
+
expect(parseWorkResult('All tests pass. **PASS**', 'qa')).toBe('passed');
|
|
83
|
+
});
|
|
84
|
+
it('detects "Verdict: PASS" without QA prefix', () => {
|
|
85
|
+
expect(parseWorkResult('**Verdict: PASS** — all criteria met', 'qa')).toBe('passed');
|
|
86
|
+
});
|
|
87
|
+
it('detects "Verdict: **PASS**" with bold', () => {
|
|
88
|
+
expect(parseWorkResult('Verdict: **PASS**', 'qa')).toBe('passed');
|
|
89
|
+
});
|
|
90
|
+
it('detects "Status: **PASS**" without QA prefix', () => {
|
|
91
|
+
expect(parseWorkResult('### Status: **PASS** — same as prior two passes', 'qa')).toBe('passed');
|
|
92
|
+
});
|
|
93
|
+
it('detects "Result: Pass" without QA prefix', () => {
|
|
94
|
+
expect(parseWorkResult('Result: Pass — no issues found', 'qa')).toBe('passed');
|
|
95
|
+
});
|
|
96
|
+
it('detects bold **FAIL**', () => {
|
|
97
|
+
expect(parseWorkResult('Build failed. **FAIL.**', 'qa')).toBe('failed');
|
|
98
|
+
});
|
|
99
|
+
it('detects "Verdict: FAIL" without QA prefix', () => {
|
|
100
|
+
expect(parseWorkResult('Verdict: FAIL — build errors detected', 'qa')).toBe('failed');
|
|
101
|
+
});
|
|
102
|
+
it('detects "Status: **FAIL**" without QA prefix', () => {
|
|
103
|
+
expect(parseWorkResult('Status: **FAIL**', 'qa')).toBe('failed');
|
|
104
|
+
});
|
|
105
|
+
it('does not false-positive on "tests pass" (no bold)', () => {
|
|
106
|
+
expect(parseWorkResult('All tests pass and everything looks good.', 'qa')).toBe('unknown');
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
// Acceptance heuristic pattern tests
|
|
110
|
+
describe('acceptance heuristic patterns', () => {
|
|
111
|
+
it('detects "## Acceptance Complete"', () => {
|
|
112
|
+
expect(parseWorkResult('## Acceptance Complete', 'acceptance')).toBe('passed');
|
|
113
|
+
});
|
|
114
|
+
it('detects "Acceptance Result: Pass"', () => {
|
|
115
|
+
expect(parseWorkResult('Acceptance Result: Pass', 'acceptance')).toBe('passed');
|
|
116
|
+
});
|
|
117
|
+
it('detects "PR has been merged successfully"', () => {
|
|
118
|
+
expect(parseWorkResult('PR has been merged successfully', 'acceptance')).toBe('passed');
|
|
119
|
+
});
|
|
120
|
+
it('detects "## Acceptance Failed"', () => {
|
|
121
|
+
expect(parseWorkResult('## Acceptance Failed', 'acceptance')).toBe('failed');
|
|
122
|
+
});
|
|
123
|
+
it('detects "Acceptance Processing Blocked"', () => {
|
|
124
|
+
expect(parseWorkResult('Acceptance Processing Blocked', 'acceptance')).toBe('failed');
|
|
125
|
+
});
|
|
126
|
+
it('detects "Cannot merge PR"', () => {
|
|
127
|
+
expect(parseWorkResult('Cannot merge PR', 'acceptance')).toBe('failed');
|
|
128
|
+
});
|
|
129
|
+
it('does not match acceptance patterns for non-acceptance work types', () => {
|
|
130
|
+
expect(parseWorkResult('## Acceptance Complete', 'qa')).toBe('unknown');
|
|
131
|
+
expect(parseWorkResult('PR has been merged successfully', 'development')).toBe('unknown');
|
|
132
|
+
});
|
|
133
|
+
it('matches acceptance patterns for acceptance-coordination work type', () => {
|
|
134
|
+
expect(parseWorkResult('## Acceptance Complete', 'acceptance-coordination')).toBe('passed');
|
|
135
|
+
expect(parseWorkResult('PR has been merged successfully', 'acceptance-coordination')).toBe('passed');
|
|
136
|
+
expect(parseWorkResult('## Acceptance Failed', 'acceptance-coordination')).toBe('failed');
|
|
137
|
+
expect(parseWorkResult('Cannot merge PR', 'acceptance-coordination')).toBe('failed');
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
// Coordination heuristic pattern tests
|
|
141
|
+
describe('coordination heuristic patterns', () => {
|
|
142
|
+
it('detects "all 8/8 sub-issues completed"', () => {
|
|
143
|
+
expect(parseWorkResult('all 8/8 sub-issues completed and marked Finished in Linear.', 'coordination')).toBe('passed');
|
|
144
|
+
});
|
|
145
|
+
it('detects "all sub-issues completed" without count', () => {
|
|
146
|
+
expect(parseWorkResult('All sub-issues completed successfully.', 'coordination')).toBe('passed');
|
|
147
|
+
});
|
|
148
|
+
it('detects "all sub-issues finished"', () => {
|
|
149
|
+
expect(parseWorkResult('All 3/3 sub-issues finished.', 'coordination')).toBe('passed');
|
|
150
|
+
});
|
|
151
|
+
it('detects "Coordination Complete"', () => {
|
|
152
|
+
expect(parseWorkResult('## Coordination Complete\nAll work done.', 'coordination')).toBe('passed');
|
|
153
|
+
});
|
|
154
|
+
it('detects "Must Fix Before Merge" as fail', () => {
|
|
155
|
+
expect(parseWorkResult('### CRITICAL — Must Fix Before Merge\n1. provision-trial.ts uses removed fields', 'coordination')).toBe('failed');
|
|
156
|
+
});
|
|
157
|
+
it('detects "N Critical Issues (Block Merge)" as fail', () => {
|
|
158
|
+
expect(parseWorkResult('### 3 Critical Issues (Block Merge)\n1. Bad migration', 'coordination')).toBe('failed');
|
|
159
|
+
});
|
|
160
|
+
it('detects "sub-issues need work" as fail', () => {
|
|
161
|
+
expect(parseWorkResult('2 sub-issues need work before this can proceed.', 'coordination')).toBe('failed');
|
|
162
|
+
});
|
|
163
|
+
it('detects "Parent issue marked Finished"', () => {
|
|
164
|
+
expect(parseWorkResult('Execution: Wave 1...Wave 2...Wave 3. Parent issue marked Finished in Linear.', 'coordination')).toBe('passed');
|
|
165
|
+
});
|
|
166
|
+
it('does not match coordination patterns for non-coordination work types', () => {
|
|
167
|
+
expect(parseWorkResult('All sub-issues completed.', 'development')).toBe('unknown');
|
|
168
|
+
expect(parseWorkResult('All sub-issues completed.', 'qa')).toBe('unknown');
|
|
169
|
+
});
|
|
170
|
+
it('checks fail patterns before pass patterns', () => {
|
|
171
|
+
expect(parseWorkResult('All 8/8 sub-issues completed.\n### Must Fix Before Merge\n1. Bad code', 'coordination')).toBe('failed');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
// QA coordination with real agent output formats
|
|
175
|
+
describe('QA coordination real-world patterns', () => {
|
|
176
|
+
it('detects "Status: N Issues Found" as fail', () => {
|
|
177
|
+
expect(parseWorkResult('### Status: 3 Issues Found (1 Critical, 2 Minor)', 'qa-coordination')).toBe('failed');
|
|
178
|
+
});
|
|
179
|
+
it('detects "Must Fix Before Merge" in QA context as fail', () => {
|
|
180
|
+
expect(parseWorkResult('## QA Report\n### CRITICAL — Must Fix Before Merge\n1. Bad migration', 'qa')).toBe('failed');
|
|
181
|
+
});
|
|
182
|
+
it('detects "N Critical Issues (Block Merge)" in QA context as fail', () => {
|
|
183
|
+
expect(parseWorkResult('### 3 Critical Issues (Block Merge)\n1. Bad code', 'qa-coordination')).toBe('failed');
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
// Acceptance coordination with real agent output formats
|
|
187
|
+
describe('acceptance coordination real-world patterns', () => {
|
|
188
|
+
it('detects "Must Fix Before Merge" in acceptance context as fail', () => {
|
|
189
|
+
expect(parseWorkResult('## Acceptance Coordination Report\n### CRITICAL — Must Fix Before Merge', 'acceptance-coordination')).toBe('failed');
|
|
190
|
+
});
|
|
191
|
+
it('detects "N Critical Issues (Block Merge)" in acceptance context as fail', () => {
|
|
192
|
+
expect(parseWorkResult('### 3 Critical Issues (Block Merge)\n1. provision-trial.ts uses removed fields', 'acceptance-coordination')).toBe('failed');
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
// Unknown result tests
|
|
196
|
+
describe('unknown results', () => {
|
|
197
|
+
it('returns unknown for undefined message', () => {
|
|
198
|
+
expect(parseWorkResult(undefined, 'qa')).toBe('unknown');
|
|
199
|
+
});
|
|
200
|
+
it('returns unknown for empty string', () => {
|
|
201
|
+
expect(parseWorkResult('', 'qa')).toBe('unknown');
|
|
202
|
+
});
|
|
203
|
+
it('returns unknown for message without any markers or patterns', () => {
|
|
204
|
+
expect(parseWorkResult('Work completed successfully. All looks good.', 'qa')).toBe('unknown');
|
|
205
|
+
});
|
|
206
|
+
it('returns unknown for generic success messages without structured marker', () => {
|
|
207
|
+
expect(parseWorkResult('Everything passed! Great work.', 'qa')).toBe('unknown');
|
|
208
|
+
});
|
|
209
|
+
it('returns unknown for message with only whitespace', () => {
|
|
210
|
+
expect(parseWorkResult(' \n\n \t ', 'qa')).toBe('unknown');
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
// Priority / edge cases
|
|
214
|
+
describe('edge cases', () => {
|
|
215
|
+
it('prefers structured marker over heuristic patterns', () => {
|
|
216
|
+
const msg = '## QA Failed\n\nActually wait, it passed.\n\n<!-- WORK_RESULT:passed -->';
|
|
217
|
+
expect(parseWorkResult(msg, 'qa')).toBe('passed');
|
|
218
|
+
});
|
|
219
|
+
it('handles messages with multiple structured markers (takes first)', () => {
|
|
220
|
+
const msg = '<!-- WORK_RESULT:passed -->\nOops\n<!-- WORK_RESULT:failed -->';
|
|
221
|
+
expect(parseWorkResult(msg, 'qa')).toBe('passed');
|
|
222
|
+
});
|
|
223
|
+
it('handles very long messages', () => {
|
|
224
|
+
const long = 'x'.repeat(100000) +
|
|
225
|
+
'<!-- WORK_RESULT:passed -->' +
|
|
226
|
+
'y'.repeat(100000);
|
|
227
|
+
expect(parseWorkResult(long, 'qa')).toBe('passed');
|
|
228
|
+
});
|
|
229
|
+
it('does not match partial markers', () => {
|
|
230
|
+
expect(parseWorkResult('WORK_RESULT:passed', 'qa')).toBe('unknown');
|
|
231
|
+
expect(parseWorkResult('<!-- WORK_RESULT:maybe -->', 'qa')).toBe('unknown');
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress Logger
|
|
3
|
+
*
|
|
4
|
+
* Append-only log for debugging agent activity.
|
|
5
|
+
* Format: timestamp|event_type|details
|
|
6
|
+
*/
|
|
7
|
+
import type { ProgressLoggerConfig, ProgressEventType } from './state-types.js';
|
|
8
|
+
/**
|
|
9
|
+
* ProgressLogger appends events to a log file for debugging
|
|
10
|
+
*/
|
|
11
|
+
export declare class ProgressLogger {
|
|
12
|
+
private readonly config;
|
|
13
|
+
private readonly logPath;
|
|
14
|
+
private stopped;
|
|
15
|
+
constructor(config: ProgressLoggerConfig);
|
|
16
|
+
/**
|
|
17
|
+
* Initialize the logger (create directory if needed)
|
|
18
|
+
*/
|
|
19
|
+
init(): void;
|
|
20
|
+
/**
|
|
21
|
+
* Stop the logger
|
|
22
|
+
*/
|
|
23
|
+
stop(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Log an event
|
|
26
|
+
*/
|
|
27
|
+
log(eventType: ProgressEventType, details: string | object): void;
|
|
28
|
+
/**
|
|
29
|
+
* Log agent start
|
|
30
|
+
*/
|
|
31
|
+
logStart(details: {
|
|
32
|
+
issueId: string;
|
|
33
|
+
workType: string;
|
|
34
|
+
prompt: string;
|
|
35
|
+
}): void;
|
|
36
|
+
/**
|
|
37
|
+
* Log phase change
|
|
38
|
+
*/
|
|
39
|
+
logPhase(phase: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* Log tool call
|
|
42
|
+
*/
|
|
43
|
+
logTool(toolName: string, input?: object): void;
|
|
44
|
+
/**
|
|
45
|
+
* Log error
|
|
46
|
+
*/
|
|
47
|
+
logError(message: string, error?: Error | unknown): void;
|
|
48
|
+
/**
|
|
49
|
+
* Log recovery attempt
|
|
50
|
+
*/
|
|
51
|
+
logRecovery(attempt: number, reason?: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Log completion
|
|
54
|
+
*/
|
|
55
|
+
logComplete(details?: {
|
|
56
|
+
prUrl?: string;
|
|
57
|
+
message?: string;
|
|
58
|
+
}): void;
|
|
59
|
+
/**
|
|
60
|
+
* Log stop
|
|
61
|
+
*/
|
|
62
|
+
logStop(reason: 'user_request' | 'timeout' | 'error'): void;
|
|
63
|
+
/**
|
|
64
|
+
* Rotate log file if it exceeds max size
|
|
65
|
+
*/
|
|
66
|
+
private maybeRotate;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create a progress logger for an agent
|
|
70
|
+
*/
|
|
71
|
+
export declare function createProgressLogger(config: ProgressLoggerConfig): ProgressLogger;
|
|
72
|
+
//# sourceMappingURL=progress-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress-logger.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/progress-logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAK/E;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,OAAO,CAAQ;gBAEX,MAAM,EAAE,oBAAoB;IAQxC;;OAEG;IACH,IAAI,IAAI,IAAI;IAOZ;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAkBjE;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAI9E;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7B;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAI/C;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,IAAI;IAOxD;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAInD;;OAEG;IACH,WAAW,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAIjE;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,GAAG,OAAO,GAAG,IAAI;IAI3D;;OAEG;IACH,OAAO,CAAC,WAAW;CAkBpB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,cAAc,CAIjF"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress Logger
|
|
3
|
+
*
|
|
4
|
+
* Append-only log for debugging agent activity.
|
|
5
|
+
* Format: timestamp|event_type|details
|
|
6
|
+
*/
|
|
7
|
+
import { appendFileSync, existsSync, mkdirSync, statSync, renameSync } from 'fs';
|
|
8
|
+
import { resolve, dirname } from 'path';
|
|
9
|
+
// Default max log size: 1MB
|
|
10
|
+
const DEFAULT_MAX_SIZE_BYTES = 1024 * 1024;
|
|
11
|
+
/**
|
|
12
|
+
* ProgressLogger appends events to a log file for debugging
|
|
13
|
+
*/
|
|
14
|
+
export class ProgressLogger {
|
|
15
|
+
config;
|
|
16
|
+
logPath;
|
|
17
|
+
stopped = false;
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.config = {
|
|
20
|
+
...config,
|
|
21
|
+
maxSizeBytes: config.maxSizeBytes ?? DEFAULT_MAX_SIZE_BYTES,
|
|
22
|
+
};
|
|
23
|
+
this.logPath = resolve(this.config.agentDir, 'progress.log');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Initialize the logger (create directory if needed)
|
|
27
|
+
*/
|
|
28
|
+
init() {
|
|
29
|
+
const dir = dirname(this.logPath);
|
|
30
|
+
if (!existsSync(dir)) {
|
|
31
|
+
mkdirSync(dir, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Stop the logger
|
|
36
|
+
*/
|
|
37
|
+
stop() {
|
|
38
|
+
this.stopped = true;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Log an event
|
|
42
|
+
*/
|
|
43
|
+
log(eventType, details) {
|
|
44
|
+
if (this.stopped)
|
|
45
|
+
return;
|
|
46
|
+
const timestamp = Date.now();
|
|
47
|
+
const detailsStr = typeof details === 'object' ? JSON.stringify(details) : details;
|
|
48
|
+
const line = `${timestamp}|${eventType}|${detailsStr}\n`;
|
|
49
|
+
try {
|
|
50
|
+
// Check if rotation is needed
|
|
51
|
+
this.maybeRotate();
|
|
52
|
+
// Append to log
|
|
53
|
+
appendFileSync(this.logPath, line);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
// Silently ignore errors - progress logging is best-effort
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Log agent start
|
|
61
|
+
*/
|
|
62
|
+
logStart(details) {
|
|
63
|
+
this.log('start', details);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Log phase change
|
|
67
|
+
*/
|
|
68
|
+
logPhase(phase) {
|
|
69
|
+
this.log('phase', { phase });
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Log tool call
|
|
73
|
+
*/
|
|
74
|
+
logTool(toolName, input) {
|
|
75
|
+
this.log('tool', { toolName, input: input ? JSON.stringify(input).substring(0, 200) : undefined });
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Log error
|
|
79
|
+
*/
|
|
80
|
+
logError(message, error) {
|
|
81
|
+
this.log('error', {
|
|
82
|
+
message,
|
|
83
|
+
error: error instanceof Error ? error.message : String(error),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Log recovery attempt
|
|
88
|
+
*/
|
|
89
|
+
logRecovery(attempt, reason) {
|
|
90
|
+
this.log('recovery', { attempt, reason });
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Log completion
|
|
94
|
+
*/
|
|
95
|
+
logComplete(details) {
|
|
96
|
+
this.log('complete', details ?? {});
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Log stop
|
|
100
|
+
*/
|
|
101
|
+
logStop(reason) {
|
|
102
|
+
this.log('stop', { reason });
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Rotate log file if it exceeds max size
|
|
106
|
+
*/
|
|
107
|
+
maybeRotate() {
|
|
108
|
+
try {
|
|
109
|
+
if (!existsSync(this.logPath))
|
|
110
|
+
return;
|
|
111
|
+
const stats = statSync(this.logPath);
|
|
112
|
+
if (stats.size >= this.config.maxSizeBytes) {
|
|
113
|
+
// Rotate: rename current to .old
|
|
114
|
+
const oldPath = `${this.logPath}.old`;
|
|
115
|
+
try {
|
|
116
|
+
renameSync(this.logPath, oldPath);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Ignore rotation errors
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Ignore stat errors
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Create a progress logger for an agent
|
|
130
|
+
*/
|
|
131
|
+
export function createProgressLogger(config) {
|
|
132
|
+
const logger = new ProgressLogger(config);
|
|
133
|
+
logger.init();
|
|
134
|
+
return logger;
|
|
135
|
+
}
|