codetrap 0.1.7 → 0.1.9
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/README.md +132 -98
- package/docs/installation.md +61 -63
- package/package.json +4 -3
- package/plugins/codetrap-agent/.codex-plugin/plugin.json +2 -3
- package/plugins/codetrap-agent/hooks/post-flight-capture.example.md +19 -17
- package/plugins/codetrap-agent/hooks.json +2 -2
- package/{skills → plugins/codetrap-agent/skills}/codetrap-add/SKILL.md +10 -4
- package/plugins/codetrap-agent/skills/codetrap-capture/SKILL.md +14 -3
- package/plugins/codetrap-agent/skills/codetrap-capture-external/SKILL.md +52 -9
- package/plugins/codetrap-agent/skills/codetrap-check/SKILL.md +74 -6
- package/{skills → plugins/codetrap-agent/skills}/codetrap-search/SKILL.md +6 -5
- package/plugins/codetrap-agent/templates/AGENTS.codetrap-maintainer.md +15 -0
- package/plugins/codetrap-agent/templates/AGENTS.codetrap.md +16 -5
- package/scripts/release-preflight.ts +15 -0
- package/scripts/search-policy-sweep.ts +131 -0
- package/src/commands/workflow.ts +172 -68
- package/src/db/embedding-queries.ts +230 -48
- package/src/db/queries.ts +0 -25
- package/src/db/repository.ts +32 -21
- package/src/db/schema.ts +80 -0
- package/src/index.ts +34 -4
- package/src/lib/codex-setup.ts +247 -0
- package/src/lib/command-requests.ts +112 -1
- package/src/lib/config.ts +57 -7
- package/src/lib/constants.ts +1 -1
- package/src/lib/doctor.ts +42 -12
- package/src/lib/embedder.ts +118 -3
- package/src/lib/embedding-health.ts +3 -1
- package/src/lib/embedding-job.ts +3 -0
- package/src/lib/embedding-management.ts +65 -0
- package/src/lib/embedding-runtime.ts +177 -0
- package/src/lib/output-json.ts +0 -2
- package/src/lib/scope-context.ts +12 -6
- package/src/lib/scope-migration.ts +2 -1
- package/src/lib/scope.ts +0 -2
- package/src/lib/search-eval.ts +38 -18
- package/src/lib/search-policy-sweep.ts +563 -0
- package/src/lib/search-policy.ts +0 -4
- package/src/lib/search-service.ts +14 -15
- package/src/lib/session-candidate-document.ts +175 -0
- package/src/lib/session-candidate-scope.ts +6 -0
- package/src/lib/session-capture.ts +298 -32
- package/src/lib/session-codec.ts +1 -8
- package/src/lib/session-operations.ts +83 -60
- package/src/lib/session-review.ts +327 -0
- package/src/lib/session-store.ts +87 -73
- package/src/lib/store.ts +74 -10
- package/src/lib/string-list.ts +3 -0
- package/src/lib/text-lines.ts +7 -0
- package/src/lib/trap-search-document.ts +2 -1
- package/src/lib/value-types.ts +3 -0
- package/src/web/client-review.ts +171 -0
- package/src/web/client-script.ts +426 -51
- package/src/web/client-shell.ts +414 -0
- package/src/web/client-text.ts +112 -0
- package/src/web/project-registry.ts +3 -5
- package/src/web/server.ts +117 -103
- package/src/web/static.ts +364 -19
- package/skills/codetrap-capture-external/SKILL.md +0 -62
- package/skills/codetrap-check/SKILL.md +0 -69
- package/src/lib/embedding-index.ts +0 -53
package/src/commands/workflow.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { readFileSync } from "node:fs";
|
|
|
2
2
|
import { TrapStore } from "../lib/store";
|
|
3
3
|
import { formatTrapShort, formatTrapDetails, formatTrapActionCard } from "../lib/format";
|
|
4
4
|
import type { Trap } from "../domain/trap";
|
|
5
|
-
import type { SessionMetadata } from "../domain/session";
|
|
6
5
|
import {
|
|
7
6
|
formatScopeMigrationText,
|
|
8
7
|
runScopeMigration,
|
|
@@ -11,16 +10,31 @@ import {
|
|
|
11
10
|
import { TrapOperations } from "../lib/trap-operations";
|
|
12
11
|
import { buildDoctorReport, formatDoctorText } from "../lib/doctor";
|
|
13
12
|
import { formatEmbedText } from "../lib/embed-output";
|
|
13
|
+
import {
|
|
14
|
+
formatEmbeddingProfilesText,
|
|
15
|
+
formatEmbeddingStatusText,
|
|
16
|
+
formatEmbeddingsUseText,
|
|
17
|
+
type EmbeddingsUseResult,
|
|
18
|
+
} from "../lib/embedding-management";
|
|
14
19
|
import { searchDefaultsFromConfig } from "../lib/config";
|
|
20
|
+
import { formatCodexSetupText, runCodexSetup } from "../lib/codex-setup";
|
|
15
21
|
import { SessionStore } from "../lib/session-store";
|
|
16
22
|
import { SessionOperations, type SessionConflictResult } from "../lib/session-operations";
|
|
17
23
|
import {
|
|
18
24
|
CANDIDATES_FILE,
|
|
19
25
|
NOTES_FILE,
|
|
20
26
|
RECAP_FILE,
|
|
21
|
-
sessionRelativeDir,
|
|
22
27
|
sessionRelativeFile,
|
|
23
28
|
} from "../lib/session-codec";
|
|
29
|
+
import {
|
|
30
|
+
sessionAcceptPayload,
|
|
31
|
+
sessionCliConflictPayload,
|
|
32
|
+
sessionCleanupPayload,
|
|
33
|
+
sessionConflictPayload,
|
|
34
|
+
sessionConflictText,
|
|
35
|
+
sessionPayload,
|
|
36
|
+
sessionRejectPayload,
|
|
37
|
+
} from "../lib/session-review";
|
|
24
38
|
import {
|
|
25
39
|
toCliSearchJson,
|
|
26
40
|
toListJson,
|
|
@@ -36,10 +50,12 @@ import {
|
|
|
36
50
|
import { mutationJsonPayload } from "../lib/trap-mutation-result";
|
|
37
51
|
import {
|
|
38
52
|
embedRequestFromArgs,
|
|
53
|
+
embeddingsUseRequestFromArgs,
|
|
39
54
|
evidenceRequestFromArgs,
|
|
40
55
|
listRequestFromArgs,
|
|
41
56
|
searchRequestFromArgs,
|
|
42
57
|
sessionAcceptRequestFromArgs,
|
|
58
|
+
sessionCaptureRequestFromArgs,
|
|
43
59
|
sessionCandidateRequestFromArgs,
|
|
44
60
|
sessionCloseRequestFromArgs,
|
|
45
61
|
sessionIdRequestFromArgs,
|
|
@@ -95,18 +111,22 @@ export async function executeCommand(strip: string[], store: TrapStore): Promise
|
|
|
95
111
|
return cmdStats(args, operations);
|
|
96
112
|
case "doctor":
|
|
97
113
|
return cmdDoctor(args, store, operations);
|
|
114
|
+
case "setup":
|
|
115
|
+
return cmdSetup(args);
|
|
98
116
|
case "repair-scope":
|
|
99
117
|
return cmdScopeMigration("repair-scope", args, operations);
|
|
100
118
|
case "migrate-project":
|
|
101
119
|
return cmdScopeMigration("migrate-project", args, operations);
|
|
102
120
|
case "embed":
|
|
103
121
|
return cmdEmbed(args, store);
|
|
122
|
+
case "embeddings":
|
|
123
|
+
return cmdEmbeddings(args, store);
|
|
104
124
|
case "session":
|
|
105
125
|
return cmdSession(args, store, operations);
|
|
106
126
|
default:
|
|
107
127
|
return errorResult([
|
|
108
128
|
`Unknown command: ${sub}`,
|
|
109
|
-
"Commands: init, add, search, list, show, edit, delete, add_trap_evidence, archive_trap, supersede_trap, export, import, stats, doctor, repair-scope, migrate-project, embed, session",
|
|
129
|
+
"Commands: init, add, search, list, show, edit, delete, add_trap_evidence, archive_trap, supersede_trap, export, import, stats, doctor, setup, repair-scope, migrate-project, embed, embeddings, session",
|
|
110
130
|
].join("\n"));
|
|
111
131
|
}
|
|
112
132
|
}
|
|
@@ -341,14 +361,43 @@ function cmdStats(args: string[], operations: TrapOperations): CommandResult {
|
|
|
341
361
|
: textResult(formatStatsText(stats));
|
|
342
362
|
}
|
|
343
363
|
|
|
344
|
-
function cmdDoctor(args: string[], store: TrapStore, operations: TrapOperations): CommandResult {
|
|
364
|
+
async function cmdDoctor(args: string[], store: TrapStore, operations: TrapOperations): Promise<CommandResult> {
|
|
345
365
|
const { opts } = parseArgs(args);
|
|
346
|
-
const
|
|
366
|
+
const projectRoot = store.getProjectRoot();
|
|
367
|
+
const candidateReview = projectRoot
|
|
368
|
+
? new SessionOperations(new SessionStore(projectRoot), operations).candidateReviewSummary()
|
|
369
|
+
: null;
|
|
370
|
+
const report = await buildDoctorReport(store, operations, process.cwd(), candidateReview);
|
|
347
371
|
return opts.json !== undefined
|
|
348
372
|
? jsonResult(report)
|
|
349
373
|
: textResult(formatDoctorText(report));
|
|
350
374
|
}
|
|
351
375
|
|
|
376
|
+
function cmdSetup(args: string[]): CommandResult {
|
|
377
|
+
const sub = args[0];
|
|
378
|
+
const rest = args.slice(1);
|
|
379
|
+
if (sub !== "codex") {
|
|
380
|
+
return errorResult("Usage: codetrap setup codex [--mcp] [--no-agents] [--agents-file AGENTS.md] [--codex-home <path>] [--dry-run] [--json]");
|
|
381
|
+
}
|
|
382
|
+
const { opts } = parseArgs(rest);
|
|
383
|
+
try {
|
|
384
|
+
const result = runCodexSetup({
|
|
385
|
+
cwd: process.cwd(),
|
|
386
|
+
codexHome: opts["codex-home"],
|
|
387
|
+
agentsFile: opts["agents-file"],
|
|
388
|
+
installMcp: opts.mcp !== undefined,
|
|
389
|
+
skipAgents: opts["no-agents"] !== undefined,
|
|
390
|
+
dryRun: opts["dry-run"] !== undefined,
|
|
391
|
+
});
|
|
392
|
+
if (opts.json !== undefined) return jsonResult(result, result.success ? 0 : 1);
|
|
393
|
+
return result.success
|
|
394
|
+
? textResult(formatCodexSetupText(result))
|
|
395
|
+
: errorResult(formatCodexSetupText(result));
|
|
396
|
+
} catch (error) {
|
|
397
|
+
return errorFrom(error);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
352
401
|
function cmdScopeMigration(
|
|
353
402
|
command: ScopeMigrationCommand,
|
|
354
403
|
args: string[],
|
|
@@ -388,6 +437,59 @@ async function cmdEmbed(args: string[], store: TrapStore): Promise<CommandResult
|
|
|
388
437
|
}
|
|
389
438
|
}
|
|
390
439
|
|
|
440
|
+
async function cmdEmbeddings(args: string[], store: TrapStore): Promise<CommandResult> {
|
|
441
|
+
const sub = args[0] ?? "status";
|
|
442
|
+
const rest = args.length === 0 ? [] : args.slice(1);
|
|
443
|
+
|
|
444
|
+
try {
|
|
445
|
+
switch (sub) {
|
|
446
|
+
case "status": {
|
|
447
|
+
const { opts } = parseArgs(rest);
|
|
448
|
+
const status = await store.embeddingStatus({ scope: opts.scope });
|
|
449
|
+
return opts.json !== undefined
|
|
450
|
+
? jsonResult(status)
|
|
451
|
+
: textResult(formatEmbeddingStatusText(status));
|
|
452
|
+
}
|
|
453
|
+
case "list":
|
|
454
|
+
case "profiles": {
|
|
455
|
+
const { opts } = parseArgs(rest);
|
|
456
|
+
const profiles = store.embeddingProfiles({ scope: opts.scope });
|
|
457
|
+
const payload = {
|
|
458
|
+
active_profile_id: store.embeddingRuntimeStatus().profile_id,
|
|
459
|
+
...profiles,
|
|
460
|
+
};
|
|
461
|
+
return opts.json !== undefined
|
|
462
|
+
? jsonResult(payload)
|
|
463
|
+
: textResult(formatEmbeddingProfilesText(profiles));
|
|
464
|
+
}
|
|
465
|
+
case "use": {
|
|
466
|
+
const { opts, positionals } = parseArgs(rest);
|
|
467
|
+
const request = embeddingsUseRequestFromArgs(positionals, opts);
|
|
468
|
+
const written = store.configureEmbeddings(request.embeddings);
|
|
469
|
+
const scope = store.hasProject() ? "project" : "global";
|
|
470
|
+
const result: EmbeddingsUseResult = {
|
|
471
|
+
...written,
|
|
472
|
+
embeddings: written.config.embeddings ?? request.embeddings,
|
|
473
|
+
next_action: {
|
|
474
|
+
command: `codetrap embeddings reindex --scope ${scope}`,
|
|
475
|
+
reason: "Generate embeddings for the selected profile.",
|
|
476
|
+
},
|
|
477
|
+
};
|
|
478
|
+
return opts.json !== undefined
|
|
479
|
+
? jsonResult(result)
|
|
480
|
+
: textResult(formatEmbeddingsUseText(result));
|
|
481
|
+
}
|
|
482
|
+
case "reindex":
|
|
483
|
+
case "embed":
|
|
484
|
+
return cmdEmbed(rest, store);
|
|
485
|
+
default:
|
|
486
|
+
return errorResult("Usage: codetrap embeddings <status|list|profiles|use|reindex> [--json]");
|
|
487
|
+
}
|
|
488
|
+
} catch (error) {
|
|
489
|
+
return errorFrom(error);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
391
493
|
async function cmdSession(args: string[], store: TrapStore, trapOperations: TrapOperations): Promise<CommandResult> {
|
|
392
494
|
const sub = args[0];
|
|
393
495
|
const rest = args.slice(1);
|
|
@@ -413,6 +515,8 @@ async function cmdSession(args: string[], store: TrapStore, trapOperations: Trap
|
|
|
413
515
|
return cmdSessionNotes(rest, sessions);
|
|
414
516
|
case "close":
|
|
415
517
|
return cmdSessionClose(rest, sessions);
|
|
518
|
+
case "capture":
|
|
519
|
+
return cmdSessionCapture(rest, sessions);
|
|
416
520
|
case "candidates":
|
|
417
521
|
return cmdSessionCandidates(rest, sessions);
|
|
418
522
|
case "candidate":
|
|
@@ -428,7 +532,7 @@ async function cmdSession(args: string[], store: TrapStore, trapOperations: Trap
|
|
|
428
532
|
case "cleanup":
|
|
429
533
|
return cmdSessionCleanup(rest, sessions);
|
|
430
534
|
default:
|
|
431
|
-
return errorResult("Usage: codetrap session <start|note|status|list|show|notes|close|candidates|candidate|accept|reject|delete|prune|cleanup>");
|
|
535
|
+
return errorResult("Usage: codetrap session <start|note|status|list|show|notes|close|capture|candidates|candidate|accept|reject|delete|prune|cleanup>");
|
|
432
536
|
}
|
|
433
537
|
} catch (error) {
|
|
434
538
|
return errorFrom(error);
|
|
@@ -472,14 +576,31 @@ function cmdSessionStatus(args: string[], sessions: SessionOperations): CommandR
|
|
|
472
576
|
return jsonResult({
|
|
473
577
|
active_session_id: status.active_session_id,
|
|
474
578
|
session: status.session ? sessionPayload(status.session) : null,
|
|
579
|
+
candidate_review: status.candidate_review,
|
|
475
580
|
});
|
|
476
581
|
}
|
|
477
|
-
if (!status.session)
|
|
478
|
-
|
|
582
|
+
if (!status.session) {
|
|
583
|
+
const lines = ["No active session."];
|
|
584
|
+
if (status.candidate_review.pending_count > 0) {
|
|
585
|
+
lines.push(
|
|
586
|
+
`Pending candidate review: ${status.candidate_review.pending_count} candidate(s) across ${status.candidate_review.pending_session_count} session(s).`
|
|
587
|
+
);
|
|
588
|
+
if (status.candidate_review.next_session_id) {
|
|
589
|
+
lines.push(`Review: codetrap session candidates ${status.candidate_review.next_session_id}`);
|
|
590
|
+
}
|
|
591
|
+
lines.push("Open web review: codetrap web");
|
|
592
|
+
}
|
|
593
|
+
return textResult(lines.join("\n"));
|
|
594
|
+
}
|
|
595
|
+
const lines = [
|
|
479
596
|
`Active session ${status.session.id}`,
|
|
480
597
|
`Goal: ${status.session.goal}`,
|
|
481
598
|
`Notes: ${sessionRelativeFile(status.session.id, NOTES_FILE)}`,
|
|
482
|
-
]
|
|
599
|
+
];
|
|
600
|
+
if (status.candidate_review.pending_count > 0) {
|
|
601
|
+
lines.push(`Pending candidate review: ${status.candidate_review.pending_count} candidate(s).`);
|
|
602
|
+
}
|
|
603
|
+
return textResult(lines.join("\n"));
|
|
483
604
|
}
|
|
484
605
|
|
|
485
606
|
function cmdSessionList(args: string[], sessions: SessionOperations): CommandResult {
|
|
@@ -487,7 +608,9 @@ function cmdSessionList(args: string[], sessions: SessionOperations): CommandRes
|
|
|
487
608
|
const entries = sessions.listSessions(sessionListRequestFromArgs(opts));
|
|
488
609
|
if (opts.json !== undefined) return jsonResult(entries);
|
|
489
610
|
if (entries.length === 0) return textResult("No sessions found.");
|
|
490
|
-
return textResult(entries.map((entry) =>
|
|
611
|
+
return textResult(entries.map((entry) =>
|
|
612
|
+
`${entry.id} [${entry.status}] ${entry.goal} (${entry.pending_count} pending, ${entry.reviewed_count} reviewed)`
|
|
613
|
+
).join("\n"));
|
|
491
614
|
}
|
|
492
615
|
|
|
493
616
|
function cmdSessionShow(args: string[], sessions: SessionOperations): CommandResult {
|
|
@@ -525,7 +648,6 @@ function cmdSessionClose(args: string[], sessions: SessionOperations): CommandRe
|
|
|
525
648
|
...sessionPayload(result.session),
|
|
526
649
|
recap_path: result.recap_path,
|
|
527
650
|
candidate_count: result.candidate_count,
|
|
528
|
-
traps_written: result.traps_written,
|
|
529
651
|
};
|
|
530
652
|
if (opts.json !== undefined) return jsonResult(payload);
|
|
531
653
|
const lines = [
|
|
@@ -539,6 +661,39 @@ function cmdSessionClose(args: string[], sessions: SessionOperations): CommandRe
|
|
|
539
661
|
return textResult(lines.join("\n"));
|
|
540
662
|
}
|
|
541
663
|
|
|
664
|
+
function cmdSessionCapture(args: string[], sessions: SessionOperations): CommandResult {
|
|
665
|
+
const { opts } = parseArgs(args);
|
|
666
|
+
const result = sessions.captureCandidate(sessionCaptureRequestFromArgs(opts, {
|
|
667
|
+
isTTY: process.stdin.isTTY === true,
|
|
668
|
+
readStdin: () => readFileSync(0, "utf-8"),
|
|
669
|
+
readFile: (path) => readFileSync(path, "utf-8"),
|
|
670
|
+
}));
|
|
671
|
+
const nextAction = `codetrap session candidate ${result.candidate.id} --session ${result.session.id} --json`;
|
|
672
|
+
const payload = {
|
|
673
|
+
success: true,
|
|
674
|
+
session_id: result.session.id,
|
|
675
|
+
candidate_id: result.candidate.id,
|
|
676
|
+
status: result.candidate.status,
|
|
677
|
+
quality_score: result.candidate.quality_score,
|
|
678
|
+
candidate_count: result.candidate_count,
|
|
679
|
+
created_session: result.created_session,
|
|
680
|
+
closed_session: result.closed_session,
|
|
681
|
+
duplicate: result.duplicate,
|
|
682
|
+
candidate_traps_path: sessionRelativeFile(result.session.id, CANDIDATES_FILE),
|
|
683
|
+
recap_path: result.recap_path,
|
|
684
|
+
next_action: {
|
|
685
|
+
command: nextAction,
|
|
686
|
+
},
|
|
687
|
+
};
|
|
688
|
+
if (opts.json !== undefined) return jsonResult(payload);
|
|
689
|
+
return textResult([
|
|
690
|
+
`${result.duplicate ? "Reused" : "Captured"} candidate ${result.candidate.id} in session ${result.session.id}.`,
|
|
691
|
+
result.created_session ? "Created and closed a post-flight session." : "Session remains active.",
|
|
692
|
+
`Candidate inbox: ${payload.candidate_traps_path}`,
|
|
693
|
+
`Review: ${nextAction}`,
|
|
694
|
+
].join("\n"));
|
|
695
|
+
}
|
|
696
|
+
|
|
542
697
|
function cmdSessionCandidates(args: string[], sessions: SessionOperations): CommandResult {
|
|
543
698
|
const { opts, positionals } = parseArgs(args);
|
|
544
699
|
const request = sessionIdRequestFromArgs(positionals);
|
|
@@ -562,16 +717,7 @@ async function cmdSessionAccept(args: string[], sessions: SessionOperations): Pr
|
|
|
562
717
|
const { opts, positionals } = parseArgs(args);
|
|
563
718
|
const accepted = await sessions.acceptCandidate(sessionAcceptRequestFromArgs(positionals, opts));
|
|
564
719
|
if (!accepted.success) return possibleConflictResult(accepted, opts.json !== undefined);
|
|
565
|
-
const payload =
|
|
566
|
-
success: true,
|
|
567
|
-
session_id: accepted.session.id,
|
|
568
|
-
candidate_id: accepted.candidate.id,
|
|
569
|
-
status: accepted.candidate.status,
|
|
570
|
-
trap_id: accepted.trap_id,
|
|
571
|
-
scope: accepted.scope,
|
|
572
|
-
evidence_id: accepted.evidence_id,
|
|
573
|
-
superseded_id: accepted.superseded_id,
|
|
574
|
-
};
|
|
720
|
+
const payload = sessionAcceptPayload(accepted);
|
|
575
721
|
if (opts.json !== undefined) return jsonResult(payload);
|
|
576
722
|
const lines = [`Accepted ${accepted.candidate.id}; wrote trap #${accepted.trap_id} to ${accepted.scope} scope.`];
|
|
577
723
|
if (accepted.superseded_id !== null) lines.push(`Superseded trap #${accepted.superseded_id}.`);
|
|
@@ -581,13 +727,7 @@ async function cmdSessionAccept(args: string[], sessions: SessionOperations): Pr
|
|
|
581
727
|
function cmdSessionReject(args: string[], sessions: SessionOperations): CommandResult {
|
|
582
728
|
const { opts, positionals } = parseArgs(args);
|
|
583
729
|
const rejected = sessions.rejectCandidate(sessionRejectRequestFromArgs(positionals, opts));
|
|
584
|
-
const payload =
|
|
585
|
-
success: true,
|
|
586
|
-
session_id: rejected.session.id,
|
|
587
|
-
candidate_id: rejected.candidate.id,
|
|
588
|
-
status: rejected.candidate.status,
|
|
589
|
-
reason: rejected.candidate.rejection_reason ?? null,
|
|
590
|
-
};
|
|
730
|
+
const payload = sessionRejectPayload(rejected);
|
|
591
731
|
if (opts.json !== undefined) return jsonResult(payload);
|
|
592
732
|
return textResult(`Rejected ${rejected.candidate.id}.`);
|
|
593
733
|
}
|
|
@@ -621,12 +761,7 @@ function cmdSessionCleanup(args: string[], sessions: SessionOperations): Command
|
|
|
621
761
|
}
|
|
622
762
|
const request = sessionIdRequestFromArgs(positionals);
|
|
623
763
|
const result = sessions.cleanupDeletedTrapCandidates(request.sessionId);
|
|
624
|
-
const payload =
|
|
625
|
-
success: true,
|
|
626
|
-
session_id: result.session.id,
|
|
627
|
-
removed_count: result.removed_count,
|
|
628
|
-
removed_candidate_ids: result.removed_candidate_ids,
|
|
629
|
-
};
|
|
764
|
+
const payload = sessionCleanupPayload(result);
|
|
630
765
|
if (opts.json !== undefined) return jsonResult(payload);
|
|
631
766
|
return textResult(`Removed ${result.removed_count} deleted-trap candidate(s) from session ${result.session.id}.`);
|
|
632
767
|
}
|
|
@@ -679,42 +814,11 @@ function errorMessage(error: unknown): string {
|
|
|
679
814
|
return error instanceof Error ? error.message : String(error);
|
|
680
815
|
}
|
|
681
816
|
|
|
682
|
-
function sessionPayload(session: SessionMetadata) {
|
|
683
|
-
return {
|
|
684
|
-
...session,
|
|
685
|
-
session_dir: sessionRelativeDir(session.id),
|
|
686
|
-
notes_path: sessionRelativeFile(session.id, NOTES_FILE),
|
|
687
|
-
recap_path: sessionRelativeFile(session.id, RECAP_FILE),
|
|
688
|
-
candidate_traps_path: sessionRelativeFile(session.id, CANDIDATES_FILE),
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
|
|
692
817
|
function possibleConflictResult(
|
|
693
818
|
result: SessionConflictResult,
|
|
694
819
|
asJson: boolean
|
|
695
820
|
): CommandResult {
|
|
696
|
-
const payload =
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
session_id: result.session_id,
|
|
700
|
-
candidate_id: result.candidate_id,
|
|
701
|
-
possible_conflicts: result.possible_conflicts,
|
|
702
|
-
next_actions: [
|
|
703
|
-
`codetrap session accept ${result.candidate_id} --session ${result.session_id} --accept-anyway`,
|
|
704
|
-
`codetrap session accept ${result.candidate_id} --session ${result.session_id} --supersedes <trap-id>`,
|
|
705
|
-
`codetrap session reject ${result.candidate_id} --session ${result.session_id} --reason <reason>`,
|
|
706
|
-
],
|
|
707
|
-
};
|
|
708
|
-
if (asJson) return jsonResult(payload, 1);
|
|
709
|
-
|
|
710
|
-
return errorResult([
|
|
711
|
-
"Possible active trap conflict found:",
|
|
712
|
-
...result.possible_conflicts.map((conflict) => [
|
|
713
|
-
`#${conflict.trap_id} ${conflict.title}`,
|
|
714
|
-
` reason: ${conflict.reason}`,
|
|
715
|
-
` fix: ${conflict.fix}`,
|
|
716
|
-
].join("\n")),
|
|
717
|
-
"",
|
|
718
|
-
`Use --accept-anyway to save as a new trap, or --supersedes <trap-id> to preserve lifecycle history.`,
|
|
719
|
-
].join("\n"));
|
|
821
|
+
const payload = sessionConflictPayload(result);
|
|
822
|
+
if (asJson) return jsonResult(sessionCliConflictPayload(payload), 1);
|
|
823
|
+
return errorResult(sessionConflictText(payload));
|
|
720
824
|
}
|