@outcomeeng/spx 0.6.6 → 0.6.7
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/cli.js +1157 -548
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -91,120 +91,394 @@ var DEFAULT_CLI_IO = {
|
|
|
91
91
|
exit: (exitCode) => process.exit(exitCode)
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
-
// src/
|
|
95
|
-
import {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
94
|
+
// src/interfaces/cli/agent.ts
|
|
95
|
+
import { inspect } from "util";
|
|
96
|
+
|
|
97
|
+
// src/commands/agent/resume.ts
|
|
98
|
+
import { readdir, readFile, stat } from "fs/promises";
|
|
99
|
+
import { homedir } from "os";
|
|
100
|
+
|
|
101
|
+
// src/domains/agent/protocol.ts
|
|
102
|
+
var AGENT_SESSION_KIND = {
|
|
103
|
+
CODEX: "codex",
|
|
104
|
+
CLAUDE_CODE: "claude-code"
|
|
105
|
+
};
|
|
106
|
+
var AGENT_SESSION_LABEL = {
|
|
107
|
+
[AGENT_SESSION_KIND.CODEX]: "Codex",
|
|
108
|
+
[AGENT_SESSION_KIND.CLAUDE_CODE]: "Claude Code"
|
|
109
|
+
};
|
|
110
|
+
var AGENT_RESUME_COMMAND = {
|
|
111
|
+
CODEX_BINARY: "codex",
|
|
112
|
+
CODEX_RESUME: "resume",
|
|
113
|
+
CLAUDE_BINARY: "claude",
|
|
114
|
+
CLAUDE_RESUME: "--resume"
|
|
115
|
+
};
|
|
116
|
+
var AGENT_SESSION_STORE = {
|
|
117
|
+
CODEX_DIR: ".codex",
|
|
118
|
+
CODEX_SESSIONS_DIR: "sessions",
|
|
119
|
+
CLAUDE_DIR: ".claude",
|
|
120
|
+
CLAUDE_PROJECTS_DIR: "projects",
|
|
121
|
+
JSONL_EXTENSION: ".jsonl",
|
|
122
|
+
TEXT_ENCODING: "utf8"
|
|
123
|
+
};
|
|
124
|
+
var AGENT_RESUME_LIMITS = {
|
|
125
|
+
RECENT_DAYS: 7,
|
|
126
|
+
DISPLAYED_CANDIDATES: 20,
|
|
127
|
+
HOURS_PER_DAY: 24,
|
|
128
|
+
MINUTES_PER_HOUR: 60,
|
|
129
|
+
SECONDS_PER_MINUTE: 60,
|
|
130
|
+
MILLISECONDS_PER_SECOND: 1e3,
|
|
131
|
+
ROOT_RESOLUTION_CONCURRENCY: 8
|
|
132
|
+
};
|
|
133
|
+
var AGENT_RESUME_MODE = {
|
|
134
|
+
PICK: "pick",
|
|
135
|
+
LATEST: "latest",
|
|
136
|
+
LIST: "list",
|
|
137
|
+
JSON: "json"
|
|
138
|
+
};
|
|
139
|
+
var AGENT_RESUME_TEXT = {
|
|
140
|
+
NO_MATCHES: "No matching agent sessions found.",
|
|
141
|
+
INTERACTIVE_REQUIRED: "agent resume requires an interactive terminal.",
|
|
142
|
+
MODE_CONFLICT: "Choose only one resume mode"
|
|
143
|
+
};
|
|
144
|
+
var AGENT_SESSION_JSON_FIELDS = {
|
|
145
|
+
TIMESTAMP: "timestamp",
|
|
146
|
+
TYPE: "type",
|
|
147
|
+
CWD: "cwd",
|
|
148
|
+
ORIGINATOR: "originator",
|
|
149
|
+
SOURCE: "source",
|
|
150
|
+
SESSION_ID: "session_id",
|
|
151
|
+
SESSION_ID_CAMEL: "sessionId",
|
|
152
|
+
ID: "id",
|
|
153
|
+
PAYLOAD: "payload",
|
|
154
|
+
GIT_BRANCH: "gitBranch",
|
|
155
|
+
THREAD_SOURCE: "thread_source"
|
|
156
|
+
};
|
|
157
|
+
var AGENT_SESSION_ROW_TYPE = {
|
|
158
|
+
CODEX_SESSION_META: "session_meta"
|
|
159
|
+
};
|
|
160
|
+
var CODEX_SESSION_ORIGINATOR = {
|
|
161
|
+
TUI: "codex-tui",
|
|
162
|
+
CLI: "codex_cli",
|
|
163
|
+
VSCODE: "codex_vscode",
|
|
164
|
+
VSCODE_HYPHEN: "codex-vscode",
|
|
165
|
+
EXEC: "codex-exec"
|
|
166
|
+
};
|
|
167
|
+
var AGENT_RESUME_RECENT_WINDOW_MS = AGENT_RESUME_LIMITS.RECENT_DAYS * AGENT_RESUME_LIMITS.HOURS_PER_DAY * AGENT_RESUME_LIMITS.MINUTES_PER_HOUR * AGENT_RESUME_LIMITS.SECONDS_PER_MINUTE * AGENT_RESUME_LIMITS.MILLISECONDS_PER_SECOND;
|
|
168
|
+
|
|
169
|
+
// src/domains/agent/resume.ts
|
|
170
|
+
import { resolve as resolve3 } from "path";
|
|
171
|
+
var AGENT_RESUME_PICKER_ACTION = {
|
|
172
|
+
MOVE_UP: "move-up",
|
|
173
|
+
MOVE_DOWN: "move-down",
|
|
174
|
+
CHOOSE: "choose",
|
|
175
|
+
QUIT: "quit",
|
|
176
|
+
IGNORE: "ignore"
|
|
177
|
+
};
|
|
178
|
+
var FIRST_PICKER_INDEX = 0;
|
|
179
|
+
var PICKER_MOVE_UP_DELTA = -1;
|
|
180
|
+
var PICKER_MOVE_DOWN_DELTA = 1;
|
|
181
|
+
var PICKER_QUIT_INPUT = "q";
|
|
182
|
+
var AgentResumeModeError = class extends Error {
|
|
183
|
+
constructor(selectedModes) {
|
|
184
|
+
super(`${AGENT_RESUME_TEXT.MODE_CONFLICT}: ${selectedModes.join(", ")}`);
|
|
185
|
+
this.selectedModes = selectedModes;
|
|
186
|
+
this.name = "AgentResumeModeError";
|
|
187
|
+
}
|
|
188
|
+
selectedModes;
|
|
189
|
+
};
|
|
190
|
+
function resolveAgentResumeMode(flags) {
|
|
191
|
+
const selected = [];
|
|
192
|
+
if (flags.latest === true) selected.push(AGENT_RESUME_MODE.LATEST);
|
|
193
|
+
if (flags.list === true) selected.push(AGENT_RESUME_MODE.LIST);
|
|
194
|
+
if (flags.json === true) selected.push(AGENT_RESUME_MODE.JSON);
|
|
195
|
+
if (selected.length > 1) {
|
|
196
|
+
throw new AgentResumeModeError(selected);
|
|
197
|
+
}
|
|
198
|
+
return selected[0] ?? AGENT_RESUME_MODE.PICK;
|
|
199
|
+
}
|
|
200
|
+
function initialAgentResumePickerState() {
|
|
201
|
+
return { selectedIndex: FIRST_PICKER_INDEX };
|
|
202
|
+
}
|
|
203
|
+
function resolveAgentResumePickerAction(input) {
|
|
204
|
+
if (input.upArrow) return AGENT_RESUME_PICKER_ACTION.MOVE_UP;
|
|
205
|
+
if (input.downArrow) return AGENT_RESUME_PICKER_ACTION.MOVE_DOWN;
|
|
206
|
+
if (input.return) return AGENT_RESUME_PICKER_ACTION.CHOOSE;
|
|
207
|
+
if (input.escape || input.input === PICKER_QUIT_INPUT) return AGENT_RESUME_PICKER_ACTION.QUIT;
|
|
208
|
+
return AGENT_RESUME_PICKER_ACTION.IGNORE;
|
|
209
|
+
}
|
|
210
|
+
function reduceAgentResumePickerState(state, action, candidateCount) {
|
|
211
|
+
if (action === AGENT_RESUME_PICKER_ACTION.MOVE_UP) {
|
|
212
|
+
return moveAgentResumePickerSelection(state, PICKER_MOVE_UP_DELTA, candidateCount);
|
|
213
|
+
}
|
|
214
|
+
if (action === AGENT_RESUME_PICKER_ACTION.MOVE_DOWN) {
|
|
215
|
+
return moveAgentResumePickerSelection(state, PICKER_MOVE_DOWN_DELTA, candidateCount);
|
|
216
|
+
}
|
|
217
|
+
return state;
|
|
218
|
+
}
|
|
219
|
+
function moveAgentResumePickerSelection(state, delta, candidateCount) {
|
|
220
|
+
const lastIndex = Math.max(candidateCount - 1, FIRST_PICKER_INDEX);
|
|
221
|
+
const nextIndex = Math.min(Math.max(state.selectedIndex + delta, FIRST_PICKER_INDEX), lastIndex);
|
|
222
|
+
return { selectedIndex: nextIndex };
|
|
223
|
+
}
|
|
224
|
+
function codexSessionStoreDir(homeDir) {
|
|
225
|
+
return resolve3(homeDir, AGENT_SESSION_STORE.CODEX_DIR, AGENT_SESSION_STORE.CODEX_SESSIONS_DIR);
|
|
226
|
+
}
|
|
227
|
+
function claudeCodeSessionStoreDir(homeDir) {
|
|
228
|
+
return resolve3(homeDir, AGENT_SESSION_STORE.CLAUDE_DIR, AGENT_SESSION_STORE.CLAUDE_PROJECTS_DIR);
|
|
229
|
+
}
|
|
230
|
+
async function discoverAgentResumeCandidates(options) {
|
|
231
|
+
const invocationRoot = await options.resolveWorktreeRoot(options.invocationDir);
|
|
232
|
+
if (invocationRoot === null) {
|
|
233
|
+
return [];
|
|
234
|
+
}
|
|
235
|
+
const drafts = [
|
|
236
|
+
...await discoverCodexResumeCandidates(
|
|
237
|
+
codexSessionStoreDir(options.homeDir),
|
|
238
|
+
options.fs,
|
|
239
|
+
options.nowMs
|
|
240
|
+
),
|
|
241
|
+
...await discoverClaudeCodeResumeCandidates(
|
|
242
|
+
claudeCodeSessionStoreDir(options.homeDir),
|
|
243
|
+
options.fs,
|
|
244
|
+
options.nowMs
|
|
245
|
+
)
|
|
246
|
+
];
|
|
247
|
+
const sortedDrafts = [...drafts];
|
|
248
|
+
sortedDrafts.sort(compareCandidates);
|
|
249
|
+
const rootResults = await mapWithConcurrency(
|
|
250
|
+
sortedDrafts,
|
|
251
|
+
AGENT_RESUME_LIMITS.ROOT_RESOLUTION_CONCURRENCY,
|
|
252
|
+
async (candidate) => ({
|
|
253
|
+
candidate,
|
|
254
|
+
root: await options.resolveWorktreeRoot(candidate.cwd)
|
|
255
|
+
})
|
|
256
|
+
);
|
|
257
|
+
return rootResults.filter((result) => result.root !== null && samePath(result.root, invocationRoot)).map((result) => result.candidate).slice(0, AGENT_RESUME_LIMITS.DISPLAYED_CANDIDATES);
|
|
258
|
+
}
|
|
259
|
+
function buildAgentResumeLaunchCommand(candidate) {
|
|
260
|
+
if (candidate.agent === AGENT_SESSION_KIND.CODEX) {
|
|
261
|
+
return {
|
|
262
|
+
command: AGENT_RESUME_COMMAND.CODEX_BINARY,
|
|
263
|
+
args: [AGENT_RESUME_COMMAND.CODEX_RESUME, candidate.sessionId],
|
|
264
|
+
cwd: candidate.cwd
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
return {
|
|
268
|
+
command: AGENT_RESUME_COMMAND.CLAUDE_BINARY,
|
|
269
|
+
args: [AGENT_RESUME_COMMAND.CLAUDE_RESUME, candidate.sessionId],
|
|
270
|
+
cwd: candidate.cwd
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
function renderAgentResumeList(candidates) {
|
|
274
|
+
if (candidates.length === 0) {
|
|
275
|
+
return AGENT_RESUME_TEXT.NO_MATCHES;
|
|
276
|
+
}
|
|
277
|
+
return candidates.map((candidate) => {
|
|
278
|
+
const updatedAt = candidate.updatedAt ?? new Date(candidate.modifiedAtMs).toISOString();
|
|
279
|
+
return `${updatedAt} ${AGENT_SESSION_LABEL[candidate.agent]} ${candidate.sessionId} ${candidate.cwd}`;
|
|
280
|
+
}).join("\n");
|
|
281
|
+
}
|
|
282
|
+
function renderAgentResumeJson(candidates) {
|
|
283
|
+
return JSON.stringify(candidates, null, 2);
|
|
284
|
+
}
|
|
285
|
+
async function discoverCodexResumeCandidates(root, fs8, nowMs) {
|
|
286
|
+
return discoverStoreCandidates(root, fs8, nowMs, parseCodexCandidateFile);
|
|
287
|
+
}
|
|
288
|
+
async function discoverClaudeCodeResumeCandidates(root, fs8, nowMs) {
|
|
289
|
+
return discoverStoreCandidates(root, fs8, nowMs, parseClaudeCodeCandidateFile);
|
|
290
|
+
}
|
|
291
|
+
async function discoverStoreCandidates(root, fs8, nowMs, parseCandidate) {
|
|
292
|
+
const files = await collectJsonlFiles(root, fs8);
|
|
293
|
+
const candidates = [];
|
|
294
|
+
for (const file of files) {
|
|
295
|
+
const stat7 = await fs8.stat(file).catch(() => null);
|
|
296
|
+
if (stat7 === null || !isRecentAgentSessionMtime(stat7.mtimeMs, nowMs)) {
|
|
297
|
+
continue;
|
|
117
298
|
}
|
|
118
|
-
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
throw new Error(`Failed to initialize marketplace: ${error.message}`);
|
|
299
|
+
const content = await fs8.readFile(file).catch(() => null);
|
|
300
|
+
if (content === null) {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
const candidate = parseCandidate(file, content, stat7.mtimeMs);
|
|
304
|
+
if (candidate !== null) {
|
|
305
|
+
candidates.push(candidate);
|
|
126
306
|
}
|
|
127
|
-
throw error;
|
|
128
307
|
}
|
|
308
|
+
return candidates;
|
|
129
309
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
310
|
+
async function collectJsonlFiles(root, fs8) {
|
|
311
|
+
const entries = await fs8.readDir(root).catch(() => []);
|
|
312
|
+
const files = [];
|
|
313
|
+
for (const entry of entries) {
|
|
314
|
+
const child = resolve3(root, entry.name);
|
|
315
|
+
if (entry.isDirectory) {
|
|
316
|
+
files.push(...await collectJsonlFiles(child, fs8));
|
|
317
|
+
} else if (entry.isFile && entry.name.endsWith(AGENT_SESSION_STORE.JSONL_EXTENSION)) {
|
|
318
|
+
files.push(child);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return files;
|
|
322
|
+
}
|
|
323
|
+
function isRecentAgentSessionMtime(modifiedAtMs, nowMs) {
|
|
324
|
+
return modifiedAtMs <= nowMs && nowMs - modifiedAtMs <= AGENT_RESUME_RECENT_WINDOW_MS;
|
|
325
|
+
}
|
|
326
|
+
function parseCodexCandidateFile(sourcePath, content, modifiedAtMs) {
|
|
327
|
+
let sessionId = null;
|
|
328
|
+
let cwd = null;
|
|
329
|
+
let updatedAt = null;
|
|
330
|
+
let isInteractiveSession = false;
|
|
331
|
+
for (const line of content.split("\n")) {
|
|
332
|
+
const row = parseJsonObject(line);
|
|
333
|
+
if (row === null) {
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
isInteractiveSession = isCodexInteractiveSessionRow(row) || isInteractiveSession;
|
|
337
|
+
sessionId ??= firstString(row, [
|
|
338
|
+
[AGENT_SESSION_JSON_FIELDS.SESSION_ID],
|
|
339
|
+
[AGENT_SESSION_JSON_FIELDS.ID],
|
|
340
|
+
[AGENT_SESSION_JSON_FIELDS.PAYLOAD, AGENT_SESSION_JSON_FIELDS.SESSION_ID],
|
|
341
|
+
[AGENT_SESSION_JSON_FIELDS.PAYLOAD, AGENT_SESSION_JSON_FIELDS.ID]
|
|
342
|
+
]);
|
|
343
|
+
cwd = firstString(row, [
|
|
344
|
+
[AGENT_SESSION_JSON_FIELDS.CWD],
|
|
345
|
+
[AGENT_SESSION_JSON_FIELDS.PAYLOAD, AGENT_SESSION_JSON_FIELDS.CWD]
|
|
346
|
+
]) ?? cwd;
|
|
347
|
+
updatedAt = maxIsoTimestamp(updatedAt, firstString(row, [[AGENT_SESSION_JSON_FIELDS.TIMESTAMP]]));
|
|
348
|
+
}
|
|
349
|
+
if (!isInteractiveSession || sessionId === null || cwd === null) {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
return {
|
|
353
|
+
agent: AGENT_SESSION_KIND.CODEX,
|
|
354
|
+
sessionId,
|
|
355
|
+
cwd,
|
|
356
|
+
sourcePath,
|
|
357
|
+
modifiedAtMs,
|
|
358
|
+
updatedAt,
|
|
359
|
+
branch: null
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function isCodexInteractiveSessionRow(row) {
|
|
363
|
+
if (firstString(row, [[AGENT_SESSION_JSON_FIELDS.TYPE]]) !== AGENT_SESSION_ROW_TYPE.CODEX_SESSION_META) {
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
const originator = firstString(row, [
|
|
367
|
+
[AGENT_SESSION_JSON_FIELDS.ORIGINATOR],
|
|
368
|
+
[AGENT_SESSION_JSON_FIELDS.PAYLOAD, AGENT_SESSION_JSON_FIELDS.ORIGINATOR]
|
|
369
|
+
]);
|
|
370
|
+
return originator === CODEX_SESSION_ORIGINATOR.TUI || originator === CODEX_SESSION_ORIGINATOR.CLI || originator === CODEX_SESSION_ORIGINATOR.VSCODE || originator === CODEX_SESSION_ORIGINATOR.VSCODE_HYPHEN;
|
|
371
|
+
}
|
|
372
|
+
function parseClaudeCodeCandidateFile(sourcePath, content, modifiedAtMs) {
|
|
373
|
+
let sessionId = null;
|
|
374
|
+
let cwd = null;
|
|
375
|
+
let updatedAt = null;
|
|
376
|
+
let branch = null;
|
|
377
|
+
for (const line of content.split("\n")) {
|
|
378
|
+
const row = parseJsonObject(line);
|
|
379
|
+
if (row === null) {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
sessionId ??= firstString(row, [
|
|
383
|
+
[AGENT_SESSION_JSON_FIELDS.SESSION_ID_CAMEL],
|
|
384
|
+
[AGENT_SESSION_JSON_FIELDS.SESSION_ID],
|
|
385
|
+
[AGENT_SESSION_JSON_FIELDS.PAYLOAD, AGENT_SESSION_JSON_FIELDS.SESSION_ID_CAMEL],
|
|
386
|
+
[AGENT_SESSION_JSON_FIELDS.PAYLOAD, AGENT_SESSION_JSON_FIELDS.SESSION_ID]
|
|
387
|
+
]);
|
|
388
|
+
cwd = firstString(row, [
|
|
389
|
+
[AGENT_SESSION_JSON_FIELDS.CWD],
|
|
390
|
+
[AGENT_SESSION_JSON_FIELDS.PAYLOAD, AGENT_SESSION_JSON_FIELDS.CWD]
|
|
391
|
+
]) ?? cwd;
|
|
392
|
+
updatedAt = maxIsoTimestamp(updatedAt, firstString(row, [[AGENT_SESSION_JSON_FIELDS.TIMESTAMP]]));
|
|
393
|
+
branch = firstString(row, [[AGENT_SESSION_JSON_FIELDS.GIT_BRANCH]]) ?? branch;
|
|
394
|
+
}
|
|
395
|
+
if (sessionId === null || cwd === null) {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
return {
|
|
399
|
+
agent: AGENT_SESSION_KIND.CLAUDE_CODE,
|
|
400
|
+
sessionId,
|
|
401
|
+
cwd,
|
|
402
|
+
sourcePath,
|
|
403
|
+
modifiedAtMs,
|
|
404
|
+
updatedAt,
|
|
405
|
+
branch
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
function parseJsonObject(line) {
|
|
409
|
+
const trimmed = line.trim();
|
|
410
|
+
if (trimmed.length === 0) {
|
|
411
|
+
return null;
|
|
138
412
|
}
|
|
139
|
-
visited.add(normalizedRoot);
|
|
140
413
|
try {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
414
|
+
const parsed = JSON.parse(trimmed);
|
|
415
|
+
return isRecord(parsed) ? parsed : null;
|
|
416
|
+
} catch {
|
|
417
|
+
return null;
|
|
144
418
|
}
|
|
145
419
|
}
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
420
|
+
function firstString(row, paths) {
|
|
421
|
+
for (const path7 of paths) {
|
|
422
|
+
const value = valueAtPath(row, path7);
|
|
423
|
+
if (typeof value === "string" && value.length > 0) {
|
|
424
|
+
return value;
|
|
425
|
+
}
|
|
150
426
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
function valueAtPath(row, path7) {
|
|
430
|
+
let current = row;
|
|
431
|
+
for (const segment of path7) {
|
|
432
|
+
if (!isRecord(current)) {
|
|
433
|
+
return void 0;
|
|
434
|
+
}
|
|
435
|
+
current = current[segment];
|
|
155
436
|
}
|
|
156
|
-
return
|
|
437
|
+
return current;
|
|
157
438
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return
|
|
439
|
+
function isRecord(value) {
|
|
440
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
441
|
+
}
|
|
442
|
+
function maxIsoTimestamp(left, right) {
|
|
443
|
+
if (right === null) {
|
|
444
|
+
return left;
|
|
164
445
|
}
|
|
165
|
-
|
|
446
|
+
if (left === null) {
|
|
447
|
+
return right;
|
|
448
|
+
}
|
|
449
|
+
return Date.parse(right) > Date.parse(left) ? right : left;
|
|
166
450
|
}
|
|
167
|
-
function
|
|
168
|
-
|
|
169
|
-
if (
|
|
170
|
-
|
|
171
|
-
|
|
451
|
+
function compareCandidates(left, right) {
|
|
452
|
+
const modifiedDiff = right.modifiedAtMs - left.modifiedAtMs;
|
|
453
|
+
if (modifiedDiff !== 0) {
|
|
454
|
+
return modifiedDiff;
|
|
455
|
+
}
|
|
456
|
+
return `${left.agent}:${left.sessionId}`.localeCompare(`${right.agent}:${right.sessionId}`);
|
|
172
457
|
}
|
|
173
|
-
function
|
|
174
|
-
|
|
175
|
-
if (typeof error === "number" || typeof error === "boolean" || typeof error === "bigint") return error.toString();
|
|
176
|
-
if (typeof error === "symbol") return error.description ?? "Symbol()";
|
|
177
|
-
if (error === void 0) return "undefined";
|
|
178
|
-
return Object.prototype.toString.call(error);
|
|
458
|
+
function samePath(left, right) {
|
|
459
|
+
return resolve3(left) === resolve3(right);
|
|
179
460
|
}
|
|
180
|
-
async function
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
461
|
+
async function mapWithConcurrency(items, concurrency, mapper) {
|
|
462
|
+
const results = new Array(items.length);
|
|
463
|
+
let nextIndex = 0;
|
|
464
|
+
async function worker() {
|
|
465
|
+
for (; ; ) {
|
|
466
|
+
const index = nextIndex;
|
|
467
|
+
nextIndex += 1;
|
|
468
|
+
if (index >= items.length) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
results[index] = await mapper(items[index]);
|
|
186
472
|
}
|
|
187
|
-
return path.extname(filePath) === ".json";
|
|
188
|
-
} catch {
|
|
189
|
-
return false;
|
|
190
473
|
}
|
|
474
|
+
const workerCount = Math.min(Math.max(1, concurrency), items.length);
|
|
475
|
+
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
476
|
+
return results;
|
|
191
477
|
}
|
|
192
478
|
|
|
193
|
-
// src/lib/state-store/index.ts
|
|
194
|
-
import { createHash, randomBytes as nodeRandomBytes } from "crypto";
|
|
195
|
-
import { constants as fsConstants } from "fs";
|
|
196
|
-
import {
|
|
197
|
-
lstat as nodeLstat,
|
|
198
|
-
mkdir as nodeMkdir,
|
|
199
|
-
open as nodeOpen,
|
|
200
|
-
readdir as nodeReaddir,
|
|
201
|
-
rm as nodeRm
|
|
202
|
-
} from "fs/promises";
|
|
203
|
-
import { dirname as dirname2, join as join2 } from "path";
|
|
204
|
-
|
|
205
479
|
// src/git/root.ts
|
|
206
|
-
import { execa
|
|
207
|
-
import { basename, dirname, isAbsolute, join, resolve as
|
|
480
|
+
import { execa } from "execa";
|
|
481
|
+
import { basename, dirname, isAbsolute, join, resolve as resolve4 } from "path";
|
|
208
482
|
|
|
209
483
|
// src/git/environment.ts
|
|
210
484
|
function withoutGitEnvironment(env) {
|
|
@@ -220,7 +494,7 @@ function withoutGitEnvironment(env) {
|
|
|
220
494
|
// src/git/root.ts
|
|
221
495
|
var defaultGitDependencies = {
|
|
222
496
|
execa: async (command, args, options) => {
|
|
223
|
-
const result = await
|
|
497
|
+
const result = await execa(command, args, {
|
|
224
498
|
...options,
|
|
225
499
|
env: withoutGitEnvironment(process.env),
|
|
226
500
|
extendEnv: false
|
|
@@ -257,7 +531,8 @@ var GIT_ROOT_COMMAND = {
|
|
|
257
531
|
CORE_BARE_KEY: "core.bare",
|
|
258
532
|
REMOTE: "remote",
|
|
259
533
|
GET_URL: "get-url",
|
|
260
|
-
ORIGIN: "origin"
|
|
534
|
+
ORIGIN: "origin",
|
|
535
|
+
UNTRACKED_FILES_ALL: "--untracked-files=all"
|
|
261
536
|
};
|
|
262
537
|
var GIT_URL_SUFFIX = ".git";
|
|
263
538
|
var GIT_DIR_BASENAME = ".git";
|
|
@@ -300,7 +575,8 @@ var GIT_ORIGIN_HEAD_REF_ARGS = [
|
|
|
300
575
|
];
|
|
301
576
|
var GIT_STATUS_PORCELAIN_ARGS = [
|
|
302
577
|
GIT_ROOT_COMMAND.STATUS,
|
|
303
|
-
GIT_ROOT_COMMAND.PORCELAIN
|
|
578
|
+
GIT_ROOT_COMMAND.PORCELAIN,
|
|
579
|
+
GIT_ROOT_COMMAND.UNTRACKED_FILES_ALL
|
|
304
580
|
];
|
|
305
581
|
var GIT_WORKTREE_LIST_PORCELAIN_ARGS = [
|
|
306
582
|
GIT_ROOT_COMMAND.WORKTREE,
|
|
@@ -311,7 +587,8 @@ var GIT_WORKTREE_PORCELAIN_ROOT_PREFIX = "worktree ";
|
|
|
311
587
|
var GIT_WORKTREE_PORCELAIN_BARE_LINE = "bare";
|
|
312
588
|
var GIT_WORKTREE_PORCELAIN_PRUNABLE_LINE = "prunable";
|
|
313
589
|
var GIT_WORKTREE_PORCELAIN_PRUNABLE_PREFIX = `${GIT_WORKTREE_PORCELAIN_PRUNABLE_LINE} `;
|
|
314
|
-
var
|
|
590
|
+
var POSIX_PATH_SEPARATOR = "/";
|
|
591
|
+
var WINDOWS_PATH_SEPARATOR = "\\";
|
|
315
592
|
async function detectWorktreeProductRoot(cwd = CONFIG_PROCESS_CWD.read(), deps = defaultGitDependencies) {
|
|
316
593
|
try {
|
|
317
594
|
const result = await deps.execa(
|
|
@@ -338,15 +615,20 @@ async function detectWorktreeProductRoot(cwd = CONFIG_PROCESS_CWD.read(), deps =
|
|
|
338
615
|
};
|
|
339
616
|
}
|
|
340
617
|
}
|
|
618
|
+
function stripTrailingPathSeparators(value) {
|
|
619
|
+
let end = value.length;
|
|
620
|
+
while (end > 0 && (value[end - 1] === POSIX_PATH_SEPARATOR || value[end - 1] === WINDOWS_PATH_SEPARATOR)) {
|
|
621
|
+
end -= 1;
|
|
622
|
+
}
|
|
623
|
+
return value.slice(0, end);
|
|
624
|
+
}
|
|
341
625
|
function extractStdout(stdout) {
|
|
342
626
|
if (!stdout) return "";
|
|
343
|
-
|
|
344
|
-
return str.trim().replace(TRAILING_PATH_SEPARATORS_PATTERN, "");
|
|
627
|
+
return stripTrailingPathSeparators(stdout.trim());
|
|
345
628
|
}
|
|
346
629
|
function trimStdout(stdout) {
|
|
347
630
|
if (!stdout) return "";
|
|
348
|
-
|
|
349
|
-
return str.trim();
|
|
631
|
+
return stdout.trim();
|
|
350
632
|
}
|
|
351
633
|
async function detectGitCommonDirProductRoot(cwd = CONFIG_PROCESS_CWD.read(), deps = defaultGitDependencies) {
|
|
352
634
|
try {
|
|
@@ -377,7 +659,7 @@ async function detectGitCommonDirProductRoot(cwd = CONFIG_PROCESS_CWD.read(), de
|
|
|
377
659
|
};
|
|
378
660
|
}
|
|
379
661
|
const commonDir = extractStdout(commonDirResult.stdout);
|
|
380
|
-
const absoluteCommonDir = isAbsolute(commonDir) ? commonDir :
|
|
662
|
+
const absoluteCommonDir = isAbsolute(commonDir) ? commonDir : resolve4(toplevel, commonDir);
|
|
381
663
|
const gitCommonDirProductRoot = dirname(absoluteCommonDir);
|
|
382
664
|
return {
|
|
383
665
|
productDir: gitCommonDirProductRoot,
|
|
@@ -461,7 +743,7 @@ async function isWorkingTreeClean(cwd = CONFIG_PROCESS_CWD.read(), deps = defaul
|
|
|
461
743
|
}
|
|
462
744
|
function repositoryName(originUrl) {
|
|
463
745
|
if (originUrl === null) return null;
|
|
464
|
-
const trimmed = originUrl.trim()
|
|
746
|
+
const trimmed = stripTrailingPathSeparators(originUrl.trim());
|
|
465
747
|
const lastSeparator = Math.max(
|
|
466
748
|
trimmed.lastIndexOf("/"),
|
|
467
749
|
trimmed.lastIndexOf("\\"),
|
|
@@ -472,10 +754,10 @@ function repositoryName(originUrl) {
|
|
|
472
754
|
return name.length === 0 ? null : name;
|
|
473
755
|
}
|
|
474
756
|
function normalizeGitPath(path7) {
|
|
475
|
-
return path7.trim()
|
|
757
|
+
return stripTrailingPathSeparators(path7.trim());
|
|
476
758
|
}
|
|
477
759
|
function normalizedGitPathKey(path7) {
|
|
478
|
-
return normalizeGitPath(path7).
|
|
760
|
+
return normalizeGitPath(path7).replaceAll(WINDOWS_PATH_SEPARATOR, POSIX_PATH_SEPARATOR);
|
|
479
761
|
}
|
|
480
762
|
function isObservedWorktreeRoot(worktreeRoots, candidate) {
|
|
481
763
|
const candidateKey = normalizedGitPathKey(candidate);
|
|
@@ -539,21 +821,561 @@ async function gatherGitFacts(cwd = CONFIG_PROCESS_CWD.read(), deps = defaultGit
|
|
|
539
821
|
originUrl
|
|
540
822
|
};
|
|
541
823
|
}
|
|
542
|
-
const rawCommonDir = extractStdout(commonDirResult.stdout);
|
|
543
|
-
const commonDir = isAbsolute(rawCommonDir) ? rawCommonDir :
|
|
544
|
-
const bareResult = await deps.execa(
|
|
545
|
-
GIT_ROOT_COMMAND.EXECUTABLE,
|
|
546
|
-
[...GIT_CORE_BARE_ARGS],
|
|
547
|
-
{ cwd, reject: false }
|
|
548
|
-
);
|
|
549
|
-
const commonDirIsBare = bareResult.exitCode === 0 && extractStdout(bareResult.stdout) === GIT_CORE_BARE_TRUE;
|
|
550
|
-
return { worktreeRoot, worktreeRoots, worktreeListRead, commonDir, commonDirIsBare, originUrl };
|
|
824
|
+
const rawCommonDir = extractStdout(commonDirResult.stdout);
|
|
825
|
+
const commonDir = isAbsolute(rawCommonDir) ? rawCommonDir : resolve4(worktreeRoot, rawCommonDir);
|
|
826
|
+
const bareResult = await deps.execa(
|
|
827
|
+
GIT_ROOT_COMMAND.EXECUTABLE,
|
|
828
|
+
[...GIT_CORE_BARE_ARGS],
|
|
829
|
+
{ cwd, reject: false }
|
|
830
|
+
);
|
|
831
|
+
const commonDirIsBare = bareResult.exitCode === 0 && extractStdout(bareResult.stdout) === GIT_CORE_BARE_TRUE;
|
|
832
|
+
return { worktreeRoot, worktreeRoots, worktreeListRead, commonDir, commonDirIsBare, originUrl };
|
|
833
|
+
} catch {
|
|
834
|
+
return null;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
// src/commands/agent/resume.ts
|
|
839
|
+
var nodeAgentSessionFileSystem = {
|
|
840
|
+
async readDir(path7) {
|
|
841
|
+
const entries = await readdir(path7, { withFileTypes: true });
|
|
842
|
+
return entries.map((entry) => ({
|
|
843
|
+
name: entry.name,
|
|
844
|
+
isDirectory: entry.isDirectory(),
|
|
845
|
+
isFile: entry.isFile()
|
|
846
|
+
}));
|
|
847
|
+
},
|
|
848
|
+
async readFile(path7) {
|
|
849
|
+
return readFile(path7, AGENT_SESSION_STORE.TEXT_ENCODING);
|
|
850
|
+
},
|
|
851
|
+
async stat(path7) {
|
|
852
|
+
const result = await stat(path7);
|
|
853
|
+
return { mtimeMs: result.mtimeMs };
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
var defaultAgentResumeCommandDeps = {
|
|
857
|
+
fs: nodeAgentSessionFileSystem,
|
|
858
|
+
homeDir: homedir,
|
|
859
|
+
nowMs: Date.now,
|
|
860
|
+
resolveWorktreeRoot: async (cwd) => {
|
|
861
|
+
const result = await detectWorktreeProductRoot(cwd);
|
|
862
|
+
return result.isGitRepo ? result.productDir : null;
|
|
863
|
+
}
|
|
864
|
+
};
|
|
865
|
+
async function loadAgentResumeCandidates(options) {
|
|
866
|
+
const deps = options.deps ?? defaultAgentResumeCommandDeps;
|
|
867
|
+
return discoverAgentResumeCandidates({
|
|
868
|
+
invocationDir: options.cwd,
|
|
869
|
+
homeDir: deps.homeDir(),
|
|
870
|
+
nowMs: deps.nowMs(),
|
|
871
|
+
fs: deps.fs,
|
|
872
|
+
resolveWorktreeRoot: deps.resolveWorktreeRoot
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
async function listAgentResumeSessions(options) {
|
|
876
|
+
return renderAgentResumeList(await loadAgentResumeCandidates(options));
|
|
877
|
+
}
|
|
878
|
+
async function jsonAgentResumeSessions(options) {
|
|
879
|
+
return renderAgentResumeJson(await loadAgentResumeCandidates(options));
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// src/lib/process-lifecycle/exit-codes.ts
|
|
883
|
+
var SIGINT_EXIT_CODE = 130;
|
|
884
|
+
var SIGTERM_EXIT_CODE = 143;
|
|
885
|
+
var EPIPE_EXIT_CODE = 0;
|
|
886
|
+
var UNCAUGHT_EXIT_CODE = 1;
|
|
887
|
+
|
|
888
|
+
// src/lib/process-lifecycle/foreground-handoff.ts
|
|
889
|
+
var FOREGROUND_SIGNALS = ["SIGINT", "SIGTERM"];
|
|
890
|
+
function createSignalSuspender(target) {
|
|
891
|
+
return {
|
|
892
|
+
suspend() {
|
|
893
|
+
const ignore = () => {
|
|
894
|
+
};
|
|
895
|
+
const restorers = FOREGROUND_SIGNALS.map((signal) => {
|
|
896
|
+
const originals = target.listeners(signal);
|
|
897
|
+
for (const listener of originals) target.removeListener(signal, listener);
|
|
898
|
+
target.on(signal, ignore);
|
|
899
|
+
return () => {
|
|
900
|
+
target.removeListener(signal, ignore);
|
|
901
|
+
for (const listener of originals) target.on(signal, listener);
|
|
902
|
+
};
|
|
903
|
+
});
|
|
904
|
+
return () => {
|
|
905
|
+
for (const restore of restorers) restore();
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// src/lib/process-lifecycle/handlers.ts
|
|
912
|
+
var SIGINT_NAME = "SIGINT";
|
|
913
|
+
var SIGTERM_NAME = "SIGTERM";
|
|
914
|
+
function createHandlers(deps) {
|
|
915
|
+
let cleanupOnce = false;
|
|
916
|
+
function killEachChild(signal) {
|
|
917
|
+
deps.registry.forEach((child) => {
|
|
918
|
+
if (!child.killed) child.kill(signal);
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
function exitOnce(code, killSignal) {
|
|
922
|
+
if (cleanupOnce) {
|
|
923
|
+
deps.exitController.exit(code);
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
cleanupOnce = true;
|
|
927
|
+
if (killSignal !== void 0) killEachChild(killSignal);
|
|
928
|
+
deps.exitController.exit(code);
|
|
929
|
+
}
|
|
930
|
+
return {
|
|
931
|
+
onSigint() {
|
|
932
|
+
exitOnce(SIGINT_EXIT_CODE, SIGINT_NAME);
|
|
933
|
+
},
|
|
934
|
+
onSigterm() {
|
|
935
|
+
exitOnce(SIGTERM_EXIT_CODE, SIGTERM_NAME);
|
|
936
|
+
},
|
|
937
|
+
onEpipe() {
|
|
938
|
+
exitOnce(EPIPE_EXIT_CODE, SIGTERM_NAME);
|
|
939
|
+
},
|
|
940
|
+
onUncaught(_error) {
|
|
941
|
+
exitOnce(UNCAUGHT_EXIT_CODE, SIGTERM_NAME);
|
|
942
|
+
}
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// src/lib/process-lifecycle/install.ts
|
|
947
|
+
import { spawn } from "child_process";
|
|
948
|
+
|
|
949
|
+
// src/lib/process-lifecycle/registry.ts
|
|
950
|
+
function createRegistry() {
|
|
951
|
+
const tracked = /* @__PURE__ */ new Set();
|
|
952
|
+
return {
|
|
953
|
+
add(child) {
|
|
954
|
+
tracked.add(child);
|
|
955
|
+
},
|
|
956
|
+
remove(child) {
|
|
957
|
+
tracked.delete(child);
|
|
958
|
+
},
|
|
959
|
+
forEach(fn) {
|
|
960
|
+
for (const child of tracked) fn(child);
|
|
961
|
+
},
|
|
962
|
+
get size() {
|
|
963
|
+
return tracked.size;
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// src/lib/process-lifecycle/runner.ts
|
|
969
|
+
function createLifecycleRunner(deps) {
|
|
970
|
+
return {
|
|
971
|
+
spawn(command, args, options) {
|
|
972
|
+
const child = deps.spawn(command, args, options);
|
|
973
|
+
deps.registry.add(child);
|
|
974
|
+
child.on("exit", () => deps.registry.remove(child));
|
|
975
|
+
return child;
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
// src/lib/process-lifecycle/install.ts
|
|
981
|
+
var moduleRegistry = createRegistry();
|
|
982
|
+
var moduleExitController = {
|
|
983
|
+
exit(code) {
|
|
984
|
+
process.exit(code);
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
var installed = false;
|
|
988
|
+
var lifecycleProcessRunner = createLifecycleRunner({
|
|
989
|
+
registry: moduleRegistry,
|
|
990
|
+
spawn
|
|
991
|
+
});
|
|
992
|
+
var foregroundProcessRunner = { spawn };
|
|
993
|
+
var processSignalTarget = {
|
|
994
|
+
listeners: (signal) => process.listeners(signal),
|
|
995
|
+
on: (signal, listener) => {
|
|
996
|
+
process.on(signal, listener);
|
|
997
|
+
},
|
|
998
|
+
removeListener: (signal, listener) => {
|
|
999
|
+
process.removeListener(signal, listener);
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
1002
|
+
var lifecycleSignalSuspender = createSignalSuspender(processSignalTarget);
|
|
1003
|
+
var EPIPE_CODE = "EPIPE";
|
|
1004
|
+
var UNCAUGHT_PREFIX = "Uncaught: ";
|
|
1005
|
+
var NEWLINE = "\n";
|
|
1006
|
+
function formatUncaught(error) {
|
|
1007
|
+
if (error instanceof Error && error.stack !== void 0) {
|
|
1008
|
+
return UNCAUGHT_PREFIX + error.stack + NEWLINE;
|
|
1009
|
+
}
|
|
1010
|
+
return UNCAUGHT_PREFIX + String(error) + NEWLINE;
|
|
1011
|
+
}
|
|
1012
|
+
function logUncaughtToStderr(error) {
|
|
1013
|
+
try {
|
|
1014
|
+
process.stderr.write(formatUncaught(error));
|
|
1015
|
+
} catch {
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
function installLifecycle() {
|
|
1019
|
+
if (installed) return;
|
|
1020
|
+
installed = true;
|
|
1021
|
+
const handlers = createHandlers({
|
|
1022
|
+
registry: moduleRegistry,
|
|
1023
|
+
exitController: moduleExitController
|
|
1024
|
+
});
|
|
1025
|
+
process.on("uncaughtException", (error) => {
|
|
1026
|
+
logUncaughtToStderr(error);
|
|
1027
|
+
handlers.onUncaught(error);
|
|
1028
|
+
});
|
|
1029
|
+
process.on("unhandledRejection", (reason) => {
|
|
1030
|
+
logUncaughtToStderr(reason);
|
|
1031
|
+
handlers.onUncaught(reason);
|
|
1032
|
+
});
|
|
1033
|
+
process.on("SIGTERM", () => handlers.onSigterm());
|
|
1034
|
+
process.on("SIGINT", () => handlers.onSigint());
|
|
1035
|
+
process.stdout.on("error", (error) => {
|
|
1036
|
+
if (error.code === EPIPE_CODE) {
|
|
1037
|
+
handlers.onEpipe();
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
handlers.onUncaught(error);
|
|
1041
|
+
});
|
|
1042
|
+
process.stderr.on("error", (error) => {
|
|
1043
|
+
if (error.code === EPIPE_CODE) {
|
|
1044
|
+
handlers.onEpipe();
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
handlers.onUncaught(error);
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// src/lib/process-lifecycle/managed-subprocess.ts
|
|
1052
|
+
var MANAGED_SUBPROCESS_STDIO = "pipe";
|
|
1053
|
+
function spawnManagedSubprocess(runner, command, args, options) {
|
|
1054
|
+
return runner.spawn(command, args, {
|
|
1055
|
+
...options,
|
|
1056
|
+
stdio: MANAGED_SUBPROCESS_STDIO
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// src/interfaces/cli/foreground-launch.ts
|
|
1061
|
+
var FOREGROUND_LAUNCH_STDIO = "inherit";
|
|
1062
|
+
var LAUNCH_FAILURE_STATUS = 1;
|
|
1063
|
+
function launchForegroundCommand(runner, suspender, command) {
|
|
1064
|
+
const restoreSignals = suspender.suspend();
|
|
1065
|
+
return new Promise((resolve12) => {
|
|
1066
|
+
let settled = false;
|
|
1067
|
+
const settle = (status) => {
|
|
1068
|
+
if (settled) return;
|
|
1069
|
+
settled = true;
|
|
1070
|
+
restoreSignals();
|
|
1071
|
+
resolve12(status);
|
|
1072
|
+
};
|
|
1073
|
+
const child = runner.spawn(command.command, command.args, {
|
|
1074
|
+
cwd: command.cwd,
|
|
1075
|
+
stdio: FOREGROUND_LAUNCH_STDIO
|
|
1076
|
+
});
|
|
1077
|
+
child.once("exit", (code) => settle(code ?? LAUNCH_FAILURE_STATUS));
|
|
1078
|
+
child.once("error", () => settle(LAUNCH_FAILURE_STATUS));
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// src/interfaces/cli/agent/resume/launch-agent-resume.ts
|
|
1083
|
+
function launchAgentResume(runner, suspender, command) {
|
|
1084
|
+
return launchForegroundCommand(runner, suspender, command);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// src/interfaces/cli/agent/resume/run-picker.tsx
|
|
1088
|
+
import { render } from "ink";
|
|
1089
|
+
|
|
1090
|
+
// src/interfaces/cli/agent/resume/AgentResumePicker.tsx
|
|
1091
|
+
import { Box, Text, useInput } from "ink";
|
|
1092
|
+
import { useState } from "react";
|
|
1093
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1094
|
+
var SELECTED_COLOR = "cyan";
|
|
1095
|
+
var SELECTED_MARKER = ">";
|
|
1096
|
+
var UNSELECTED_MARKER = " ";
|
|
1097
|
+
function AgentResumePicker(props) {
|
|
1098
|
+
const [state, setState] = useState(initialAgentResumePickerState);
|
|
1099
|
+
useInput((input, key) => {
|
|
1100
|
+
const action = resolveAgentResumePickerAction({
|
|
1101
|
+
input,
|
|
1102
|
+
upArrow: key.upArrow,
|
|
1103
|
+
downArrow: key.downArrow,
|
|
1104
|
+
return: key.return,
|
|
1105
|
+
escape: key.escape
|
|
1106
|
+
});
|
|
1107
|
+
if (action === AGENT_RESUME_PICKER_ACTION.CHOOSE) {
|
|
1108
|
+
const selected = props.candidates.at(state.selectedIndex);
|
|
1109
|
+
if (selected !== void 0) {
|
|
1110
|
+
props.onChoose(selected);
|
|
1111
|
+
}
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
if (action === AGENT_RESUME_PICKER_ACTION.QUIT) {
|
|
1115
|
+
props.onQuit();
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
setState((current) => reduceAgentResumePickerState(current, action, props.candidates.length));
|
|
1119
|
+
});
|
|
1120
|
+
if (props.candidates.length === 0) {
|
|
1121
|
+
return /* @__PURE__ */ jsx(Text, { children: AGENT_RESUME_TEXT.NO_MATCHES });
|
|
1122
|
+
}
|
|
1123
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: props.candidates.map((candidate, index) => /* @__PURE__ */ jsxs(
|
|
1124
|
+
Text,
|
|
1125
|
+
{
|
|
1126
|
+
color: index === state.selectedIndex ? SELECTED_COLOR : void 0,
|
|
1127
|
+
children: [
|
|
1128
|
+
index === state.selectedIndex ? SELECTED_MARKER : UNSELECTED_MARKER,
|
|
1129
|
+
" ",
|
|
1130
|
+
AGENT_SESSION_LABEL[candidate.agent],
|
|
1131
|
+
" ",
|
|
1132
|
+
candidate.sessionId,
|
|
1133
|
+
" ",
|
|
1134
|
+
candidate.cwd
|
|
1135
|
+
]
|
|
1136
|
+
},
|
|
1137
|
+
`${candidate.agent}:${candidate.sessionId}`
|
|
1138
|
+
)) });
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
// src/interfaces/cli/agent/resume/run-picker.tsx
|
|
1142
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1143
|
+
var AGENT_RESUME_PICKER_RESULT = {
|
|
1144
|
+
SELECTED: "selected",
|
|
1145
|
+
QUIT: "quit"
|
|
1146
|
+
};
|
|
1147
|
+
function selectedAgentResumeCandidate(candidate) {
|
|
1148
|
+
return { kind: AGENT_RESUME_PICKER_RESULT.SELECTED, candidate };
|
|
1149
|
+
}
|
|
1150
|
+
function quitAgentResumePicker() {
|
|
1151
|
+
return { kind: AGENT_RESUME_PICKER_RESULT.QUIT };
|
|
1152
|
+
}
|
|
1153
|
+
async function runAgentResumePicker(candidates, renderPicker = render) {
|
|
1154
|
+
let result = quitAgentResumePicker();
|
|
1155
|
+
let unmount = () => {
|
|
1156
|
+
};
|
|
1157
|
+
const instance = renderPicker(
|
|
1158
|
+
/* @__PURE__ */ jsx2(
|
|
1159
|
+
AgentResumePicker,
|
|
1160
|
+
{
|
|
1161
|
+
candidates,
|
|
1162
|
+
onChoose: (candidate) => {
|
|
1163
|
+
result = selectedAgentResumeCandidate(candidate);
|
|
1164
|
+
unmount();
|
|
1165
|
+
},
|
|
1166
|
+
onQuit: () => {
|
|
1167
|
+
result = quitAgentResumePicker();
|
|
1168
|
+
unmount();
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
)
|
|
1172
|
+
);
|
|
1173
|
+
unmount = instance.unmount;
|
|
1174
|
+
await instance.waitUntilExit();
|
|
1175
|
+
return result;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// src/interfaces/cli/agent.ts
|
|
1179
|
+
var AGENT_CLI = {
|
|
1180
|
+
commandName: "agent",
|
|
1181
|
+
resumeCommandName: "resume",
|
|
1182
|
+
flags: {
|
|
1183
|
+
latest: "--latest",
|
|
1184
|
+
list: "--list",
|
|
1185
|
+
json: "--json"
|
|
1186
|
+
}
|
|
1187
|
+
};
|
|
1188
|
+
var AGENT_CLI_EXIT = {
|
|
1189
|
+
SUCCESS: 0,
|
|
1190
|
+
FAILURE: 1
|
|
1191
|
+
};
|
|
1192
|
+
var DEFAULT_AGENT_CLI_DEPENDENCIES = {
|
|
1193
|
+
isInteractiveTerminal: () => Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY),
|
|
1194
|
+
pickCandidate: runAgentResumePicker,
|
|
1195
|
+
launchCandidate: async (candidate) => {
|
|
1196
|
+
return launchAgentResume(
|
|
1197
|
+
foregroundProcessRunner,
|
|
1198
|
+
lifecycleSignalSuspender,
|
|
1199
|
+
buildAgentResumeLaunchCommand(candidate)
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
};
|
|
1203
|
+
function writeOutput(invocation, output) {
|
|
1204
|
+
invocation.io.writeStdout(`${output}
|
|
1205
|
+
`);
|
|
1206
|
+
}
|
|
1207
|
+
function writeError(invocation, output) {
|
|
1208
|
+
invocation.io.writeStderr(`${output}
|
|
1209
|
+
`);
|
|
1210
|
+
}
|
|
1211
|
+
function handleError(invocation, error) {
|
|
1212
|
+
const message = error instanceof Error ? `${error.name}: ${error.message}` : inspect(error);
|
|
1213
|
+
writeError(invocation, `Error: ${message}`);
|
|
1214
|
+
return invocation.io.exit(AGENT_CLI_EXIT.FAILURE);
|
|
1215
|
+
}
|
|
1216
|
+
function createAgentDomain(deps = {}) {
|
|
1217
|
+
const resolvedDeps = {
|
|
1218
|
+
...DEFAULT_AGENT_CLI_DEPENDENCIES,
|
|
1219
|
+
...deps
|
|
1220
|
+
};
|
|
1221
|
+
return {
|
|
1222
|
+
name: AGENT_CLI.commandName,
|
|
1223
|
+
description: "Find and resume coding-agent sessions",
|
|
1224
|
+
register: (program, invocation) => {
|
|
1225
|
+
const agentCmd = program.command(AGENT_CLI.commandName).description("Find and resume coding-agent sessions");
|
|
1226
|
+
agentCmd.command(AGENT_CLI.resumeCommandName).description("Resume a Codex or Claude Code agent session for this worktree").option(AGENT_CLI.flags.latest, "Launch the newest matching session").option(AGENT_CLI.flags.list, "List matching sessions").option(AGENT_CLI.flags.json, "Print matching sessions as JSON").action(async (options) => {
|
|
1227
|
+
let requestedExitCode = AGENT_CLI_EXIT.SUCCESS;
|
|
1228
|
+
try {
|
|
1229
|
+
const mode = resolveAgentResumeMode(options);
|
|
1230
|
+
if (mode === AGENT_RESUME_MODE.PICK && !resolvedDeps.isInteractiveTerminal()) {
|
|
1231
|
+
writeError(invocation, AGENT_RESUME_TEXT.INTERACTIVE_REQUIRED);
|
|
1232
|
+
requestedExitCode = AGENT_CLI_EXIT.FAILURE;
|
|
1233
|
+
} else {
|
|
1234
|
+
const commandOptions = {
|
|
1235
|
+
cwd: invocation.resolveEffectiveInvocationDir(),
|
|
1236
|
+
deps: resolvedDeps.resumeDeps
|
|
1237
|
+
};
|
|
1238
|
+
if (mode === AGENT_RESUME_MODE.JSON) {
|
|
1239
|
+
writeOutput(invocation, await jsonAgentResumeSessions(commandOptions));
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
if (mode === AGENT_RESUME_MODE.LIST) {
|
|
1243
|
+
writeOutput(invocation, await listAgentResumeSessions(commandOptions));
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
const candidates = await loadAgentResumeCandidates(commandOptions);
|
|
1247
|
+
if (candidates.length === 0) {
|
|
1248
|
+
writeError(invocation, AGENT_RESUME_TEXT.NO_MATCHES);
|
|
1249
|
+
requestedExitCode = AGENT_CLI_EXIT.FAILURE;
|
|
1250
|
+
} else if (mode === AGENT_RESUME_MODE.LATEST) {
|
|
1251
|
+
requestedExitCode = await resolvedDeps.launchCandidate(candidates[0]);
|
|
1252
|
+
} else {
|
|
1253
|
+
const pickerResult = await resolvedDeps.pickCandidate(candidates);
|
|
1254
|
+
if (pickerResult.kind === AGENT_RESUME_PICKER_RESULT.SELECTED) {
|
|
1255
|
+
requestedExitCode = await resolvedDeps.launchCandidate(pickerResult.candidate);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
} catch (error) {
|
|
1260
|
+
handleError(invocation, error);
|
|
1261
|
+
}
|
|
1262
|
+
return invocation.io.exit(requestedExitCode);
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
1267
|
+
var agentDomain = createAgentDomain();
|
|
1268
|
+
|
|
1269
|
+
// src/commands/claude/init.ts
|
|
1270
|
+
import { execa as execa2 } from "execa";
|
|
1271
|
+
async function initCommand(options = {}) {
|
|
1272
|
+
const cwd = options.cwd || CONFIG_PROCESS_CWD.read();
|
|
1273
|
+
try {
|
|
1274
|
+
const { stdout: listOutput } = await execa2(
|
|
1275
|
+
"claude",
|
|
1276
|
+
["plugin", "marketplace", "list"],
|
|
1277
|
+
{ cwd }
|
|
1278
|
+
);
|
|
1279
|
+
const exists = listOutput.includes("outcomeeng");
|
|
1280
|
+
if (!exists) {
|
|
1281
|
+
await execa2(
|
|
1282
|
+
"claude",
|
|
1283
|
+
["plugin", "marketplace", "add", "outcomeeng/plugins"],
|
|
1284
|
+
{ cwd }
|
|
1285
|
+
);
|
|
1286
|
+
return "\u2713 outcomeeng marketplace installed successfully\n\nRun 'claude plugin marketplace list' to view all marketplaces.";
|
|
1287
|
+
} else {
|
|
1288
|
+
await execa2("claude", ["plugin", "marketplace", "update", "outcomeeng"], {
|
|
1289
|
+
cwd
|
|
1290
|
+
});
|
|
1291
|
+
return "\u2713 outcomeeng marketplace updated successfully\n\nThe marketplace is now up to date.";
|
|
1292
|
+
}
|
|
1293
|
+
} catch (error) {
|
|
1294
|
+
if (error instanceof Error) {
|
|
1295
|
+
if (error.message.includes("ENOENT") || error.message.includes("command not found")) {
|
|
1296
|
+
throw new Error(
|
|
1297
|
+
"Claude CLI not found. Please install Claude Code first.\n\nVisit: https://docs.anthropic.com/claude-code"
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
throw new Error(`Failed to initialize marketplace: ${error.message}`);
|
|
1301
|
+
}
|
|
1302
|
+
throw error;
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
// src/lib/claude/permissions/discovery.ts
|
|
1307
|
+
import fs from "fs/promises";
|
|
1308
|
+
import path from "path";
|
|
1309
|
+
async function findSettingsFiles(root, visited = /* @__PURE__ */ new Set()) {
|
|
1310
|
+
const normalizedRoot = path.resolve(root.replace(/^~/, process.env.HOME || "~"));
|
|
1311
|
+
if (visited.has(normalizedRoot)) {
|
|
1312
|
+
return [];
|
|
1313
|
+
}
|
|
1314
|
+
visited.add(normalizedRoot);
|
|
1315
|
+
try {
|
|
1316
|
+
return await findSettingsFilesInDirectory(normalizedRoot, visited);
|
|
1317
|
+
} catch (error) {
|
|
1318
|
+
throw discoveryError(normalizedRoot, error);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
async function findSettingsFilesInDirectory(normalizedRoot, visited) {
|
|
1322
|
+
const stats = await fs.stat(normalizedRoot);
|
|
1323
|
+
if (!stats.isDirectory()) {
|
|
1324
|
+
throw new Error(`Path is not a directory: ${normalizedRoot}`);
|
|
1325
|
+
}
|
|
1326
|
+
const entries = await fs.readdir(normalizedRoot, { withFileTypes: true });
|
|
1327
|
+
const results = [];
|
|
1328
|
+
for (const entry of entries) {
|
|
1329
|
+
results.push(...await settingsFilesForEntry(normalizedRoot, entry, visited));
|
|
1330
|
+
}
|
|
1331
|
+
return results;
|
|
1332
|
+
}
|
|
1333
|
+
async function settingsFilesForEntry(normalizedRoot, entry, visited) {
|
|
1334
|
+
if (!entry.isDirectory()) return [];
|
|
1335
|
+
const fullPath = path.join(normalizedRoot, entry.name);
|
|
1336
|
+
if (entry.name === ".claude") {
|
|
1337
|
+
const settingsPath = path.join(fullPath, "settings.local.json");
|
|
1338
|
+
return await isValidSettingsFile(settingsPath) ? [settingsPath] : [];
|
|
1339
|
+
}
|
|
1340
|
+
return findSettingsFiles(fullPath, visited);
|
|
1341
|
+
}
|
|
1342
|
+
function discoveryError(normalizedRoot, error) {
|
|
1343
|
+
if (!(error instanceof Error)) return new Error(unknownErrorMessage(error));
|
|
1344
|
+
if (error.message.includes("ENOENT")) return new Error(`Directory not found: ${normalizedRoot}`);
|
|
1345
|
+
if (error.message.includes("EACCES")) return new Error(`Permission denied: ${normalizedRoot}`);
|
|
1346
|
+
return new Error(`Failed to search directory "${normalizedRoot}": ${error.message}`);
|
|
1347
|
+
}
|
|
1348
|
+
function unknownErrorMessage(error) {
|
|
1349
|
+
if (typeof error === "string") return error;
|
|
1350
|
+
if (typeof error === "number" || typeof error === "boolean" || typeof error === "bigint") return error.toString();
|
|
1351
|
+
if (typeof error === "symbol") return error.description ?? "Symbol()";
|
|
1352
|
+
if (error === void 0) return "undefined";
|
|
1353
|
+
return Object.prototype.toString.call(error);
|
|
1354
|
+
}
|
|
1355
|
+
async function isValidSettingsFile(filePath) {
|
|
1356
|
+
try {
|
|
1357
|
+
await fs.access(filePath, fs.constants.R_OK);
|
|
1358
|
+
const stats = await fs.stat(filePath);
|
|
1359
|
+
if (!stats.isFile()) {
|
|
1360
|
+
return false;
|
|
1361
|
+
}
|
|
1362
|
+
return path.extname(filePath) === ".json";
|
|
551
1363
|
} catch {
|
|
552
|
-
return
|
|
1364
|
+
return false;
|
|
553
1365
|
}
|
|
554
1366
|
}
|
|
555
1367
|
|
|
556
1368
|
// src/lib/state-store/index.ts
|
|
1369
|
+
import { createHash, randomBytes as nodeRandomBytes } from "crypto";
|
|
1370
|
+
import { constants as fsConstants } from "fs";
|
|
1371
|
+
import {
|
|
1372
|
+
lstat as nodeLstat,
|
|
1373
|
+
mkdir as nodeMkdir,
|
|
1374
|
+
open as nodeOpen,
|
|
1375
|
+
readdir as nodeReaddir,
|
|
1376
|
+
rm as nodeRm
|
|
1377
|
+
} from "fs/promises";
|
|
1378
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
557
1379
|
var STATE_STORE_PATH = {
|
|
558
1380
|
SPX_DIR: ".spx",
|
|
559
1381
|
BRANCH_SCOPE: "branch",
|
|
@@ -1405,16 +2227,16 @@ function formatError(error) {
|
|
|
1405
2227
|
}
|
|
1406
2228
|
return "Unknown error";
|
|
1407
2229
|
}
|
|
1408
|
-
function
|
|
2230
|
+
function writeOutput2(io, output) {
|
|
1409
2231
|
io.writeStdout(`${output}
|
|
1410
2232
|
`);
|
|
1411
2233
|
}
|
|
1412
|
-
function
|
|
2234
|
+
function writeError2(io, output) {
|
|
1413
2235
|
io.writeStderr(`${output}
|
|
1414
2236
|
`);
|
|
1415
2237
|
}
|
|
1416
2238
|
function exitWithError(io, error) {
|
|
1417
|
-
|
|
2239
|
+
writeError2(io, `Error: ${formatError(error)}`);
|
|
1418
2240
|
return io.exit(1);
|
|
1419
2241
|
}
|
|
1420
2242
|
function registerClaudeCommands(claudeCmd, invocation) {
|
|
@@ -1422,7 +2244,7 @@ function registerClaudeCommands(claudeCmd, invocation) {
|
|
|
1422
2244
|
claudeCmd.command("init").description("Initialize or update outcomeeng marketplace plugin").action(async () => {
|
|
1423
2245
|
try {
|
|
1424
2246
|
const output = await initCommand({ cwd: productDir() });
|
|
1425
|
-
|
|
2247
|
+
writeOutput2(invocation.io, output);
|
|
1426
2248
|
} catch (error) {
|
|
1427
2249
|
exitWithError(invocation.io, error);
|
|
1428
2250
|
}
|
|
@@ -1443,7 +2265,7 @@ function registerClaudeCommands(claudeCmd, invocation) {
|
|
|
1443
2265
|
async (options) => {
|
|
1444
2266
|
try {
|
|
1445
2267
|
if (options.write && options.outputFile) {
|
|
1446
|
-
|
|
2268
|
+
writeError2(
|
|
1447
2269
|
invocation.io,
|
|
1448
2270
|
"Error: --write and --output-file are mutually exclusive\nUse --write to modify global settings, or --output-file to write to a different location"
|
|
1449
2271
|
);
|
|
@@ -1455,7 +2277,7 @@ function registerClaudeCommands(claudeCmd, invocation) {
|
|
|
1455
2277
|
root: options.root,
|
|
1456
2278
|
globalSettings: options.globalSettings
|
|
1457
2279
|
});
|
|
1458
|
-
|
|
2280
|
+
writeOutput2(invocation.io, output);
|
|
1459
2281
|
} catch (error) {
|
|
1460
2282
|
exitWithError(invocation.io, error);
|
|
1461
2283
|
}
|
|
@@ -1645,14 +2467,14 @@ async function compactRetrieveCommand(options) {
|
|
|
1645
2467
|
}
|
|
1646
2468
|
|
|
1647
2469
|
// src/commands/compact/store.ts
|
|
1648
|
-
import { readFile } from "fs/promises";
|
|
2470
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
1649
2471
|
var UTF8_ENCODING = "utf8";
|
|
1650
2472
|
async function compactStoreCommand(options) {
|
|
1651
2473
|
const sessionToken = resolveCompactSessionToken(options.sessionId, options.env ?? process.env);
|
|
1652
2474
|
if (sessionToken === void 0) return 1;
|
|
1653
2475
|
let transcript;
|
|
1654
2476
|
try {
|
|
1655
|
-
transcript = await
|
|
2477
|
+
transcript = await readFile2(options.transcript, UTF8_ENCODING);
|
|
1656
2478
|
} catch {
|
|
1657
2479
|
return 1;
|
|
1658
2480
|
}
|
|
@@ -1708,7 +2530,7 @@ var compactDomain = {
|
|
|
1708
2530
|
};
|
|
1709
2531
|
|
|
1710
2532
|
// src/config/index.ts
|
|
1711
|
-
import { readFile as
|
|
2533
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
1712
2534
|
import { join as join5 } from "path";
|
|
1713
2535
|
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
|
|
1714
2536
|
import { parse as parseYaml, parseDocument as parseYamlDocument, stringify as stringifyYaml } from "yaml";
|
|
@@ -1811,7 +2633,7 @@ var AGENT_ENVIRONMENT_SKILL_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
|
|
|
1811
2633
|
AGENT_ENVIRONMENT_CONFIG_FIELDS.SOURCE,
|
|
1812
2634
|
AGENT_ENVIRONMENT_CONFIG_FIELDS.VERSION
|
|
1813
2635
|
]);
|
|
1814
|
-
function
|
|
2636
|
+
function isRecord2(value) {
|
|
1815
2637
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1816
2638
|
}
|
|
1817
2639
|
function rejectUnknownFields(path7, value, allowed) {
|
|
@@ -1864,7 +2686,7 @@ function validateRuntimeArray(path7, value) {
|
|
|
1864
2686
|
}
|
|
1865
2687
|
function validateInstructions(raw) {
|
|
1866
2688
|
const sectionPath = `${AGENT_ENVIRONMENT_SECTION}.${AGENT_ENVIRONMENT_CONFIG_FIELDS.INSTRUCTIONS}`;
|
|
1867
|
-
if (!
|
|
2689
|
+
if (!isRecord2(raw)) {
|
|
1868
2690
|
return { ok: false, error: `${sectionPath} must be an object` };
|
|
1869
2691
|
}
|
|
1870
2692
|
const unknown = rejectUnknownFields(sectionPath, raw, AGENT_ENVIRONMENT_INSTRUCTIONS_ALLOWED_FIELDS);
|
|
@@ -1888,7 +2710,7 @@ function validateInstructions(raw) {
|
|
|
1888
2710
|
return { ok: true, value: { files } };
|
|
1889
2711
|
}
|
|
1890
2712
|
function validateInstructionFile(path7, raw) {
|
|
1891
|
-
if (!
|
|
2713
|
+
if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
|
|
1892
2714
|
const unknown = rejectUnknownFields(
|
|
1893
2715
|
path7,
|
|
1894
2716
|
raw,
|
|
@@ -1909,7 +2731,7 @@ function validateInstructionFile(path7, raw) {
|
|
|
1909
2731
|
}
|
|
1910
2732
|
function validateRuntimes(raw) {
|
|
1911
2733
|
const sectionPath = `${AGENT_ENVIRONMENT_SECTION}.${AGENT_ENVIRONMENT_CONFIG_FIELDS.RUNTIMES}`;
|
|
1912
|
-
if (!
|
|
2734
|
+
if (!isRecord2(raw)) {
|
|
1913
2735
|
return { ok: false, error: `${sectionPath} must be an object` };
|
|
1914
2736
|
}
|
|
1915
2737
|
const runtimes = { ...DEFAULT_AGENT_ENVIRONMENT_CONFIG.runtimes };
|
|
@@ -1923,7 +2745,7 @@ function validateRuntimes(raw) {
|
|
|
1923
2745
|
return { ok: true, value: runtimes };
|
|
1924
2746
|
}
|
|
1925
2747
|
function validateRuntimeConfig(path7, raw, defaults5) {
|
|
1926
|
-
if (!
|
|
2748
|
+
if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
|
|
1927
2749
|
const unknown = rejectUnknownFields(path7, raw, AGENT_ENVIRONMENT_RUNTIME_CONFIG_ALLOWED_FIELDS);
|
|
1928
2750
|
if (!unknown.ok) return unknown;
|
|
1929
2751
|
const enabledRaw = raw[AGENT_ENVIRONMENT_CONFIG_FIELDS.ENABLED];
|
|
@@ -1934,7 +2756,7 @@ function validateRuntimeConfig(path7, raw, defaults5) {
|
|
|
1934
2756
|
}
|
|
1935
2757
|
function validatePluginBootstrap(raw) {
|
|
1936
2758
|
const sectionPath = `${AGENT_ENVIRONMENT_SECTION}.${AGENT_ENVIRONMENT_CONFIG_FIELDS.PLUGIN_BOOTSTRAP}`;
|
|
1937
|
-
if (!
|
|
2759
|
+
if (!isRecord2(raw)) {
|
|
1938
2760
|
return { ok: false, error: `${sectionPath} must be an object` };
|
|
1939
2761
|
}
|
|
1940
2762
|
const unknown = rejectUnknownFields(
|
|
@@ -2053,7 +2875,7 @@ function validatePluginMarketplaceReferences(path7, marketplaces, plugins) {
|
|
|
2053
2875
|
return { ok: true, value: void 0 };
|
|
2054
2876
|
}
|
|
2055
2877
|
function validateMarketplace(path7, raw) {
|
|
2056
|
-
if (!
|
|
2878
|
+
if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
|
|
2057
2879
|
const unknown = rejectUnknownFields(
|
|
2058
2880
|
path7,
|
|
2059
2881
|
raw,
|
|
@@ -2070,7 +2892,7 @@ function validateMarketplace(path7, raw) {
|
|
|
2070
2892
|
return { ok: true, value: { ...base.value, source: source.value } };
|
|
2071
2893
|
}
|
|
2072
2894
|
function validatePlugin(path7, raw) {
|
|
2073
|
-
if (!
|
|
2895
|
+
if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
|
|
2074
2896
|
const unknown = rejectUnknownFields(
|
|
2075
2897
|
path7,
|
|
2076
2898
|
raw,
|
|
@@ -2099,7 +2921,7 @@ function validatePlugin(path7, raw) {
|
|
|
2099
2921
|
};
|
|
2100
2922
|
}
|
|
2101
2923
|
function validateSkill(path7, raw) {
|
|
2102
|
-
if (!
|
|
2924
|
+
if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
|
|
2103
2925
|
const unknown = rejectUnknownFields(
|
|
2104
2926
|
path7,
|
|
2105
2927
|
raw,
|
|
@@ -2145,7 +2967,7 @@ function validateOptionalString(path7, value) {
|
|
|
2145
2967
|
return validateNonEmptyString(path7, value);
|
|
2146
2968
|
}
|
|
2147
2969
|
function validate(value) {
|
|
2148
|
-
if (!
|
|
2970
|
+
if (!isRecord2(value)) {
|
|
2149
2971
|
return { ok: false, error: `${AGENT_ENVIRONMENT_SECTION} section must be an object` };
|
|
2150
2972
|
}
|
|
2151
2973
|
const unknown = rejectUnknownFields(
|
|
@@ -2179,7 +3001,7 @@ var agentEnvironmentConfigDescriptor = {
|
|
|
2179
3001
|
};
|
|
2180
3002
|
|
|
2181
3003
|
// src/domains/diagnose/facts.ts
|
|
2182
|
-
function
|
|
3004
|
+
function isRecord3(value) {
|
|
2183
3005
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2184
3006
|
}
|
|
2185
3007
|
function isNonEmptyString(value) {
|
|
@@ -2189,7 +3011,7 @@ function isNonEmptyStringArray(value) {
|
|
|
2189
3011
|
return Array.isArray(value) && value.length > 0 && value.every(isNonEmptyString);
|
|
2190
3012
|
}
|
|
2191
3013
|
function validateMarketplaceIdentity(value, field) {
|
|
2192
|
-
if (!
|
|
3014
|
+
if (!isRecord3(value) || !isNonEmptyString(value.name) || !isNonEmptyString(value.source)) {
|
|
2193
3015
|
return { ok: false, error: `${field} must carry a non-empty \`name\` and \`source\`` };
|
|
2194
3016
|
}
|
|
2195
3017
|
return { ok: true, value: { name: value.name, source: value.source } };
|
|
@@ -2721,7 +3543,7 @@ var defaults2 = {
|
|
|
2721
3543
|
scope: DEFAULT_SCOPE_CONFIG,
|
|
2722
3544
|
tools: DEFAULT_TOOLS_CONFIG
|
|
2723
3545
|
};
|
|
2724
|
-
function
|
|
3546
|
+
function isRecord4(value) {
|
|
2725
3547
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2726
3548
|
}
|
|
2727
3549
|
function validateStringField(section, field, value) {
|
|
@@ -2744,7 +3566,7 @@ function rejectUnknownFields2(section, value, allowed) {
|
|
|
2744
3566
|
return { ok: true, value: void 0 };
|
|
2745
3567
|
}
|
|
2746
3568
|
function validateScope(raw) {
|
|
2747
|
-
if (!
|
|
3569
|
+
if (!isRecord4(raw)) {
|
|
2748
3570
|
return {
|
|
2749
3571
|
ok: false,
|
|
2750
3572
|
error: `${FILE_INCLUSION_SECTION}.${FILE_INCLUSION_CONFIG_FIELDS.SCOPE} must be an object`
|
|
@@ -2801,7 +3623,7 @@ function validateScope(raw) {
|
|
|
2801
3623
|
};
|
|
2802
3624
|
}
|
|
2803
3625
|
function validateTools(raw) {
|
|
2804
|
-
if (!
|
|
3626
|
+
if (!isRecord4(raw)) {
|
|
2805
3627
|
return {
|
|
2806
3628
|
ok: false,
|
|
2807
3629
|
error: `${FILE_INCLUSION_SECTION}.${FILE_INCLUSION_CONFIG_FIELDS.TOOLS} must be an object`
|
|
@@ -2816,7 +3638,7 @@ function validateTools(raw) {
|
|
|
2816
3638
|
error: `${FILE_INCLUSION_SECTION}.${FILE_INCLUSION_CONFIG_FIELDS.TOOLS}.${toolName} is not a recognized tool`
|
|
2817
3639
|
};
|
|
2818
3640
|
}
|
|
2819
|
-
if (!
|
|
3641
|
+
if (!isRecord4(adapterRaw)) {
|
|
2820
3642
|
return {
|
|
2821
3643
|
ok: false,
|
|
2822
3644
|
error: `${FILE_INCLUSION_SECTION}.${FILE_INCLUSION_CONFIG_FIELDS.TOOLS}.${toolName} must be an object`
|
|
@@ -3418,7 +4240,7 @@ async function readProductConfigFile(productDir) {
|
|
|
3418
4240
|
const path7 = join5(productDir, filename);
|
|
3419
4241
|
let raw;
|
|
3420
4242
|
try {
|
|
3421
|
-
raw = await
|
|
4243
|
+
raw = await readFile3(path7, "utf8");
|
|
3422
4244
|
} catch (error) {
|
|
3423
4245
|
if (isFileNotFound(error)) continue;
|
|
3424
4246
|
return { ok: false, error: `failed to read ${filename}: ${toMessage(error)}` };
|
|
@@ -3702,7 +4524,7 @@ var configDomain = {
|
|
|
3702
4524
|
};
|
|
3703
4525
|
|
|
3704
4526
|
// src/interfaces/cli/diagnose.ts
|
|
3705
|
-
import { readFile as
|
|
4527
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
3706
4528
|
import { Option } from "commander";
|
|
3707
4529
|
|
|
3708
4530
|
// src/domains/diagnose/types.ts
|
|
@@ -3786,7 +4608,7 @@ function parseManifest(rawJson, availableChecks) {
|
|
|
3786
4608
|
} catch (error) {
|
|
3787
4609
|
return { ok: false, error: `manifest is not valid JSON: ${error.message}` };
|
|
3788
4610
|
}
|
|
3789
|
-
if (!
|
|
4611
|
+
if (!isRecord3(parsed)) {
|
|
3790
4612
|
return { ok: false, error: "manifest must be a JSON object" };
|
|
3791
4613
|
}
|
|
3792
4614
|
const checks = validateChecks(parsed.checks, new Set(availableChecks));
|
|
@@ -4099,10 +4921,16 @@ function resolveHookSessionStartProductDir(payload, cwd) {
|
|
|
4099
4921
|
return payload.cwd ?? cwd;
|
|
4100
4922
|
}
|
|
4101
4923
|
var NO_STARTUP_DIRECTIVE = "";
|
|
4924
|
+
var HOOK_COMPACT_FOUNDATION_ACTION = {
|
|
4925
|
+
CONTEXTUALIZE: "/contextualize",
|
|
4926
|
+
UNDERSTAND: "/understand"
|
|
4927
|
+
};
|
|
4928
|
+
var HOOK_COMPACT_FOUNDATION_REASON = `Hook fired because the agent runtime reported ${HOOK_SESSION_START_PAYLOAD.SOURCE}=${HOOK_SESSION_START_SOURCE.COMPACT}.`;
|
|
4102
4929
|
var HOOK_COMPACT_FOUNDATION_DIRECTIVE = [
|
|
4930
|
+
HOOK_COMPACT_FOUNDATION_REASON,
|
|
4103
4931
|
"Spec-tree foundation was reset by this compaction.",
|
|
4104
|
-
|
|
4105
|
-
"
|
|
4932
|
+
`Before any spec-governed action, including resuming an in-flight PR, /apply, or /handoff, re-invoke ${HOOK_COMPACT_FOUNDATION_ACTION.UNDERSTAND} then ${HOOK_COMPACT_FOUNDATION_ACTION.CONTEXTUALIZE} on every spec node still in scope (not just the next one) before any gh/git archaeology or reading spec-governed source.`,
|
|
4933
|
+
"Skill text carried in the compaction summary is context only, outside active tool authority."
|
|
4106
4934
|
].join("\n");
|
|
4107
4935
|
function renderSessionStartStdout(source) {
|
|
4108
4936
|
return source === HOOK_SESSION_START_SOURCE.COMPACT ? HOOK_COMPACT_FOUNDATION_DIRECTIVE : NO_STARTUP_DIRECTIVE;
|
|
@@ -4883,7 +5711,7 @@ var DEFAULT_REGISTRY = {
|
|
|
4883
5711
|
[CHECK_NAME.SESSION_STORE]: sessionStoreRunner(defaultSessionStoreProbe),
|
|
4884
5712
|
[CHECK_NAME.MARKETPLACE_INSTALL]: marketplaceInstallRunner(defaultMarketplaceInstallProbe)
|
|
4885
5713
|
};
|
|
4886
|
-
function
|
|
5714
|
+
function handleError2(error, io) {
|
|
4887
5715
|
io.writeStderr(`Error: ${sanitizeCliArgument(error)}
|
|
4888
5716
|
`);
|
|
4889
5717
|
return io.exit(1);
|
|
@@ -4908,10 +5736,10 @@ var diagnoseDomain = {
|
|
|
4908
5736
|
isTty: Boolean(process.stdout.isTTY)
|
|
4909
5737
|
}),
|
|
4910
5738
|
registry: DEFAULT_REGISTRY,
|
|
4911
|
-
fs: { readFile: (path7) =>
|
|
5739
|
+
fs: { readFile: (path7) => readFile4(path7, "utf8") }
|
|
4912
5740
|
});
|
|
4913
5741
|
if (!result.ok) {
|
|
4914
|
-
|
|
5742
|
+
handleError2(result.error, invocation.io);
|
|
4915
5743
|
}
|
|
4916
5744
|
invocation.io.writeStdout(`${result.value.output}
|
|
4917
5745
|
`);
|
|
@@ -4969,7 +5797,7 @@ function isValidPid(pid) {
|
|
|
4969
5797
|
}
|
|
4970
5798
|
|
|
4971
5799
|
// src/domains/worktree/resolve.ts
|
|
4972
|
-
import { dirname as dirname4, resolve as
|
|
5800
|
+
import { dirname as dirname4, resolve as resolve5 } from "path";
|
|
4973
5801
|
var WORKTREE_RESOLVE_ERROR = {
|
|
4974
5802
|
NOT_A_WORKTREE: "path resolves to no worktree",
|
|
4975
5803
|
WORKTREE_LIST_UNAVAILABLE: "git worktree list is unavailable"
|
|
@@ -5002,7 +5830,7 @@ async function resolveAllTargetWorktrees(options) {
|
|
|
5002
5830
|
}
|
|
5003
5831
|
async function resolveTargetWorktree(options) {
|
|
5004
5832
|
const base = options.cwd;
|
|
5005
|
-
const targetPath = options.worktree === void 0 ? base :
|
|
5833
|
+
const targetPath = options.worktree === void 0 ? base : resolve5(base, options.worktree);
|
|
5006
5834
|
const targetGitPath = await options.pathInfo.isExistingNonDirectory(targetPath) ? dirname4(targetPath) : targetPath;
|
|
5007
5835
|
const worktree = await detectWorktreeProductRoot(targetGitPath, options.gitDeps);
|
|
5008
5836
|
if (!worktree.isGitRepo) {
|
|
@@ -5168,17 +5996,17 @@ function createProcessHookIo(streams) {
|
|
|
5168
5996
|
return {
|
|
5169
5997
|
readStdin: async () => {
|
|
5170
5998
|
if (streams.stdin.isTTY) return { ok: true, value: void 0 };
|
|
5171
|
-
return new Promise((
|
|
5999
|
+
return new Promise((resolve12) => {
|
|
5172
6000
|
let data = "";
|
|
5173
6001
|
streams.stdin.setEncoding("utf-8");
|
|
5174
6002
|
streams.stdin.on(HOOK_PROCESS_IO_EVENT.DATA, (chunk) => {
|
|
5175
6003
|
data += chunk;
|
|
5176
6004
|
});
|
|
5177
6005
|
streams.stdin.on(HOOK_PROCESS_IO_EVENT.END, () => {
|
|
5178
|
-
|
|
6006
|
+
resolve12({ ok: true, value: data.length === 0 ? void 0 : data });
|
|
5179
6007
|
});
|
|
5180
6008
|
streams.stdin.on(HOOK_PROCESS_IO_EVENT.ERROR, (error) => {
|
|
5181
|
-
|
|
6009
|
+
resolve12({ ok: false, error: formatStdinReadError(error) });
|
|
5182
6010
|
});
|
|
5183
6011
|
});
|
|
5184
6012
|
},
|
|
@@ -5225,13 +6053,13 @@ var HOOK_CLI = {
|
|
|
5225
6053
|
WORKTREES_DIR_FLAG: "--worktrees-dir"
|
|
5226
6054
|
};
|
|
5227
6055
|
var HOOK_DOMAIN_DESCRIPTION = "Run host lifecycle hook events";
|
|
5228
|
-
function
|
|
6056
|
+
function writeError3(invocation, output) {
|
|
5229
6057
|
invocation.io.writeStderr(`${output}
|
|
5230
6058
|
`);
|
|
5231
6059
|
}
|
|
5232
6060
|
function writeInvocationWarning(invocation, warning) {
|
|
5233
6061
|
if (warning !== void 0) {
|
|
5234
|
-
|
|
6062
|
+
writeError3(invocation, warning);
|
|
5235
6063
|
}
|
|
5236
6064
|
}
|
|
5237
6065
|
function registerHookCommands(hookCmd, invocation) {
|
|
@@ -6214,7 +7042,7 @@ function sessionOptionToken(option) {
|
|
|
6214
7042
|
}
|
|
6215
7043
|
|
|
6216
7044
|
// src/commands/session/archive.ts
|
|
6217
|
-
import { mkdir, rename, stat } from "fs/promises";
|
|
7045
|
+
import { mkdir, rename, stat as stat2 } from "fs/promises";
|
|
6218
7046
|
import { dirname as dirname6, join as join9 } from "path";
|
|
6219
7047
|
|
|
6220
7048
|
// src/domains/session/archive.ts
|
|
@@ -6527,7 +7355,7 @@ var SessionAlreadyArchivedError = class extends Error {
|
|
|
6527
7355
|
};
|
|
6528
7356
|
async function fileExists(path7) {
|
|
6529
7357
|
try {
|
|
6530
|
-
const stats = await
|
|
7358
|
+
const stats = await stat2(path7);
|
|
6531
7359
|
return stats.isFile();
|
|
6532
7360
|
} catch {
|
|
6533
7361
|
return false;
|
|
@@ -6569,7 +7397,7 @@ async function archiveCommand(options) {
|
|
|
6569
7397
|
}
|
|
6570
7398
|
|
|
6571
7399
|
// src/commands/session/delete.ts
|
|
6572
|
-
import { stat as
|
|
7400
|
+
import { stat as stat3, unlink } from "fs/promises";
|
|
6573
7401
|
|
|
6574
7402
|
// src/domains/session/delete.ts
|
|
6575
7403
|
function resolveDeletePath(sessionId, existingPaths) {
|
|
@@ -7018,7 +7846,7 @@ async function findExistingPaths(paths) {
|
|
|
7018
7846
|
const existing = [];
|
|
7019
7847
|
for (const path7 of paths) {
|
|
7020
7848
|
try {
|
|
7021
|
-
const stats = await
|
|
7849
|
+
const stats = await stat3(path7);
|
|
7022
7850
|
if (stats.isFile()) {
|
|
7023
7851
|
existing.push(path7);
|
|
7024
7852
|
}
|
|
@@ -7040,8 +7868,8 @@ async function deleteCommand(options) {
|
|
|
7040
7868
|
}
|
|
7041
7869
|
|
|
7042
7870
|
// src/commands/session/handoff.ts
|
|
7043
|
-
import { mkdir as mkdir2, stat as
|
|
7044
|
-
import { join as join11, resolve as
|
|
7871
|
+
import { mkdir as mkdir2, stat as stat4, writeFile } from "fs/promises";
|
|
7872
|
+
import { join as join11, resolve as resolve6 } from "path";
|
|
7045
7873
|
import { stringify as stringifyYaml3 } from "yaml";
|
|
7046
7874
|
|
|
7047
7875
|
// src/domains/session/create.ts
|
|
@@ -7291,7 +8119,7 @@ async function rejectDirectoryInjectionEntries(entries, cwd) {
|
|
|
7291
8119
|
if (entry.length === 0) continue;
|
|
7292
8120
|
let entryIsDirectory = false;
|
|
7293
8121
|
try {
|
|
7294
|
-
entryIsDirectory = (await
|
|
8122
|
+
entryIsDirectory = (await stat4(resolve6(cwd, entry))).isDirectory();
|
|
7295
8123
|
} catch {
|
|
7296
8124
|
continue;
|
|
7297
8125
|
}
|
|
@@ -7340,7 +8168,7 @@ async function handoffCommand(options) {
|
|
|
7340
8168
|
const fullContent = `${SESSION_FRONT_MATTER_OPEN}${yaml}${SESSION_FRONT_MATTER_CLOSE}${body}`;
|
|
7341
8169
|
const filename = `${sessionId}.md`;
|
|
7342
8170
|
const sessionPath = join11(config.todoDir, filename);
|
|
7343
|
-
const absolutePath =
|
|
8171
|
+
const absolutePath = resolve6(sessionPath);
|
|
7344
8172
|
await mkdir2(config.todoDir, { recursive: true });
|
|
7345
8173
|
await writeFile(sessionPath, fullContent, SESSION_FILE_ENCODING);
|
|
7346
8174
|
const output = `Created handoff session ${formatSessionOutputMarker(SESSION_OUTPUT_MARKER.HANDOFF_ID, sessionId)}
|
|
@@ -7349,7 +8177,7 @@ ${formatSessionOutputMarker(SESSION_OUTPUT_MARKER.SESSION_FILE, absolutePath)}`;
|
|
|
7349
8177
|
}
|
|
7350
8178
|
|
|
7351
8179
|
// src/commands/session/list.ts
|
|
7352
|
-
import { readdir, readFile as
|
|
8180
|
+
import { readdir as readdir2, readFile as readFile5 } from "fs/promises";
|
|
7353
8181
|
import { join as join12 } from "path";
|
|
7354
8182
|
var SESSION_LIST_FORMAT = {
|
|
7355
8183
|
TEXT: "text",
|
|
@@ -7358,13 +8186,13 @@ var SESSION_LIST_FORMAT = {
|
|
|
7358
8186
|
var SESSION_LIST_EMPTY_TEXT = "(no sessions)";
|
|
7359
8187
|
async function loadSessionsFromDir(dir, status) {
|
|
7360
8188
|
try {
|
|
7361
|
-
const files = await
|
|
8189
|
+
const files = await readdir2(dir);
|
|
7362
8190
|
const sessions = [];
|
|
7363
8191
|
for (const file of files) {
|
|
7364
8192
|
if (!file.endsWith(".md")) continue;
|
|
7365
8193
|
const id = file.replace(".md", "");
|
|
7366
8194
|
const filePath = join12(dir, file);
|
|
7367
|
-
const content = await
|
|
8195
|
+
const content = await readFile5(filePath, SESSION_FILE_ENCODING);
|
|
7368
8196
|
const metadata = parseSessionMetadata(content);
|
|
7369
8197
|
sessions.push({
|
|
7370
8198
|
id,
|
|
@@ -7427,8 +8255,8 @@ async function listCommand(options) {
|
|
|
7427
8255
|
}
|
|
7428
8256
|
|
|
7429
8257
|
// src/commands/session/pickup.ts
|
|
7430
|
-
import { mkdir as mkdir3, readdir as
|
|
7431
|
-
import { join as join13, resolve as
|
|
8258
|
+
import { mkdir as mkdir3, readdir as readdir3, readFile as readFile6, rename as rename2 } from "fs/promises";
|
|
8259
|
+
import { join as join13, resolve as resolve7 } from "path";
|
|
7432
8260
|
|
|
7433
8261
|
// src/domains/session/pickup.ts
|
|
7434
8262
|
function buildClaimPaths(sessionId, config) {
|
|
@@ -7467,8 +8295,8 @@ function selectBestSession(sessions) {
|
|
|
7467
8295
|
var PICKUP_TARGET_STATUS = SESSION_STATUSES[1];
|
|
7468
8296
|
var PICKUP_DEPS = {
|
|
7469
8297
|
mkdir: mkdir3,
|
|
7470
|
-
readdir:
|
|
7471
|
-
readFile:
|
|
8298
|
+
readdir: readdir3,
|
|
8299
|
+
readFile: readFile6,
|
|
7472
8300
|
rename: rename2
|
|
7473
8301
|
};
|
|
7474
8302
|
async function loadTodoSessions(config) {
|
|
@@ -7503,7 +8331,7 @@ var SESSION_INJECTION_SECTION_PREFIX = "Injected file";
|
|
|
7503
8331
|
var SESSION_INJECTION_MISSING_WARNING_PREFIX = "Warning: missing session injection file";
|
|
7504
8332
|
var SESSION_INJECTION_UNREADABLE_WARNING_PREFIX = "Warning: unreadable session injection path";
|
|
7505
8333
|
function injectionPath(cwd, filePath) {
|
|
7506
|
-
return
|
|
8334
|
+
return resolve7(cwd, filePath);
|
|
7507
8335
|
}
|
|
7508
8336
|
function formatInjectedFile(listedPath, content) {
|
|
7509
8337
|
return `${SESSION_INJECTION_SECTION_PREFIX}: ${listedPath}
|
|
@@ -7577,7 +8405,7 @@ async function loadPickCandidates(options) {
|
|
|
7577
8405
|
}
|
|
7578
8406
|
|
|
7579
8407
|
// src/commands/session/prune.ts
|
|
7580
|
-
import { readdir as
|
|
8408
|
+
import { readdir as readdir4, readFile as readFile7, unlink as unlink2 } from "fs/promises";
|
|
7581
8409
|
import { join as join14 } from "path";
|
|
7582
8410
|
|
|
7583
8411
|
// src/domains/session/prune.ts
|
|
@@ -7622,13 +8450,13 @@ function validatePruneOptions(options) {
|
|
|
7622
8450
|
}
|
|
7623
8451
|
async function loadArchiveSessions(config) {
|
|
7624
8452
|
try {
|
|
7625
|
-
const files = await
|
|
8453
|
+
const files = await readdir4(config.archiveDir);
|
|
7626
8454
|
const sessions = [];
|
|
7627
8455
|
for (const file of files) {
|
|
7628
8456
|
if (!file.endsWith(".md")) continue;
|
|
7629
8457
|
const id = file.replace(".md", "");
|
|
7630
8458
|
const filePath = join14(config.archiveDir, file);
|
|
7631
|
-
const content = await
|
|
8459
|
+
const content = await readFile7(filePath, SESSION_FILE_ENCODING);
|
|
7632
8460
|
const metadata = parseSessionMetadata(content);
|
|
7633
8461
|
sessions.push({
|
|
7634
8462
|
id,
|
|
@@ -7677,7 +8505,7 @@ async function pruneCommand(options) {
|
|
|
7677
8505
|
}
|
|
7678
8506
|
|
|
7679
8507
|
// src/commands/session/release.ts
|
|
7680
|
-
import { readdir as
|
|
8508
|
+
import { readdir as readdir5, rename as rename3 } from "fs/promises";
|
|
7681
8509
|
|
|
7682
8510
|
// src/domains/session/release.ts
|
|
7683
8511
|
function buildReleasePaths(sessionId, config) {
|
|
@@ -7708,7 +8536,7 @@ var SESSION_RELEASE_OUTPUT = {
|
|
|
7708
8536
|
};
|
|
7709
8537
|
async function loadDoingSessions(config) {
|
|
7710
8538
|
try {
|
|
7711
|
-
const files = await
|
|
8539
|
+
const files = await readdir5(config.doingDir);
|
|
7712
8540
|
return files.filter((file) => file.endsWith(".md")).map((file) => ({ id: file.replace(".md", "") }));
|
|
7713
8541
|
} catch (error) {
|
|
7714
8542
|
if (error instanceof Error && "code" in error && error.code === SESSION_FILE_ERROR_CODE.NOT_FOUND) {
|
|
@@ -7745,12 +8573,12 @@ async function releaseCommand(options) {
|
|
|
7745
8573
|
}
|
|
7746
8574
|
|
|
7747
8575
|
// src/commands/session/show.ts
|
|
7748
|
-
import { readFile as
|
|
8576
|
+
import { readFile as readFile8, stat as stat5 } from "fs/promises";
|
|
7749
8577
|
async function findExistingPath(paths, _config) {
|
|
7750
8578
|
for (let i = 0; i < paths.length; i++) {
|
|
7751
8579
|
const filePath = paths[i];
|
|
7752
8580
|
try {
|
|
7753
|
-
const stats = await
|
|
8581
|
+
const stats = await stat5(filePath);
|
|
7754
8582
|
if (stats.isFile()) {
|
|
7755
8583
|
return { path: filePath, status: SEARCH_ORDER[i] };
|
|
7756
8584
|
}
|
|
@@ -7765,7 +8593,7 @@ async function resolveSession(sessionId, config) {
|
|
|
7765
8593
|
if (!found) {
|
|
7766
8594
|
throw new SessionNotFoundError(sessionId);
|
|
7767
8595
|
}
|
|
7768
|
-
const content = await
|
|
8596
|
+
const content = await readFile8(found.path, SESSION_FILE_ENCODING);
|
|
7769
8597
|
return { status: found.status, path: found.path, content };
|
|
7770
8598
|
}
|
|
7771
8599
|
async function showSingle(sessionId, config) {
|
|
@@ -7878,7 +8706,7 @@ Output:
|
|
|
7878
8706
|
`;
|
|
7879
8707
|
|
|
7880
8708
|
// src/domains/session/pick-model.ts
|
|
7881
|
-
import { resolve as
|
|
8709
|
+
import { resolve as resolve8 } from "path";
|
|
7882
8710
|
var ELLIPSIS = "\u2026";
|
|
7883
8711
|
var PICKER_RUNTIME = {
|
|
7884
8712
|
CLAUDE: "claude",
|
|
@@ -7895,7 +8723,7 @@ function buildPickupCommand(runtime, autoContinue, reference) {
|
|
|
7895
8723
|
return { command: runtime, args: [prompt] };
|
|
7896
8724
|
}
|
|
7897
8725
|
function pickupReference(session, sessionsDir, cwd) {
|
|
7898
|
-
return sessionsDir === void 0 ? session.id :
|
|
8726
|
+
return sessionsDir === void 0 ? session.id : resolve8(cwd, session.path);
|
|
7899
8727
|
}
|
|
7900
8728
|
function toSingleLine(text) {
|
|
7901
8729
|
return text.replaceAll(/\s+/g, " ").trim();
|
|
@@ -8010,209 +8838,18 @@ function reducePicker(state, action) {
|
|
|
8010
8838
|
}
|
|
8011
8839
|
}
|
|
8012
8840
|
|
|
8013
|
-
// src/lib/process-lifecycle/exit-codes.ts
|
|
8014
|
-
var SIGINT_EXIT_CODE = 130;
|
|
8015
|
-
var SIGTERM_EXIT_CODE = 143;
|
|
8016
|
-
var EPIPE_EXIT_CODE = 0;
|
|
8017
|
-
var UNCAUGHT_EXIT_CODE = 1;
|
|
8018
|
-
|
|
8019
|
-
// src/lib/process-lifecycle/foreground-handoff.ts
|
|
8020
|
-
var FOREGROUND_SIGNALS = ["SIGINT", "SIGTERM"];
|
|
8021
|
-
function createSignalSuspender(target) {
|
|
8022
|
-
return {
|
|
8023
|
-
suspend() {
|
|
8024
|
-
const ignore = () => {
|
|
8025
|
-
};
|
|
8026
|
-
const restorers = FOREGROUND_SIGNALS.map((signal) => {
|
|
8027
|
-
const originals = target.listeners(signal);
|
|
8028
|
-
for (const listener of originals) target.removeListener(signal, listener);
|
|
8029
|
-
target.on(signal, ignore);
|
|
8030
|
-
return () => {
|
|
8031
|
-
target.removeListener(signal, ignore);
|
|
8032
|
-
for (const listener of originals) target.on(signal, listener);
|
|
8033
|
-
};
|
|
8034
|
-
});
|
|
8035
|
-
return () => {
|
|
8036
|
-
for (const restore of restorers) restore();
|
|
8037
|
-
};
|
|
8038
|
-
}
|
|
8039
|
-
};
|
|
8040
|
-
}
|
|
8041
|
-
|
|
8042
|
-
// src/lib/process-lifecycle/handlers.ts
|
|
8043
|
-
var SIGINT_NAME = "SIGINT";
|
|
8044
|
-
var SIGTERM_NAME = "SIGTERM";
|
|
8045
|
-
function createHandlers(deps) {
|
|
8046
|
-
let cleanupOnce = false;
|
|
8047
|
-
function killEachChild(signal) {
|
|
8048
|
-
deps.registry.forEach((child) => {
|
|
8049
|
-
if (!child.killed) child.kill(signal);
|
|
8050
|
-
});
|
|
8051
|
-
}
|
|
8052
|
-
function exitOnce(code, killSignal) {
|
|
8053
|
-
if (cleanupOnce) {
|
|
8054
|
-
deps.exitController.exit(code);
|
|
8055
|
-
return;
|
|
8056
|
-
}
|
|
8057
|
-
cleanupOnce = true;
|
|
8058
|
-
if (killSignal !== void 0) killEachChild(killSignal);
|
|
8059
|
-
deps.exitController.exit(code);
|
|
8060
|
-
}
|
|
8061
|
-
return {
|
|
8062
|
-
onSigint() {
|
|
8063
|
-
exitOnce(SIGINT_EXIT_CODE, SIGINT_NAME);
|
|
8064
|
-
},
|
|
8065
|
-
onSigterm() {
|
|
8066
|
-
exitOnce(SIGTERM_EXIT_CODE, SIGTERM_NAME);
|
|
8067
|
-
},
|
|
8068
|
-
onEpipe() {
|
|
8069
|
-
exitOnce(EPIPE_EXIT_CODE, SIGTERM_NAME);
|
|
8070
|
-
},
|
|
8071
|
-
onUncaught(_error) {
|
|
8072
|
-
exitOnce(UNCAUGHT_EXIT_CODE, SIGTERM_NAME);
|
|
8073
|
-
}
|
|
8074
|
-
};
|
|
8075
|
-
}
|
|
8076
|
-
|
|
8077
|
-
// src/lib/process-lifecycle/install.ts
|
|
8078
|
-
import { spawn } from "child_process";
|
|
8079
|
-
|
|
8080
|
-
// src/lib/process-lifecycle/registry.ts
|
|
8081
|
-
function createRegistry() {
|
|
8082
|
-
const tracked = /* @__PURE__ */ new Set();
|
|
8083
|
-
return {
|
|
8084
|
-
add(child) {
|
|
8085
|
-
tracked.add(child);
|
|
8086
|
-
},
|
|
8087
|
-
remove(child) {
|
|
8088
|
-
tracked.delete(child);
|
|
8089
|
-
},
|
|
8090
|
-
forEach(fn) {
|
|
8091
|
-
for (const child of tracked) fn(child);
|
|
8092
|
-
},
|
|
8093
|
-
get size() {
|
|
8094
|
-
return tracked.size;
|
|
8095
|
-
}
|
|
8096
|
-
};
|
|
8097
|
-
}
|
|
8098
|
-
|
|
8099
|
-
// src/lib/process-lifecycle/runner.ts
|
|
8100
|
-
function createLifecycleRunner(deps) {
|
|
8101
|
-
return {
|
|
8102
|
-
spawn(command, args, options) {
|
|
8103
|
-
const child = deps.spawn(command, args, options);
|
|
8104
|
-
deps.registry.add(child);
|
|
8105
|
-
child.on("exit", () => deps.registry.remove(child));
|
|
8106
|
-
return child;
|
|
8107
|
-
}
|
|
8108
|
-
};
|
|
8109
|
-
}
|
|
8110
|
-
|
|
8111
|
-
// src/lib/process-lifecycle/install.ts
|
|
8112
|
-
var moduleRegistry = createRegistry();
|
|
8113
|
-
var moduleExitController = {
|
|
8114
|
-
exit(code) {
|
|
8115
|
-
process.exit(code);
|
|
8116
|
-
}
|
|
8117
|
-
};
|
|
8118
|
-
var installed = false;
|
|
8119
|
-
var lifecycleProcessRunner = createLifecycleRunner({
|
|
8120
|
-
registry: moduleRegistry,
|
|
8121
|
-
spawn
|
|
8122
|
-
});
|
|
8123
|
-
var foregroundProcessRunner = { spawn };
|
|
8124
|
-
var processSignalTarget = {
|
|
8125
|
-
listeners: (signal) => process.listeners(signal),
|
|
8126
|
-
on: (signal, listener) => {
|
|
8127
|
-
process.on(signal, listener);
|
|
8128
|
-
},
|
|
8129
|
-
removeListener: (signal, listener) => {
|
|
8130
|
-
process.removeListener(signal, listener);
|
|
8131
|
-
}
|
|
8132
|
-
};
|
|
8133
|
-
var lifecycleSignalSuspender = createSignalSuspender(processSignalTarget);
|
|
8134
|
-
var EPIPE_CODE = "EPIPE";
|
|
8135
|
-
var UNCAUGHT_PREFIX = "Uncaught: ";
|
|
8136
|
-
var NEWLINE = "\n";
|
|
8137
|
-
function formatUncaught(error) {
|
|
8138
|
-
if (error instanceof Error && error.stack !== void 0) {
|
|
8139
|
-
return UNCAUGHT_PREFIX + error.stack + NEWLINE;
|
|
8140
|
-
}
|
|
8141
|
-
return UNCAUGHT_PREFIX + String(error) + NEWLINE;
|
|
8142
|
-
}
|
|
8143
|
-
function logUncaughtToStderr(error) {
|
|
8144
|
-
try {
|
|
8145
|
-
process.stderr.write(formatUncaught(error));
|
|
8146
|
-
} catch {
|
|
8147
|
-
}
|
|
8148
|
-
}
|
|
8149
|
-
function installLifecycle() {
|
|
8150
|
-
if (installed) return;
|
|
8151
|
-
installed = true;
|
|
8152
|
-
const handlers = createHandlers({
|
|
8153
|
-
registry: moduleRegistry,
|
|
8154
|
-
exitController: moduleExitController
|
|
8155
|
-
});
|
|
8156
|
-
process.on("uncaughtException", (error) => {
|
|
8157
|
-
logUncaughtToStderr(error);
|
|
8158
|
-
handlers.onUncaught(error);
|
|
8159
|
-
});
|
|
8160
|
-
process.on("unhandledRejection", (reason) => {
|
|
8161
|
-
logUncaughtToStderr(reason);
|
|
8162
|
-
handlers.onUncaught(reason);
|
|
8163
|
-
});
|
|
8164
|
-
process.on("SIGTERM", () => handlers.onSigterm());
|
|
8165
|
-
process.on("SIGINT", () => handlers.onSigint());
|
|
8166
|
-
process.stdout.on("error", (error) => {
|
|
8167
|
-
if (error.code === EPIPE_CODE) {
|
|
8168
|
-
handlers.onEpipe();
|
|
8169
|
-
return;
|
|
8170
|
-
}
|
|
8171
|
-
handlers.onUncaught(error);
|
|
8172
|
-
});
|
|
8173
|
-
process.stderr.on("error", (error) => {
|
|
8174
|
-
if (error.code === EPIPE_CODE) {
|
|
8175
|
-
handlers.onEpipe();
|
|
8176
|
-
return;
|
|
8177
|
-
}
|
|
8178
|
-
handlers.onUncaught(error);
|
|
8179
|
-
});
|
|
8180
|
-
}
|
|
8181
|
-
|
|
8182
|
-
// src/lib/process-lifecycle/managed-subprocess.ts
|
|
8183
|
-
var MANAGED_SUBPROCESS_STDIO = "pipe";
|
|
8184
|
-
function spawnManagedSubprocess(runner, command, args, options) {
|
|
8185
|
-
return runner.spawn(command, args, {
|
|
8186
|
-
...options,
|
|
8187
|
-
stdio: MANAGED_SUBPROCESS_STDIO
|
|
8188
|
-
});
|
|
8189
|
-
}
|
|
8190
|
-
|
|
8191
8841
|
// src/interfaces/cli/session/pick/launch-agent.ts
|
|
8192
|
-
var LAUNCH_FAILURE_STATUS = 1;
|
|
8193
8842
|
function launchAgent(runner, suspender, command) {
|
|
8194
|
-
|
|
8195
|
-
return new Promise((resolve11) => {
|
|
8196
|
-
let settled = false;
|
|
8197
|
-
const settle = (status) => {
|
|
8198
|
-
if (settled) return;
|
|
8199
|
-
settled = true;
|
|
8200
|
-
restoreSignals();
|
|
8201
|
-
resolve11(status);
|
|
8202
|
-
};
|
|
8203
|
-
const child = runner.spawn(command.command, command.args, { stdio: "inherit" });
|
|
8204
|
-
child.once("exit", (code) => settle(code ?? LAUNCH_FAILURE_STATUS));
|
|
8205
|
-
child.once("error", () => settle(LAUNCH_FAILURE_STATUS));
|
|
8206
|
-
});
|
|
8843
|
+
return launchForegroundCommand(runner, suspender, command);
|
|
8207
8844
|
}
|
|
8208
8845
|
|
|
8209
8846
|
// src/interfaces/cli/session/pick/run-picker.tsx
|
|
8210
|
-
import { render } from "ink";
|
|
8847
|
+
import { render as render2 } from "ink";
|
|
8211
8848
|
|
|
8212
8849
|
// src/interfaces/cli/session/pick/SessionPicker.tsx
|
|
8213
|
-
import { Box, Text, useInput, useStdout } from "ink";
|
|
8214
|
-
import { useState } from "react";
|
|
8215
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8850
|
+
import { Box as Box2, Text as Text2, useInput as useInput2, useStdout } from "ink";
|
|
8851
|
+
import { useState as useState2 } from "react";
|
|
8852
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
8216
8853
|
var SESSION_PICKER_TITLE = "Pick a session to launch";
|
|
8217
8854
|
var SESSION_PICKER_EMPTY_TEXT = "No claimable sessions.";
|
|
8218
8855
|
var SESSION_PICKER_BROWSE_HINT = "\u2191\u2193 move \xB7 / filter \xB7 c/C claude \xB7 x/X codex \xB7 q quit";
|
|
@@ -8245,33 +8882,33 @@ function SessionRow({ session, selected, columns }) {
|
|
|
8245
8882
|
const badge = priority === DEFAULT_PRIORITY ? "" : ` [${priority}]`;
|
|
8246
8883
|
const reserved = visibleWidth(marker) + visibleWidth(" ") + visibleWidth(session.id) + visibleWidth(badge) + visibleWidth(" ");
|
|
8247
8884
|
const goal = truncateToWidth(toSingleLine(session.metadata.goal), Math.max(MIN_GOAL_WIDTH, columns - reserved));
|
|
8248
|
-
return /* @__PURE__ */
|
|
8885
|
+
return /* @__PURE__ */ jsxs2(Text2, { wrap: "truncate", color: selected ? "cyan" : void 0, children: [
|
|
8249
8886
|
marker,
|
|
8250
8887
|
" ",
|
|
8251
8888
|
session.id,
|
|
8252
|
-
/* @__PURE__ */
|
|
8889
|
+
/* @__PURE__ */ jsx3(Text2, { color: PRIORITY_COLOR[priority], children: badge }),
|
|
8253
8890
|
" ",
|
|
8254
8891
|
goal
|
|
8255
8892
|
] });
|
|
8256
8893
|
}
|
|
8257
8894
|
function PreviewField({ label, value }) {
|
|
8258
|
-
return /* @__PURE__ */
|
|
8895
|
+
return /* @__PURE__ */ jsx3(Text2, { children: `${label} ${value}` });
|
|
8259
8896
|
}
|
|
8260
8897
|
function PreviewPane({ session }) {
|
|
8261
8898
|
if (session === null) {
|
|
8262
|
-
return /* @__PURE__ */
|
|
8899
|
+
return /* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: SESSION_PICKER_EMPTY_TEXT }) });
|
|
8263
8900
|
}
|
|
8264
|
-
return /* @__PURE__ */
|
|
8265
|
-
/* @__PURE__ */
|
|
8266
|
-
/* @__PURE__ */
|
|
8901
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: 1, children: [
|
|
8902
|
+
/* @__PURE__ */ jsx3(PreviewField, { label: PREVIEW_GOAL_LABEL, value: session.metadata.goal }),
|
|
8903
|
+
/* @__PURE__ */ jsx3(PreviewField, { label: PREVIEW_NEXT_LABEL, value: session.metadata.next_step })
|
|
8267
8904
|
] });
|
|
8268
8905
|
}
|
|
8269
8906
|
function SessionPicker({ sessions, onLaunch, onQuit, columns: columnsProp }) {
|
|
8270
8907
|
const { stdout } = useStdout();
|
|
8271
8908
|
const stdoutColumns = Reflect.get(stdout, "columns");
|
|
8272
8909
|
const columns = columnsProp ?? (typeof stdoutColumns === "number" ? stdoutColumns : FALLBACK_COLUMNS);
|
|
8273
|
-
const [state, setState] =
|
|
8274
|
-
|
|
8910
|
+
const [state, setState] = useState2(() => initialPickerState(sessions));
|
|
8911
|
+
useInput2((input, key) => {
|
|
8275
8912
|
const action = keyToAction(toPickerKey(input, key), state.mode);
|
|
8276
8913
|
if (action === null) return;
|
|
8277
8914
|
if (action.type === PICKER_ACTION.LAUNCH) {
|
|
@@ -8288,28 +8925,28 @@ function SessionPicker({ sessions, onLaunch, onQuit, columns: columnsProp }) {
|
|
|
8288
8925
|
const visible = visibleCandidates(state);
|
|
8289
8926
|
const selected = selectedSession(state);
|
|
8290
8927
|
const hint = state.mode === PICKER_MODE.FILTER ? SESSION_PICKER_FILTER_HINT : SESSION_PICKER_BROWSE_HINT;
|
|
8291
|
-
return /* @__PURE__ */
|
|
8292
|
-
/* @__PURE__ */
|
|
8293
|
-
/* @__PURE__ */
|
|
8928
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
8929
|
+
/* @__PURE__ */ jsx3(Text2, { bold: true, children: SESSION_PICKER_TITLE }),
|
|
8930
|
+
/* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
8294
8931
|
SESSION_PICKER_FILTER_LABEL,
|
|
8295
8932
|
" ",
|
|
8296
8933
|
state.query
|
|
8297
8934
|
] }),
|
|
8298
|
-
visible.length === 0 ? /* @__PURE__ */
|
|
8299
|
-
/* @__PURE__ */
|
|
8300
|
-
/* @__PURE__ */
|
|
8935
|
+
visible.length === 0 ? /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: SESSION_PICKER_EMPTY_TEXT }) : visible.map((session, index) => /* @__PURE__ */ jsx3(SessionRow, { session, selected: index === state.selectedIndex, columns }, session.id)),
|
|
8936
|
+
/* @__PURE__ */ jsx3(PreviewPane, { session: selected }),
|
|
8937
|
+
/* @__PURE__ */ jsx3(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: hint }) })
|
|
8301
8938
|
] });
|
|
8302
8939
|
}
|
|
8303
8940
|
|
|
8304
8941
|
// src/interfaces/cli/session/pick/run-picker.tsx
|
|
8305
|
-
import { jsx as
|
|
8942
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
8306
8943
|
var PICK_NON_TTY_MESSAGE = "session pick requires an interactive terminal. Run `claude '/pickup <id>'` or `codex '$pickup <id>'` directly in a non-interactive context.";
|
|
8307
|
-
async function runPicker(sessions, renderPicker =
|
|
8944
|
+
async function runPicker(sessions, renderPicker = render2) {
|
|
8308
8945
|
let choice = null;
|
|
8309
8946
|
let unmount = () => {
|
|
8310
8947
|
};
|
|
8311
8948
|
const instance = renderPicker(
|
|
8312
|
-
/* @__PURE__ */
|
|
8949
|
+
/* @__PURE__ */ jsx4(
|
|
8313
8950
|
SessionPicker,
|
|
8314
8951
|
{
|
|
8315
8952
|
sessions,
|
|
@@ -8333,31 +8970,31 @@ async function readStdin() {
|
|
|
8333
8970
|
if (process.stdin.isTTY) {
|
|
8334
8971
|
return void 0;
|
|
8335
8972
|
}
|
|
8336
|
-
return new Promise((
|
|
8973
|
+
return new Promise((resolve12) => {
|
|
8337
8974
|
let data = "";
|
|
8338
8975
|
process.stdin.setEncoding(SESSION_FILE_ENCODING);
|
|
8339
8976
|
process.stdin.on("data", (chunk) => {
|
|
8340
8977
|
data += chunk;
|
|
8341
8978
|
});
|
|
8342
8979
|
process.stdin.on("end", () => {
|
|
8343
|
-
|
|
8980
|
+
resolve12(data.length === 0 ? void 0 : data);
|
|
8344
8981
|
});
|
|
8345
8982
|
process.stdin.on("error", () => {
|
|
8346
|
-
|
|
8983
|
+
resolve12(void 0);
|
|
8347
8984
|
});
|
|
8348
8985
|
});
|
|
8349
8986
|
}
|
|
8350
|
-
function
|
|
8987
|
+
function writeOutput3(invocation, output) {
|
|
8351
8988
|
invocation.io.writeStdout(`${output}
|
|
8352
8989
|
`);
|
|
8353
8990
|
}
|
|
8354
|
-
function
|
|
8991
|
+
function writeError4(invocation, output) {
|
|
8355
8992
|
invocation.io.writeStderr(`${output}
|
|
8356
8993
|
`);
|
|
8357
8994
|
}
|
|
8358
8995
|
function writeInvocationWarning2(invocation, warning) {
|
|
8359
8996
|
if (warning !== void 0) {
|
|
8360
|
-
|
|
8997
|
+
writeError4(invocation, warning);
|
|
8361
8998
|
}
|
|
8362
8999
|
}
|
|
8363
9000
|
function formatError2(error) {
|
|
@@ -8366,8 +9003,8 @@ function formatError2(error) {
|
|
|
8366
9003
|
}
|
|
8367
9004
|
return toMessage(error);
|
|
8368
9005
|
}
|
|
8369
|
-
function
|
|
8370
|
-
|
|
9006
|
+
function handleError3(invocation, error) {
|
|
9007
|
+
writeError4(invocation, `Error: ${formatError2(error)}`);
|
|
8371
9008
|
return invocation.io.exit(1);
|
|
8372
9009
|
}
|
|
8373
9010
|
function colorFlagFromOption(colorOption) {
|
|
@@ -8420,9 +9057,9 @@ function registerSessionCommands(sessionCmd, invocation) {
|
|
|
8420
9057
|
cwd: effectiveInvocationDir(),
|
|
8421
9058
|
onWarning: (warning) => writeInvocationWarning2(invocation, warning)
|
|
8422
9059
|
});
|
|
8423
|
-
|
|
9060
|
+
writeOutput3(invocation, output);
|
|
8424
9061
|
} catch (error) {
|
|
8425
|
-
|
|
9062
|
+
handleError3(invocation, error);
|
|
8426
9063
|
}
|
|
8427
9064
|
}
|
|
8428
9065
|
);
|
|
@@ -8432,7 +9069,7 @@ function registerSessionCommands(sessionCmd, invocation) {
|
|
|
8432
9069
|
).action(async (options) => {
|
|
8433
9070
|
try {
|
|
8434
9071
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
8435
|
-
|
|
9072
|
+
writeError4(invocation, PICK_NON_TTY_MESSAGE);
|
|
8436
9073
|
invocation.io.exit(1);
|
|
8437
9074
|
}
|
|
8438
9075
|
const sessions = await loadPickCandidates({
|
|
@@ -8448,7 +9085,7 @@ function registerSessionCommands(sessionCmd, invocation) {
|
|
|
8448
9085
|
invocation.io.exit(code);
|
|
8449
9086
|
}
|
|
8450
9087
|
} catch (error) {
|
|
8451
|
-
|
|
9088
|
+
handleError3(invocation, error);
|
|
8452
9089
|
}
|
|
8453
9090
|
});
|
|
8454
9091
|
addSessionOptions(
|
|
@@ -8466,9 +9103,9 @@ function registerSessionCommands(sessionCmd, invocation) {
|
|
|
8466
9103
|
cwd: effectiveInvocationDir(),
|
|
8467
9104
|
onWarning: (warning) => writeInvocationWarning2(invocation, warning)
|
|
8468
9105
|
});
|
|
8469
|
-
|
|
9106
|
+
writeOutput3(invocation, output);
|
|
8470
9107
|
} catch (error) {
|
|
8471
|
-
|
|
9108
|
+
handleError3(invocation, error);
|
|
8472
9109
|
}
|
|
8473
9110
|
});
|
|
8474
9111
|
addSessionOptions(
|
|
@@ -8483,9 +9120,9 @@ function registerSessionCommands(sessionCmd, invocation) {
|
|
|
8483
9120
|
cwd: effectiveInvocationDir(),
|
|
8484
9121
|
onWarning: (warning) => writeInvocationWarning2(invocation, warning)
|
|
8485
9122
|
});
|
|
8486
|
-
|
|
9123
|
+
writeOutput3(invocation, output);
|
|
8487
9124
|
} catch (error) {
|
|
8488
|
-
|
|
9125
|
+
handleError3(invocation, error);
|
|
8489
9126
|
}
|
|
8490
9127
|
});
|
|
8491
9128
|
addSessionOptions(
|
|
@@ -8494,7 +9131,7 @@ function registerSessionCommands(sessionCmd, invocation) {
|
|
|
8494
9131
|
).addHelpText("after", PICKUP_SELECTION_HELP).action(async (ids, options) => {
|
|
8495
9132
|
try {
|
|
8496
9133
|
if (ids.length === 0 && !options.auto) {
|
|
8497
|
-
|
|
9134
|
+
writeError4(invocation, "Error: Either session ID or --auto flag is required");
|
|
8498
9135
|
invocation.io.exit(1);
|
|
8499
9136
|
}
|
|
8500
9137
|
const output = await pickupCommand({
|
|
@@ -8505,9 +9142,9 @@ function registerSessionCommands(sessionCmd, invocation) {
|
|
|
8505
9142
|
cwd: effectiveInvocationDir(),
|
|
8506
9143
|
onWarning: (warning) => writeInvocationWarning2(invocation, warning)
|
|
8507
9144
|
});
|
|
8508
|
-
|
|
9145
|
+
writeOutput3(invocation, output);
|
|
8509
9146
|
} catch (error) {
|
|
8510
|
-
|
|
9147
|
+
handleError3(invocation, error);
|
|
8511
9148
|
}
|
|
8512
9149
|
});
|
|
8513
9150
|
addSessionOptions(
|
|
@@ -8521,9 +9158,9 @@ function registerSessionCommands(sessionCmd, invocation) {
|
|
|
8521
9158
|
cwd: effectiveInvocationDir(),
|
|
8522
9159
|
onWarning: (warning) => writeInvocationWarning2(invocation, warning)
|
|
8523
9160
|
});
|
|
8524
|
-
|
|
9161
|
+
writeOutput3(invocation, output);
|
|
8525
9162
|
} catch (error) {
|
|
8526
|
-
|
|
9163
|
+
handleError3(invocation, error);
|
|
8527
9164
|
}
|
|
8528
9165
|
});
|
|
8529
9166
|
addSessionOptions(
|
|
@@ -8538,17 +9175,17 @@ function registerSessionCommands(sessionCmd, invocation) {
|
|
|
8538
9175
|
cwd: effectiveInvocationDir(),
|
|
8539
9176
|
env: process.env
|
|
8540
9177
|
});
|
|
8541
|
-
|
|
9178
|
+
writeOutput3(invocation, result.output);
|
|
8542
9179
|
} catch (error) {
|
|
8543
9180
|
if (error instanceof SessionHandoffBaseError) {
|
|
8544
9181
|
if (error.checklist !== null) {
|
|
8545
|
-
|
|
9182
|
+
writeError4(invocation, renderHandoffBaseChecklist(error.checklist));
|
|
8546
9183
|
} else if (!error.silent) {
|
|
8547
|
-
|
|
9184
|
+
writeError4(invocation, `Error: ${error.name}: ${error.message}`);
|
|
8548
9185
|
}
|
|
8549
9186
|
invocation.io.exit(1);
|
|
8550
9187
|
}
|
|
8551
|
-
|
|
9188
|
+
handleError3(invocation, error);
|
|
8552
9189
|
}
|
|
8553
9190
|
});
|
|
8554
9191
|
addSessionOptions(
|
|
@@ -8562,9 +9199,9 @@ function registerSessionCommands(sessionCmd, invocation) {
|
|
|
8562
9199
|
cwd: effectiveInvocationDir(),
|
|
8563
9200
|
onWarning: (warning) => writeInvocationWarning2(invocation, warning)
|
|
8564
9201
|
});
|
|
8565
|
-
|
|
9202
|
+
writeOutput3(invocation, output);
|
|
8566
9203
|
} catch (error) {
|
|
8567
|
-
|
|
9204
|
+
handleError3(invocation, error);
|
|
8568
9205
|
}
|
|
8569
9206
|
});
|
|
8570
9207
|
addSessionOptions(
|
|
@@ -8580,13 +9217,13 @@ function registerSessionCommands(sessionCmd, invocation) {
|
|
|
8580
9217
|
cwd: effectiveInvocationDir(),
|
|
8581
9218
|
onWarning: (warning) => writeInvocationWarning2(invocation, warning)
|
|
8582
9219
|
});
|
|
8583
|
-
|
|
9220
|
+
writeOutput3(invocation, output);
|
|
8584
9221
|
} catch (error) {
|
|
8585
9222
|
if (error instanceof PruneValidationError) {
|
|
8586
|
-
|
|
9223
|
+
writeError4(invocation, `Error: ${error.message}`);
|
|
8587
9224
|
invocation.io.exit(1);
|
|
8588
9225
|
}
|
|
8589
|
-
|
|
9226
|
+
handleError3(invocation, error);
|
|
8590
9227
|
}
|
|
8591
9228
|
});
|
|
8592
9229
|
addSessionOptions(
|
|
@@ -8600,13 +9237,13 @@ function registerSessionCommands(sessionCmd, invocation) {
|
|
|
8600
9237
|
cwd: effectiveInvocationDir(),
|
|
8601
9238
|
onWarning: (warning) => writeInvocationWarning2(invocation, warning)
|
|
8602
9239
|
});
|
|
8603
|
-
|
|
9240
|
+
writeOutput3(invocation, output);
|
|
8604
9241
|
} catch (error) {
|
|
8605
9242
|
if (error instanceof SessionAlreadyArchivedError) {
|
|
8606
|
-
|
|
9243
|
+
writeError4(invocation, `Error: ${error.message}`);
|
|
8607
9244
|
invocation.io.exit(1);
|
|
8608
9245
|
}
|
|
8609
|
-
|
|
9246
|
+
handleError3(invocation, error);
|
|
8610
9247
|
}
|
|
8611
9248
|
});
|
|
8612
9249
|
}
|
|
@@ -8620,7 +9257,7 @@ var sessionDomain = {
|
|
|
8620
9257
|
};
|
|
8621
9258
|
|
|
8622
9259
|
// src/lib/spec-tree/index.ts
|
|
8623
|
-
import { readdir as
|
|
9260
|
+
import { readdir as readdir6, readFile as readFile9 } from "fs/promises";
|
|
8624
9261
|
import { join as join15 } from "path";
|
|
8625
9262
|
var SPEC_TREE_FIELD_KEY = {
|
|
8626
9263
|
VERSION: "version",
|
|
@@ -8705,7 +9342,7 @@ function createFilesystemSpecTreeSource(options) {
|
|
|
8705
9342
|
if (ref.path === void 0) {
|
|
8706
9343
|
throw new Error("Filesystem source refs require a path");
|
|
8707
9344
|
}
|
|
8708
|
-
return
|
|
9345
|
+
return readFile9(join15(options.productDir, ref.path), SPEC_TREE_TEXT_ENCODING);
|
|
8709
9346
|
}
|
|
8710
9347
|
};
|
|
8711
9348
|
}
|
|
@@ -8996,7 +9633,7 @@ async function* readFilesystemSourceEntries(productDir, registry, schemaVersions
|
|
|
8996
9633
|
async function* walkFilesystemDirectory(context) {
|
|
8997
9634
|
let entries;
|
|
8998
9635
|
try {
|
|
8999
|
-
entries = await
|
|
9636
|
+
entries = await readdir6(context.absolutePath, { withFileTypes: true });
|
|
9000
9637
|
} catch (error) {
|
|
9001
9638
|
if (isFileNotFound2(error)) return;
|
|
9002
9639
|
throw error;
|
|
@@ -9168,7 +9805,7 @@ function formatNextNode(node) {
|
|
|
9168
9805
|
}
|
|
9169
9806
|
|
|
9170
9807
|
// src/commands/test/discovery.ts
|
|
9171
|
-
import { readdir as
|
|
9808
|
+
import { readdir as readdir7 } from "fs/promises";
|
|
9172
9809
|
import { join as join16, relative, sep } from "path";
|
|
9173
9810
|
var TESTS_DIRECTORY_NAME = SPEC_TREE_EVIDENCE_FILE.DIRECTORY_NAME;
|
|
9174
9811
|
var SPEC_ROOT_DIRECTORY = SPEC_TREE_CONFIG.ROOT_DIRECTORY;
|
|
@@ -9182,7 +9819,7 @@ async function discoverTestFiles(productDir) {
|
|
|
9182
9819
|
async function collectTestFiles(directory, insideTestsDir, found) {
|
|
9183
9820
|
let entries;
|
|
9184
9821
|
try {
|
|
9185
|
-
entries = await
|
|
9822
|
+
entries = await readdir7(directory, { withFileTypes: true });
|
|
9186
9823
|
} catch (error) {
|
|
9187
9824
|
if (hasErrorCode2(error, ERROR_CODE_NOT_FOUND2)) return;
|
|
9188
9825
|
throw error;
|
|
@@ -9516,7 +10153,7 @@ async function readTestRunStatePath(runFilePath, fs8) {
|
|
|
9516
10153
|
return { ok: true, value: validated.value };
|
|
9517
10154
|
}
|
|
9518
10155
|
function validateTestRunState(value) {
|
|
9519
|
-
if (!
|
|
10156
|
+
if (!isRecord5(value)) return { ok: false, error: "testing run state must be an object" };
|
|
9520
10157
|
const branchName = readString(value, TEST_RUN_STATE_FIELDS.BRANCH_NAME);
|
|
9521
10158
|
if (!branchName.ok) return branchName;
|
|
9522
10159
|
const headSha = readString(value, TEST_RUN_STATE_FIELDS.HEAD_SHA);
|
|
@@ -9559,7 +10196,7 @@ function readRunnerOutcomes(raw) {
|
|
|
9559
10196
|
}
|
|
9560
10197
|
const outcomes = [];
|
|
9561
10198
|
for (const entry of raw) {
|
|
9562
|
-
if (!
|
|
10199
|
+
if (!isRecord5(entry)) {
|
|
9563
10200
|
return { ok: false, error: `${TEST_RUN_STATE_FIELDS.RUNNER_OUTCOMES} entries must be objects` };
|
|
9564
10201
|
}
|
|
9565
10202
|
const runnerId = readString(entry, TEST_RUNNER_OUTCOME_FIELDS.RUNNER_ID);
|
|
@@ -9580,7 +10217,7 @@ function readProductInputDigests(raw) {
|
|
|
9580
10217
|
}
|
|
9581
10218
|
const digests = [];
|
|
9582
10219
|
for (const entry of raw) {
|
|
9583
|
-
if (!
|
|
10220
|
+
if (!isRecord5(entry)) {
|
|
9584
10221
|
return { ok: false, error: `${TEST_RUN_STATE_FIELDS.PRODUCT_INPUT_DIGESTS} entries must be objects` };
|
|
9585
10222
|
}
|
|
9586
10223
|
const descriptorId = readString(entry, PRODUCT_INPUT_DIGEST_FIELDS.DESCRIPTOR_ID);
|
|
@@ -9642,7 +10279,7 @@ function testingWriteError(error) {
|
|
|
9642
10279
|
function withDomainErrorDetail(domainError, detail) {
|
|
9643
10280
|
return detail === void 0 ? domainError : `${domainError}: ${detail}`;
|
|
9644
10281
|
}
|
|
9645
|
-
function
|
|
10282
|
+
function isRecord5(value) {
|
|
9646
10283
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9647
10284
|
}
|
|
9648
10285
|
function sha256Hex2(value) {
|
|
@@ -10024,7 +10661,7 @@ function createNodeStatusProvider(productDir) {
|
|
|
10024
10661
|
}
|
|
10025
10662
|
|
|
10026
10663
|
// src/lib/node-status/update.ts
|
|
10027
|
-
import { mkdir as mkdir4, readdir as
|
|
10664
|
+
import { mkdir as mkdir4, readdir as readdir8, rm, writeFile as writeFile2 } from "fs/promises";
|
|
10028
10665
|
import { dirname as dirname7, join as join21 } from "path";
|
|
10029
10666
|
|
|
10030
10667
|
// src/git/tracked-paths.ts
|
|
@@ -10151,7 +10788,7 @@ async function collectNodeStatusFiles(directory) {
|
|
|
10151
10788
|
}
|
|
10152
10789
|
async function readDirectoryEntries(directory) {
|
|
10153
10790
|
try {
|
|
10154
|
-
return await
|
|
10791
|
+
return await readdir8(directory, { withFileTypes: true });
|
|
10155
10792
|
} catch (error) {
|
|
10156
10793
|
if (isNodeError3(error) && error.code === "ENOENT") return [];
|
|
10157
10794
|
throw error;
|
|
@@ -10654,7 +11291,7 @@ var VALID_STATUS_FORMATS = [
|
|
|
10654
11291
|
OUTPUT_FORMAT.TABLE
|
|
10655
11292
|
];
|
|
10656
11293
|
var UNPRINTABLE_ERROR_MESSAGE = "unprintable error";
|
|
10657
|
-
function
|
|
11294
|
+
function writeOutput4(io, output) {
|
|
10658
11295
|
io.writeStdout(`${output}
|
|
10659
11296
|
`);
|
|
10660
11297
|
}
|
|
@@ -10712,7 +11349,7 @@ function registerSpecCommands(specCmd, invocation) {
|
|
|
10712
11349
|
runnerDepsFor: createRunnerDepsFor(productDir2, process.stderr)
|
|
10713
11350
|
})
|
|
10714
11351
|
}) : await statusCommand({ cwd: productDir(), format: format2, onWarning });
|
|
10715
|
-
|
|
11352
|
+
writeOutput4(invocation.io, output);
|
|
10716
11353
|
} catch (error) {
|
|
10717
11354
|
handleCommandError(invocation.io, error);
|
|
10718
11355
|
}
|
|
@@ -10720,7 +11357,7 @@ function registerSpecCommands(specCmd, invocation) {
|
|
|
10720
11357
|
specCmd.command(SPEC_DOMAIN_CLI.NEXT_COMMAND).description("Find next spec-tree node to work on").action(async () => {
|
|
10721
11358
|
try {
|
|
10722
11359
|
const output = await nextCommand({ cwd: productDir(), onWarning });
|
|
10723
|
-
|
|
11360
|
+
writeOutput4(invocation.io, output);
|
|
10724
11361
|
} catch (error) {
|
|
10725
11362
|
handleCommandError(invocation.io, error);
|
|
10726
11363
|
}
|
|
@@ -10974,7 +11611,7 @@ var testingDomain = createTestingDomain();
|
|
|
10974
11611
|
|
|
10975
11612
|
// src/interfaces/cli/validation.ts
|
|
10976
11613
|
import { existsSync as existsSync8, realpathSync } from "fs";
|
|
10977
|
-
import { isAbsolute as isAbsolute9, relative as relative9, resolve as
|
|
11614
|
+
import { isAbsolute as isAbsolute9, relative as relative9, resolve as resolve11, sep as sep3 } from "path";
|
|
10978
11615
|
|
|
10979
11616
|
// src/commands/validation/formatting.ts
|
|
10980
11617
|
import { existsSync, statSync } from "fs";
|
|
@@ -11165,7 +11802,7 @@ function buildDprintCheckArgs(options) {
|
|
|
11165
11802
|
}
|
|
11166
11803
|
async function validateFormatting(context, runner = defaultFormattingProcessRunner) {
|
|
11167
11804
|
const args = buildDprintCheckArgs({ files: context.files, excludes: context.excludes });
|
|
11168
|
-
return new Promise((
|
|
11805
|
+
return new Promise((resolve12) => {
|
|
11169
11806
|
const child = spawnManagedSubprocess(runner, DPRINT_COMMAND, args, { cwd: context.projectRoot });
|
|
11170
11807
|
const chunks = [];
|
|
11171
11808
|
const capture = (chunk) => {
|
|
@@ -11174,10 +11811,10 @@ async function validateFormatting(context, runner = defaultFormattingProcessRunn
|
|
|
11174
11811
|
child.stdout?.on(VALIDATION_SUBPROCESS_EVENTS.DATA, capture);
|
|
11175
11812
|
child.stderr?.on(VALIDATION_SUBPROCESS_EVENTS.DATA, capture);
|
|
11176
11813
|
child.on(VALIDATION_SUBPROCESS_EVENTS.CLOSE, (code) => {
|
|
11177
|
-
|
|
11814
|
+
resolve12({ success: code === 0, output: chunks.join("") });
|
|
11178
11815
|
});
|
|
11179
11816
|
child.on(VALIDATION_SUBPROCESS_EVENTS.ERROR, (error) => {
|
|
11180
|
-
|
|
11817
|
+
resolve12({ success: false, output: chunks.join(""), error: error.message });
|
|
11181
11818
|
});
|
|
11182
11819
|
});
|
|
11183
11820
|
}
|
|
@@ -12195,39 +12832,39 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12195
12832
|
const token = _scanner.scan();
|
|
12196
12833
|
switch (_scanner.getTokenError()) {
|
|
12197
12834
|
case 4:
|
|
12198
|
-
|
|
12835
|
+
handleError5(
|
|
12199
12836
|
14
|
|
12200
12837
|
/* ParseErrorCode.InvalidUnicode */
|
|
12201
12838
|
);
|
|
12202
12839
|
break;
|
|
12203
12840
|
case 5:
|
|
12204
|
-
|
|
12841
|
+
handleError5(
|
|
12205
12842
|
15
|
|
12206
12843
|
/* ParseErrorCode.InvalidEscapeCharacter */
|
|
12207
12844
|
);
|
|
12208
12845
|
break;
|
|
12209
12846
|
case 3:
|
|
12210
|
-
|
|
12847
|
+
handleError5(
|
|
12211
12848
|
13
|
|
12212
12849
|
/* ParseErrorCode.UnexpectedEndOfNumber */
|
|
12213
12850
|
);
|
|
12214
12851
|
break;
|
|
12215
12852
|
case 1:
|
|
12216
12853
|
if (!disallowComments) {
|
|
12217
|
-
|
|
12854
|
+
handleError5(
|
|
12218
12855
|
11
|
|
12219
12856
|
/* ParseErrorCode.UnexpectedEndOfComment */
|
|
12220
12857
|
);
|
|
12221
12858
|
}
|
|
12222
12859
|
break;
|
|
12223
12860
|
case 2:
|
|
12224
|
-
|
|
12861
|
+
handleError5(
|
|
12225
12862
|
12
|
|
12226
12863
|
/* ParseErrorCode.UnexpectedEndOfString */
|
|
12227
12864
|
);
|
|
12228
12865
|
break;
|
|
12229
12866
|
case 6:
|
|
12230
|
-
|
|
12867
|
+
handleError5(
|
|
12231
12868
|
16
|
|
12232
12869
|
/* ParseErrorCode.InvalidCharacter */
|
|
12233
12870
|
);
|
|
@@ -12237,7 +12874,7 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12237
12874
|
case 12:
|
|
12238
12875
|
case 13:
|
|
12239
12876
|
if (disallowComments) {
|
|
12240
|
-
|
|
12877
|
+
handleError5(
|
|
12241
12878
|
10
|
|
12242
12879
|
/* ParseErrorCode.InvalidCommentToken */
|
|
12243
12880
|
);
|
|
@@ -12246,7 +12883,7 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12246
12883
|
}
|
|
12247
12884
|
break;
|
|
12248
12885
|
case 16:
|
|
12249
|
-
|
|
12886
|
+
handleError5(
|
|
12250
12887
|
1
|
|
12251
12888
|
/* ParseErrorCode.InvalidSymbol */
|
|
12252
12889
|
);
|
|
@@ -12259,7 +12896,7 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12259
12896
|
}
|
|
12260
12897
|
}
|
|
12261
12898
|
}
|
|
12262
|
-
function
|
|
12899
|
+
function handleError5(error, skipUntilAfter = [], skipUntil = []) {
|
|
12263
12900
|
onError(error);
|
|
12264
12901
|
if (skipUntilAfter.length + skipUntil.length > 0) {
|
|
12265
12902
|
let token = _scanner.getToken();
|
|
@@ -12291,7 +12928,7 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12291
12928
|
const tokenValue = _scanner.getTokenValue();
|
|
12292
12929
|
let value = Number(tokenValue);
|
|
12293
12930
|
if (isNaN(value)) {
|
|
12294
|
-
|
|
12931
|
+
handleError5(
|
|
12295
12932
|
2
|
|
12296
12933
|
/* ParseErrorCode.InvalidNumberFormat */
|
|
12297
12934
|
);
|
|
@@ -12316,7 +12953,7 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12316
12953
|
}
|
|
12317
12954
|
function parseProperty() {
|
|
12318
12955
|
if (_scanner.getToken() !== 10) {
|
|
12319
|
-
|
|
12956
|
+
handleError5(3, [], [
|
|
12320
12957
|
2,
|
|
12321
12958
|
5
|
|
12322
12959
|
/* SyntaxKind.CommaToken */
|
|
@@ -12328,14 +12965,14 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12328
12965
|
onSeparator(":");
|
|
12329
12966
|
scanNext();
|
|
12330
12967
|
if (!parseValue()) {
|
|
12331
|
-
|
|
12968
|
+
handleError5(4, [], [
|
|
12332
12969
|
2,
|
|
12333
12970
|
5
|
|
12334
12971
|
/* SyntaxKind.CommaToken */
|
|
12335
12972
|
]);
|
|
12336
12973
|
}
|
|
12337
12974
|
} else {
|
|
12338
|
-
|
|
12975
|
+
handleError5(5, [], [
|
|
12339
12976
|
2,
|
|
12340
12977
|
5
|
|
12341
12978
|
/* SyntaxKind.CommaToken */
|
|
@@ -12351,7 +12988,7 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12351
12988
|
while (_scanner.getToken() !== 2 && _scanner.getToken() !== 17) {
|
|
12352
12989
|
if (_scanner.getToken() === 5) {
|
|
12353
12990
|
if (!needsComma) {
|
|
12354
|
-
|
|
12991
|
+
handleError5(4, [], []);
|
|
12355
12992
|
}
|
|
12356
12993
|
onSeparator(",");
|
|
12357
12994
|
scanNext();
|
|
@@ -12359,10 +12996,10 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12359
12996
|
break;
|
|
12360
12997
|
}
|
|
12361
12998
|
} else if (needsComma) {
|
|
12362
|
-
|
|
12999
|
+
handleError5(6, [], []);
|
|
12363
13000
|
}
|
|
12364
13001
|
if (!parseProperty()) {
|
|
12365
|
-
|
|
13002
|
+
handleError5(4, [], [
|
|
12366
13003
|
2,
|
|
12367
13004
|
5
|
|
12368
13005
|
/* SyntaxKind.CommaToken */
|
|
@@ -12372,7 +13009,7 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12372
13009
|
}
|
|
12373
13010
|
onObjectEnd();
|
|
12374
13011
|
if (_scanner.getToken() !== 2) {
|
|
12375
|
-
|
|
13012
|
+
handleError5(7, [
|
|
12376
13013
|
2
|
|
12377
13014
|
/* SyntaxKind.CloseBraceToken */
|
|
12378
13015
|
], []);
|
|
@@ -12389,7 +13026,7 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12389
13026
|
while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) {
|
|
12390
13027
|
if (_scanner.getToken() === 5) {
|
|
12391
13028
|
if (!needsComma) {
|
|
12392
|
-
|
|
13029
|
+
handleError5(4, [], []);
|
|
12393
13030
|
}
|
|
12394
13031
|
onSeparator(",");
|
|
12395
13032
|
scanNext();
|
|
@@ -12397,7 +13034,7 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12397
13034
|
break;
|
|
12398
13035
|
}
|
|
12399
13036
|
} else if (needsComma) {
|
|
12400
|
-
|
|
13037
|
+
handleError5(6, [], []);
|
|
12401
13038
|
}
|
|
12402
13039
|
if (isFirstElement) {
|
|
12403
13040
|
_jsonPath.push(0);
|
|
@@ -12406,7 +13043,7 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12406
13043
|
_jsonPath[_jsonPath.length - 1]++;
|
|
12407
13044
|
}
|
|
12408
13045
|
if (!parseValue()) {
|
|
12409
|
-
|
|
13046
|
+
handleError5(4, [], [
|
|
12410
13047
|
4,
|
|
12411
13048
|
5
|
|
12412
13049
|
/* SyntaxKind.CommaToken */
|
|
@@ -12419,7 +13056,7 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12419
13056
|
_jsonPath.pop();
|
|
12420
13057
|
}
|
|
12421
13058
|
if (_scanner.getToken() !== 4) {
|
|
12422
|
-
|
|
13059
|
+
handleError5(8, [
|
|
12423
13060
|
4
|
|
12424
13061
|
/* SyntaxKind.CloseBracketToken */
|
|
12425
13062
|
], []);
|
|
@@ -12445,15 +13082,15 @@ function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
|
12445
13082
|
if (options.allowEmptyContent) {
|
|
12446
13083
|
return true;
|
|
12447
13084
|
}
|
|
12448
|
-
|
|
13085
|
+
handleError5(4, [], []);
|
|
12449
13086
|
return false;
|
|
12450
13087
|
}
|
|
12451
13088
|
if (!parseValue()) {
|
|
12452
|
-
|
|
13089
|
+
handleError5(4, [], []);
|
|
12453
13090
|
return false;
|
|
12454
13091
|
}
|
|
12455
13092
|
if (_scanner.getToken() !== 17) {
|
|
12456
|
-
|
|
13093
|
+
handleError5(9, [], []);
|
|
12457
13094
|
}
|
|
12458
13095
|
return true;
|
|
12459
13096
|
}
|
|
@@ -12512,7 +13149,7 @@ var ParseErrorCode;
|
|
|
12512
13149
|
|
|
12513
13150
|
// src/validation/config/scope.ts
|
|
12514
13151
|
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3 } from "fs";
|
|
12515
|
-
import { isAbsolute as isAbsolute5, join as join27, relative as relative5, resolve as
|
|
13152
|
+
import { isAbsolute as isAbsolute5, join as join27, relative as relative5, resolve as resolve9 } from "path";
|
|
12516
13153
|
var TSCONFIG_FILES = {
|
|
12517
13154
|
full: "tsconfig.json",
|
|
12518
13155
|
production: "tsconfig.production.json"
|
|
@@ -12665,7 +13302,7 @@ function directoryPassesIncludePatterns(directory, patterns, projectRoot, deps)
|
|
|
12665
13302
|
(pattern) => includePatternTargetsTypeScriptScope(pattern, projectRoot, deps) && typeScriptScopePatternIntersectsDirectory(pattern, directory)
|
|
12666
13303
|
);
|
|
12667
13304
|
}
|
|
12668
|
-
function
|
|
13305
|
+
function stripTrailingPathSeparators2(value) {
|
|
12669
13306
|
let end = value.length;
|
|
12670
13307
|
while (end > 0 && value.charAt(end - 1) === PATH_SEGMENT_SEPARATOR3) {
|
|
12671
13308
|
end -= 1;
|
|
@@ -12674,7 +13311,7 @@ function stripTrailingPathSeparators(value) {
|
|
|
12674
13311
|
}
|
|
12675
13312
|
function normalizeTypeScriptScopePath(path7) {
|
|
12676
13313
|
const joined = path7.split(/[\\/]/gu).join(PATH_SEGMENT_SEPARATOR3).replace(/^\.\//u, "");
|
|
12677
|
-
return
|
|
13314
|
+
return stripTrailingPathSeparators2(joined);
|
|
12678
13315
|
}
|
|
12679
13316
|
function pathMatchesLiteralPrefix(path7, prefix) {
|
|
12680
13317
|
const normalizedPath = normalizeTypeScriptScopePath(path7);
|
|
@@ -12694,7 +13331,7 @@ function globLiteralPrefix(pattern) {
|
|
|
12694
13331
|
if (globIndex === -1) {
|
|
12695
13332
|
return normalizedPattern;
|
|
12696
13333
|
}
|
|
12697
|
-
return
|
|
13334
|
+
return stripTrailingPathSeparators2(normalizedPattern.slice(0, globIndex));
|
|
12698
13335
|
}
|
|
12699
13336
|
function firstGlobMarkerIndex(path7) {
|
|
12700
13337
|
const globIndex = path7.indexOf(GLOB_MARKER);
|
|
@@ -12886,13 +13523,13 @@ function pathPassesTypeScriptScope(path7, scopeConfig) {
|
|
|
12886
13523
|
return included && !excluded;
|
|
12887
13524
|
}
|
|
12888
13525
|
function pathStaysInsideTypeScriptScopeRoot(projectRoot, path7) {
|
|
12889
|
-
const resolvedPath = isAbsolute5(path7) ?
|
|
13526
|
+
const resolvedPath = isAbsolute5(path7) ? resolve9(path7) : resolve9(projectRoot, path7);
|
|
12890
13527
|
const relativePath = relative5(projectRoot, resolvedPath);
|
|
12891
13528
|
const segments = normalizeTypeScriptScopePath(relativePath).split(PATH_SEGMENT_SEPARATOR3);
|
|
12892
13529
|
return relativePath.length === 0 || !segments.includes("..") && !isAbsolute5(relativePath);
|
|
12893
13530
|
}
|
|
12894
13531
|
function toProjectRelativeTypeScriptScopePath(projectRoot, path7) {
|
|
12895
|
-
const resolvedPath = isAbsolute5(path7) ?
|
|
13532
|
+
const resolvedPath = isAbsolute5(path7) ? resolve9(path7) : resolve9(projectRoot, path7);
|
|
12896
13533
|
const relativePath = relative5(projectRoot, resolvedPath);
|
|
12897
13534
|
return relativePath.length === 0 ? TYPESCRIPT_SCOPE_PROJECT_ROOT : normalizeTypeScriptScopePath(relativePath);
|
|
12898
13535
|
}
|
|
@@ -13645,13 +14282,13 @@ async function runKnipSubprocess(projectRoot, typescriptScope, runner, deps) {
|
|
|
13645
14282
|
knipProcess.stderr?.on("data", (data) => {
|
|
13646
14283
|
knipError += data.toString();
|
|
13647
14284
|
});
|
|
13648
|
-
return new Promise((
|
|
14285
|
+
return new Promise((resolve12) => {
|
|
13649
14286
|
const resolveAfterCleanup = (result) => {
|
|
13650
14287
|
if (resultResolved) {
|
|
13651
14288
|
return;
|
|
13652
14289
|
}
|
|
13653
14290
|
resultResolved = true;
|
|
13654
|
-
void cleanupOnce().finally(() =>
|
|
14291
|
+
void cleanupOnce().finally(() => resolve12(result));
|
|
13655
14292
|
};
|
|
13656
14293
|
knipProcess.on("close", (code) => {
|
|
13657
14294
|
if (code === 0) {
|
|
@@ -14078,7 +14715,7 @@ async function validateESLint(context, runner = defaultEslintProcessRunner, outp
|
|
|
14078
14715
|
scope: scope2,
|
|
14079
14716
|
scopeConfig: context.scopeConfig
|
|
14080
14717
|
});
|
|
14081
|
-
return new Promise((
|
|
14718
|
+
return new Promise((resolve12) => {
|
|
14082
14719
|
const localBin = join31(projectRoot, ...ESLINT_LOCAL_BIN_SEGMENTS);
|
|
14083
14720
|
const binary = existsSync6(localBin) ? localBin : "npx";
|
|
14084
14721
|
const spawnArgs = binary === "npx" ? eslintArgs : eslintArgs.slice(1);
|
|
@@ -14088,13 +14725,13 @@ async function validateESLint(context, runner = defaultEslintProcessRunner, outp
|
|
|
14088
14725
|
forwardValidationSubprocessOutput(eslintProcess, outputStreams);
|
|
14089
14726
|
eslintProcess.on(VALIDATION_SUBPROCESS_EVENTS.CLOSE, (code) => {
|
|
14090
14727
|
if (code === 0) {
|
|
14091
|
-
|
|
14728
|
+
resolve12({ success: true });
|
|
14092
14729
|
} else {
|
|
14093
|
-
|
|
14730
|
+
resolve12({ success: false, error: `ESLint exited with code ${code}` });
|
|
14094
14731
|
}
|
|
14095
14732
|
});
|
|
14096
14733
|
eslintProcess.on(VALIDATION_SUBPROCESS_EVENTS.ERROR, (error) => {
|
|
14097
|
-
|
|
14734
|
+
resolve12({ success: false, error: error.message });
|
|
14098
14735
|
});
|
|
14099
14736
|
});
|
|
14100
14737
|
}
|
|
@@ -14192,8 +14829,8 @@ function formatLintResult(result, quiet, durationMs) {
|
|
|
14192
14829
|
}
|
|
14193
14830
|
|
|
14194
14831
|
// src/validation/literal/index.ts
|
|
14195
|
-
import { readFile as
|
|
14196
|
-
import { isAbsolute as isAbsolute7, relative as relative7, resolve as
|
|
14832
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
14833
|
+
import { isAbsolute as isAbsolute7, relative as relative7, resolve as resolve10 } from "path";
|
|
14197
14834
|
|
|
14198
14835
|
// src/lib/file-inclusion/predicates/ignore-source.ts
|
|
14199
14836
|
var IGNORE_SOURCE_LAYER = "ignore-source";
|
|
@@ -14227,7 +14864,7 @@ var ignoreSourceLayer = makeLayer(
|
|
|
14227
14864
|
);
|
|
14228
14865
|
|
|
14229
14866
|
// src/lib/file-inclusion/pipeline.ts
|
|
14230
|
-
import { readdir as
|
|
14867
|
+
import { readdir as readdir9 } from "fs/promises";
|
|
14231
14868
|
import { join as join32, relative as relative6, sep as sep2 } from "path";
|
|
14232
14869
|
var EXPLICIT_OVERRIDE_LAYER = "explicit-override";
|
|
14233
14870
|
function isNodeError4(err) {
|
|
@@ -14236,7 +14873,7 @@ function isNodeError4(err) {
|
|
|
14236
14873
|
async function collectPaths(absoluteDir, projectRoot, result, artifactDirs) {
|
|
14237
14874
|
let dirEntries;
|
|
14238
14875
|
try {
|
|
14239
|
-
dirEntries = await
|
|
14876
|
+
dirEntries = await readdir9(absoluteDir, { withFileTypes: true });
|
|
14240
14877
|
} catch (err) {
|
|
14241
14878
|
if (isNodeError4(err) && (err.code === "ENOENT" || err.code === "ENOTDIR")) {
|
|
14242
14879
|
return;
|
|
@@ -14733,37 +15370,22 @@ function isTestFile(relPath) {
|
|
|
14733
15370
|
}
|
|
14734
15371
|
|
|
14735
15372
|
// src/validation/literal/index.ts
|
|
14736
|
-
var PATH_PREFIX_SEPARATOR2 = "/";
|
|
14737
15373
|
var DEFAULT_LITERAL_COLLECT_OPTIONS = {
|
|
14738
15374
|
visitorKeys: defaultVisitorKeys,
|
|
14739
15375
|
minStringLength: literalConfigDescriptor.defaults.minStringLength,
|
|
14740
15376
|
minNumberDigits: literalConfigDescriptor.defaults.minNumberDigits
|
|
14741
15377
|
};
|
|
14742
|
-
function normalizePathPrefix3(prefix) {
|
|
14743
|
-
const posix = prefix.split(/[\\/]/g).join(PATH_PREFIX_SEPARATOR2);
|
|
14744
|
-
return posix.endsWith(PATH_PREFIX_SEPARATOR2) ? posix : `${posix}${PATH_PREFIX_SEPARATOR2}`;
|
|
14745
|
-
}
|
|
14746
15378
|
function applyPathFilter2(entries, pathConfig) {
|
|
14747
15379
|
if (pathConfig === void 0) {
|
|
14748
15380
|
return entries;
|
|
14749
15381
|
}
|
|
14750
|
-
|
|
14751
|
-
const excludePrefixes = (pathConfig.exclude ?? []).map(normalizePathPrefix3);
|
|
14752
|
-
return entries.filter((entry) => {
|
|
14753
|
-
if (includePrefixes.length > 0 && !includePrefixes.some((p) => entry.path.startsWith(p))) {
|
|
14754
|
-
return false;
|
|
14755
|
-
}
|
|
14756
|
-
if (excludePrefixes.some((p) => entry.path.startsWith(p))) {
|
|
14757
|
-
return false;
|
|
14758
|
-
}
|
|
14759
|
-
return true;
|
|
14760
|
-
});
|
|
15382
|
+
return entries.filter((entry) => pathPassesValidationFilter(entry.path, pathConfig));
|
|
14761
15383
|
}
|
|
14762
15384
|
async function validateLiteralReuse(input) {
|
|
14763
15385
|
const config = input.config ?? literalConfigDescriptor.defaults;
|
|
14764
15386
|
const request = input.scopeConfig === void 0 && input.files ? {
|
|
14765
15387
|
explicit: input.files.map((f) => {
|
|
14766
|
-
const abs = isAbsolute7(f) ? f :
|
|
15388
|
+
const abs = isAbsolute7(f) ? f : resolve10(input.productDir, f);
|
|
14767
15389
|
return relative7(input.productDir, abs).split(/[\\/]/g).join("/");
|
|
14768
15390
|
})
|
|
14769
15391
|
} : { walkRoot: input.productDir };
|
|
@@ -14777,7 +15399,7 @@ async function validateLiteralReuse(input) {
|
|
|
14777
15399
|
const pathFiltered = applyPathFilter2(scope2.included, input.pathConfig);
|
|
14778
15400
|
const literalScopeConfig = input.scopeConfig;
|
|
14779
15401
|
const filtered = literalScopeConfig === void 0 ? pathFiltered : pathFiltered.filter((entry) => pathPassesTypeScriptScope(entry.path, literalScopeConfig));
|
|
14780
|
-
const candidateFiles = filtered.filter((entry) => isTypescriptSource(entry.path)).map((entry) =>
|
|
15402
|
+
const candidateFiles = filtered.filter((entry) => isTypescriptSource(entry.path)).map((entry) => resolve10(input.productDir, entry.path));
|
|
14781
15403
|
const collectOptions = {
|
|
14782
15404
|
visitorKeys: defaultVisitorKeys,
|
|
14783
15405
|
minStringLength: config.minStringLength,
|
|
@@ -14812,7 +15434,7 @@ async function validateLiteralReuse(input) {
|
|
|
14812
15434
|
}
|
|
14813
15435
|
async function readSafe(path7) {
|
|
14814
15436
|
try {
|
|
14815
|
-
return await
|
|
15437
|
+
return await readFile10(path7, "utf8");
|
|
14816
15438
|
} catch (err) {
|
|
14817
15439
|
if (typeof err === "object" && err !== null && "code" in err) {
|
|
14818
15440
|
const code = err.code;
|
|
@@ -15175,7 +15797,7 @@ function resolveProjectTscInvocation(projectRoot, deps, tscArgs) {
|
|
|
15175
15797
|
}
|
|
15176
15798
|
function runTypeScriptInvocation(projectRoot, invocation, runner, outputStreams, cleanup = () => {
|
|
15177
15799
|
}) {
|
|
15178
|
-
return new Promise((
|
|
15800
|
+
return new Promise((resolve12) => {
|
|
15179
15801
|
const tscProcess = spawnManagedSubprocess(runner, invocation.tool, invocation.args, {
|
|
15180
15802
|
cwd: projectRoot
|
|
15181
15803
|
});
|
|
@@ -15183,14 +15805,14 @@ function runTypeScriptInvocation(projectRoot, invocation, runner, outputStreams,
|
|
|
15183
15805
|
tscProcess.on(VALIDATION_SUBPROCESS_EVENTS.CLOSE, (code) => {
|
|
15184
15806
|
cleanup();
|
|
15185
15807
|
if (code === 0) {
|
|
15186
|
-
|
|
15808
|
+
resolve12({ success: true, skipped: false });
|
|
15187
15809
|
} else {
|
|
15188
|
-
|
|
15810
|
+
resolve12({ success: false, error: `TypeScript exited with code ${code}` });
|
|
15189
15811
|
}
|
|
15190
15812
|
});
|
|
15191
15813
|
tscProcess.on(VALIDATION_SUBPROCESS_EVENTS.ERROR, (error) => {
|
|
15192
15814
|
cleanup();
|
|
15193
|
-
|
|
15815
|
+
resolve12({ success: false, error: error.message });
|
|
15194
15816
|
});
|
|
15195
15817
|
});
|
|
15196
15818
|
}
|
|
@@ -15457,17 +16079,22 @@ async function allowlistExisting(options) {
|
|
|
15457
16079
|
if (configRead.kind === "ambiguous") {
|
|
15458
16080
|
return { exitCode: EXIT_ERROR, output: formatConfigFileAmbiguityError(configRead.detected) };
|
|
15459
16081
|
}
|
|
15460
|
-
const
|
|
15461
|
-
if (!
|
|
15462
|
-
return { exitCode: EXIT_ERROR, output:
|
|
16082
|
+
const resolvedConfig = resolveConfigFromReadResult(configRead, [validationConfigDescriptor]);
|
|
16083
|
+
if (!resolvedConfig.ok) {
|
|
16084
|
+
return { exitCode: EXIT_ERROR, output: resolvedConfig.error };
|
|
15463
16085
|
}
|
|
16086
|
+
const validationConfig = resolvedConfig.value[validationConfigDescriptor.section];
|
|
15464
16087
|
const detection = await validateLiteralReuse({
|
|
15465
16088
|
productDir: options.productDir,
|
|
15466
|
-
config:
|
|
16089
|
+
config: validationConfig.literal.values,
|
|
16090
|
+
pathConfig: validationPathFilterForTool(
|
|
16091
|
+
validationConfig.paths,
|
|
16092
|
+
VALIDATION_PATH_TOOL_SUBSECTIONS.LITERAL
|
|
16093
|
+
)
|
|
15467
16094
|
});
|
|
15468
16095
|
const findingValues = collectFindingValues(detection.findings);
|
|
15469
16096
|
const updatedInclude = computeUpdatedInclude(
|
|
15470
|
-
|
|
16097
|
+
validationConfig.literal.values.include,
|
|
15471
16098
|
findingValues
|
|
15472
16099
|
);
|
|
15473
16100
|
const target = configRead.kind === "ok" ? configRead.file : configFileForFormat(options.productDir, DEFAULT_CONFIG_FILE_FORMAT);
|
|
@@ -15478,25 +16105,6 @@ async function allowlistExisting(options) {
|
|
|
15478
16105
|
await writer.write(target.path, serialized.value);
|
|
15479
16106
|
return { exitCode: EXIT_OK, output: "" };
|
|
15480
16107
|
}
|
|
15481
|
-
function readCurrentLiteralConfig(read) {
|
|
15482
|
-
if (read.kind !== "ok") return { ok: true, value: literalConfigDescriptor.defaults };
|
|
15483
|
-
const sections = parseConfigFileSections(read.file);
|
|
15484
|
-
if (!sections.ok) return sections;
|
|
15485
|
-
const validationRaw = sections.value[VALIDATION_SECTION];
|
|
15486
|
-
if (typeof validationRaw !== "object" || validationRaw === null) {
|
|
15487
|
-
return { ok: true, value: literalConfigDescriptor.defaults };
|
|
15488
|
-
}
|
|
15489
|
-
const literalRaw = validationRaw[VALIDATION_LITERAL_SUBSECTION];
|
|
15490
|
-
if (typeof literalRaw !== "object" || literalRaw === null) {
|
|
15491
|
-
return { ok: true, value: literalConfigDescriptor.defaults };
|
|
15492
|
-
}
|
|
15493
|
-
const valuesRaw = literalRaw[VALIDATION_LITERAL_VALUES_SUBSECTION];
|
|
15494
|
-
if (valuesRaw === void 0) {
|
|
15495
|
-
return { ok: true, value: literalConfigDescriptor.defaults };
|
|
15496
|
-
}
|
|
15497
|
-
const validated = literalConfigDescriptor.validate(valuesRaw);
|
|
15498
|
-
return validated.ok ? validated : { ok: true, value: literalConfigDescriptor.defaults };
|
|
15499
|
-
}
|
|
15500
16108
|
function collectFindingValues(findings) {
|
|
15501
16109
|
const values = /* @__PURE__ */ new Set();
|
|
15502
16110
|
for (const finding of findings.srcReuse) values.add(finding.value);
|
|
@@ -15637,9 +16245,9 @@ function addCommonOptions(cmd) {
|
|
|
15637
16245
|
return cmd.argument(pathOperands.optionalVariadic, pathOperands.description).option("--scope <scope>", "Validation scope (full|production)", "full").option("--quiet", "Suppress progress output").option("--json", "Output results as JSON");
|
|
15638
16246
|
}
|
|
15639
16247
|
function normalizeProductPathOperand(productDir, effectiveInvocationDir, operand) {
|
|
15640
|
-
const resolvedProductDir = canonicalExistingPath(
|
|
15641
|
-
const resolvedInvocationDir = canonicalExistingPath(
|
|
15642
|
-
const absoluteOperand = canonicalExistingPath(
|
|
16248
|
+
const resolvedProductDir = canonicalExistingPath(resolve11(productDir));
|
|
16249
|
+
const resolvedInvocationDir = canonicalExistingPath(resolve11(effectiveInvocationDir));
|
|
16250
|
+
const absoluteOperand = canonicalExistingPath(resolve11(resolvedInvocationDir, operand));
|
|
15643
16251
|
const relativeOperand = relative9(resolvedProductDir, absoluteOperand);
|
|
15644
16252
|
if (relativeOperand === ".." || relativeOperand.startsWith(`..${sep3}`) || isAbsolute9(relativeOperand)) {
|
|
15645
16253
|
return void 0;
|
|
@@ -16169,11 +16777,11 @@ function renderTextStatus(record6) {
|
|
|
16169
16777
|
}
|
|
16170
16778
|
|
|
16171
16779
|
// src/lib/worktree-path-info.ts
|
|
16172
|
-
import { stat as
|
|
16780
|
+
import { stat as stat6 } from "fs/promises";
|
|
16173
16781
|
var defaultWorktreePathInfo = {
|
|
16174
16782
|
isExistingNonDirectory: async (path7) => {
|
|
16175
16783
|
try {
|
|
16176
|
-
const pathStats = await
|
|
16784
|
+
const pathStats = await stat6(path7);
|
|
16177
16785
|
return !pathStats.isDirectory();
|
|
16178
16786
|
} catch {
|
|
16179
16787
|
return false;
|
|
@@ -16194,21 +16802,21 @@ var WORKTREE_CLI = {
|
|
|
16194
16802
|
WORKTREES_DIR_FLAG: "--worktrees-dir"
|
|
16195
16803
|
};
|
|
16196
16804
|
var WORKTREE_DOMAIN_DESCRIPTION = "Coordinate worktree occupancy across a bare-repository pool";
|
|
16197
|
-
function
|
|
16805
|
+
function writeOutput5(invocation, output) {
|
|
16198
16806
|
invocation.io.writeStdout(`${output}
|
|
16199
16807
|
`);
|
|
16200
16808
|
}
|
|
16201
|
-
function
|
|
16809
|
+
function writeError5(invocation, output) {
|
|
16202
16810
|
invocation.io.writeStderr(`${output}
|
|
16203
16811
|
`);
|
|
16204
16812
|
}
|
|
16205
16813
|
function writeInvocationWarning4(invocation, warning) {
|
|
16206
16814
|
if (warning !== void 0) {
|
|
16207
|
-
|
|
16815
|
+
writeError5(invocation, warning);
|
|
16208
16816
|
}
|
|
16209
16817
|
}
|
|
16210
|
-
function
|
|
16211
|
-
|
|
16818
|
+
function handleError4(invocation, error) {
|
|
16819
|
+
writeError5(invocation, `Error: ${error}`);
|
|
16212
16820
|
return invocation.io.exit(1);
|
|
16213
16821
|
}
|
|
16214
16822
|
function registerWorktreeCommands(worktreeCmd, invocation) {
|
|
@@ -16226,7 +16834,7 @@ function registerWorktreeCommands(worktreeCmd, invocation) {
|
|
|
16226
16834
|
worktreesDir: options.worktreesDir,
|
|
16227
16835
|
onWarning: (warning) => writeInvocationWarning4(invocation, warning)
|
|
16228
16836
|
});
|
|
16229
|
-
if (!result.ok)
|
|
16837
|
+
if (!result.ok) handleError4(invocation, result.error);
|
|
16230
16838
|
});
|
|
16231
16839
|
worktreeCmd.command(`${WORKTREE_CLI.STATUS} ${WORKTREE_CLI.WORKTREE_ARGUMENT}`).description("Report a worktree's occupancy (running | free)").option(WORKTREE_CLI.ALL_FLAG, "Report every git-observed worktree").option(`${WORKTREE_CLI.FORMAT_FLAG} <format>`, "Output format (text|json)", WORKTREE_STATUS_FORMAT.TEXT).option(`${WORKTREE_CLI.WORKTREES_DIR_FLAG} <path>`, "Explicit .spx/worktrees directory").action(
|
|
16232
16840
|
async (worktrees, options) => {
|
|
@@ -16242,8 +16850,8 @@ function registerWorktreeCommands(worktreeCmd, invocation) {
|
|
|
16242
16850
|
worktreesDir: options.worktreesDir,
|
|
16243
16851
|
onWarning: (warning) => writeInvocationWarning4(invocation, warning)
|
|
16244
16852
|
});
|
|
16245
|
-
if (!result.ok)
|
|
16246
|
-
|
|
16853
|
+
if (!result.ok) handleError4(invocation, result.error);
|
|
16854
|
+
writeOutput5(invocation, result.value);
|
|
16247
16855
|
}
|
|
16248
16856
|
);
|
|
16249
16857
|
worktreeCmd.command(WORKTREE_CLI.RELEASE).description("Release the running worktree's occupancy claim").option(`${WORKTREE_CLI.WORKTREES_DIR_FLAG} <path>`, "Explicit .spx/worktrees directory").action(async (options) => {
|
|
@@ -16254,7 +16862,7 @@ function registerWorktreeCommands(worktreeCmd, invocation) {
|
|
|
16254
16862
|
worktreesDir: options.worktreesDir,
|
|
16255
16863
|
onWarning: (warning) => writeInvocationWarning4(invocation, warning)
|
|
16256
16864
|
});
|
|
16257
|
-
if (!result.ok)
|
|
16865
|
+
if (!result.ok) handleError4(invocation, result.error);
|
|
16258
16866
|
});
|
|
16259
16867
|
}
|
|
16260
16868
|
var worktreeDomain = {
|
|
@@ -16268,6 +16876,7 @@ var worktreeDomain = {
|
|
|
16268
16876
|
|
|
16269
16877
|
// src/interfaces/cli/registry.ts
|
|
16270
16878
|
var CLI_DOMAINS = [
|
|
16879
|
+
agentDomain,
|
|
16271
16880
|
claudeDomain,
|
|
16272
16881
|
compactDomain,
|
|
16273
16882
|
configDomain,
|