principles-disciple 1.11.0 → 1.13.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.
Files changed (233) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +66 -0
  3. package/esbuild.config.js +1 -1
  4. package/openclaw.plugin.json +4 -4
  5. package/package.json +2 -3
  6. package/run-nocturnal.mjs +30 -0
  7. package/scripts/db-migrate.mjs +170 -0
  8. package/scripts/sync-plugin.mjs +250 -6
  9. package/src/commands/archive-impl.ts +136 -0
  10. package/src/commands/capabilities.ts +4 -2
  11. package/src/commands/context.ts +5 -1
  12. package/src/commands/disable-impl.ts +151 -0
  13. package/src/commands/evolution-status.ts +64 -19
  14. package/src/commands/export.ts +8 -6
  15. package/src/commands/focus.ts +8 -20
  16. package/src/commands/nocturnal-review.ts +5 -7
  17. package/src/commands/nocturnal-rollout.ts +1 -12
  18. package/src/commands/nocturnal-train.ts +21 -47
  19. package/src/commands/pain.ts +10 -5
  20. package/src/commands/principle-rollback.ts +4 -2
  21. package/src/commands/promote-impl.ts +274 -0
  22. package/src/commands/rollback-impl.ts +234 -0
  23. package/src/commands/rollback.ts +6 -3
  24. package/src/commands/samples.ts +2 -0
  25. package/src/commands/thinking-os.ts +3 -4
  26. package/src/commands/workflow-debug.ts +2 -1
  27. package/src/config/errors.ts +1 -0
  28. package/src/core/AGENTS.md +34 -0
  29. package/src/core/adaptive-thresholds.ts +4 -3
  30. package/src/core/code-implementation-storage.ts +241 -0
  31. package/src/core/config.ts +5 -2
  32. package/src/core/control-ui-db.ts +29 -10
  33. package/src/core/detection-funnel.ts +12 -7
  34. package/src/core/diagnostician-task-store.ts +156 -0
  35. package/src/core/dictionary.ts +4 -4
  36. package/src/core/empathy-keyword-matcher.ts +7 -3
  37. package/src/core/empathy-types.ts +13 -2
  38. package/src/core/event-log.ts +14 -6
  39. package/src/core/evolution-engine.ts +27 -31
  40. package/src/core/evolution-logger.ts +3 -2
  41. package/src/core/evolution-reducer.ts +110 -31
  42. package/src/core/evolution-types.ts +10 -0
  43. package/src/core/external-training-contract.ts +1 -0
  44. package/src/core/focus-history.ts +38 -24
  45. package/src/core/hygiene/tracker.ts +10 -6
  46. package/src/core/init.ts +5 -2
  47. package/src/core/migration.ts +3 -3
  48. package/src/core/model-deployment-registry.ts +6 -4
  49. package/src/core/model-training-registry.ts +5 -3
  50. package/src/core/nocturnal-arbiter.ts +13 -14
  51. package/src/core/nocturnal-artifact-lineage.ts +117 -0
  52. package/src/core/nocturnal-artificer.ts +257 -0
  53. package/src/core/nocturnal-candidate-scoring.ts +4 -2
  54. package/src/core/nocturnal-compliance.ts +67 -19
  55. package/src/core/nocturnal-dataset.ts +95 -2
  56. package/src/core/nocturnal-executability.ts +2 -3
  57. package/src/core/nocturnal-export.ts +6 -3
  58. package/src/core/nocturnal-rule-implementation-validator.ts +245 -0
  59. package/src/core/nocturnal-trajectory-extractor.ts +10 -3
  60. package/src/core/nocturnal-trinity.ts +319 -61
  61. package/src/core/pain-context-extractor.ts +29 -15
  62. package/src/core/pain.ts +7 -5
  63. package/src/core/path-resolver.ts +16 -15
  64. package/src/core/paths.ts +2 -1
  65. package/src/core/pd-task-reconciler.ts +463 -0
  66. package/src/core/pd-task-service.ts +42 -0
  67. package/src/core/pd-task-store.ts +77 -0
  68. package/src/core/pd-task-types.ts +128 -0
  69. package/src/core/principle-internalization/deprecated-readiness.ts +91 -0
  70. package/src/core/principle-internalization/internalization-routing-policy.ts +208 -0
  71. package/src/core/principle-internalization/lifecycle-metrics.ts +149 -0
  72. package/src/core/principle-internalization/lifecycle-read-model.ts +243 -0
  73. package/src/core/principle-internalization/lifecycle-refresh.ts +11 -0
  74. package/src/core/principle-internalization/principle-lifecycle-service.ts +167 -0
  75. package/src/core/principle-training-state.ts +95 -370
  76. package/src/core/principle-tree-ledger.ts +733 -0
  77. package/src/core/principle-tree-migration.ts +195 -0
  78. package/src/core/profile.ts +3 -1
  79. package/src/core/promotion-gate.ts +14 -18
  80. package/src/core/replay-engine.ts +562 -0
  81. package/src/core/risk-calculator.ts +6 -4
  82. package/src/core/rule-host-helpers.ts +39 -0
  83. package/src/core/rule-host-types.ts +82 -0
  84. package/src/core/rule-host.ts +245 -0
  85. package/src/core/rule-implementation-runtime.ts +38 -0
  86. package/src/core/schema/db-types.ts +16 -0
  87. package/src/core/schema/index.ts +26 -0
  88. package/src/core/schema/migration-runner.ts +207 -0
  89. package/src/core/schema/migrations/001-init-trajectory.ts +211 -0
  90. package/src/core/schema/migrations/002-init-central.ts +122 -0
  91. package/src/core/schema/migrations/003-init-workflow.ts +55 -0
  92. package/src/core/schema/migrations/004-add-thinking-and-gfi.ts +74 -0
  93. package/src/core/schema/migrations/index.ts +31 -0
  94. package/src/core/schema/schema-definitions.ts +650 -0
  95. package/src/core/session-tracker.ts +6 -4
  96. package/src/core/shadow-observation-registry.ts +6 -3
  97. package/src/core/system-logger.ts +2 -2
  98. package/src/core/thinking-models.ts +182 -46
  99. package/src/core/thinking-os-parser.ts +156 -0
  100. package/src/core/training-program.ts +7 -7
  101. package/src/core/trajectory.ts +42 -36
  102. package/src/core/workspace-context.ts +77 -11
  103. package/src/core/workspace-dir-validation.ts +152 -0
  104. package/src/hooks/AGENTS.md +31 -0
  105. package/src/hooks/bash-risk.ts +3 -1
  106. package/src/hooks/edit-verification.ts +9 -5
  107. package/src/hooks/gate-block-helper.ts +5 -1
  108. package/src/hooks/gate.ts +152 -5
  109. package/src/hooks/gfi-gate.ts +9 -2
  110. package/src/hooks/lifecycle-routing.ts +124 -0
  111. package/src/hooks/lifecycle.ts +12 -12
  112. package/src/hooks/llm.ts +17 -109
  113. package/src/hooks/message-sanitize.ts +5 -3
  114. package/src/hooks/pain.ts +19 -15
  115. package/src/hooks/progressive-trust-gate.ts +7 -1
  116. package/src/hooks/prompt.ts +169 -60
  117. package/src/hooks/subagent.ts +5 -4
  118. package/src/hooks/thinking-checkpoint.ts +2 -0
  119. package/src/hooks/trajectory-collector.ts +15 -12
  120. package/src/http/principles-console-route.ts +31 -68
  121. package/src/i18n/commands.ts +2 -2
  122. package/src/index.ts +130 -40
  123. package/src/service/central-database.ts +131 -43
  124. package/src/service/central-health-service.ts +47 -0
  125. package/src/service/central-overview-service.ts +135 -0
  126. package/src/service/central-sync-service.ts +87 -0
  127. package/src/service/control-ui-query-service.ts +46 -36
  128. package/src/service/event-log-auditor.ts +261 -0
  129. package/src/service/evolution-query-service.ts +23 -22
  130. package/src/service/evolution-worker.ts +565 -261
  131. package/src/service/health-query-service.ts +213 -36
  132. package/src/service/nocturnal-runtime.ts +8 -4
  133. package/src/service/nocturnal-service.ts +503 -59
  134. package/src/service/nocturnal-target-selector.ts +5 -7
  135. package/src/service/runtime-summary-service.ts +2 -1
  136. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +25 -336
  137. package/src/service/subagent-workflow/dynamic-timeout.ts +30 -0
  138. package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +48 -386
  139. package/src/service/subagent-workflow/index.ts +2 -0
  140. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +169 -284
  141. package/src/service/subagent-workflow/runtime-direct-driver.ts +114 -16
  142. package/src/service/subagent-workflow/subagent-error-utils.ts +25 -0
  143. package/src/service/subagent-workflow/types.ts +9 -4
  144. package/src/service/subagent-workflow/workflow-manager-base.ts +573 -0
  145. package/src/service/subagent-workflow/workflow-store.ts +71 -11
  146. package/src/service/trajectory-service.ts +2 -1
  147. package/src/tools/critique-prompt.ts +1 -1
  148. package/src/tools/deep-reflect.ts +175 -209
  149. package/src/tools/model-index.ts +2 -1
  150. package/src/types/event-types.ts +2 -2
  151. package/src/types/principle-tree-schema.ts +29 -23
  152. package/src/utils/file-lock.ts +5 -3
  153. package/src/utils/io.ts +5 -2
  154. package/src/utils/nlp.ts +5 -46
  155. package/src/utils/node-vm-polyfill.ts +11 -0
  156. package/src/utils/plugin-logger.ts +2 -0
  157. package/src/utils/retry.ts +572 -0
  158. package/src/utils/subagent-probe.ts +1 -1
  159. package/templates/langs/en/core/AGENTS.md +0 -13
  160. package/templates/langs/en/core/SOUL.md +1 -31
  161. package/templates/langs/en/core/TOOLS.md +0 -4
  162. package/templates/langs/en/principles/THINKING_OS.md +77 -0
  163. package/templates/langs/en/skills/admin/SKILL.md +0 -1
  164. package/templates/langs/en/skills/evolution-framework-update/SKILL.md +1 -1
  165. package/templates/langs/en/skills/pd-diagnostician/SKILL.md +18 -5
  166. package/templates/langs/zh/core/AGENTS.md +0 -22
  167. package/templates/langs/zh/core/SOUL.md +1 -31
  168. package/templates/langs/zh/core/TOOLS.md +0 -4
  169. package/templates/langs/zh/principles/THINKING_OS.md +77 -0
  170. package/templates/langs/zh/skills/admin/SKILL.md +0 -1
  171. package/templates/langs/zh/skills/evolution-framework-update/SKILL.md +1 -1
  172. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +25 -4
  173. package/tests/commands/evolution-status.test.ts +119 -0
  174. package/tests/commands/implementation-lifecycle.test.ts +362 -0
  175. package/tests/core/code-implementation-storage.test.ts +398 -0
  176. package/tests/core/evolution-reducer.detector-metadata.test.ts +28 -28
  177. package/tests/core/nocturnal-artifact-lineage.test.ts +53 -0
  178. package/tests/core/nocturnal-artificer.test.ts +241 -0
  179. package/tests/core/nocturnal-compliance-p-principles.test.ts +133 -0
  180. package/tests/core/nocturnal-rule-implementation-validator.test.ts +127 -0
  181. package/tests/core/pd-task-store.test.ts +126 -0
  182. package/tests/core/principle-internalization/deprecated-readiness.test.ts +193 -0
  183. package/tests/core/principle-internalization/internalization-routing-policy.test.ts +212 -0
  184. package/tests/core/principle-internalization/lifecycle-metrics.test.ts +350 -0
  185. package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +211 -0
  186. package/tests/core/principle-training-state.test.ts +228 -1
  187. package/tests/core/principle-tree-ledger.test.ts +423 -0
  188. package/tests/core/regression-v1-9-1.test.ts +265 -0
  189. package/tests/core/replay-engine.test.ts +234 -0
  190. package/tests/core/rule-host-helpers.test.ts +120 -0
  191. package/tests/core/rule-host.test.ts +389 -0
  192. package/tests/core/rule-implementation-runtime.test.ts +64 -0
  193. package/tests/core/workspace-context.test.ts +53 -0
  194. package/tests/core/workspace-dir-validation.test.ts +272 -0
  195. package/tests/hooks/gate-rule-host-pipeline.test.ts +385 -0
  196. package/tests/hooks/pain.test.ts +74 -10
  197. package/tests/hooks/prompt.test.ts +63 -1
  198. package/tests/integration/principle-lifecycle.e2e.test.ts +197 -0
  199. package/tests/integration/tool-hooks-workspace-dir.e2e.test.ts +211 -0
  200. package/tests/service/data-endpoints-regression.test.ts +834 -0
  201. package/tests/service/evolution-worker.test.ts +0 -123
  202. package/tests/service/nocturnal-service-code-candidate.test.ts +330 -0
  203. package/tests/utils/nlp.test.ts +1 -19
  204. package/tests/utils/retry.test.ts +327 -0
  205. package/ui/src/App.tsx +1 -1
  206. package/ui/src/api.ts +4 -0
  207. package/ui/src/charts.tsx +366 -0
  208. package/ui/src/components/WorkspaceConfig.tsx +107 -75
  209. package/ui/src/i18n/ui.ts +89 -31
  210. package/ui/src/pages/EvolutionPage.tsx +1 -1
  211. package/ui/src/pages/OverviewPage.tsx +441 -81
  212. package/ui/src/pages/ThinkingModelsPage.tsx +287 -69
  213. package/ui/src/styles.css +43 -0
  214. package/ui/src/types.ts +17 -1
  215. package/src/agents/nocturnal-dreamer.md +0 -152
  216. package/src/agents/nocturnal-philosopher.md +0 -138
  217. package/src/agents/nocturnal-reflector.md +0 -126
  218. package/src/agents/nocturnal-scribe.md +0 -164
  219. package/templates/workspace/.principles/00-kernel.md +0 -51
  220. package/templates/workspace/.principles/DECISION_POLICY.json +0 -44
  221. package/templates/workspace/.principles/PRINCIPLES.md +0 -20
  222. package/templates/workspace/.principles/PROFILE.json +0 -54
  223. package/templates/workspace/.principles/PROFILE.schema.json +0 -56
  224. package/templates/workspace/.principles/THINKING_OS.md +0 -64
  225. package/templates/workspace/.principles/THINKING_OS_ARCHIVE.md +0 -7
  226. package/templates/workspace/.principles/THINKING_OS_CANDIDATES.md +0 -9
  227. package/templates/workspace/.principles/models/_INDEX.md +0 -27
  228. package/templates/workspace/.principles/models/first_principles.md +0 -62
  229. package/templates/workspace/.principles/models/marketing_4p.md +0 -52
  230. package/templates/workspace/.principles/models/porter_five.md +0 -63
  231. package/templates/workspace/.principles/models/swot.md +0 -60
  232. package/templates/workspace/.principles/models/user_story_map.md +0 -63
  233. package/templates/workspace/.state/WORKBOARD.json +0 -4
@@ -36,22 +36,18 @@
36
36
  * - diagnostics: scoring and filtering details
37
37
  */
38
38
 
39
- import {
39
+ import type {
40
40
  NocturnalTrajectoryExtractor,
41
41
  NocturnalSessionSummary,
42
42
  } from '../core/nocturnal-trajectory-extractor.js';
43
43
  import {
44
44
  listEvaluablePrinciples,
45
- loadStore,
46
45
  type PrincipleTrainingState,
47
46
  } from '../core/principle-training-state.js';
48
47
  import {
49
48
  checkWorkspaceIdle,
50
49
  checkCooldown,
51
- checkPreflight,
52
50
  DEFAULT_IDLE_THRESHOLD_MS,
53
- DEFAULT_PRINCIPLE_COOLDOWN_MS,
54
- DEFAULT_GLOBAL_COOLDOWN_MS,
55
51
  type IdleCheckResult,
56
52
  } from './nocturnal-runtime.js';
57
53
  import { detectViolation } from '../core/nocturnal-compliance.js';
@@ -290,6 +286,7 @@ export class NocturnalTargetSelector {
290
286
  recentMaxPainScore: number;
291
287
  };
292
288
 
289
+ /* eslint-disable @typescript-eslint/max-params -- Reason: Constructor requires all parameters for proper initialization */
293
290
  constructor(
294
291
  workspaceDir: string,
295
292
  stateDir: string,
@@ -425,7 +422,7 @@ export class NocturnalTargetSelector {
425
422
  diagnostics.passedPrinciples = activeCandidates.map((p) => p.principleId);
426
423
 
427
424
  // Select the top candidate
428
- const selected = activeCandidates[0];
425
+ const [selected] = activeCandidates;
429
426
  diagnostics.selectedPrincipleScore = selected.score;
430
427
 
431
428
  // Step 5: Find violating sessions for the selected principle
@@ -500,7 +497,7 @@ export class NocturnalTargetSelector {
500
497
 
501
498
  // Sort by violation severity descending (most violating first)
502
499
  violating.sort((a, b) => b.violationSeverity - a.violationSeverity);
503
- const selectedSession = violating[0];
500
+ const [selectedSession] = violating;
504
501
  diagnostics.selectedSessionViolationDensity = selectedSession.violationSeverity;
505
502
 
506
503
  return {
@@ -521,6 +518,7 @@ export class NocturnalTargetSelector {
521
518
  *
522
519
  * This is a convenience wrapper for the common case.
523
520
  */
521
+ /* eslint-disable @typescript-eslint/max-params -- Reason: Function signature requires all parameters for type-safe selection */
524
522
  export function selectNocturnalTarget(
525
523
  workspaceDir: string,
526
524
  stateDir: string,
@@ -5,7 +5,7 @@ import { listSessions } from '../core/session-tracker.js';
5
5
  import { WorkspaceContext } from '../core/workspace-context.js';
6
6
  import { evaluatePhase3Inputs } from './phase3-input-filter.js';
7
7
  import { TrajectoryRegistry } from '../core/trajectory.js';
8
- import type { RuntimeTruth, AnalyticsTruth, TrendMetrics } from '../types/runtime-summary.js';
8
+ import type { RuntimeTruth, AnalyticsTruth } from '../types/runtime-summary.js';
9
9
 
10
10
  export type RuntimeDataQuality = 'authoritative' | 'partial';
11
11
  export type RuntimeRewardPolicy =
@@ -418,6 +418,7 @@ export class RuntimeSummaryService {
418
418
  * NOT a truth source for Phase 3 eligibility or decisions.
419
419
  * Queue is the only authoritative execution truth source.
420
420
  */
421
+ /* eslint-disable @typescript-eslint/max-params -- Reason: Directive summary requires queue, directive, timestamp, and warnings */
421
422
  private static buildDirectiveSummary(
422
423
  queue: QueueItem[] | null,
423
424
  directive: DirectiveFile | null,
@@ -1,21 +1,18 @@
1
1
  import type { PluginLogger } from '../../openclaw-sdk.js';
2
2
  import type {
3
- WorkflowManager,
4
- WorkflowHandle,
5
3
  SubagentWorkflowSpec,
6
- WorkflowMetadata,
7
- WorkflowDebugSummary,
8
4
  DeepReflectResult,
9
5
  WorkflowResultContext,
10
6
  WorkflowPersistContext,
7
+ WorkflowHandle,
11
8
  } from './types.js';
12
9
 
13
10
  // Re-export DeepReflectResult so index.ts can re-export it
14
11
  export type { DeepReflectResult } from './types.js';
15
- import { RuntimeDirectDriver, type RunParams } from './runtime-direct-driver.js';
16
- import { WorkflowStore } from './workflow-store.js';
12
+ import type { RuntimeDirectDriver } from './runtime-direct-driver.js';
17
13
  import { isSubagentRuntimeAvailable } from '../../utils/subagent-probe.js';
18
14
  import { buildCritiquePromptV2 } from '../../tools/critique-prompt.js';
15
+ import { WorkflowManagerBase } from './workflow-manager-base.js';
19
16
 
20
17
  const WORKFLOW_SESSION_PREFIX = 'agent:main:subagent:workflow-';
21
18
 
@@ -26,23 +23,22 @@ export interface DeepReflectWorkflowOptions {
26
23
  workspaceDir: string;
27
24
  logger: PluginLogger;
28
25
  subagent: RuntimeDirectDriver['subagent'];
26
+ /** Pass api.runtime.agent.session to enable heartbeat-safe cleanup (#188) */
27
+ agentSession?: RuntimeDirectDriver['agentSession'];
29
28
  }
30
29
 
31
- export class DeepReflectWorkflowManager implements WorkflowManager {
32
- private readonly store: WorkflowStore;
33
- private readonly driver: RuntimeDirectDriver;
34
- private readonly logger: PluginLogger;
35
- private readonly workspaceDir: string;
36
-
37
- private activeWorkflows = new Map<string, NodeJS.Timeout>();
38
- private completedWorkflows = new Map<string, number>();
39
- private workflowSpecs = new Map<string, SubagentWorkflowSpec<unknown>>();
40
-
30
+ export class DeepReflectWorkflowManager extends WorkflowManagerBase {
41
31
  constructor(opts: DeepReflectWorkflowOptions) {
42
- this.workspaceDir = opts.workspaceDir;
43
- this.logger = opts.logger;
44
- this.store = new WorkflowStore({ workspaceDir: opts.workspaceDir });
45
- this.driver = new RuntimeDirectDriver({ subagent: opts.subagent, logger: opts.logger });
32
+ super({
33
+ workspaceDir: opts.workspaceDir,
34
+ logger: opts.logger,
35
+ subagent: opts.subagent,
36
+ agentSession: opts.agentSession,
37
+ workflowType: 'deep-reflect',
38
+ sessionPrefix: WORKFLOW_SESSION_PREFIX,
39
+ defaultTimeoutMs: DEFAULT_TIMEOUT_MS,
40
+ defaultTtlMs: DEFAULT_TTL_MS,
41
+ });
46
42
  }
47
43
 
48
44
  async startWorkflow<TResult>(
@@ -54,21 +50,6 @@ export class DeepReflectWorkflowManager implements WorkflowManager {
54
50
  metadata?: Record<string, unknown>;
55
51
  }
56
52
  ): Promise<WorkflowHandle> {
57
- const workflowId = this.generateWorkflowId();
58
- const childSessionKey = this.buildChildSessionKey(options.parentSessionId);
59
- const now = Date.now();
60
-
61
- const metadata: WorkflowMetadata = {
62
- parentSessionId: options.parentSessionId,
63
- workspaceDir: options.workspaceDir,
64
- taskInput: options.taskInput,
65
- startedAt: now,
66
- workflowType: spec.workflowType,
67
- ...options.metadata,
68
- };
69
-
70
- this.logger.info(`[PD:DeepReflectWorkflow] Starting workflow: workflowId=${workflowId}, type=${spec.workflowType}`);
71
-
72
53
  // Surface degrade: skip boot sessions
73
54
  if (options.parentSessionId.startsWith('boot-')) {
74
55
  this.logger.info(`[PD:DeepReflectWorkflow] Skipping workflow: boot session`);
@@ -85,311 +66,16 @@ export class DeepReflectWorkflowManager implements WorkflowManager {
85
66
  throw new Error(`DeepReflectWorkflowManager only supports runtime_direct transport`);
86
67
  }
87
68
 
88
- const runParams = this.buildRunParams(spec, options, childSessionKey);
89
- const runResult = await this.driver.run(runParams);
90
-
91
- this.store.createWorkflow({
92
- workflow_id: workflowId,
93
- workflow_type: spec.workflowType,
94
- transport: spec.transport,
95
- parent_session_id: options.parentSessionId,
96
- child_session_key: childSessionKey,
97
- run_id: runResult.runId,
98
- state: 'active',
99
- created_at: now,
100
- updated_at: now,
101
- metadata_json: JSON.stringify(metadata),
102
- });
103
- this.store.recordEvent(workflowId, 'spawned', null, 'active', 'subagent spawned', { runId: runResult.runId });
104
- this.workflowSpecs.set(workflowId, spec as SubagentWorkflowSpec<unknown>);
105
-
106
- this.scheduleWaitPoll(workflowId, spec.timeoutMs ?? DEFAULT_TIMEOUT_MS, runResult.runId);
107
-
108
- return {
109
- workflowId,
110
- childSessionKey,
111
- runId: runResult.runId,
112
- state: 'active',
113
- };
114
- }
115
-
116
- private buildRunParams<TResult>(
117
- spec: SubagentWorkflowSpec<TResult>,
118
- options: {
119
- parentSessionId: string;
120
- workspaceDir?: string;
121
- taskInput: unknown;
122
- metadata?: Record<string, unknown>;
123
- },
124
- childSessionKey: string
125
- ): RunParams {
126
- const message = spec.buildPrompt(options.taskInput, {
127
- parentSessionId: options.parentSessionId,
128
- workspaceDir: options.workspaceDir,
129
- taskInput: options.taskInput,
130
- startedAt: Date.now(),
131
- workflowType: spec.workflowType,
132
- ...(options.metadata ?? {}),
133
- });
134
-
135
- return {
136
- sessionKey: childSessionKey,
137
- message,
138
- lane: 'subagent',
139
- deliver: false,
140
- idempotencyKey: options.parentSessionId
141
- ? `${options.parentSessionId}:${Date.now()}`
142
- : `pd:${childSessionKey}:${Date.now()}`,
143
- expectsCompletionMessage: true,
144
- };
145
- }
146
-
147
- private scheduleWaitPoll(
148
- workflowId: string,
149
- timeoutMs: number,
150
- runId: string
151
- ): void {
152
- const effectiveTimeoutMs = timeoutMs ?? DEFAULT_TIMEOUT_MS;
153
-
154
- const timeout = setTimeout(async () => {
155
- try {
156
- const result = await this.driver.wait({ runId, timeoutMs: effectiveTimeoutMs });
157
- await this.notifyWaitResult(workflowId, result.status, result.error);
158
- } catch (error) {
159
- this.logger.error(`[PD:DeepReflectWorkflow] Wait poll failed: ${String(error)}`);
160
- await this.notifyWaitResult(workflowId, 'error', String(error));
161
- }
162
- }, 100);
163
-
164
- this.activeWorkflows.set(workflowId, timeout);
165
- }
166
-
167
- async notifyWaitResult(
168
- workflowId: string,
169
- status: 'ok' | 'error' | 'timeout',
170
- error?: string
171
- ): Promise<void> {
172
- const workflow = this.store.getWorkflow(workflowId);
173
- if (!workflow) {
174
- this.logger.warn(`[PD:DeepReflectWorkflow] notifyWaitResult: workflow not found: ${workflowId}`);
175
- return;
176
- }
177
-
178
- if (workflow.state === 'completed' || workflow.state === 'terminal_error' || workflow.state === 'expired') {
179
- this.logger.info(`[PD:DeepReflectWorkflow] notifyWaitResult: ignoring terminal workflow: ${workflowId}, state=${workflow.state}`);
180
- return;
181
- }
182
-
183
- this.logger.info(`[PD:DeepReflectWorkflow] notifyWaitResult: workflowId=${workflowId}, status=${status}`);
184
-
185
- const previousState = workflow.state;
186
- this.store.updateWorkflowState(workflowId, 'wait_result');
187
- this.store.recordEvent(workflowId, 'wait_result', previousState, 'wait_result', `wait completed: ${status}`, { error });
188
-
189
- const spec = this.workflowSpecs.get(workflowId);
190
- const shouldFinalize = spec ? spec.shouldFinalizeOnWaitStatus(status) : status === 'ok';
191
-
192
- if (shouldFinalize) {
193
- await this.finalizeOnce(workflowId);
194
- } else {
195
- this.store.updateWorkflowState(workflowId, 'terminal_error');
196
- this.store.recordEvent(workflowId, 'finalize_skipped', 'wait_result', 'terminal_error', `wait status: ${status}`, { error });
197
- }
198
- }
199
-
200
- async notifyLifecycleEvent(
201
- workflowId: string,
202
- event: 'subagent_spawned' | 'subagent_ended',
203
- data?: { outcome?: 'ok' | 'error' | 'timeout' | 'killed' | 'reset' | 'deleted'; error?: string }
204
- ): Promise<void> {
205
- this.logger.info(`[PD:DeepReflectWorkflow] notifyLifecycleEvent: workflowId=${workflowId}, event=${event}`);
206
-
207
- if (event === 'subagent_ended' && data?.outcome) {
208
- await this.notifyWaitResult(workflowId, data.outcome === 'ok' ? 'ok' : data.outcome === 'error' ? 'error' : 'timeout', data.error);
209
- }
210
- }
211
-
212
- async finalizeOnce(workflowId: string): Promise<void> {
213
- const workflow = this.store.getWorkflow(workflowId);
214
- if (!workflow) {
215
- this.logger.warn(`[PD:DeepReflectWorkflow] finalizeOnce: workflow not found: ${workflowId}`);
216
- return;
217
- }
218
-
219
- const spec = this.workflowSpecs.get(workflowId);
220
- if (!spec) {
221
- throw new Error(`Workflow spec not registered for ${workflowId}`);
222
- }
223
-
224
- if (this.isCompleted(workflowId)) {
225
- this.logger.info(`[PD:DeepReflectWorkflow] finalizeOnce: already completed: ${workflowId}`);
226
- return;
227
- }
228
-
229
- this.logger.info(`[PD:DeepReflectWorkflow] Finalizing workflow: ${workflowId}`);
230
-
231
- this.store.updateWorkflowState(workflowId, 'finalizing');
232
-
233
- try {
234
- const result = await this.driver.getResult({ sessionKey: workflow.child_session_key, limit: 20 });
235
-
236
- const metadata = JSON.parse(workflow.metadata_json) as WorkflowMetadata;
237
- const parsed = await spec.parseResult({
238
- messages: result.messages,
239
- assistantTexts: result.assistantTexts,
240
- metadata,
241
- waitStatus: 'ok',
242
- });
243
-
244
- if (!parsed) {
245
- this.store.updateWorkflowState(workflowId, 'terminal_error');
246
- this.store.recordEvent(workflowId, 'parse_failed', 'finalizing', 'terminal_error', 'spec.parseResult returned null', {});
247
- return;
248
- }
249
-
250
- await spec.persistResult({
251
- result: parsed,
252
- metadata,
253
- workspaceDir: this.workspaceDir,
254
- });
255
- this.store.recordEvent(workflowId, 'persisted', 'finalizing', 'finalizing', 'result persisted', {});
256
-
257
- if (spec.shouldDeleteSessionAfterFinalize && workflow.run_id) {
258
- try {
259
- await this.driver.cleanup({ sessionKey: workflow.child_session_key });
260
- this.store.updateCleanupState(workflowId, 'completed');
261
- } catch (cleanupError) {
262
- this.logger.error(`[PD:DeepReflectWorkflow] cleanup failed after persistence: ${String(cleanupError)}`);
263
- this.store.updateCleanupState(workflowId, 'failed');
264
- this.store.updateWorkflowState(workflowId, 'cleanup_pending');
265
- this.store.recordEvent(workflowId, 'cleanup_failed', 'finalizing', 'cleanup_pending', String(cleanupError), {});
266
- this.markCompleted(workflowId);
267
- return;
268
- }
269
- }
270
-
271
- this.store.updateWorkflowState(workflowId, 'completed');
272
- this.store.recordEvent(workflowId, 'finalized', 'finalizing', 'completed', 'success', {});
273
- this.markCompleted(workflowId);
274
-
275
- } catch (error) {
276
- this.logger.error(`[PD:DeepReflectWorkflow] finalizeOnce failed: ${String(error)}`);
277
- this.store.updateWorkflowState(workflowId, 'terminal_error');
278
- this.store.recordEvent(workflowId, 'finalize_error', 'finalizing', 'terminal_error', String(error), {});
279
- throw error;
280
- }
69
+ return super.startWorkflow(spec, options);
281
70
  }
282
71
 
283
- async sweepExpiredWorkflows(maxAgeMs = DEFAULT_TTL_MS): Promise<number> {
284
- const expired = this.store.getExpiredWorkflows(maxAgeMs);
285
-
286
- this.logger.info(`[PD:DeepReflectWorkflow] sweepExpiredWorkflows: found ${expired.length} expired`);
287
-
288
- for (const workflow of expired) {
289
- try {
290
- this.logger.info(`[PD:DeepReflectWorkflow] Sweeping expired workflow: ${workflow.workflow_id}`);
291
-
292
- await this.driver.cleanup({ sessionKey: workflow.child_session_key });
293
- this.store.updateCleanupState(workflow.workflow_id, 'completed');
294
- this.store.updateWorkflowState(workflow.workflow_id, 'expired');
295
- this.store.recordEvent(workflow.workflow_id, 'swept', workflow.state, 'expired', 'TTL expired', {});
296
-
297
- } catch (error) {
298
- this.logger.error(`[PD:DeepReflectWorkflow] Sweep cleanup failed for ${workflow.workflow_id}: ${String(error)}`);
299
- this.store.updateCleanupState(workflow.workflow_id, 'failed');
300
- }
301
- }
302
-
303
- // Clean up memory Maps to prevent leaks
304
- const cutoff = Date.now() - 60_000;
305
- for (const [id, timestamp] of this.completedWorkflows) {
306
- if (timestamp < cutoff) {
307
- this.completedWorkflows.delete(id);
308
- }
309
- }
310
- for (const [id, timeout] of this.activeWorkflows) {
311
- const wf = this.store.getWorkflow(id);
312
- if (!wf || wf.state === 'expired' || wf.state === 'completed' || wf.state === 'terminal_error') {
313
- clearTimeout(timeout);
314
- this.activeWorkflows.delete(id);
315
- }
316
- }
317
-
318
- return expired.length;
319
- }
320
-
321
- async getWorkflowDebugSummary(workflowId: string, eventLimit = 10): Promise<WorkflowDebugSummary | null> {
322
- const workflow = this.store.getWorkflow(workflowId);
323
- if (!workflow) return null;
324
-
325
- const metadata = JSON.parse(workflow.metadata_json) as WorkflowMetadata;
326
- const recentEvents = this.store
327
- .getEvents(workflowId)
328
- .slice(-eventLimit)
329
- .map((event) => ({
330
- eventType: event.event_type,
331
- fromState: event.from_state,
332
- toState: event.to_state,
333
- reason: event.reason,
334
- createdAt: event.created_at,
335
- payload: JSON.parse(event.payload_json || '{}') as Record<string, unknown>,
336
- }));
337
-
338
- return {
339
- workflowId: workflow.workflow_id,
340
- workflowType: workflow.workflow_type,
341
- transport: workflow.transport,
342
- parentSessionId: workflow.parent_session_id,
343
- childSessionKey: workflow.child_session_key,
344
- runId: workflow.run_id,
345
- state: workflow.state,
346
- cleanupState: workflow.cleanup_state,
347
- lastObservedAt: workflow.last_observed_at ?? null,
348
- metadata,
349
- recentEvents,
350
- };
351
- }
352
-
353
- private generateWorkflowId(): string {
72
+ /* eslint-disable @typescript-eslint/class-methods-use-this -- Reason: Subclass overrides id generation pattern */
73
+ protected override generateWorkflowId(): string {
354
74
  return `wf_dr_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
355
75
  }
356
-
357
- private buildChildSessionKey(parentSessionId: string): string {
358
- const safeParentSessionId = parentSessionId
359
- .replace(/[^a-zA-Z0-9_-]/g, '_')
360
- .substring(0, 64);
361
- const timestamp = Date.now();
362
- return `${WORKFLOW_SESSION_PREFIX}${safeParentSessionId}-${timestamp}`;
363
- }
364
-
365
- private isCompleted(workflowId: string): boolean {
366
- const timestamp = this.completedWorkflows.get(workflowId);
367
- if (!timestamp) return false;
368
- return Date.now() - timestamp < 60_000; // 1 minute dedup window
369
- }
370
-
371
- private markCompleted(workflowId: string): void {
372
- const timeout = this.activeWorkflows.get(workflowId);
373
- if (timeout) {
374
- clearTimeout(timeout);
375
- this.activeWorkflows.delete(workflowId);
376
- }
377
- this.completedWorkflows.set(workflowId, Date.now());
378
- }
379
-
380
- dispose(): void {
381
- for (const [workflowId, timeout] of this.activeWorkflows) {
382
- clearTimeout(timeout);
383
- this.logger.info(`[PD:DeepReflectWorkflow] Disposed active workflow: ${workflowId}`);
384
- }
385
- this.activeWorkflows.clear();
386
- this.completedWorkflows.clear();
387
- this.workflowSpecs.clear();
388
- this.store.dispose();
389
- }
390
76
  }
391
77
 
392
- // ─── Workflow Spec ───────────────────────────────────────────────
78
+ // ─── Interfaces ───────────────────────────────────────────────────────────────
393
79
 
394
80
  export interface DeepReflectTaskInput {
395
81
  context: string;
@@ -405,6 +91,8 @@ export interface DeepReflectBuildPromptContext {
405
91
  workflowType: string;
406
92
  }
407
93
 
94
+ // ─── Workflow Spec ─────────────────────────────────────────────────────────────
95
+
408
96
  export const deepReflectWorkflowSpec: SubagentWorkflowSpec<DeepReflectResult> = {
409
97
  workflowType: 'deep-reflect',
410
98
  transport: 'runtime_direct',
@@ -439,8 +127,9 @@ export const deepReflectWorkflowSpec: SubagentWorkflowSpec<DeepReflectResult> =
439
127
  if (typeof lastMessage?.content === 'string') {
440
128
  insights = lastMessage.content;
441
129
  } else if (Array.isArray(lastMessage?.content)) {
442
- insights = (lastMessage.content as Array<{ type?: string; text?: string }>)
130
+ insights = (lastMessage.content as { type?: string; text?: string }[])
443
131
  .filter((c) => c?.type === 'text' && typeof c.text === 'string')
132
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Reason: filter ensures c.text is a string
444
133
  .map((c) => c.text!)
445
134
  .join('\n');
446
135
  }
@@ -507,7 +196,7 @@ ${result.insights}
507
196
  fs.default.renameSync(tempPath, reflectionLogPath);
508
197
  } catch (err) {
509
198
  // Let the error propagate to finalizeOnce for proper event logging
510
- throw new Error(`DeepReflectWorkflow persistResult failed: ${String(err)}`);
199
+ throw new Error(`DeepReflectWorkflow persistResult failed: ${String(err)}`, { cause: err });
511
200
  }
512
201
  },
513
202
  };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Dynamic Timeout Calculator for Subagent Workflows
3
+ *
4
+ * This module is now a thin re-export layer for backwards compatibility.
5
+ * All functionality has been consolidated into utils/retry.ts.
6
+ *
7
+ * @module subagent-workflow/dynamic-timeout
8
+ * @deprecated Use `../../utils/retry.js` directly instead
9
+ */
10
+
11
+ // Re-export everything from the unified retry module
12
+ export {
13
+ // Constants
14
+ MIN_SAMPLES,
15
+ LOOKBACK_WINDOW,
16
+ SAFETY_MULTIPLIER,
17
+ MIN_TIMEOUT_MS,
18
+ MAX_TIMEOUT_MS,
19
+ MAX_TIMEOUT_RETRIES,
20
+ RETRY_BACKOFF_MULTIPLIER,
21
+
22
+ // Interfaces
23
+ DurationDataSource,
24
+
25
+ // Functions
26
+ percentile,
27
+ clampTimeout,
28
+ computeDynamicTimeout,
29
+ computeRetrySchedule,
30
+ } from '../../utils/retry.js';