pm-orchestrator-runner 1.0.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 (215) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +108 -0
  3. package/dist/cli/cli-interface.d.ts +150 -0
  4. package/dist/cli/cli-interface.d.ts.map +1 -0
  5. package/dist/cli/cli-interface.js +606 -0
  6. package/dist/cli/cli-interface.js.map +1 -0
  7. package/dist/cli/index.d.ts +13 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli/index.js +243 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/cli/llm-sentinel.d.ts +15 -0
  12. package/dist/cli/llm-sentinel.d.ts.map +1 -0
  13. package/dist/cli/llm-sentinel.js +184 -0
  14. package/dist/cli/llm-sentinel.js.map +1 -0
  15. package/dist/config/configuration-manager.d.ts +149 -0
  16. package/dist/config/configuration-manager.d.ts.map +1 -0
  17. package/dist/config/configuration-manager.js +241 -0
  18. package/dist/config/configuration-manager.js.map +1 -0
  19. package/dist/continuation/continuation-control-manager.d.ts +154 -0
  20. package/dist/continuation/continuation-control-manager.d.ts.map +1 -0
  21. package/dist/continuation/continuation-control-manager.js +303 -0
  22. package/dist/continuation/continuation-control-manager.js.map +1 -0
  23. package/dist/core/runner-core.d.ts +474 -0
  24. package/dist/core/runner-core.d.ts.map +1 -0
  25. package/dist/core/runner-core.js +1311 -0
  26. package/dist/core/runner-core.js.map +1 -0
  27. package/dist/errors/error-codes.d.ts +105 -0
  28. package/dist/errors/error-codes.d.ts.map +1 -0
  29. package/dist/errors/error-codes.js +198 -0
  30. package/dist/errors/error-codes.js.map +1 -0
  31. package/dist/errors/runner-error.d.ts +14 -0
  32. package/dist/errors/runner-error.d.ts.map +1 -0
  33. package/dist/errors/runner-error.js +33 -0
  34. package/dist/errors/runner-error.js.map +1 -0
  35. package/dist/evidence/evidence-manager.d.ts +112 -0
  36. package/dist/evidence/evidence-manager.d.ts.map +1 -0
  37. package/dist/evidence/evidence-manager.js +337 -0
  38. package/dist/evidence/evidence-manager.js.map +1 -0
  39. package/dist/executor/claude-code-executor.d.ts +136 -0
  40. package/dist/executor/claude-code-executor.d.ts.map +1 -0
  41. package/dist/executor/claude-code-executor.js +643 -0
  42. package/dist/executor/claude-code-executor.js.map +1 -0
  43. package/dist/executor/deterministic-executor.d.ts +40 -0
  44. package/dist/executor/deterministic-executor.d.ts.map +1 -0
  45. package/dist/executor/deterministic-executor.js +269 -0
  46. package/dist/executor/deterministic-executor.js.map +1 -0
  47. package/dist/lifecycle/lifecycle-controller.d.ts +270 -0
  48. package/dist/lifecycle/lifecycle-controller.d.ts.map +1 -0
  49. package/dist/lifecycle/lifecycle-controller.js +596 -0
  50. package/dist/lifecycle/lifecycle-controller.js.map +1 -0
  51. package/dist/limits/resource-limit-manager.d.ts +200 -0
  52. package/dist/limits/resource-limit-manager.d.ts.map +1 -0
  53. package/dist/limits/resource-limit-manager.js +376 -0
  54. package/dist/limits/resource-limit-manager.js.map +1 -0
  55. package/dist/locks/lock-manager.d.ts +116 -0
  56. package/dist/locks/lock-manager.d.ts.map +1 -0
  57. package/dist/locks/lock-manager.js +306 -0
  58. package/dist/locks/lock-manager.js.map +1 -0
  59. package/dist/logging/index.d.ts +8 -0
  60. package/dist/logging/index.d.ts.map +1 -0
  61. package/dist/logging/index.js +22 -0
  62. package/dist/logging/index.js.map +1 -0
  63. package/dist/logging/sensitive-data-masker.d.ts +90 -0
  64. package/dist/logging/sensitive-data-masker.d.ts.map +1 -0
  65. package/dist/logging/sensitive-data-masker.js +228 -0
  66. package/dist/logging/sensitive-data-masker.js.map +1 -0
  67. package/dist/logging/task-log-manager.d.ts +215 -0
  68. package/dist/logging/task-log-manager.d.ts.map +1 -0
  69. package/dist/logging/task-log-manager.js +743 -0
  70. package/dist/logging/task-log-manager.js.map +1 -0
  71. package/dist/mediation/fail-closed-runner.d.ts +131 -0
  72. package/dist/mediation/fail-closed-runner.d.ts.map +1 -0
  73. package/dist/mediation/fail-closed-runner.js +245 -0
  74. package/dist/mediation/fail-closed-runner.js.map +1 -0
  75. package/dist/mediation/llm-client-with-evidence.d.ts +123 -0
  76. package/dist/mediation/llm-client-with-evidence.d.ts.map +1 -0
  77. package/dist/mediation/llm-client-with-evidence.js +245 -0
  78. package/dist/mediation/llm-client-with-evidence.js.map +1 -0
  79. package/dist/mediation/llm-client.d.ts +102 -0
  80. package/dist/mediation/llm-client.d.ts.map +1 -0
  81. package/dist/mediation/llm-client.js +206 -0
  82. package/dist/mediation/llm-client.js.map +1 -0
  83. package/dist/mediation/llm-evidence-manager.d.ts +108 -0
  84. package/dist/mediation/llm-evidence-manager.d.ts.map +1 -0
  85. package/dist/mediation/llm-evidence-manager.js +230 -0
  86. package/dist/mediation/llm-evidence-manager.js.map +1 -0
  87. package/dist/mediation/llm-mediation-layer.d.ts +175 -0
  88. package/dist/mediation/llm-mediation-layer.d.ts.map +1 -0
  89. package/dist/mediation/llm-mediation-layer.js +315 -0
  90. package/dist/mediation/llm-mediation-layer.js.map +1 -0
  91. package/dist/mediation/llm-sentinel.d.ts +107 -0
  92. package/dist/mediation/llm-sentinel.d.ts.map +1 -0
  93. package/dist/mediation/llm-sentinel.js +187 -0
  94. package/dist/mediation/llm-sentinel.js.map +1 -0
  95. package/dist/mediation/real-llm-mediation-layer.d.ts +104 -0
  96. package/dist/mediation/real-llm-mediation-layer.d.ts.map +1 -0
  97. package/dist/mediation/real-llm-mediation-layer.js +322 -0
  98. package/dist/mediation/real-llm-mediation-layer.js.map +1 -0
  99. package/dist/mediation/verdict-reporter.d.ts +61 -0
  100. package/dist/mediation/verdict-reporter.d.ts.map +1 -0
  101. package/dist/mediation/verdict-reporter.js +178 -0
  102. package/dist/mediation/verdict-reporter.js.map +1 -0
  103. package/dist/models/enums.d.ts +133 -0
  104. package/dist/models/enums.d.ts.map +1 -0
  105. package/dist/models/enums.js +201 -0
  106. package/dist/models/enums.js.map +1 -0
  107. package/dist/models/evidence.d.ts +60 -0
  108. package/dist/models/evidence.d.ts.map +1 -0
  109. package/dist/models/evidence.js +135 -0
  110. package/dist/models/evidence.js.map +1 -0
  111. package/dist/models/execution-result.d.ts +89 -0
  112. package/dist/models/execution-result.d.ts.map +1 -0
  113. package/dist/models/execution-result.js +197 -0
  114. package/dist/models/execution-result.js.map +1 -0
  115. package/dist/models/file-lock.d.ts +62 -0
  116. package/dist/models/file-lock.d.ts.map +1 -0
  117. package/dist/models/file-lock.js +133 -0
  118. package/dist/models/file-lock.js.map +1 -0
  119. package/dist/models/index.d.ts +12 -0
  120. package/dist/models/index.d.ts.map +1 -0
  121. package/dist/models/index.js +91 -0
  122. package/dist/models/index.js.map +1 -0
  123. package/dist/models/repl/index.d.ts +7 -0
  124. package/dist/models/repl/index.d.ts.map +1 -0
  125. package/dist/models/repl/index.js +32 -0
  126. package/dist/models/repl/index.js.map +1 -0
  127. package/dist/models/repl/model-registry.d.ts +73 -0
  128. package/dist/models/repl/model-registry.d.ts.map +1 -0
  129. package/dist/models/repl/model-registry.js +116 -0
  130. package/dist/models/repl/model-registry.js.map +1 -0
  131. package/dist/models/repl/repl-state.d.ts +86 -0
  132. package/dist/models/repl/repl-state.d.ts.map +1 -0
  133. package/dist/models/repl/repl-state.js +152 -0
  134. package/dist/models/repl/repl-state.js.map +1 -0
  135. package/dist/models/repl/task-log.d.ts +247 -0
  136. package/dist/models/repl/task-log.d.ts.map +1 -0
  137. package/dist/models/repl/task-log.js +178 -0
  138. package/dist/models/repl/task-log.js.map +1 -0
  139. package/dist/models/session.d.ts +71 -0
  140. package/dist/models/session.d.ts.map +1 -0
  141. package/dist/models/session.js +140 -0
  142. package/dist/models/session.js.map +1 -0
  143. package/dist/models/supporting.d.ts +97 -0
  144. package/dist/models/supporting.d.ts.map +1 -0
  145. package/dist/models/supporting.js +208 -0
  146. package/dist/models/supporting.js.map +1 -0
  147. package/dist/models/task.d.ts +77 -0
  148. package/dist/models/task.d.ts.map +1 -0
  149. package/dist/models/task.js +170 -0
  150. package/dist/models/task.js.map +1 -0
  151. package/dist/output/output-control-manager.d.ts +217 -0
  152. package/dist/output/output-control-manager.d.ts.map +1 -0
  153. package/dist/output/output-control-manager.js +378 -0
  154. package/dist/output/output-control-manager.js.map +1 -0
  155. package/dist/pool/agent-pool.d.ts +284 -0
  156. package/dist/pool/agent-pool.d.ts.map +1 -0
  157. package/dist/pool/agent-pool.js +451 -0
  158. package/dist/pool/agent-pool.js.map +1 -0
  159. package/dist/repl/commands/index.d.ts +12 -0
  160. package/dist/repl/commands/index.d.ts.map +1 -0
  161. package/dist/repl/commands/index.js +26 -0
  162. package/dist/repl/commands/index.js.map +1 -0
  163. package/dist/repl/commands/init.d.ts +31 -0
  164. package/dist/repl/commands/init.d.ts.map +1 -0
  165. package/dist/repl/commands/init.js +234 -0
  166. package/dist/repl/commands/init.js.map +1 -0
  167. package/dist/repl/commands/keys.d.ts +63 -0
  168. package/dist/repl/commands/keys.d.ts.map +1 -0
  169. package/dist/repl/commands/keys.js +114 -0
  170. package/dist/repl/commands/keys.js.map +1 -0
  171. package/dist/repl/commands/logs.d.ts +91 -0
  172. package/dist/repl/commands/logs.d.ts.map +1 -0
  173. package/dist/repl/commands/logs.js +200 -0
  174. package/dist/repl/commands/logs.js.map +1 -0
  175. package/dist/repl/commands/model.d.ts +85 -0
  176. package/dist/repl/commands/model.d.ts.map +1 -0
  177. package/dist/repl/commands/model.js +225 -0
  178. package/dist/repl/commands/model.js.map +1 -0
  179. package/dist/repl/commands/models.d.ts +50 -0
  180. package/dist/repl/commands/models.d.ts.map +1 -0
  181. package/dist/repl/commands/models.js +180 -0
  182. package/dist/repl/commands/models.js.map +1 -0
  183. package/dist/repl/commands/provider.d.ts +79 -0
  184. package/dist/repl/commands/provider.d.ts.map +1 -0
  185. package/dist/repl/commands/provider.js +291 -0
  186. package/dist/repl/commands/provider.js.map +1 -0
  187. package/dist/repl/commands/session.d.ts +50 -0
  188. package/dist/repl/commands/session.d.ts.map +1 -0
  189. package/dist/repl/commands/session.js +152 -0
  190. package/dist/repl/commands/session.js.map +1 -0
  191. package/dist/repl/commands/status.d.ts +55 -0
  192. package/dist/repl/commands/status.d.ts.map +1 -0
  193. package/dist/repl/commands/status.js +182 -0
  194. package/dist/repl/commands/status.js.map +1 -0
  195. package/dist/repl/index.d.ts +6 -0
  196. package/dist/repl/index.d.ts.map +1 -0
  197. package/dist/repl/index.js +25 -0
  198. package/dist/repl/index.js.map +1 -0
  199. package/dist/repl/repl-interface.d.ts +371 -0
  200. package/dist/repl/repl-interface.d.ts.map +1 -0
  201. package/dist/repl/repl-interface.js +1214 -0
  202. package/dist/repl/repl-interface.js.map +1 -0
  203. package/dist/session/session-manager.d.ts +85 -0
  204. package/dist/session/session-manager.d.ts.map +1 -0
  205. package/dist/session/session-manager.js +217 -0
  206. package/dist/session/session-manager.js.map +1 -0
  207. package/dist/supervisor/executor-supervisor.d.ts +90 -0
  208. package/dist/supervisor/executor-supervisor.d.ts.map +1 -0
  209. package/dist/supervisor/executor-supervisor.js +223 -0
  210. package/dist/supervisor/executor-supervisor.js.map +1 -0
  211. package/dist/supervisor/index.d.ts +5 -0
  212. package/dist/supervisor/index.d.ts.map +1 -0
  213. package/dist/supervisor/index.js +9 -0
  214. package/dist/supervisor/index.js.map +1 -0
  215. package/package.json +57 -0
@@ -0,0 +1,743 @@
1
+ "use strict";
2
+ /**
3
+ * Task Log Manager
4
+ *
5
+ * Per spec 13_LOGGING_AND_OBSERVABILITY.md:
6
+ * - Logs stored in .claude/logs/sessions/<session_id>/
7
+ * - Two-layer viewing (list and detail)
8
+ * - Visibility control (summary/full)
9
+ * - Thread/Run/Task hierarchy support (v2.0)
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.SESSION_FILE = exports.SESSIONS_DIR = exports.RAW_DIR = exports.TASKS_DIR = exports.INDEX_FILE = exports.LOG_DIR = exports.TaskLogManager = void 0;
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ const task_log_1 = require("../models/repl/task-log");
49
+ const sensitive_data_masker_1 = require("./sensitive-data-masker");
50
+ /**
51
+ * Log directory structure
52
+ * Per spec 13_LOGGING_AND_OBSERVABILITY.md Section 1.1
53
+ */
54
+ const LOG_DIR = 'logs';
55
+ exports.LOG_DIR = LOG_DIR;
56
+ const SESSIONS_DIR = 'sessions';
57
+ exports.SESSIONS_DIR = SESSIONS_DIR;
58
+ const TASKS_DIR = 'tasks';
59
+ exports.TASKS_DIR = TASKS_DIR;
60
+ const RAW_DIR = 'raw';
61
+ exports.RAW_DIR = RAW_DIR;
62
+ const INDEX_FILE = 'index.json';
63
+ exports.INDEX_FILE = INDEX_FILE;
64
+ const SESSION_FILE = 'session.json';
65
+ exports.SESSION_FILE = SESSION_FILE;
66
+ /**
67
+ * Task Log Manager class
68
+ * Supports Thread/Run/Task hierarchy (v2.0)
69
+ */
70
+ class TaskLogManager {
71
+ projectPath;
72
+ logsPath;
73
+ // Session-scoped counters for sequential IDs
74
+ threadCounters = new Map();
75
+ runCounters = new Map();
76
+ taskCounters = new Map();
77
+ constructor(projectPath) {
78
+ this.projectPath = projectPath;
79
+ this.logsPath = path.join(projectPath, '.claude', LOG_DIR);
80
+ }
81
+ /**
82
+ * Get session directory path
83
+ */
84
+ getSessionPath(sessionId) {
85
+ return path.join(this.logsPath, SESSIONS_DIR, sessionId);
86
+ }
87
+ /**
88
+ * Get session tasks directory path
89
+ */
90
+ getSessionTasksPath(sessionId) {
91
+ return path.join(this.getSessionPath(sessionId), TASKS_DIR);
92
+ }
93
+ /**
94
+ * Ensure log directories exist (legacy support)
95
+ * Per spec 13_LOGGING_AND_OBSERVABILITY.md Section 1.3
96
+ */
97
+ async ensureLogDirectories() {
98
+ const dirs = [
99
+ this.logsPath,
100
+ path.join(this.logsPath, SESSIONS_DIR),
101
+ ];
102
+ for (const dir of dirs) {
103
+ if (!fs.existsSync(dir)) {
104
+ fs.mkdirSync(dir, { recursive: true });
105
+ }
106
+ }
107
+ }
108
+ /**
109
+ * Ensure session-based directories exist
110
+ * Per spec 13_LOGGING_AND_OBSERVABILITY.md Section 1.1
111
+ */
112
+ async ensureSessionDirectories(sessionId) {
113
+ await this.ensureLogDirectories();
114
+ const sessionPath = this.getSessionPath(sessionId);
115
+ const tasksPath = this.getSessionTasksPath(sessionId);
116
+ const rawPath = path.join(sessionPath, RAW_DIR);
117
+ const dirs = [sessionPath, tasksPath, rawPath];
118
+ for (const dir of dirs) {
119
+ if (!fs.existsSync(dir)) {
120
+ fs.mkdirSync(dir, { recursive: true });
121
+ }
122
+ }
123
+ }
124
+ /**
125
+ * Initialize a new session
126
+ * Per spec 13_LOGGING_AND_OBSERVABILITY.md Section 1.2
127
+ */
128
+ async initializeSession(sessionId) {
129
+ await this.ensureSessionDirectories(sessionId);
130
+ // Initialize counters for this session
131
+ this.threadCounters.set(sessionId, 0);
132
+ this.runCounters.set(sessionId, 0);
133
+ this.taskCounters.set(sessionId, 0);
134
+ // Create session metadata
135
+ const sessionMeta = (0, task_log_1.createSessionMetadata)(sessionId);
136
+ const sessionMetaPath = path.join(this.getSessionPath(sessionId), SESSION_FILE);
137
+ fs.writeFileSync(sessionMetaPath, JSON.stringify(sessionMeta, null, 2), 'utf-8');
138
+ // Create session index
139
+ const sessionIndex = (0, task_log_1.createTaskLogIndex)(sessionId);
140
+ const sessionIndexPath = path.join(this.getSessionPath(sessionId), INDEX_FILE);
141
+ fs.writeFileSync(sessionIndexPath, JSON.stringify(sessionIndex, null, 2), 'utf-8');
142
+ // Update global index
143
+ await this.updateGlobalIndex(sessionId);
144
+ return sessionMeta;
145
+ }
146
+ /**
147
+ * Update global index with new session
148
+ */
149
+ async updateGlobalIndex(sessionId) {
150
+ const globalIndexPath = path.join(this.logsPath, INDEX_FILE);
151
+ let globalIndex;
152
+ if (fs.existsSync(globalIndexPath)) {
153
+ try {
154
+ const content = fs.readFileSync(globalIndexPath, 'utf-8');
155
+ globalIndex = JSON.parse(content);
156
+ }
157
+ catch {
158
+ globalIndex = (0, task_log_1.createGlobalLogIndex)();
159
+ }
160
+ }
161
+ else {
162
+ globalIndex = (0, task_log_1.createGlobalLogIndex)();
163
+ }
164
+ // Add session if not already present
165
+ if (!globalIndex.sessions.some(s => s.session_id === sessionId)) {
166
+ globalIndex.sessions.push({
167
+ session_id: sessionId,
168
+ started_at: new Date().toISOString(),
169
+ task_count: 0,
170
+ });
171
+ }
172
+ globalIndex.updated_at = new Date().toISOString();
173
+ fs.writeFileSync(globalIndexPath, JSON.stringify(globalIndex, null, 2), 'utf-8');
174
+ }
175
+ /**
176
+ * Get session metadata
177
+ */
178
+ async getSessionMetadata(sessionId) {
179
+ const sessionMetaPath = path.join(this.getSessionPath(sessionId), SESSION_FILE);
180
+ if (!fs.existsSync(sessionMetaPath)) {
181
+ return (0, task_log_1.createSessionMetadata)(sessionId);
182
+ }
183
+ try {
184
+ const content = fs.readFileSync(sessionMetaPath, 'utf-8');
185
+ return JSON.parse(content);
186
+ }
187
+ catch {
188
+ return (0, task_log_1.createSessionMetadata)(sessionId);
189
+ }
190
+ }
191
+ /**
192
+ * Save session metadata
193
+ */
194
+ async saveSessionMetadata(sessionId, metadata) {
195
+ const sessionMetaPath = path.join(this.getSessionPath(sessionId), SESSION_FILE);
196
+ fs.writeFileSync(sessionMetaPath, JSON.stringify(metadata, null, 2), 'utf-8');
197
+ }
198
+ /**
199
+ * Get session index
200
+ */
201
+ async getSessionIndex(sessionId) {
202
+ const sessionIndexPath = path.join(this.getSessionPath(sessionId), INDEX_FILE);
203
+ if (!fs.existsSync(sessionIndexPath)) {
204
+ return (0, task_log_1.createTaskLogIndex)(sessionId);
205
+ }
206
+ try {
207
+ const content = fs.readFileSync(sessionIndexPath, 'utf-8');
208
+ return JSON.parse(content);
209
+ }
210
+ catch {
211
+ // Per spec: On corruption, return empty entries
212
+ return (0, task_log_1.createTaskLogIndex)(sessionId);
213
+ }
214
+ }
215
+ /**
216
+ * Save session index
217
+ */
218
+ async saveSessionIndex(sessionId, index) {
219
+ const sessionIndexPath = path.join(this.getSessionPath(sessionId), INDEX_FILE);
220
+ index.updated_at = new Date().toISOString();
221
+ fs.writeFileSync(sessionIndexPath, JSON.stringify((0, sensitive_data_masker_1.maskSensitiveObject)(index), null, 2), 'utf-8');
222
+ }
223
+ /**
224
+ * Generate next thread ID for session
225
+ */
226
+ generateThreadId(sessionId) {
227
+ const current = this.threadCounters.get(sessionId) ?? 0;
228
+ const next = current + 1;
229
+ this.threadCounters.set(sessionId, next);
230
+ return 'thr-' + String(next).padStart(3, '0');
231
+ }
232
+ /**
233
+ * Generate next run ID for session
234
+ */
235
+ generateRunId(sessionId) {
236
+ const current = this.runCounters.get(sessionId) ?? 0;
237
+ const next = current + 1;
238
+ this.runCounters.set(sessionId, next);
239
+ return 'run-' + String(next).padStart(3, '0');
240
+ }
241
+ /**
242
+ * Generate next task ID for session
243
+ */
244
+ generateTaskId(sessionId) {
245
+ const current = this.taskCounters.get(sessionId) ?? 0;
246
+ const next = current + 1;
247
+ this.taskCounters.set(sessionId, next);
248
+ return 'task-' + String(next).padStart(3, '0');
249
+ }
250
+ /**
251
+ * Create a new thread
252
+ * Per spec 05_DATA_MODELS.md Section "Thread"
253
+ */
254
+ async createThread(sessionId, threadType, description) {
255
+ const threadId = this.generateThreadId(sessionId);
256
+ const thread = (0, task_log_1.createThread)(threadId, sessionId, threadType, description);
257
+ // Add to session metadata
258
+ const metadata = await this.getSessionMetadata(sessionId);
259
+ metadata.threads.push({ thread_id: threadId, thread_type: threadType });
260
+ await this.saveSessionMetadata(sessionId, metadata);
261
+ return thread;
262
+ }
263
+ /**
264
+ * Create a new run
265
+ * Per spec 05_DATA_MODELS.md Section "Run"
266
+ */
267
+ async createRun(sessionId, threadId, trigger) {
268
+ const runId = this.generateRunId(sessionId);
269
+ const run = (0, task_log_1.createRun)(runId, threadId, sessionId, trigger);
270
+ // Add to session metadata
271
+ const metadata = await this.getSessionMetadata(sessionId);
272
+ metadata.runs.push({ run_id: runId, thread_id: threadId, status: 'RUNNING' });
273
+ await this.saveSessionMetadata(sessionId, metadata);
274
+ return run;
275
+ }
276
+ /**
277
+ * Get a run by ID
278
+ */
279
+ async getRun(sessionId, runId) {
280
+ const metadata = await this.getSessionMetadata(sessionId);
281
+ const runInfo = metadata.runs.find(r => r.run_id === runId);
282
+ if (!runInfo) {
283
+ return null;
284
+ }
285
+ // Reconstruct run from metadata (simplified)
286
+ return {
287
+ run_id: runId,
288
+ thread_id: runInfo.thread_id,
289
+ session_id: sessionId,
290
+ started_at: metadata.started_at,
291
+ completed_at: runInfo.status !== 'RUNNING' ? new Date().toISOString() : null,
292
+ status: runInfo.status,
293
+ trigger: 'USER_INPUT', // Default, actual trigger not stored in minimal metadata
294
+ };
295
+ }
296
+ /**
297
+ * Complete a run
298
+ */
299
+ async completeRun(sessionId, runId, status) {
300
+ const metadata = await this.getSessionMetadata(sessionId);
301
+ const runInfo = metadata.runs.find(r => r.run_id === runId);
302
+ if (runInfo) {
303
+ runInfo.status = status;
304
+ await this.saveSessionMetadata(sessionId, metadata);
305
+ }
306
+ }
307
+ /**
308
+ * Complete a task with session context
309
+ * Per spec 06_CORRECTNESS_PROPERTIES.md Property 26: Fail-Closed Logging
310
+ * TaskLog MUST be saved for ALL terminal states (COMPLETE, INCOMPLETE, ERROR)
311
+ * Per spec 10_REPL_UX.md Section 10: Records executor blocking info (Property 34-36)
312
+ */
313
+ async completeTaskWithSession(taskId, sessionId, status, filesModified = [], evidenceRef, errorMessage, options) {
314
+ const log = await this.getTaskLogWithSession(taskId, sessionId);
315
+ if (!log) {
316
+ throw new Error('Task log not found: ' + taskId);
317
+ }
318
+ // Per spec 10_REPL_UX.md Section 10: Record executor blocking info (Property 34-36)
319
+ // Update TaskLog with executor_blocked fields if provided
320
+ if (options?.executorBlocked !== undefined) {
321
+ log.executor_blocked = options.executorBlocked;
322
+ log.blocked_reason = options.blockedReason;
323
+ log.timeout_ms = options.timeoutMs;
324
+ log.terminated_by = options.terminatedBy;
325
+ await this.saveTaskLogWithSession(log, sessionId);
326
+ }
327
+ // Add completion event
328
+ const eventType = status === 'ERROR' ? 'TASK_ERROR' : 'TASK_COMPLETED';
329
+ await this.addEventWithSession(taskId, sessionId, eventType, {
330
+ status,
331
+ files_modified: filesModified,
332
+ evidence_ref: evidenceRef,
333
+ error_message: errorMessage,
334
+ });
335
+ // Update session index entry
336
+ const index = await this.getSessionIndex(sessionId);
337
+ const entry = index.entries.find(e => e.task_id === taskId);
338
+ if (entry) {
339
+ entry.status = status;
340
+ entry.completed_at = new Date().toISOString();
341
+ entry.duration_ms = new Date(entry.completed_at).getTime() - new Date(entry.started_at).getTime();
342
+ entry.files_modified_count = filesModified.length;
343
+ // Per spec 10_REPL_UX.md Section 10: Record executor blocking info in index (Property 34-36)
344
+ if (options?.executorBlocked !== undefined) {
345
+ entry.executor_blocked = options.executorBlocked;
346
+ entry.blocked_reason = options.blockedReason;
347
+ }
348
+ }
349
+ await this.saveSessionIndex(sessionId, index);
350
+ }
351
+ /**
352
+ * Create a task with thread/run context
353
+ * Per spec 13_LOGGING_AND_OBSERVABILITY.md Section 2.3
354
+ */
355
+ async createTaskWithContext(sessionId, threadId, runId, parentTaskId) {
356
+ await this.ensureSessionDirectories(sessionId);
357
+ // Validate parent task is in same thread if specified
358
+ if (parentTaskId) {
359
+ const parentLog = await this.getTaskLogWithSession(parentTaskId, sessionId);
360
+ if (parentLog && parentLog.thread_id !== threadId) {
361
+ throw new Error('parent_task_id must be within same thread');
362
+ }
363
+ }
364
+ const taskId = this.generateTaskId(sessionId);
365
+ const log = (0, task_log_1.createTaskLog)(taskId, sessionId, threadId, runId, parentTaskId ?? null);
366
+ await this.saveTaskLogWithSession(log, sessionId);
367
+ // Update session index
368
+ const index = await this.getSessionIndex(sessionId);
369
+ const entry = {
370
+ task_id: taskId,
371
+ thread_id: threadId,
372
+ run_id: runId,
373
+ parent_task_id: parentTaskId ?? null,
374
+ status: 'RUNNING',
375
+ started_at: log.created_at,
376
+ completed_at: null,
377
+ duration_ms: 0,
378
+ files_modified_count: 0,
379
+ tests_run_count: 0,
380
+ log_file: path.join(TASKS_DIR, taskId + '.json'),
381
+ };
382
+ index.entries.push(entry);
383
+ await this.saveSessionIndex(sessionId, index);
384
+ // Update global index task count
385
+ await this.incrementGlobalTaskCount(sessionId);
386
+ return log;
387
+ }
388
+ /**
389
+ * Increment task count in global index
390
+ */
391
+ async incrementGlobalTaskCount(sessionId) {
392
+ const globalIndexPath = path.join(this.logsPath, INDEX_FILE);
393
+ if (fs.existsSync(globalIndexPath)) {
394
+ try {
395
+ const content = fs.readFileSync(globalIndexPath, 'utf-8');
396
+ const globalIndex = JSON.parse(content);
397
+ const session = globalIndex.sessions.find(s => s.session_id === sessionId);
398
+ if (session) {
399
+ session.task_count++;
400
+ globalIndex.updated_at = new Date().toISOString();
401
+ fs.writeFileSync(globalIndexPath, JSON.stringify(globalIndex, null, 2), 'utf-8');
402
+ }
403
+ }
404
+ catch {
405
+ // Ignore errors in global index update
406
+ }
407
+ }
408
+ }
409
+ /**
410
+ * Get task log with session context
411
+ */
412
+ async getTaskLogWithSession(taskId, sessionId) {
413
+ const logPath = path.join(this.getSessionTasksPath(sessionId), taskId + '.json');
414
+ if (!fs.existsSync(logPath)) {
415
+ return null;
416
+ }
417
+ try {
418
+ const content = fs.readFileSync(logPath, 'utf-8');
419
+ return JSON.parse(content);
420
+ }
421
+ catch {
422
+ return null;
423
+ }
424
+ }
425
+ /**
426
+ * Save task log with session context
427
+ */
428
+ async saveTaskLogWithSession(log, sessionId) {
429
+ await this.ensureSessionDirectories(sessionId);
430
+ const logPath = path.join(this.getSessionTasksPath(sessionId), log.task_id + '.json');
431
+ // Mask sensitive data before saving
432
+ const maskedLog = (0, sensitive_data_masker_1.maskSensitiveObject)(log);
433
+ fs.writeFileSync(logPath, JSON.stringify(maskedLog, null, 2), 'utf-8');
434
+ }
435
+ /**
436
+ * Add event to task log with session context
437
+ */
438
+ async addEventWithSession(taskId, sessionId, eventType, content, metadata) {
439
+ const log = await this.getTaskLogWithSession(taskId, sessionId);
440
+ if (!log) {
441
+ throw new Error('Task log not found: ' + taskId);
442
+ }
443
+ const eventId = 'evt-' + String(log.events.length + 1).padStart(3, '0');
444
+ const event = (0, task_log_1.createLogEvent)(eventId, eventType, content, metadata);
445
+ const updatedLog = (0, task_log_1.addEventToTaskLog)(log, event);
446
+ await this.saveTaskLogWithSession(updatedLog, sessionId);
447
+ return event;
448
+ }
449
+ /**
450
+ * Get task detail with session context
451
+ * Per spec 13_LOGGING_AND_OBSERVABILITY.md Section 2.2
452
+ */
453
+ async getTaskDetailWithSession(taskId, sessionId, visibility = 'summary') {
454
+ const log = await this.getTaskLogWithSession(taskId, sessionId);
455
+ if (!log) {
456
+ return { log: null, events: [] };
457
+ }
458
+ const events = (0, task_log_1.filterEventsByVisibility)(log.events, visibility);
459
+ // Mask any remaining sensitive data in display
460
+ const maskedEvents = events.map(e => ({
461
+ ...e,
462
+ content: (0, sensitive_data_masker_1.maskSensitiveObject)(e.content),
463
+ }));
464
+ return { log, events: maskedEvents };
465
+ }
466
+ /**
467
+ * Format tree view of session hierarchy
468
+ * Per spec 13_LOGGING_AND_OBSERVABILITY.md Section 2.5
469
+ */
470
+ async formatTreeView(sessionId) {
471
+ const metadata = await this.getSessionMetadata(sessionId);
472
+ const index = await this.getSessionIndex(sessionId);
473
+ let output = 'Session: ' + sessionId + '\n';
474
+ output += 'Started: ' + metadata.started_at + '\n\n';
475
+ // Group tasks by thread and run
476
+ for (const threadInfo of metadata.threads) {
477
+ output += ' Thread: ' + threadInfo.thread_id + ' (' + threadInfo.thread_type + ')\n';
478
+ // Find runs for this thread
479
+ const threadRuns = metadata.runs.filter(r => r.thread_id === threadInfo.thread_id);
480
+ for (const runInfo of threadRuns) {
481
+ output += ' Run: ' + runInfo.run_id + ' [' + runInfo.status + ']\n';
482
+ // Find tasks for this run
483
+ const runTasks = index.entries.filter(e => e.run_id === runInfo.run_id);
484
+ for (const task of runTasks) {
485
+ const indent = task.parent_task_id ? ' ' : ' ';
486
+ output += indent + 'Task: ' + task.task_id + ' [' + task.status + ']\n';
487
+ }
488
+ }
489
+ }
490
+ return output;
491
+ }
492
+ // ========================================
493
+ // Legacy methods for backward compatibility
494
+ // ========================================
495
+ /**
496
+ * Get or create log index (legacy)
497
+ */
498
+ async getOrCreateIndex(sessionId) {
499
+ await this.ensureLogDirectories();
500
+ // Fixed: Read session-specific index, not global index
501
+ const indexPath = path.join(this.getSessionPath(sessionId), INDEX_FILE);
502
+ if (fs.existsSync(indexPath)) {
503
+ try {
504
+ const content = fs.readFileSync(indexPath, 'utf-8');
505
+ return JSON.parse(content);
506
+ }
507
+ catch {
508
+ // Per spec: On corruption, return empty list
509
+ return (0, task_log_1.createTaskLogIndex)(sessionId);
510
+ }
511
+ }
512
+ return (0, task_log_1.createTaskLogIndex)(sessionId);
513
+ }
514
+ /**
515
+ * Save log index (legacy)
516
+ */
517
+ async saveIndex(index) {
518
+ await this.ensureLogDirectories();
519
+ // Fixed: Save to session-specific index, not global index
520
+ const indexPath = path.join(this.getSessionPath(index.session_id), INDEX_FILE);
521
+ // Mask any sensitive data before saving
522
+ const maskedIndex = (0, sensitive_data_masker_1.maskSensitiveObject)(index);
523
+ maskedIndex.updated_at = new Date().toISOString();
524
+ fs.writeFileSync(indexPath, JSON.stringify(maskedIndex, null, 2), 'utf-8');
525
+ }
526
+ /**
527
+ * Create a new task log (legacy - without thread/run context)
528
+ */
529
+ async createTask(taskId, sessionId) {
530
+ await this.ensureLogDirectories();
531
+ const log = (0, task_log_1.createTaskLog)(taskId, sessionId);
532
+ await this.saveTaskLog(log);
533
+ // Update index
534
+ const index = await this.getOrCreateIndex(sessionId);
535
+ const entry = {
536
+ task_id: taskId,
537
+ thread_id: '',
538
+ run_id: '',
539
+ parent_task_id: null,
540
+ status: 'RUNNING',
541
+ started_at: log.created_at,
542
+ completed_at: null,
543
+ duration_ms: 0,
544
+ files_modified_count: 0,
545
+ tests_run_count: 0,
546
+ log_file: path.join(TASKS_DIR, taskId + '.json'),
547
+ };
548
+ index.entries.push(entry);
549
+ await this.saveIndex(index);
550
+ return log;
551
+ }
552
+ /**
553
+ * Get task log by ID (legacy)
554
+ */
555
+ async getTaskLog(taskId) {
556
+ const logPath = path.join(this.logsPath, TASKS_DIR, taskId + '.json');
557
+ if (!fs.existsSync(logPath)) {
558
+ return null;
559
+ }
560
+ try {
561
+ const content = fs.readFileSync(logPath, 'utf-8');
562
+ return JSON.parse(content);
563
+ }
564
+ catch {
565
+ return null;
566
+ }
567
+ }
568
+ /**
569
+ * Save task log (legacy)
570
+ */
571
+ async saveTaskLog(log) {
572
+ await this.ensureLogDirectories();
573
+ const tasksDir = path.join(this.logsPath, TASKS_DIR);
574
+ if (!fs.existsSync(tasksDir)) {
575
+ fs.mkdirSync(tasksDir, { recursive: true });
576
+ }
577
+ const logPath = path.join(tasksDir, log.task_id + '.json');
578
+ // Mask sensitive data before saving
579
+ const maskedLog = (0, sensitive_data_masker_1.maskSensitiveObject)(log);
580
+ fs.writeFileSync(logPath, JSON.stringify(maskedLog, null, 2), 'utf-8');
581
+ }
582
+ /**
583
+ * Add event to task log (legacy)
584
+ */
585
+ async addEvent(taskId, eventType, content, metadata) {
586
+ const log = await this.getTaskLog(taskId);
587
+ if (!log) {
588
+ throw new Error('Task log not found: ' + taskId);
589
+ }
590
+ const eventId = 'evt-' + String(log.events.length + 1).padStart(3, '0');
591
+ const event = (0, task_log_1.createLogEvent)(eventId, eventType, content, metadata);
592
+ const updatedLog = (0, task_log_1.addEventToTaskLog)(log, event);
593
+ await this.saveTaskLog(updatedLog);
594
+ return event;
595
+ }
596
+ /**
597
+ * Complete a task (legacy)
598
+ */
599
+ async completeTask(taskId, status, filesModified = [], evidenceRef, errorMessage) {
600
+ const log = await this.getTaskLog(taskId);
601
+ if (!log) {
602
+ throw new Error('Task log not found: ' + taskId);
603
+ }
604
+ // Add completion event
605
+ await this.addEvent(taskId, status === 'ERROR' ? 'TASK_ERROR' : 'TASK_COMPLETED', {
606
+ status,
607
+ files_modified: filesModified,
608
+ evidence_ref: evidenceRef,
609
+ error_message: errorMessage,
610
+ });
611
+ // Update index entry
612
+ const index = await this.getOrCreateIndex(log.session_id);
613
+ const entry = index.entries.find(e => e.task_id === taskId);
614
+ if (entry) {
615
+ entry.status = status;
616
+ entry.completed_at = new Date().toISOString();
617
+ entry.duration_ms = new Date(entry.completed_at).getTime() - new Date(entry.started_at).getTime();
618
+ entry.files_modified_count = filesModified.length;
619
+ }
620
+ await this.saveIndex(index);
621
+ }
622
+ /**
623
+ * Get task list for display (Layer 1) (legacy)
624
+ * Per spec 13_LOGGING_AND_OBSERVABILITY.md Section 2.1
625
+ */
626
+ async getTaskList(sessionId) {
627
+ const index = await this.getOrCreateIndex(sessionId);
628
+ return index.entries;
629
+ }
630
+ /**
631
+ * Get task detail for display (Layer 2) (legacy)
632
+ * Per spec 13_LOGGING_AND_OBSERVABILITY.md Section 2.2
633
+ */
634
+ async getTaskDetail(taskId, visibility = 'summary') {
635
+ const log = await this.getTaskLog(taskId);
636
+ if (!log) {
637
+ return { log: null, events: [] };
638
+ }
639
+ const events = (0, task_log_1.filterEventsByVisibility)(log.events, visibility);
640
+ // Mask any remaining sensitive data in display
641
+ const maskedEvents = events.map(e => ({
642
+ ...e,
643
+ content: (0, sensitive_data_masker_1.maskSensitiveObject)(e.content),
644
+ }));
645
+ return { log, events: maskedEvents };
646
+ }
647
+ /**
648
+ * Format task list for REPL display (legacy)
649
+ */
650
+ formatTaskList(entries, sessionId) {
651
+ if (entries.length === 0) {
652
+ return 'No tasks logged for this session.';
653
+ }
654
+ let output = 'Task Logs (session: ' + sessionId + '):\n\n';
655
+ output += ' # | Task ID | Status | Duration | Files | Tests\n';
656
+ output += ' --|--------------|------------|----------|-------|------\n';
657
+ entries.forEach((entry, index) => {
658
+ const duration = entry.duration_ms > 0
659
+ ? (entry.duration_ms / 1000).toFixed(1) + 's'
660
+ : '-';
661
+ output += ' ' + (index + 1) + ' | ' +
662
+ entry.task_id.padEnd(12) + ' | ' +
663
+ entry.status.padEnd(10) + ' | ' +
664
+ duration.padEnd(8) + ' | ' +
665
+ String(entry.files_modified_count).padEnd(5) + ' | ' +
666
+ entry.tests_run_count + '\n';
667
+ });
668
+ output += '\nUse /logs <task-id> to view details.\n';
669
+ output += 'Use /logs <task-id> --full for executor-level logs.';
670
+ return output;
671
+ }
672
+ /**
673
+ * Format task detail for REPL display (legacy)
674
+ */
675
+ formatTaskDetail(taskId, log, events, isFull) {
676
+ let output = 'Task Log: ' + taskId;
677
+ if (isFull) {
678
+ output += ' (FULL)';
679
+ }
680
+ output += '\n\n';
681
+ for (const event of events) {
682
+ const time = new Date(event.timestamp).toLocaleTimeString();
683
+ output += '[' + time + '] ' + event.event_type + '\n';
684
+ // Format content based on event type
685
+ if (event.content.text) {
686
+ output += ' "' + (0, sensitive_data_masker_1.maskSensitiveData)(event.content.text) + '"\n';
687
+ }
688
+ if (event.content.question) {
689
+ output += ' "' + (0, sensitive_data_masker_1.maskSensitiveData)(event.content.question) + '"\n';
690
+ }
691
+ if (event.content.action) {
692
+ output += ' Action: ' + event.content.action + '\n';
693
+ }
694
+ if (event.content.target_file) {
695
+ output += ' Target: ' + event.content.target_file + '\n';
696
+ }
697
+ if (event.content.status) {
698
+ output += ' Status: ' + event.content.status + '\n';
699
+ }
700
+ if (event.content.files_modified && event.content.files_modified.length > 0) {
701
+ output += ' Files modified: ' + event.content.files_modified.join(', ') + '\n';
702
+ }
703
+ if (event.content.evidence_ref) {
704
+ output += ' Evidence: ' + event.content.evidence_ref + '\n';
705
+ }
706
+ if (event.content.error_message) {
707
+ output += ' Error: ' + (0, sensitive_data_masker_1.maskSensitiveData)(event.content.error_message) + '\n';
708
+ }
709
+ // Full mode specific content
710
+ if (isFull) {
711
+ if (event.content.provider) {
712
+ output += ' Provider: ' + event.content.provider + '\n';
713
+ }
714
+ if (event.content.model) {
715
+ output += ' Model: ' + event.content.model + '\n';
716
+ }
717
+ if (event.content.tokens_input !== undefined) {
718
+ output += ' Tokens: ' + event.content.tokens_input + ' input';
719
+ if (event.content.tokens_output !== undefined) {
720
+ output += ', ' + event.content.tokens_output + ' output';
721
+ }
722
+ output += '\n';
723
+ }
724
+ if (event.content.latency_ms !== undefined) {
725
+ output += ' Latency: ' + event.content.latency_ms + 'ms\n';
726
+ }
727
+ if (event.content.exit_code !== undefined) {
728
+ output += ' Exit code: ' + event.content.exit_code + '\n';
729
+ }
730
+ if (event.content.output_summary) {
731
+ output += ' Output: ' + (0, sensitive_data_masker_1.maskSensitiveData)(event.content.output_summary) + '\n';
732
+ }
733
+ }
734
+ output += '\n';
735
+ }
736
+ if (!isFull) {
737
+ output += 'Use --full to see executor details.';
738
+ }
739
+ return output;
740
+ }
741
+ }
742
+ exports.TaskLogManager = TaskLogManager;
743
+ //# sourceMappingURL=task-log-manager.js.map