@telora/factory 0.4.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/dist/audit.d.ts +69 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +376 -0
- package/dist/audit.js.map +1 -0
- package/dist/builder-completion.d.ts +35 -0
- package/dist/builder-completion.d.ts.map +1 -0
- package/dist/builder-completion.js +375 -0
- package/dist/builder-completion.js.map +1 -0
- package/dist/builder-spawner.d.ts +40 -0
- package/dist/builder-spawner.d.ts.map +1 -0
- package/dist/builder-spawner.js +493 -0
- package/dist/builder-spawner.js.map +1 -0
- package/dist/completion-gate.d.ts +52 -0
- package/dist/completion-gate.d.ts.map +1 -0
- package/dist/completion-gate.js +336 -0
- package/dist/completion-gate.js.map +1 -0
- package/dist/completion-report.d.ts +36 -0
- package/dist/completion-report.d.ts.map +1 -0
- package/dist/completion-report.js +348 -0
- package/dist/completion-report.js.map +1 -0
- package/dist/completion.d.ts +58 -0
- package/dist/completion.d.ts.map +1 -0
- package/dist/completion.js +287 -0
- package/dist/completion.js.map +1 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +57 -0
- package/dist/config.js.map +1 -0
- package/dist/context-manager.d.ts +152 -0
- package/dist/context-manager.d.ts.map +1 -0
- package/dist/context-manager.js +421 -0
- package/dist/context-manager.js.map +1 -0
- package/dist/crash-detection.d.ts +70 -0
- package/dist/crash-detection.d.ts.map +1 -0
- package/dist/crash-detection.js +123 -0
- package/dist/crash-detection.js.map +1 -0
- package/dist/crash-recovery.d.ts +83 -0
- package/dist/crash-recovery.d.ts.map +1 -0
- package/dist/crash-recovery.js +522 -0
- package/dist/crash-recovery.js.map +1 -0
- package/dist/crash-resolution.d.ts +34 -0
- package/dist/crash-resolution.d.ts.map +1 -0
- package/dist/crash-resolution.js +382 -0
- package/dist/crash-resolution.js.map +1 -0
- package/dist/escalation.d.ts +150 -0
- package/dist/escalation.d.ts.map +1 -0
- package/dist/escalation.js +352 -0
- package/dist/escalation.js.map +1 -0
- package/dist/execution-target.d.ts +31 -0
- package/dist/execution-target.d.ts.map +1 -0
- package/dist/execution-target.js +71 -0
- package/dist/execution-target.js.map +1 -0
- package/dist/execution-unit-init.d.ts +28 -0
- package/dist/execution-unit-init.d.ts.map +1 -0
- package/dist/execution-unit-init.js +115 -0
- package/dist/execution-unit-init.js.map +1 -0
- package/dist/execution.d.ts +17 -0
- package/dist/execution.d.ts.map +1 -0
- package/dist/execution.js +20 -0
- package/dist/execution.js.map +1 -0
- package/dist/factory-engine.d.ts +100 -0
- package/dist/factory-engine.d.ts.map +1 -0
- package/dist/factory-engine.js +243 -0
- package/dist/factory-engine.js.map +1 -0
- package/dist/gap-detection.d.ts +43 -0
- package/dist/gap-detection.d.ts.map +1 -0
- package/dist/gap-detection.js +149 -0
- package/dist/gap-detection.js.map +1 -0
- package/dist/gate-context.d.ts +23 -0
- package/dist/gate-context.d.ts.map +1 -0
- package/dist/gate-context.js +63 -0
- package/dist/gate-context.js.map +1 -0
- package/dist/gate-engine.d.ts +55 -0
- package/dist/gate-engine.d.ts.map +1 -0
- package/dist/gate-engine.js +191 -0
- package/dist/gate-engine.js.map +1 -0
- package/dist/gates/adversarial.d.ts +59 -0
- package/dist/gates/adversarial.d.ts.map +1 -0
- package/dist/gates/adversarial.js +426 -0
- package/dist/gates/adversarial.js.map +1 -0
- package/dist/gates/adversary-spawner.d.ts +35 -0
- package/dist/gates/adversary-spawner.d.ts.map +1 -0
- package/dist/gates/adversary-spawner.js +286 -0
- package/dist/gates/adversary-spawner.js.map +1 -0
- package/dist/gates/adversary-test-dir.d.ts +41 -0
- package/dist/gates/adversary-test-dir.d.ts.map +1 -0
- package/dist/gates/adversary-test-dir.js +150 -0
- package/dist/gates/adversary-test-dir.js.map +1 -0
- package/dist/gates/behavioral-parser.d.ts +32 -0
- package/dist/gates/behavioral-parser.d.ts.map +1 -0
- package/dist/gates/behavioral-parser.js +190 -0
- package/dist/gates/behavioral-parser.js.map +1 -0
- package/dist/gates/behavioral-runner.d.ts +36 -0
- package/dist/gates/behavioral-runner.d.ts.map +1 -0
- package/dist/gates/behavioral-runner.js +306 -0
- package/dist/gates/behavioral-runner.js.map +1 -0
- package/dist/gates/behavioral.d.ts +37 -0
- package/dist/gates/behavioral.d.ts.map +1 -0
- package/dist/gates/behavioral.js +485 -0
- package/dist/gates/behavioral.js.map +1 -0
- package/dist/gates/deterministic.d.ts +24 -0
- package/dist/gates/deterministic.d.ts.map +1 -0
- package/dist/gates/deterministic.js +186 -0
- package/dist/gates/deterministic.js.map +1 -0
- package/dist/git-factory.d.ts +59 -0
- package/dist/git-factory.d.ts.map +1 -0
- package/dist/git-factory.js +102 -0
- package/dist/git-factory.js.map +1 -0
- package/dist/guard-evaluation.d.ts +48 -0
- package/dist/guard-evaluation.d.ts.map +1 -0
- package/dist/guard-evaluation.js +416 -0
- package/dist/guard-evaluation.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/instance-completion.d.ts +34 -0
- package/dist/instance-completion.d.ts.map +1 -0
- package/dist/instance-completion.js +366 -0
- package/dist/instance-completion.js.map +1 -0
- package/dist/instance-lifecycle.d.ts +15 -0
- package/dist/instance-lifecycle.d.ts.map +1 -0
- package/dist/instance-lifecycle.js +18 -0
- package/dist/instance-lifecycle.js.map +1 -0
- package/dist/instance-phase-dispatch.d.ts +75 -0
- package/dist/instance-phase-dispatch.d.ts.map +1 -0
- package/dist/instance-phase-dispatch.js +674 -0
- package/dist/instance-phase-dispatch.js.map +1 -0
- package/dist/instance-poll-loop.d.ts +43 -0
- package/dist/instance-poll-loop.d.ts.map +1 -0
- package/dist/instance-poll-loop.js +360 -0
- package/dist/instance-poll-loop.js.map +1 -0
- package/dist/instance-state-machine.d.ts +52 -0
- package/dist/instance-state-machine.d.ts.map +1 -0
- package/dist/instance-state-machine.js +235 -0
- package/dist/instance-state-machine.js.map +1 -0
- package/dist/log-manager.d.ts +28 -0
- package/dist/log-manager.d.ts.map +1 -0
- package/dist/log-manager.js +71 -0
- package/dist/log-manager.js.map +1 -0
- package/dist/pipeline-evaluator.d.ts +61 -0
- package/dist/pipeline-evaluator.d.ts.map +1 -0
- package/dist/pipeline-evaluator.js +107 -0
- package/dist/pipeline-evaluator.js.map +1 -0
- package/dist/pipeline-metrics.d.ts +52 -0
- package/dist/pipeline-metrics.d.ts.map +1 -0
- package/dist/pipeline-metrics.js +40 -0
- package/dist/pipeline-metrics.js.map +1 -0
- package/dist/pipeline-traversal.d.ts +43 -0
- package/dist/pipeline-traversal.d.ts.map +1 -0
- package/dist/pipeline-traversal.js +68 -0
- package/dist/pipeline-traversal.js.map +1 -0
- package/dist/plan-parser.d.ts +76 -0
- package/dist/plan-parser.d.ts.map +1 -0
- package/dist/plan-parser.js +223 -0
- package/dist/plan-parser.js.map +1 -0
- package/dist/planning-phase.d.ts +52 -0
- package/dist/planning-phase.d.ts.map +1 -0
- package/dist/planning-phase.js +444 -0
- package/dist/planning-phase.js.map +1 -0
- package/dist/planning-prompt.d.ts +64 -0
- package/dist/planning-prompt.d.ts.map +1 -0
- package/dist/planning-prompt.js +251 -0
- package/dist/planning-prompt.js.map +1 -0
- package/dist/planning.d.ts +16 -0
- package/dist/planning.d.ts.map +1 -0
- package/dist/planning.js +17 -0
- package/dist/planning.js.map +1 -0
- package/dist/process-runner.d.ts +41 -0
- package/dist/process-runner.d.ts.map +1 -0
- package/dist/process-runner.js +81 -0
- package/dist/process-runner.js.map +1 -0
- package/dist/product-config.d.ts +34 -0
- package/dist/product-config.d.ts.map +1 -0
- package/dist/product-config.js +43 -0
- package/dist/product-config.js.map +1 -0
- package/dist/queries/cycle-evaluations.d.ts +23 -0
- package/dist/queries/cycle-evaluations.d.ts.map +1 -0
- package/dist/queries/cycle-evaluations.js +37 -0
- package/dist/queries/cycle-evaluations.js.map +1 -0
- package/dist/queries/escalations.d.ts +30 -0
- package/dist/queries/escalations.d.ts.map +1 -0
- package/dist/queries/escalations.js +42 -0
- package/dist/queries/escalations.js.map +1 -0
- package/dist/queries/execution-units.d.ts +76 -0
- package/dist/queries/execution-units.d.ts.map +1 -0
- package/dist/queries/execution-units.js +109 -0
- package/dist/queries/execution-units.js.map +1 -0
- package/dist/queries/gate-results.d.ts +32 -0
- package/dist/queries/gate-results.d.ts.map +1 -0
- package/dist/queries/gate-results.js +44 -0
- package/dist/queries/gate-results.js.map +1 -0
- package/dist/queries/instances.d.ts +51 -0
- package/dist/queries/instances.d.ts.map +1 -0
- package/dist/queries/instances.js +77 -0
- package/dist/queries/instances.js.map +1 -0
- package/dist/queries/sessions.d.ts +50 -0
- package/dist/queries/sessions.d.ts.map +1 -0
- package/dist/queries/sessions.js +81 -0
- package/dist/queries/sessions.js.map +1 -0
- package/dist/queries/shared.d.ts +38 -0
- package/dist/queries/shared.d.ts.map +1 -0
- package/dist/queries/shared.js +119 -0
- package/dist/queries/shared.js.map +1 -0
- package/dist/queries/specs.d.ts +12 -0
- package/dist/queries/specs.d.ts.map +1 -0
- package/dist/queries/specs.js +21 -0
- package/dist/queries/specs.js.map +1 -0
- package/dist/queries/strategies.d.ts +14 -0
- package/dist/queries/strategies.d.ts.map +1 -0
- package/dist/queries/strategies.js +18 -0
- package/dist/queries/strategies.js.map +1 -0
- package/dist/queries/work-units.d.ts +42 -0
- package/dist/queries/work-units.d.ts.map +1 -0
- package/dist/queries/work-units.js +57 -0
- package/dist/queries/work-units.js.map +1 -0
- package/dist/queries/workflows.d.ts +29 -0
- package/dist/queries/workflows.d.ts.map +1 -0
- package/dist/queries/workflows.js +103 -0
- package/dist/queries/workflows.js.map +1 -0
- package/dist/remediation-units.d.ts +40 -0
- package/dist/remediation-units.d.ts.map +1 -0
- package/dist/remediation-units.js +263 -0
- package/dist/remediation-units.js.map +1 -0
- package/dist/replanning.d.ts +72 -0
- package/dist/replanning.d.ts.map +1 -0
- package/dist/replanning.js +403 -0
- package/dist/replanning.js.map +1 -0
- package/dist/resource-limits.d.ts +62 -0
- package/dist/resource-limits.d.ts.map +1 -0
- package/dist/resource-limits.js +322 -0
- package/dist/resource-limits.js.map +1 -0
- package/dist/scheduler.d.ts +98 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +203 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/session-adapter.d.ts +89 -0
- package/dist/session-adapter.d.ts.map +1 -0
- package/dist/session-adapter.js +108 -0
- package/dist/session-adapter.js.map +1 -0
- package/dist/sop-generator.d.ts +29 -0
- package/dist/sop-generator.d.ts.map +1 -0
- package/dist/sop-generator.js +235 -0
- package/dist/sop-generator.js.map +1 -0
- package/dist/spec-profiles.d.ts +41 -0
- package/dist/spec-profiles.d.ts.map +1 -0
- package/dist/spec-profiles.js +131 -0
- package/dist/spec-profiles.js.map +1 -0
- package/dist/strategy-design-graph.d.ts +23 -0
- package/dist/strategy-design-graph.d.ts.map +1 -0
- package/dist/strategy-design-graph.js +205 -0
- package/dist/strategy-design-graph.js.map +1 -0
- package/dist/strategy-design-prompt.d.ts +28 -0
- package/dist/strategy-design-prompt.d.ts.map +1 -0
- package/dist/strategy-design-prompt.js +108 -0
- package/dist/strategy-design-prompt.js.map +1 -0
- package/dist/strategy-design-schema.d.ts +767 -0
- package/dist/strategy-design-schema.d.ts.map +1 -0
- package/dist/strategy-design-schema.js +126 -0
- package/dist/strategy-design-schema.js.map +1 -0
- package/dist/strategy-design.d.ts +69 -0
- package/dist/strategy-design.d.ts.map +1 -0
- package/dist/strategy-design.js +411 -0
- package/dist/strategy-design.js.map +1 -0
- package/dist/strategy-gating.d.ts +31 -0
- package/dist/strategy-gating.d.ts.map +1 -0
- package/dist/strategy-gating.js +276 -0
- package/dist/strategy-gating.js.map +1 -0
- package/dist/team-prompt-builder.d.ts +47 -0
- package/dist/team-prompt-builder.d.ts.map +1 -0
- package/dist/team-prompt-builder.js +362 -0
- package/dist/team-prompt-builder.js.map +1 -0
- package/dist/trace-engine.d.ts +40 -0
- package/dist/trace-engine.d.ts.map +1 -0
- package/dist/trace-engine.js +344 -0
- package/dist/trace-engine.js.map +1 -0
- package/dist/types.d.ts +612 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/unit-session-lifecycle.d.ts +78 -0
- package/dist/unit-session-lifecycle.d.ts.map +1 -0
- package/dist/unit-session-lifecycle.js +141 -0
- package/dist/unit-session-lifecycle.js.map +1 -0
- package/dist/unit-session.d.ts +30 -0
- package/dist/unit-session.d.ts.map +1 -0
- package/dist/unit-session.js +370 -0
- package/dist/unit-session.js.map +1 -0
- package/dist/watchdogs.d.ts +33 -0
- package/dist/watchdogs.d.ts.map +1 -0
- package/dist/watchdogs.js +170 -0
- package/dist/watchdogs.js.map +1 -0
- package/dist/work-unit-scheduler.d.ts +34 -0
- package/dist/work-unit-scheduler.d.ts.map +1 -0
- package/dist/work-unit-scheduler.js +91 -0
- package/dist/work-unit-scheduler.js.map +1 -0
- package/dist/workflow-transition.d.ts +90 -0
- package/dist/workflow-transition.d.ts.map +1 -0
- package/dist/workflow-transition.js +340 -0
- package/dist/workflow-transition.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution unit session lifecycle -- pure functions and process management.
|
|
3
|
+
*
|
|
4
|
+
* This module contains the testable parts of the unit session lifecycle
|
|
5
|
+
* that do NOT depend on @telora/daemon-core:
|
|
6
|
+
* - shouldResumeSession: resume-vs-fresh decision logic
|
|
7
|
+
* - terminateUnitSession: graceful session termination
|
|
8
|
+
* - terminateAllUnits: terminate all running units for an instance
|
|
9
|
+
*
|
|
10
|
+
* The spawn function (spawnUnitSession) lives in unit-session.ts since
|
|
11
|
+
* it depends on daemon-core for StreamJsonParser, ActivityTracker, etc.
|
|
12
|
+
*/
|
|
13
|
+
import type { ExecutionUnitState, FactoryInstanceState } from './types.js';
|
|
14
|
+
/** Context about the strategy being assigned to a unit. */
|
|
15
|
+
export interface UnitStrategyContext {
|
|
16
|
+
strategyId: string;
|
|
17
|
+
strategyName: string;
|
|
18
|
+
dependsOn: string[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Determine whether to resume an existing session or start fresh.
|
|
22
|
+
*
|
|
23
|
+
* Resume when:
|
|
24
|
+
* 1. The unit has a claudeSessionId from a previous run
|
|
25
|
+
* 2. The new strategy's dependsOn contains the unit's previousStrategyId
|
|
26
|
+
*
|
|
27
|
+
* This preserves valuable context when consecutive strategies are related.
|
|
28
|
+
*/
|
|
29
|
+
export declare function shouldResumeSession(unit: ExecutionUnitState, strategy: UnitStrategyContext): {
|
|
30
|
+
resume: boolean;
|
|
31
|
+
reason: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Gracefully terminate a running unit session.
|
|
35
|
+
*
|
|
36
|
+
* Closes stdin and sends SIGTERM. Used on instance cancellation,
|
|
37
|
+
* daemon shutdown, or unrecoverable error.
|
|
38
|
+
*/
|
|
39
|
+
export declare function terminateUnitSession(unit: ExecutionUnitState): void;
|
|
40
|
+
/**
|
|
41
|
+
* Terminate all running unit sessions for an instance.
|
|
42
|
+
*
|
|
43
|
+
* Used during instance cancellation or daemon shutdown.
|
|
44
|
+
*/
|
|
45
|
+
export declare function terminateAllUnits(state: FactoryInstanceState): void;
|
|
46
|
+
/**
|
|
47
|
+
* Validate that a claude_session_id still exists in active (non-terminal)
|
|
48
|
+
* factory sessions before attempting --resume.
|
|
49
|
+
*
|
|
50
|
+
* If the session is stale or the query fails, returns { valid: false } so
|
|
51
|
+
* the caller can fall back to a fresh spawn. The fetchActiveSessions callback
|
|
52
|
+
* is injected for testability (avoids daemon-core transitive dependency).
|
|
53
|
+
*
|
|
54
|
+
* @param claudeSessionId - The stored claude_session_id to validate.
|
|
55
|
+
* @param instanceId - The factory instance to search sessions for.
|
|
56
|
+
* @param slotIndex - The unit's slot index (for logging).
|
|
57
|
+
* @param fetchActiveSessions - Callback that returns active sessions for an instance.
|
|
58
|
+
* @returns { valid: true } if session found, { valid: false, reason } otherwise.
|
|
59
|
+
*/
|
|
60
|
+
export declare function validateSessionForResume(claudeSessionId: string, instanceId: string, slotIndex: number, fetchActiveSessions: (instanceId: string) => Promise<Array<{
|
|
61
|
+
claudeSessionId: string | null;
|
|
62
|
+
}>>): Promise<{
|
|
63
|
+
valid: boolean;
|
|
64
|
+
reason: string;
|
|
65
|
+
}>;
|
|
66
|
+
/**
|
|
67
|
+
* Consume pending gate failure feedback for a unit's assigned strategy.
|
|
68
|
+
*
|
|
69
|
+
* If the unit has an assigned strategy and state.gateFailureFeedback has
|
|
70
|
+
* stored feedback for it, returns the feedback and removes it from the map
|
|
71
|
+
* (but only when stdinAvailable is true -- otherwise the feedback is kept
|
|
72
|
+
* for the next spawn attempt).
|
|
73
|
+
*
|
|
74
|
+
* Returns the feedback string to send, or null if no feedback is pending
|
|
75
|
+
* or stdin is not available.
|
|
76
|
+
*/
|
|
77
|
+
export declare function consumeGateFailureFeedback(state: FactoryInstanceState, strategyId: string | null, stdinAvailable: boolean): string | null;
|
|
78
|
+
//# sourceMappingURL=unit-session-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-session-lifecycle.d.ts","sourceRoot":"","sources":["../src/unit-session-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAQpB,2DAA2D;AAC3D,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAMD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,mBAAmB,GAC5B;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAiBrC;AAMD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAoBnE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAMnE;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,wBAAwB,CAC5C,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,mBAAmB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC;IAAE,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAAC,GAC9F,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAmB7C;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,oBAAoB,EAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,cAAc,EAAE,OAAO,GACtB,MAAM,GAAG,IAAI,CASf"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution unit session lifecycle -- pure functions and process management.
|
|
3
|
+
*
|
|
4
|
+
* This module contains the testable parts of the unit session lifecycle
|
|
5
|
+
* that do NOT depend on @telora/daemon-core:
|
|
6
|
+
* - shouldResumeSession: resume-vs-fresh decision logic
|
|
7
|
+
* - terminateUnitSession: graceful session termination
|
|
8
|
+
* - terminateAllUnits: terminate all running units for an instance
|
|
9
|
+
*
|
|
10
|
+
* The spawn function (spawnUnitSession) lives in unit-session.ts since
|
|
11
|
+
* it depends on daemon-core for StreamJsonParser, ActivityTracker, etc.
|
|
12
|
+
*/
|
|
13
|
+
const LOG_PREFIX = '[unit-session]';
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// Resume-vs-fresh decision
|
|
16
|
+
// ============================================================================
|
|
17
|
+
/**
|
|
18
|
+
* Determine whether to resume an existing session or start fresh.
|
|
19
|
+
*
|
|
20
|
+
* Resume when:
|
|
21
|
+
* 1. The unit has a claudeSessionId from a previous run
|
|
22
|
+
* 2. The new strategy's dependsOn contains the unit's previousStrategyId
|
|
23
|
+
*
|
|
24
|
+
* This preserves valuable context when consecutive strategies are related.
|
|
25
|
+
*/
|
|
26
|
+
export function shouldResumeSession(unit, strategy) {
|
|
27
|
+
if (!unit.claudeSessionId) {
|
|
28
|
+
return { resume: false, reason: 'no prior session' };
|
|
29
|
+
}
|
|
30
|
+
if (!unit.previousStrategyId) {
|
|
31
|
+
return { resume: false, reason: 'no previous strategy' };
|
|
32
|
+
}
|
|
33
|
+
if (strategy.dependsOn.includes(unit.previousStrategyId)) {
|
|
34
|
+
return {
|
|
35
|
+
resume: true,
|
|
36
|
+
reason: `strategy "${strategy.strategyName}" depends on prior work`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return { resume: false, reason: 'no dependency on prior work' };
|
|
40
|
+
}
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Session termination
|
|
43
|
+
// ============================================================================
|
|
44
|
+
/**
|
|
45
|
+
* Gracefully terminate a running unit session.
|
|
46
|
+
*
|
|
47
|
+
* Closes stdin and sends SIGTERM. Used on instance cancellation,
|
|
48
|
+
* daemon shutdown, or unrecoverable error.
|
|
49
|
+
*/
|
|
50
|
+
export function terminateUnitSession(unit) {
|
|
51
|
+
if (!unit.pid)
|
|
52
|
+
return;
|
|
53
|
+
// Close stdin
|
|
54
|
+
if (unit.stdin && !unit.stdin.destroyed) {
|
|
55
|
+
unit.stdin.end();
|
|
56
|
+
}
|
|
57
|
+
// Send SIGTERM
|
|
58
|
+
try {
|
|
59
|
+
process.kill(unit.pid, 'SIGTERM');
|
|
60
|
+
console.log(`${LOG_PREFIX} Sent SIGTERM to unit ${unit.slotIndex} (pid: ${unit.pid})`);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Process already exited
|
|
64
|
+
}
|
|
65
|
+
// Mark as terminated (the close handler will reset to idle)
|
|
66
|
+
unit.status = 'terminated';
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Terminate all running unit sessions for an instance.
|
|
70
|
+
*
|
|
71
|
+
* Used during instance cancellation or daemon shutdown.
|
|
72
|
+
*/
|
|
73
|
+
export function terminateAllUnits(state) {
|
|
74
|
+
for (const unit of state.executionUnits.values()) {
|
|
75
|
+
if (unit.status === 'running') {
|
|
76
|
+
terminateUnitSession(unit);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// ============================================================================
|
|
81
|
+
// Session validation for resume
|
|
82
|
+
// ============================================================================
|
|
83
|
+
/**
|
|
84
|
+
* Validate that a claude_session_id still exists in active (non-terminal)
|
|
85
|
+
* factory sessions before attempting --resume.
|
|
86
|
+
*
|
|
87
|
+
* If the session is stale or the query fails, returns { valid: false } so
|
|
88
|
+
* the caller can fall back to a fresh spawn. The fetchActiveSessions callback
|
|
89
|
+
* is injected for testability (avoids daemon-core transitive dependency).
|
|
90
|
+
*
|
|
91
|
+
* @param claudeSessionId - The stored claude_session_id to validate.
|
|
92
|
+
* @param instanceId - The factory instance to search sessions for.
|
|
93
|
+
* @param slotIndex - The unit's slot index (for logging).
|
|
94
|
+
* @param fetchActiveSessions - Callback that returns active sessions for an instance.
|
|
95
|
+
* @returns { valid: true } if session found, { valid: false, reason } otherwise.
|
|
96
|
+
*/
|
|
97
|
+
export async function validateSessionForResume(claudeSessionId, instanceId, slotIndex, fetchActiveSessions) {
|
|
98
|
+
try {
|
|
99
|
+
const sessions = await fetchActiveSessions(instanceId);
|
|
100
|
+
const match = sessions.find((s) => s.claudeSessionId === claudeSessionId);
|
|
101
|
+
if (!match) {
|
|
102
|
+
const reason = `Unit ${slotIndex}: claude_session_id "${claudeSessionId}" ` +
|
|
103
|
+
`not found in active sessions -- falling back to fresh spawn`;
|
|
104
|
+
console.warn(`${LOG_PREFIX} ${reason}`);
|
|
105
|
+
return { valid: false, reason };
|
|
106
|
+
}
|
|
107
|
+
return { valid: true, reason: 'session found in active sessions' };
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
const reason = `Unit ${slotIndex}: session validation failed -- ` +
|
|
111
|
+
`falling back to fresh spawn: ${err.message}`;
|
|
112
|
+
console.warn(`${LOG_PREFIX} ${reason}`);
|
|
113
|
+
return { valid: false, reason };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// ============================================================================
|
|
117
|
+
// Gate failure feedback re-delivery
|
|
118
|
+
// ============================================================================
|
|
119
|
+
/**
|
|
120
|
+
* Consume pending gate failure feedback for a unit's assigned strategy.
|
|
121
|
+
*
|
|
122
|
+
* If the unit has an assigned strategy and state.gateFailureFeedback has
|
|
123
|
+
* stored feedback for it, returns the feedback and removes it from the map
|
|
124
|
+
* (but only when stdinAvailable is true -- otherwise the feedback is kept
|
|
125
|
+
* for the next spawn attempt).
|
|
126
|
+
*
|
|
127
|
+
* Returns the feedback string to send, or null if no feedback is pending
|
|
128
|
+
* or stdin is not available.
|
|
129
|
+
*/
|
|
130
|
+
export function consumeGateFailureFeedback(state, strategyId, stdinAvailable) {
|
|
131
|
+
if (!strategyId)
|
|
132
|
+
return null;
|
|
133
|
+
const feedback = state.gateFailureFeedback.get(strategyId);
|
|
134
|
+
if (!feedback)
|
|
135
|
+
return null;
|
|
136
|
+
if (!stdinAvailable)
|
|
137
|
+
return null;
|
|
138
|
+
state.gateFailureFeedback.delete(strategyId);
|
|
139
|
+
return feedback;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=unit-session-lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-session-lifecycle.js","sourceRoot":"","sources":["../src/unit-session-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,MAAM,UAAU,GAAG,gBAAgB,CAAC;AAapC,+EAA+E;AAC/E,2BAA2B;AAC3B,+EAA+E;AAE/E;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAwB,EACxB,QAA6B;IAE7B,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;QAC1B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IACvD,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC7B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IAC3D,CAAC;IAED,IAAI,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACzD,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,aAAa,QAAQ,CAAC,YAAY,yBAAyB;SACpE,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,6BAA6B,EAAE,CAAC;AAClE,CAAC;AAED,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAwB;IAC3D,IAAI,CAAC,IAAI,CAAC,GAAG;QAAE,OAAO;IAEtB,cAAc;IACd,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QACxC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;IACnB,CAAC;IAED,eAAe;IACf,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CACT,GAAG,UAAU,yBAAyB,IAAI,CAAC,SAAS,UAAU,IAAI,CAAC,GAAG,GAAG,CAC1E,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,yBAAyB;IAC3B,CAAC;IAED,4DAA4D;IAC5D,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAA2B;IAC3D,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,EAAE,CAAC;QACjD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,gCAAgC;AAChC,+EAA+E;AAE/E;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,eAAuB,EACvB,UAAkB,EAClB,SAAiB,EACjB,mBAA+F;IAE/F,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,KAAK,eAAe,CAAC,CAAC;QAC1E,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,MAAM,GACV,QAAQ,SAAS,wBAAwB,eAAe,IAAI;gBAC5D,6DAA6D,CAAC;YAChE,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,IAAI,MAAM,EAAE,CAAC,CAAC;YACxC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAClC,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,kCAAkC,EAAE,CAAC;IACrE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GACV,QAAQ,SAAS,iCAAiC;YAClD,gCAAiC,GAAa,CAAC,OAAO,EAAE,CAAC;QAC3D,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,IAAI,MAAM,EAAE,CAAC,CAAC;QACxC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAClC,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,oCAAoC;AACpC,+EAA+E;AAE/E;;;;;;;;;;GAUG;AACH,MAAM,UAAU,0BAA0B,CACxC,KAA2B,EAC3B,UAAyB,EACzB,cAAuB;IAEvB,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAE7B,MAAM,QAAQ,GAAG,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC3D,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,IAAI,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IAEjC,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC7C,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution unit session lifecycle -- spawn, exit handling, and termination.
|
|
3
|
+
*
|
|
4
|
+
* Each execution unit manages its own Claude Code session. The lifecycle is:
|
|
5
|
+
* assigned -> spawnUnitSession -> running -> (exit) -> idle
|
|
6
|
+
*
|
|
7
|
+
* Resume-vs-fresh decision: if the new strategy depends on the unit's
|
|
8
|
+
* previous strategy AND a claude_session_id exists, spawn with --resume.
|
|
9
|
+
* Otherwise start fresh.
|
|
10
|
+
*
|
|
11
|
+
* All communication with the session goes through a SessionCommunicationAdapter.
|
|
12
|
+
*/
|
|
13
|
+
import type { ResourceGovernor } from '@telora/daemon-core';
|
|
14
|
+
import type { FactoryConfig, FactoryInstanceState, ExecutionUnitState } from './types.js';
|
|
15
|
+
import type { SessionCommunicationAdapter } from './session-adapter.js';
|
|
16
|
+
import type { UnitStrategyContext } from './unit-session-lifecycle.js';
|
|
17
|
+
export { shouldResumeSession, validateSessionForResume, terminateUnitSession, terminateAllUnits } from './unit-session-lifecycle.js';
|
|
18
|
+
export type { UnitStrategyContext } from './unit-session-lifecycle.js';
|
|
19
|
+
/**
|
|
20
|
+
* Spawn a Claude Code session for an execution unit.
|
|
21
|
+
*
|
|
22
|
+
* Creates a factory_sessions record linked to the unit, launches Claude Code
|
|
23
|
+
* with Agent Teams enabled and stream-json I/O, sets up signal parsing via
|
|
24
|
+
* a SessionCommunicationAdapter, and sends the initial team lead prompt.
|
|
25
|
+
*
|
|
26
|
+
* On process exit: unit returns to 'idle', governor slot released, session
|
|
27
|
+
* marked completed/failed.
|
|
28
|
+
*/
|
|
29
|
+
export declare function spawnUnitSession(unit: ExecutionUnitState, strategy: UnitStrategyContext, state: FactoryInstanceState, config: FactoryConfig, governor?: ResourceGovernor | null): Promise<SessionCommunicationAdapter>;
|
|
30
|
+
//# sourceMappingURL=unit-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-session.d.ts","sourceRoot":"","sources":["../src/unit-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAeH,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,qBAAqB,CAAC;AAE9E,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAQpB,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAIxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAGvE,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrI,YAAY,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAQvE;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,kBAAkB,EACxB,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,aAAa,EACrB,QAAQ,CAAC,EAAE,gBAAgB,GAAG,IAAI,GACjC,OAAO,CAAC,2BAA2B,CAAC,CA+XtC"}
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execution unit session lifecycle -- spawn, exit handling, and termination.
|
|
3
|
+
*
|
|
4
|
+
* Each execution unit manages its own Claude Code session. The lifecycle is:
|
|
5
|
+
* assigned -> spawnUnitSession -> running -> (exit) -> idle
|
|
6
|
+
*
|
|
7
|
+
* Resume-vs-fresh decision: if the new strategy depends on the unit's
|
|
8
|
+
* previous strategy AND a claude_session_id exists, spawn with --resume.
|
|
9
|
+
* Otherwise start fresh.
|
|
10
|
+
*
|
|
11
|
+
* All communication with the session goes through a SessionCommunicationAdapter.
|
|
12
|
+
*/
|
|
13
|
+
import { spawn } from 'node:child_process';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { mkdirSync, existsSync } from 'node:fs';
|
|
16
|
+
import { buildStreamJsonArgs, stripClaudeCodeEnvVars, createLogStream, sendMessage, StreamJsonParser, ActivityTracker, buildOtelEnv, } from '@telora/daemon-core';
|
|
17
|
+
import { updateExecutionUnit } from './queries/execution-units.js';
|
|
18
|
+
import { createFactorySession, updateFactorySession } from './queries/sessions.js';
|
|
19
|
+
import { updateWorkUnitWorkflowStage } from './queries/work-units.js';
|
|
20
|
+
import { TokenSniffingTransform } from './queries/shared.js';
|
|
21
|
+
import { buildTeamLeadPrompt } from './team-prompt-builder.js';
|
|
22
|
+
import { McpAdapter } from './session-adapter.js';
|
|
23
|
+
import { getOrResolveWorkflow } from './workflow-transition.js';
|
|
24
|
+
import { buildWorkBatchDirective } from './team-prompt-builder.js';
|
|
25
|
+
import { shouldResumeSession, validateSessionForResume, terminateUnitSession, consumeGateFailureFeedback } from './unit-session-lifecycle.js';
|
|
26
|
+
// Re-export from lifecycle module (no daemon-core dep, so testable)
|
|
27
|
+
export { shouldResumeSession, validateSessionForResume, terminateUnitSession, terminateAllUnits } from './unit-session-lifecycle.js';
|
|
28
|
+
const LOG_PREFIX = '[unit-session]';
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Session spawning (TEL-2)
|
|
31
|
+
// ============================================================================
|
|
32
|
+
/**
|
|
33
|
+
* Spawn a Claude Code session for an execution unit.
|
|
34
|
+
*
|
|
35
|
+
* Creates a factory_sessions record linked to the unit, launches Claude Code
|
|
36
|
+
* with Agent Teams enabled and stream-json I/O, sets up signal parsing via
|
|
37
|
+
* a SessionCommunicationAdapter, and sends the initial team lead prompt.
|
|
38
|
+
*
|
|
39
|
+
* On process exit: unit returns to 'idle', governor slot released, session
|
|
40
|
+
* marked completed/failed.
|
|
41
|
+
*/
|
|
42
|
+
export async function spawnUnitSession(unit, strategy, state, config, governor) {
|
|
43
|
+
const worktreePath = state.worktreePath;
|
|
44
|
+
if (!worktreePath) {
|
|
45
|
+
throw new Error(`${LOG_PREFIX} Instance ${state.instanceId} has no worktreePath -- ` +
|
|
46
|
+
'cannot spawn unit session');
|
|
47
|
+
}
|
|
48
|
+
// Ensure log directory exists
|
|
49
|
+
if (!existsSync(config.logDir)) {
|
|
50
|
+
mkdirSync(config.logDir, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
// Log file paths
|
|
53
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
54
|
+
const logBaseName = `factory-${state.instanceId.slice(0, 8)}-unit${unit.slotIndex}-${timestamp}`;
|
|
55
|
+
const stdoutPath = join(config.logDir, `${logBaseName}.stdout.log`);
|
|
56
|
+
const stderrPath = join(config.logDir, `${logBaseName}.stderr.log`);
|
|
57
|
+
// Create session record in DB, linked to execution unit
|
|
58
|
+
const session = await createFactorySession({
|
|
59
|
+
instanceId: state.instanceId,
|
|
60
|
+
sessionType: 'builder',
|
|
61
|
+
workUnitId: null,
|
|
62
|
+
executionUnitId: unit.unitId,
|
|
63
|
+
stdoutPath,
|
|
64
|
+
stderrPath,
|
|
65
|
+
});
|
|
66
|
+
// Resume-vs-fresh decision
|
|
67
|
+
const decision = shouldResumeSession(unit, strategy);
|
|
68
|
+
let resumeClaudeSessionId = decision.resume ? unit.claudeSessionId : null;
|
|
69
|
+
// Validate the session exists and is not in a terminal state before resuming
|
|
70
|
+
if (resumeClaudeSessionId) {
|
|
71
|
+
const { getActiveSessionsForInstance } = await import('./queries/sessions.js');
|
|
72
|
+
const validation = await validateSessionForResume(resumeClaudeSessionId, state.instanceId, unit.slotIndex, getActiveSessionsForInstance);
|
|
73
|
+
if (!validation.valid) {
|
|
74
|
+
resumeClaudeSessionId = null;
|
|
75
|
+
unit.claudeSessionId = null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!resumeClaudeSessionId) {
|
|
79
|
+
// Clear stale session ID for a fresh start
|
|
80
|
+
unit.claudeSessionId = null;
|
|
81
|
+
}
|
|
82
|
+
console.log(`${LOG_PREFIX} Unit ${unit.slotIndex}: ${decision.resume ? 'resuming' : 'fresh'} session ` +
|
|
83
|
+
`(${decision.reason}) for strategy "${strategy.strategyName}"`);
|
|
84
|
+
// Build Claude Code arguments
|
|
85
|
+
const args = [];
|
|
86
|
+
if (resumeClaudeSessionId) {
|
|
87
|
+
args.push('--resume', resumeClaudeSessionId);
|
|
88
|
+
}
|
|
89
|
+
args.push(...buildStreamJsonArgs({ mcpConfigPath: config.mcpConfigPath }));
|
|
90
|
+
args.push('--teammate-mode', 'in-process');
|
|
91
|
+
// Acquire a resource governor slot
|
|
92
|
+
let slotAcquired = false;
|
|
93
|
+
if (governor) {
|
|
94
|
+
await governor.acquireSlot('factory');
|
|
95
|
+
slotAcquired = true;
|
|
96
|
+
}
|
|
97
|
+
// Build spawn environment
|
|
98
|
+
const env = buildUnitEnv(config, state);
|
|
99
|
+
const proc = spawn(config.claudeCodePath, args, {
|
|
100
|
+
cwd: worktreePath,
|
|
101
|
+
env,
|
|
102
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
103
|
+
});
|
|
104
|
+
const pid = proc.pid;
|
|
105
|
+
if (pid === undefined) {
|
|
106
|
+
if (slotAcquired)
|
|
107
|
+
governor.releaseSlot('factory');
|
|
108
|
+
await updateFactorySession(session.id, {
|
|
109
|
+
status: 'failed',
|
|
110
|
+
endedAt: new Date().toISOString(),
|
|
111
|
+
});
|
|
112
|
+
throw new Error(`${LOG_PREFIX} Failed to spawn unit process -- pid is undefined`);
|
|
113
|
+
}
|
|
114
|
+
// Update unit state
|
|
115
|
+
unit.pid = pid;
|
|
116
|
+
unit.status = 'running';
|
|
117
|
+
unit.startedAt = new Date();
|
|
118
|
+
unit.previousStrategyId = strategy.strategyId;
|
|
119
|
+
// Update DB records
|
|
120
|
+
await Promise.all([
|
|
121
|
+
updateExecutionUnit(unit.unitId, { status: 'running' }),
|
|
122
|
+
updateFactorySession(session.id, {
|
|
123
|
+
status: 'running',
|
|
124
|
+
pid,
|
|
125
|
+
startedAt: new Date().toISOString(),
|
|
126
|
+
}),
|
|
127
|
+
]);
|
|
128
|
+
// Pipe stderr to log file
|
|
129
|
+
const stderrStream = createLogStream(stderrPath);
|
|
130
|
+
proc.stderr?.pipe(stderrStream);
|
|
131
|
+
// Raw NDJSON stream log
|
|
132
|
+
const jsonlPath = join(config.logDir, `${logBaseName}.stream.jsonl`);
|
|
133
|
+
const jsonlStream = createLogStream(jsonlPath);
|
|
134
|
+
// Token-sniffing transform
|
|
135
|
+
const tokenParser = new TokenSniffingTransform();
|
|
136
|
+
proc.stdout?.pipe(tokenParser).pipe(jsonlStream);
|
|
137
|
+
// Set up StreamJsonParser
|
|
138
|
+
const streamParser = new StreamJsonParser();
|
|
139
|
+
if (proc.stdout) {
|
|
140
|
+
streamParser.attach(proc.stdout);
|
|
141
|
+
}
|
|
142
|
+
unit.streamParser = streamParser;
|
|
143
|
+
// Track stdout activity for signal silence watchdog
|
|
144
|
+
if (proc.stdout) {
|
|
145
|
+
proc.stdout.on('data', () => {
|
|
146
|
+
unit.lastActivityAt = new Date();
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// Capture Claude session ID from init event
|
|
150
|
+
streamParser.on('init', (event) => {
|
|
151
|
+
unit.claudeSessionId = event.session_id;
|
|
152
|
+
updateFactorySession(session.id, {
|
|
153
|
+
claudeSessionId: event.session_id,
|
|
154
|
+
}).catch((err) => {
|
|
155
|
+
console.warn(`${LOG_PREFIX} Failed to persist Claude session ID for unit ${unit.slotIndex}:`, err.message);
|
|
156
|
+
});
|
|
157
|
+
// Re-deliver pending gate failure feedback if the unit's strategy has any.
|
|
158
|
+
// This ensures a respawned session knows what gate failures to fix.
|
|
159
|
+
const pendingFeedback = consumeGateFailureFeedback(state, unit.assignedStrategyId, !!proc.stdin);
|
|
160
|
+
if (pendingFeedback) {
|
|
161
|
+
sendMessage(proc.stdin, pendingFeedback);
|
|
162
|
+
console.log(`${LOG_PREFIX} Re-delivered gate feedback for strategy ${unit.assignedStrategyId} ` +
|
|
163
|
+
`to unit ${unit.slotIndex} on resume`);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
// Activity tracker
|
|
167
|
+
const activityTracker = new ActivityTracker(session.id, async (snapshot) => {
|
|
168
|
+
await updateFactorySession(session.id, {
|
|
169
|
+
activitySummary: snapshot,
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
activityTracker.attach(streamParser);
|
|
173
|
+
unit.activityTracker = activityTracker;
|
|
174
|
+
// Wire narration
|
|
175
|
+
activityTracker.onNarration((text) => {
|
|
176
|
+
updateFactorySession(session.id, {
|
|
177
|
+
lastNarration: text,
|
|
178
|
+
lastNarrationAt: new Date().toISOString(),
|
|
179
|
+
}).catch((err) => {
|
|
180
|
+
console.warn(`${LOG_PREFIX} Failed to update narration for unit ${unit.slotIndex}:`, err.message);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
// Create the MCP communication adapter
|
|
184
|
+
const adapter = new McpAdapter({
|
|
185
|
+
instanceId: state.instanceId,
|
|
186
|
+
stdin: proc.stdin ?? null,
|
|
187
|
+
sendMessageFn: sendMessage,
|
|
188
|
+
buildDirectiveFn: buildWorkBatchDirective,
|
|
189
|
+
});
|
|
190
|
+
unit.adapter = adapter;
|
|
191
|
+
unit.stdin = proc.stdin ?? null;
|
|
192
|
+
// Wire work unit completion through the adapter.
|
|
193
|
+
// The agent already set status='completed' via MCP tool call,
|
|
194
|
+
// so we only update the workflow stage here.
|
|
195
|
+
adapter.onWorkUnitComplete((workUnitId) => {
|
|
196
|
+
console.log(`${LOG_PREFIX} Unit ${unit.slotIndex}: work unit complete for ${workUnitId}`);
|
|
197
|
+
// Remove completed unit from pending set and reset/clear dispatch timer
|
|
198
|
+
unit.dispatchedWorkUnitIds.delete(workUnitId);
|
|
199
|
+
if (unit.dispatchedWorkUnitIds.size > 0) {
|
|
200
|
+
// Restart timeout clock for remaining pending work units
|
|
201
|
+
unit.dispatchedAt = new Date();
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// All dispatched units completed -- clear the timer
|
|
205
|
+
unit.dispatchedAt = null;
|
|
206
|
+
}
|
|
207
|
+
const completeUnit = async () => {
|
|
208
|
+
const wuWorkflow = await getOrResolveWorkflow('factory_work_unit');
|
|
209
|
+
if (wuWorkflow) {
|
|
210
|
+
const completedStage = wuWorkflow.stageByName.get('completed');
|
|
211
|
+
if (completedStage) {
|
|
212
|
+
await updateWorkUnitWorkflowStage(workUnitId, completedStage.id);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
completeUnit().catch((err) => {
|
|
217
|
+
console.error(`${LOG_PREFIX} Failed to complete work unit ${workUnitId}:`, err.message);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
// Wire result events for cost/token tracking + error detection
|
|
221
|
+
streamParser.on('result', (resultEvent) => {
|
|
222
|
+
const usage = resultEvent.usage;
|
|
223
|
+
const totalCost = resultEvent.total_cost_usd;
|
|
224
|
+
if (usage) {
|
|
225
|
+
const inputTokens = typeof usage.input_tokens === 'number' ? usage.input_tokens : 0;
|
|
226
|
+
const outputTokens = typeof usage.output_tokens === 'number' ? usage.output_tokens : 0;
|
|
227
|
+
unit.tokensUsed += inputTokens + outputTokens;
|
|
228
|
+
state.tokensUsed += inputTokens + outputTokens;
|
|
229
|
+
}
|
|
230
|
+
if (typeof totalCost === 'number') {
|
|
231
|
+
unit.costUsed += totalCost;
|
|
232
|
+
state.costUsed += totalCost;
|
|
233
|
+
}
|
|
234
|
+
// Detect error results
|
|
235
|
+
if (resultEvent.is_error === true) {
|
|
236
|
+
const subtype = resultEvent.subtype ?? 'unknown';
|
|
237
|
+
const errors = Array.isArray(resultEvent.errors) ? resultEvent.errors : [];
|
|
238
|
+
console.error(`${LOG_PREFIX} Unit ${unit.slotIndex} result error (${subtype}): ${errors.join('; ') || 'no details'}`);
|
|
239
|
+
terminateUnitSession(unit);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
// Capture the strategy this session was spawned for. Used in the close handler
|
|
243
|
+
// to detect if the unit was eagerly re-assigned after gate pass, and skip
|
|
244
|
+
// overwriting the new assignment's state.
|
|
245
|
+
const sessionStrategyId = unit.assignedStrategyId;
|
|
246
|
+
// Handle process exit (TEL-4)
|
|
247
|
+
proc.on('close', (code) => {
|
|
248
|
+
if (slotAcquired)
|
|
249
|
+
governor.releaseSlot('factory');
|
|
250
|
+
// Null out process handles (safe regardless of assignment state)
|
|
251
|
+
unit.stdin = null;
|
|
252
|
+
unit.pid = null;
|
|
253
|
+
adapter.updateStdin(null);
|
|
254
|
+
console.log(`${LOG_PREFIX} Unit ${unit.slotIndex} session exited (code: ${code}, session: ${session.id})`);
|
|
255
|
+
const sessionStatus = code === 0 ? 'completed' : 'failed';
|
|
256
|
+
// Guard: if the unit has been eagerly released and re-assigned to a new
|
|
257
|
+
// strategy since this session was spawned, don't overwrite the new state.
|
|
258
|
+
if (unit.assignedStrategyId !== sessionStrategyId) {
|
|
259
|
+
console.log(`${LOG_PREFIX} Unit ${unit.slotIndex} was re-assigned since session start ` +
|
|
260
|
+
`-- skipping unit state reset`);
|
|
261
|
+
updateFactorySession(session.id, {
|
|
262
|
+
status: sessionStatus,
|
|
263
|
+
endedAt: new Date().toISOString(),
|
|
264
|
+
tokenCount: tokenParser.totalTokens || undefined,
|
|
265
|
+
costEstimate: tokenParser.usage?.totalCostUsd ?? undefined,
|
|
266
|
+
}).catch((err) => {
|
|
267
|
+
console.error(`${LOG_PREFIX} Failed to update session on unit ${unit.slotIndex} exit:`, err.message);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
// Normal path: release unit back to idle
|
|
272
|
+
unit.status = 'idle';
|
|
273
|
+
unit.assignedStrategyId = null;
|
|
274
|
+
unit.assignedAt = null;
|
|
275
|
+
unit.startedAt = null;
|
|
276
|
+
Promise.all([
|
|
277
|
+
updateExecutionUnit(unit.unitId, {
|
|
278
|
+
status: 'idle',
|
|
279
|
+
assignedStrategyId: null,
|
|
280
|
+
assignedAt: null,
|
|
281
|
+
}),
|
|
282
|
+
updateFactorySession(session.id, {
|
|
283
|
+
status: sessionStatus,
|
|
284
|
+
endedAt: new Date().toISOString(),
|
|
285
|
+
tokenCount: tokenParser.totalTokens || undefined,
|
|
286
|
+
costEstimate: tokenParser.usage?.totalCostUsd ?? undefined,
|
|
287
|
+
}),
|
|
288
|
+
]).catch((err) => {
|
|
289
|
+
console.error(`${LOG_PREFIX} Failed to update records on unit ${unit.slotIndex} exit:`, err.message);
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
// Dispose adapter
|
|
293
|
+
adapter.dispose();
|
|
294
|
+
// Clean up log streams
|
|
295
|
+
stderrStream.end();
|
|
296
|
+
jsonlStream.end();
|
|
297
|
+
});
|
|
298
|
+
proc.on('error', (error) => {
|
|
299
|
+
if (slotAcquired)
|
|
300
|
+
governor.releaseSlot('factory');
|
|
301
|
+
unit.stdin = null;
|
|
302
|
+
unit.pid = null;
|
|
303
|
+
adapter.updateStdin(null);
|
|
304
|
+
console.error(`${LOG_PREFIX} Unit ${unit.slotIndex} process error:`, error.message);
|
|
305
|
+
// Same re-assignment guard as the close handler
|
|
306
|
+
if (unit.assignedStrategyId !== sessionStrategyId) {
|
|
307
|
+
updateFactorySession(session.id, {
|
|
308
|
+
status: 'failed',
|
|
309
|
+
endedAt: new Date().toISOString(),
|
|
310
|
+
}).catch((err) => {
|
|
311
|
+
console.error(`${LOG_PREFIX} Failed to mark session ${session.id} as failed:`, err.message);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
unit.status = 'idle';
|
|
316
|
+
unit.assignedStrategyId = null;
|
|
317
|
+
unit.assignedAt = null;
|
|
318
|
+
unit.startedAt = null;
|
|
319
|
+
Promise.all([
|
|
320
|
+
updateExecutionUnit(unit.unitId, {
|
|
321
|
+
status: 'idle',
|
|
322
|
+
assignedStrategyId: null,
|
|
323
|
+
assignedAt: null,
|
|
324
|
+
}),
|
|
325
|
+
updateFactorySession(session.id, {
|
|
326
|
+
status: 'failed',
|
|
327
|
+
endedAt: new Date().toISOString(),
|
|
328
|
+
}),
|
|
329
|
+
]).catch((err) => {
|
|
330
|
+
console.error(`${LOG_PREFIX} Failed to update unit/session state for unit ${unit.slotIndex}:`, err.message);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
adapter.dispose();
|
|
334
|
+
stderrStream.end();
|
|
335
|
+
jsonlStream.end();
|
|
336
|
+
});
|
|
337
|
+
// Send initial team lead prompt (only if not resuming)
|
|
338
|
+
if (!resumeClaudeSessionId && proc.stdin) {
|
|
339
|
+
const initialPrompt = buildTeamLeadPrompt(state);
|
|
340
|
+
sendMessage(proc.stdin, initialPrompt);
|
|
341
|
+
}
|
|
342
|
+
console.log(`${LOG_PREFIX} Spawned unit ${unit.slotIndex} session ` +
|
|
343
|
+
`(session: ${session.id}, pid: ${pid}, strategy: "${strategy.strategyName}")`);
|
|
344
|
+
return adapter;
|
|
345
|
+
}
|
|
346
|
+
// ============================================================================
|
|
347
|
+
// Environment builder
|
|
348
|
+
// ============================================================================
|
|
349
|
+
/**
|
|
350
|
+
* Build the spawn environment for a unit session.
|
|
351
|
+
*/
|
|
352
|
+
function buildUnitEnv(config, state) {
|
|
353
|
+
const env = stripClaudeCodeEnvVars({
|
|
354
|
+
...process.env,
|
|
355
|
+
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: '1',
|
|
356
|
+
TELORA_TRACKER_ID: config.trackerId,
|
|
357
|
+
}, { preserve: ['CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS'] });
|
|
358
|
+
const otelEnv = buildOtelEnv({
|
|
359
|
+
enabled: config.telemetry.enabled,
|
|
360
|
+
port: config.telemetry.port,
|
|
361
|
+
resourceAttributes: {
|
|
362
|
+
'telora.org_id': config.organizationId,
|
|
363
|
+
'telora.instance_id': state.instanceId,
|
|
364
|
+
'telora.spec_id': state.specId ?? undefined,
|
|
365
|
+
},
|
|
366
|
+
});
|
|
367
|
+
Object.assign(env, otelEnv);
|
|
368
|
+
return env;
|
|
369
|
+
}
|
|
370
|
+
//# sourceMappingURL=unit-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-session.js","sourceRoot":"","sources":["../src/unit-session.ts"],"names":[],"mappings":"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"}
|