@longtable/cli 0.1.54 → 0.1.56
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 +326 -20
- package/dist/panel-runtime.d.ts +20 -0
- package/dist/panel-runtime.js +525 -0
- package/dist/panel.d.ts +4 -1
- package/dist/panel.js +34 -7
- package/dist/project-session.d.ts +35 -1
- package/dist/project-session.js +372 -2
- package/package.json +7 -7
package/dist/cli.js
CHANGED
|
@@ -18,8 +18,9 @@ import { installCodexPromptAliases, listInstalledCodexPromptAliases, removeCodex
|
|
|
18
18
|
import { buildPersonaGuidance, parseInvocationDirective } from "./persona-router.js";
|
|
19
19
|
import { PERSONA_DEFINITIONS, listRoleDefinitions } from "./personas.js";
|
|
20
20
|
import { buildPanelFallback, renderPanelSummary } from "./panel.js";
|
|
21
|
+
import { createPanelWorkerRun, launchPanelWorkerRun, panelWorkerRunPath, readPanelWorkerRun, refreshPanelWorkerRun, requestPanelWorkerStop, resumePanelWorkerRun, waitForPanelWorkerRun } from "./panel-runtime.js";
|
|
21
22
|
import { LONGTABLE_MANAGED_HOOK_EVENTS, codexHooksEnabled, enableCodexHooksFeature, getMissingManagedCodexHookEvents, getMissingManagedCodexHookTrustState, mergeCodexHookTrustState, mergeManagedCodexHooksConfig, removeCodexHookTrustState, removeManagedCodexHooks } from "./codex-hooks.js";
|
|
22
|
-
import { appendInvocationRecordToWorkspace, applyResearchSpecificationPatch, assertWorkspaceNotBlocked, answerWorkspaceQuestion, buildQuestionOpportunitySpecs, clearWorkspaceQuestion, createWorkspaceFollowUpQuestions, createWorkspaceQuestion, createOrUpdateProjectWorkspace, diffResearchSpecifications, inspectProjectWorkspace, loadWorkspaceState, loadProjectContextFromDirectory, findUnincorporatedResearchEvidence, proposeResearchSpecificationPatch, pruneWorkspaceQuestions, readResearchSpecificationHistory, repairWorkspaceStateConsistency, renderProjectWorkspaceSummary, syncCurrentWorkspaceView } from "./project-session.js";
|
|
23
|
+
import { appendInvocationRecordToWorkspace, applyResearchSpecificationPatch, assertWorkspaceNotBlocked, answerWorkspaceQuestion, buildQuestionOpportunitySpecs, clearWorkspaceQuestion, createWorkspaceFollowUpQuestions, createWorkspaceQuestion, createOrUpdateProjectWorkspace, createWorkspaceHandoff, diffResearchSpecifications, inspectProjectWorkspace, loadWorkspaceState, loadProjectContextFromDirectory, findUnincorporatedResearchEvidence, proposeResearchSpecificationPatch, pruneWorkspaceQuestions, readResearchSpecificationHistory, recordPanelResultInWorkspace, repairWorkspaceStateConsistency, renderProjectWorkspaceSummary, syncCurrentWorkspaceView } from "./project-session.js";
|
|
23
24
|
import { buildTeamDebate } from "./debate.js";
|
|
24
25
|
import { createPromptRenderer } from "./prompt-renderer.js";
|
|
25
26
|
const VALID_MODES = new Set([
|
|
@@ -158,7 +159,12 @@ function usage() {
|
|
|
158
159
|
" longtable clarify --prompt <task-context> [--provider codex|claude] [--required|--advisory] [--print] [--cwd <path>] [--json] [--force]",
|
|
159
160
|
" longtable question --prompt <decision-context> [--title <text>] [--text <question>] [--provider codex|claude] [--required|--advisory] [--print] [--cwd <path>] [--json]",
|
|
160
161
|
" longtable clear-question --question <id> --reason <text> [--cwd <path>] [--json]",
|
|
161
|
-
" longtable panel [--prompt <text>] [--role <role[,role]>] [--mode review|critique|draft|commit] [--visibility synthesis_only|show_on_conflict|always_visible] [--print] [--json] [--setup <path>] [--cwd <path>]",
|
|
162
|
+
" longtable panel [--prompt <text>] [--role <role[,role]>] [--mode review|critique|draft|commit] [--visibility synthesis_only|show_on_conflict|always_visible] [--provider codex|claude] [--native-workers|--native-subagents] [--wait [ms]] [--print] [--json] [--setup <path>] [--cwd <path>]",
|
|
163
|
+
" longtable panel status --run <panel_run_id> [--wait [ms]] [--cwd <path>] [--json]",
|
|
164
|
+
" longtable panel stop --run <panel_run_id> [--cwd <path>] [--json]",
|
|
165
|
+
" longtable panel resume --run <panel_run_id> [--wait [ms]] [--cwd <path>] [--json]",
|
|
166
|
+
" longtable panel record [--invocation <id>] --result-file <json> [--surface sequential_fallback|native_subagents|native_workers] [--cwd <path>] [--json]",
|
|
167
|
+
" longtable handoff [--cwd <path>] [--output <file>] [--print] [--json]",
|
|
162
168
|
" longtable decide [--question <id>] --answer <value-or-text> [--rationale <text>] [--provider codex|claude] [--cwd <path>] [--json]",
|
|
163
169
|
" longtable explore|review|critique|draft|commit|submit [--prompt <text>] [--role <role[,role]>] [--panel] [--show-conflicts] [--show-deliberation] [--print] [--json] [--stage <stage>] [--setup <path>] [--cwd <path>]",
|
|
164
170
|
" longtable codex persist-init [--answers-json <json> | --stdin | full setup flags] [--install-skills] [--install-prompts] [--json]",
|
|
@@ -194,7 +200,7 @@ function parseArgs(argv) {
|
|
|
194
200
|
const values = {};
|
|
195
201
|
let subcommand = maybeSubcommand;
|
|
196
202
|
const modeCommand = command && VALID_MODES.has(command);
|
|
197
|
-
const directCommand = command && ["init", "setup", "start", "resume", "doctor", "status", "audit", "roles", "show", "install", "mcp", "codex", "claude", "ask", "clarify", "question", "clear-question", "prune-questions", "panel", "
|
|
203
|
+
const directCommand = command && ["init", "setup", "start", "resume", "doctor", "status", "audit", "roles", "show", "install", "mcp", "codex", "claude", "ask", "clarify", "question", "clear-question", "prune-questions", "panel", "handoff", "decide", "sentinel", "access", "search", "spec"].includes(command);
|
|
198
204
|
let startIndex = 1;
|
|
199
205
|
if (modeCommand) {
|
|
200
206
|
subcommand = undefined;
|
|
@@ -203,7 +209,7 @@ function parseArgs(argv) {
|
|
|
203
209
|
else if (command === "codex" || command === "claude" || command === "mcp") {
|
|
204
210
|
startIndex = 2;
|
|
205
211
|
}
|
|
206
|
-
else if ((command === "access" || command === "search" || command === "spec") && maybeSubcommand && !maybeSubcommand.startsWith("--")) {
|
|
212
|
+
else if ((command === "access" || command === "search" || command === "spec" || command === "panel") && maybeSubcommand && !maybeSubcommand.startsWith("--")) {
|
|
207
213
|
subcommand = maybeSubcommand;
|
|
208
214
|
startIndex = 2;
|
|
209
215
|
}
|
|
@@ -2302,6 +2308,132 @@ function parsePanelMode(value) {
|
|
|
2302
2308
|
}
|
|
2303
2309
|
return "review";
|
|
2304
2310
|
}
|
|
2311
|
+
function requireRunId(args) {
|
|
2312
|
+
if (typeof args.run !== "string" || args.run.trim().length === 0) {
|
|
2313
|
+
throw new Error("A panel run id is required. Pass --run <panel_run_id>.");
|
|
2314
|
+
}
|
|
2315
|
+
return args.run.trim();
|
|
2316
|
+
}
|
|
2317
|
+
function commandAvailable(command) {
|
|
2318
|
+
try {
|
|
2319
|
+
execSync(`command -v ${command}`, { stdio: "ignore" });
|
|
2320
|
+
return true;
|
|
2321
|
+
}
|
|
2322
|
+
catch {
|
|
2323
|
+
return false;
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
function parseWaitMs(value) {
|
|
2327
|
+
if (value === undefined || value === false) {
|
|
2328
|
+
return undefined;
|
|
2329
|
+
}
|
|
2330
|
+
if (value === true) {
|
|
2331
|
+
return 30_000;
|
|
2332
|
+
}
|
|
2333
|
+
const trimmed = value.trim();
|
|
2334
|
+
const multiplier = trimmed.endsWith("s") ? 1000 : 1;
|
|
2335
|
+
const numeric = Number.parseInt(trimmed.endsWith("s") ? trimmed.slice(0, -1) : trimmed, 10);
|
|
2336
|
+
if (!Number.isFinite(numeric) || numeric <= 0) {
|
|
2337
|
+
throw new Error(`Invalid --wait value: ${value}. Use milliseconds or a value like 30s.`);
|
|
2338
|
+
}
|
|
2339
|
+
return numeric * multiplier;
|
|
2340
|
+
}
|
|
2341
|
+
function panelWorkerNextCommands(context, runId) {
|
|
2342
|
+
const cwdFlag = `--cwd "${context.project.projectPath}"`;
|
|
2343
|
+
return {
|
|
2344
|
+
status: `longtable panel status ${cwdFlag} --run ${runId}`,
|
|
2345
|
+
stop: `longtable panel stop ${cwdFlag} --run ${runId}`,
|
|
2346
|
+
resume: `longtable panel resume ${cwdFlag} --run ${runId}`
|
|
2347
|
+
};
|
|
2348
|
+
}
|
|
2349
|
+
async function recordTerminalNativeWorkerRun(context, run) {
|
|
2350
|
+
if ((run.status !== "completed" && run.status !== "blocked") || !existsSync(run.aggregateResultPath)) {
|
|
2351
|
+
return null;
|
|
2352
|
+
}
|
|
2353
|
+
const aggregate = JSON.parse(await readFile(run.aggregateResultPath, "utf8"));
|
|
2354
|
+
return recordPanelResultInWorkspace({
|
|
2355
|
+
context,
|
|
2356
|
+
result: {
|
|
2357
|
+
...aggregate,
|
|
2358
|
+
invocationId: run.invocationId,
|
|
2359
|
+
surface: "native_workers",
|
|
2360
|
+
status: aggregate.status ?? run.status
|
|
2361
|
+
}
|
|
2362
|
+
});
|
|
2363
|
+
}
|
|
2364
|
+
function summarizePanelRecordOutput(result) {
|
|
2365
|
+
if (!result) {
|
|
2366
|
+
return null;
|
|
2367
|
+
}
|
|
2368
|
+
return {
|
|
2369
|
+
invocationId: result.invocation.id,
|
|
2370
|
+
status: result.invocation.status,
|
|
2371
|
+
surface: result.invocation.surface,
|
|
2372
|
+
evidenceRecordIds: result.evidenceRecords.map((record) => record.id)
|
|
2373
|
+
};
|
|
2374
|
+
}
|
|
2375
|
+
async function runPanelStatusCommand(args) {
|
|
2376
|
+
const context = await requireWorkspaceContext(args);
|
|
2377
|
+
const runId = requireRunId(args);
|
|
2378
|
+
const waitMs = parseWaitMs(args.wait);
|
|
2379
|
+
const initial = await refreshPanelWorkerRun(await readPanelWorkerRun(context.project.projectPath, runId));
|
|
2380
|
+
const refreshed = waitMs ? await waitForPanelWorkerRun(initial.run, waitMs) : initial.run;
|
|
2381
|
+
const recordedPanelResult = await recordTerminalNativeWorkerRun(context, refreshed);
|
|
2382
|
+
const nextCommands = panelWorkerNextCommands(context, refreshed.id);
|
|
2383
|
+
if (args.json === true) {
|
|
2384
|
+
console.log(JSON.stringify({ ...refreshed, nextCommands, recordedPanelResult: summarizePanelRecordOutput(recordedPanelResult) }, null, 2));
|
|
2385
|
+
return;
|
|
2386
|
+
}
|
|
2387
|
+
console.log("LongTable panel run status");
|
|
2388
|
+
console.log(`- run: ${refreshed.id}`);
|
|
2389
|
+
console.log(`- status: ${refreshed.status}`);
|
|
2390
|
+
for (const worker of refreshed.workers) {
|
|
2391
|
+
console.log(`- ${worker.label} (${worker.role}): ${worker.status}`);
|
|
2392
|
+
}
|
|
2393
|
+
console.log(`- stop: ${nextCommands.stop}`);
|
|
2394
|
+
console.log(`- resume: ${nextCommands.resume}`);
|
|
2395
|
+
if (recordedPanelResult) {
|
|
2396
|
+
console.log(`- recorded evidence: ${recordedPanelResult.evidenceRecords.length}`);
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
async function runPanelStopCommand(args) {
|
|
2400
|
+
const context = await requireWorkspaceContext(args);
|
|
2401
|
+
const runId = requireRunId(args);
|
|
2402
|
+
const stopped = await requestPanelWorkerStop(await readPanelWorkerRun(context.project.projectPath, runId));
|
|
2403
|
+
const nextCommands = panelWorkerNextCommands(context, stopped.id);
|
|
2404
|
+
if (args.json === true) {
|
|
2405
|
+
console.log(JSON.stringify({ ...stopped, nextCommands }, null, 2));
|
|
2406
|
+
return;
|
|
2407
|
+
}
|
|
2408
|
+
console.log("LongTable panel run stop requested");
|
|
2409
|
+
console.log(`- run: ${stopped.id}`);
|
|
2410
|
+
console.log(`- status: ${stopped.status}`);
|
|
2411
|
+
for (const worker of stopped.workers) {
|
|
2412
|
+
console.log(`- ${worker.label} (${worker.role}): ${worker.status}`);
|
|
2413
|
+
}
|
|
2414
|
+
console.log(`- resume: ${nextCommands.resume}`);
|
|
2415
|
+
}
|
|
2416
|
+
async function runPanelResumeCommand(args) {
|
|
2417
|
+
const context = await requireWorkspaceContext(args);
|
|
2418
|
+
const runId = requireRunId(args);
|
|
2419
|
+
const waitMs = parseWaitMs(args.wait);
|
|
2420
|
+
const { run } = await refreshPanelWorkerRun(await readPanelWorkerRun(context.project.projectPath, runId));
|
|
2421
|
+
const resumed = run.status === "completed" ? run : await launchPanelWorkerRun(await resumePanelWorkerRun(run));
|
|
2422
|
+
const finalRun = waitMs ? await waitForPanelWorkerRun(resumed, waitMs) : resumed;
|
|
2423
|
+
const recordedPanelResult = await recordTerminalNativeWorkerRun(context, finalRun);
|
|
2424
|
+
const nextCommands = panelWorkerNextCommands(context, finalRun.id);
|
|
2425
|
+
if (args.json === true) {
|
|
2426
|
+
console.log(JSON.stringify({ ...finalRun, nextCommands, recordedPanelResult: summarizePanelRecordOutput(recordedPanelResult) }, null, 2));
|
|
2427
|
+
return;
|
|
2428
|
+
}
|
|
2429
|
+
console.log("LongTable panel run resume requested");
|
|
2430
|
+
console.log(`- run: ${finalRun.id}`);
|
|
2431
|
+
console.log(`- status: ${finalRun.status}`);
|
|
2432
|
+
console.log(`- status command: ${nextCommands.status}`);
|
|
2433
|
+
if (recordedPanelResult) {
|
|
2434
|
+
console.log(`- recorded evidence: ${recordedPanelResult.evidenceRecords.length}`);
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2305
2437
|
async function loadOptionalSetup(path) {
|
|
2306
2438
|
try {
|
|
2307
2439
|
return await loadSetupOutput(path);
|
|
@@ -2388,7 +2520,9 @@ async function runPanelCommand(args) {
|
|
|
2388
2520
|
await assertWorkspaceNotBlocked(existingContext);
|
|
2389
2521
|
}
|
|
2390
2522
|
const projectAware = await buildProjectAwarePrompt(prompt, workingDirectory);
|
|
2391
|
-
const provider =
|
|
2523
|
+
const provider = args.provider === "codex" || args.provider === "claude"
|
|
2524
|
+
? args.provider
|
|
2525
|
+
: setup?.providerSelection.provider;
|
|
2392
2526
|
const visibility = parsePanelVisibility(typeof args.visibility === "string" ? args.visibility : undefined) ??
|
|
2393
2527
|
parsePanelVisibility(setup?.profileSeed.panelPreference) ??
|
|
2394
2528
|
"always_visible";
|
|
@@ -2398,7 +2532,9 @@ async function runPanelCommand(args) {
|
|
|
2398
2532
|
mode,
|
|
2399
2533
|
roleFlag: typeof args.role === "string" ? args.role : undefined,
|
|
2400
2534
|
provider,
|
|
2401
|
-
visibility
|
|
2535
|
+
visibility,
|
|
2536
|
+
nativeSubagents: args["native-subagents"] === true,
|
|
2537
|
+
nativeWorkers: args["native-workers"] === true
|
|
2402
2538
|
});
|
|
2403
2539
|
if (projectAware.projectContextFound) {
|
|
2404
2540
|
const context = await loadProjectContextFromDirectory(workingDirectory);
|
|
@@ -2406,6 +2542,30 @@ async function runPanelCommand(args) {
|
|
|
2406
2542
|
await appendInvocationRecordToWorkspace(context, fallback.invocationRecord, [fallback.questionRecord]);
|
|
2407
2543
|
}
|
|
2408
2544
|
}
|
|
2545
|
+
if (args.print === true) {
|
|
2546
|
+
console.log(fallback.prompt);
|
|
2547
|
+
return;
|
|
2548
|
+
}
|
|
2549
|
+
const waitMs = parseWaitMs(args.wait);
|
|
2550
|
+
const nativeWorkersRequested = args["native-workers"] === true && fallback.plan.preferredSurface === "native_workers";
|
|
2551
|
+
const nativeRunContext = nativeWorkersRequested
|
|
2552
|
+
? await loadProjectContextFromDirectory(workingDirectory)
|
|
2553
|
+
: null;
|
|
2554
|
+
const nativeRun = nativeWorkersRequested && nativeRunContext
|
|
2555
|
+
? await launchPanelWorkerRun(await createPanelWorkerRun({
|
|
2556
|
+
workingDirectory: nativeRunContext.project.projectPath,
|
|
2557
|
+
fallback,
|
|
2558
|
+
initialStatus: "planned",
|
|
2559
|
+
diagnostics: [
|
|
2560
|
+
commandAvailable("tmux") ? "tmux:available" : "tmux:unavailable",
|
|
2561
|
+
commandAvailable("codex") ? "codex:available" : "codex:unavailable"
|
|
2562
|
+
]
|
|
2563
|
+
}))
|
|
2564
|
+
: null;
|
|
2565
|
+
const finalNativeRun = nativeRun && waitMs ? await waitForPanelWorkerRun(nativeRun, waitMs) : nativeRun;
|
|
2566
|
+
const recordedPanelResult = finalNativeRun && nativeRunContext
|
|
2567
|
+
? await recordTerminalNativeWorkerRun(nativeRunContext, finalNativeRun)
|
|
2568
|
+
: null;
|
|
2409
2569
|
if (args.json === true) {
|
|
2410
2570
|
console.log(JSON.stringify({
|
|
2411
2571
|
intent: fallback.intent,
|
|
@@ -2414,22 +2574,51 @@ async function runPanelCommand(args) {
|
|
|
2414
2574
|
invocationRecord: fallback.invocationRecord,
|
|
2415
2575
|
questionRecord: fallback.questionRecord,
|
|
2416
2576
|
execution: {
|
|
2417
|
-
status: "planned",
|
|
2577
|
+
status: finalNativeRun?.status ?? "planned",
|
|
2418
2578
|
stableSurface: "sequential_fallback",
|
|
2419
|
-
|
|
2579
|
+
preferredSurface: fallback.plan.preferredSurface,
|
|
2580
|
+
nativeParallel: fallback.plan.preferredSurface === "native_workers"
|
|
2581
|
+
? "longtable_native_workers"
|
|
2582
|
+
: fallback.plan.preferredSurface === "native_subagents"
|
|
2583
|
+
? "session_dependent"
|
|
2584
|
+
: "not_requested",
|
|
2420
2585
|
projectContextFound: projectAware.projectContextFound,
|
|
2421
|
-
invocationLogged: projectAware.projectContextFound
|
|
2586
|
+
invocationLogged: projectAware.projectContextFound,
|
|
2587
|
+
nativeRunCreated: Boolean(finalNativeRun),
|
|
2588
|
+
waitMs,
|
|
2589
|
+
degradedReason: nativeWorkersRequested && !finalNativeRun
|
|
2590
|
+
? "native workers require an existing LongTable workspace; sequential fallback prompt returned"
|
|
2591
|
+
: finalNativeRun?.status === "degraded"
|
|
2592
|
+
? "native workers require local tmux and codex commands; sequential fallback remains available"
|
|
2593
|
+
: undefined
|
|
2422
2594
|
},
|
|
2595
|
+
nativeRun: finalNativeRun,
|
|
2596
|
+
recordedPanelResult: summarizePanelRecordOutput(recordedPanelResult),
|
|
2423
2597
|
fallbackPrompt: fallback.prompt
|
|
2424
2598
|
}, null, 2));
|
|
2425
2599
|
return;
|
|
2426
2600
|
}
|
|
2427
|
-
if (args.print === true) {
|
|
2428
|
-
console.log(fallback.prompt);
|
|
2429
|
-
return;
|
|
2430
|
-
}
|
|
2431
2601
|
console.log(renderPanelSummary(fallback.plan));
|
|
2432
2602
|
console.log("");
|
|
2603
|
+
if (finalNativeRun) {
|
|
2604
|
+
console.log("LongTable native panel worker run created");
|
|
2605
|
+
console.log(`- run: ${finalNativeRun.id}`);
|
|
2606
|
+
console.log(`- status: ${finalNativeRun.status}`);
|
|
2607
|
+
console.log(`- state: ${panelWorkerRunPath(nativeRunContext.project.projectPath, finalNativeRun.id)}`);
|
|
2608
|
+
const nextCommands = panelWorkerNextCommands(nativeRunContext, finalNativeRun.id);
|
|
2609
|
+
console.log(`- next status: ${nextCommands.status}`);
|
|
2610
|
+
console.log(`- stop: ${nextCommands.stop}`);
|
|
2611
|
+
console.log(`- resume: ${nextCommands.resume}`);
|
|
2612
|
+
if (recordedPanelResult) {
|
|
2613
|
+
console.log(`- recorded evidence: ${recordedPanelResult.evidenceRecords.length}`);
|
|
2614
|
+
}
|
|
2615
|
+
if (finalNativeRun.status === "degraded") {
|
|
2616
|
+
console.log("- degraded: native workers are unavailable; use the sequential fallback prompt below.");
|
|
2617
|
+
console.log("");
|
|
2618
|
+
console.log(fallback.prompt);
|
|
2619
|
+
}
|
|
2620
|
+
return;
|
|
2621
|
+
}
|
|
2433
2622
|
const exitCode = await runCodexThinWrapper({
|
|
2434
2623
|
prompt: fallback.prompt,
|
|
2435
2624
|
mode,
|
|
@@ -2439,6 +2628,106 @@ async function runPanelCommand(args) {
|
|
|
2439
2628
|
});
|
|
2440
2629
|
exit(exitCode);
|
|
2441
2630
|
}
|
|
2631
|
+
function parseInvocationSurface(value) {
|
|
2632
|
+
if (value === undefined || value === true) {
|
|
2633
|
+
return undefined;
|
|
2634
|
+
}
|
|
2635
|
+
const allowed = [
|
|
2636
|
+
"native_parallel",
|
|
2637
|
+
"native_subagents",
|
|
2638
|
+
"native_workers",
|
|
2639
|
+
"generated_skill",
|
|
2640
|
+
"prompt_alias",
|
|
2641
|
+
"sequential_fallback",
|
|
2642
|
+
"file_backed_panel_debate",
|
|
2643
|
+
"file_backed_debate",
|
|
2644
|
+
"mcp_transport"
|
|
2645
|
+
];
|
|
2646
|
+
if (allowed.includes(value)) {
|
|
2647
|
+
return value;
|
|
2648
|
+
}
|
|
2649
|
+
throw new Error(`Invalid panel result surface: ${value}.`);
|
|
2650
|
+
}
|
|
2651
|
+
function parseInvocationStatus(value) {
|
|
2652
|
+
if (value === undefined || value === true) {
|
|
2653
|
+
return undefined;
|
|
2654
|
+
}
|
|
2655
|
+
const allowed = ["planned", "running", "completed", "blocked", "degraded", "error"];
|
|
2656
|
+
if (allowed.includes(value)) {
|
|
2657
|
+
return value;
|
|
2658
|
+
}
|
|
2659
|
+
throw new Error(`Invalid panel result status: ${value}.`);
|
|
2660
|
+
}
|
|
2661
|
+
async function readPanelResultRecordInput(args) {
|
|
2662
|
+
const resultFile = typeof args["result-file"] === "string" ? args["result-file"] : undefined;
|
|
2663
|
+
const baseDirectory = typeof args.cwd === "string" ? args.cwd : cwd();
|
|
2664
|
+
const fromFile = resultFile
|
|
2665
|
+
? JSON.parse(await readFile(resolve(baseDirectory, resultFile), "utf8"))
|
|
2666
|
+
: {};
|
|
2667
|
+
const result = {
|
|
2668
|
+
...fromFile,
|
|
2669
|
+
...(typeof args.invocation === "string" ? { invocationId: args.invocation } : {}),
|
|
2670
|
+
...(typeof args.synthesis === "string" ? { synthesis: args.synthesis } : {}),
|
|
2671
|
+
...(typeof args["conflict-summary"] === "string" ? { conflictSummary: args["conflict-summary"] } : {}),
|
|
2672
|
+
...(typeof args["decision-prompt"] === "string" ? { decisionPrompt: args["decision-prompt"] } : {}),
|
|
2673
|
+
...(parseInvocationSurface(args.surface) ? { surface: parseInvocationSurface(args.surface) } : {}),
|
|
2674
|
+
...(parseInvocationStatus(args.status) ? { status: parseInvocationStatus(args.status) } : {})
|
|
2675
|
+
};
|
|
2676
|
+
if (!result.synthesis &&
|
|
2677
|
+
!result.conflictSummary &&
|
|
2678
|
+
!result.decisionPrompt &&
|
|
2679
|
+
(!result.memberResults || result.memberResults.length === 0)) {
|
|
2680
|
+
throw new Error("Panel result content is required. Pass --result-file with synthesis, conflictSummary, decisionPrompt, or memberResults.");
|
|
2681
|
+
}
|
|
2682
|
+
return result;
|
|
2683
|
+
}
|
|
2684
|
+
async function runPanelRecordCommand(args) {
|
|
2685
|
+
const context = await requireWorkspaceContext(args);
|
|
2686
|
+
const resultInput = await readPanelResultRecordInput(args);
|
|
2687
|
+
const result = await recordPanelResultInWorkspace({
|
|
2688
|
+
context,
|
|
2689
|
+
result: resultInput
|
|
2690
|
+
});
|
|
2691
|
+
if (args.json === true) {
|
|
2692
|
+
console.log(JSON.stringify({
|
|
2693
|
+
invocation: result.invocation,
|
|
2694
|
+
evidenceRecords: result.evidenceRecords,
|
|
2695
|
+
files: {
|
|
2696
|
+
state: context.stateFilePath,
|
|
2697
|
+
current: context.currentFilePath
|
|
2698
|
+
}
|
|
2699
|
+
}, null, 2));
|
|
2700
|
+
return;
|
|
2701
|
+
}
|
|
2702
|
+
console.log("LongTable panel result recorded");
|
|
2703
|
+
console.log(`- invocation: ${result.invocation.id}`);
|
|
2704
|
+
console.log(`- status: ${result.invocation.status}`);
|
|
2705
|
+
console.log(`- surface: ${result.invocation.surface}`);
|
|
2706
|
+
console.log(`- evidence records: ${result.evidenceRecords.length}`);
|
|
2707
|
+
console.log(`- unincorporated evidence: longtable spec unincorporated --cwd "${context.project.projectPath}"`);
|
|
2708
|
+
console.log(`- next handoff: longtable handoff --cwd "${context.project.projectPath}"`);
|
|
2709
|
+
}
|
|
2710
|
+
async function runHandoff(args) {
|
|
2711
|
+
const context = await requireWorkspaceContext(args);
|
|
2712
|
+
const result = await createWorkspaceHandoff({
|
|
2713
|
+
context,
|
|
2714
|
+
outputPath: typeof args.output === "string" ? args.output : undefined
|
|
2715
|
+
});
|
|
2716
|
+
if (args.json === true) {
|
|
2717
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2718
|
+
return;
|
|
2719
|
+
}
|
|
2720
|
+
if (args.print === true) {
|
|
2721
|
+
console.log(result.content);
|
|
2722
|
+
return;
|
|
2723
|
+
}
|
|
2724
|
+
console.log("LongTable handoff created");
|
|
2725
|
+
console.log(`- file: ${result.path}`);
|
|
2726
|
+
console.log(`- latest invocation: ${result.latestInvocationId ?? "none"}`);
|
|
2727
|
+
console.log(`- unincorporated evidence: ${result.sourceEvidenceIds.length}`);
|
|
2728
|
+
console.log(`- pending decisions: ${result.pendingQuestionIds.length}`);
|
|
2729
|
+
console.log("Use this handoff directly in Codex/Claude, or paste it into OMX `$ralplan` when OMX is installed.");
|
|
2730
|
+
}
|
|
2442
2731
|
function parseLimit(value) {
|
|
2443
2732
|
if (typeof value !== "string") {
|
|
2444
2733
|
return undefined;
|
|
@@ -3555,9 +3844,6 @@ async function runPanelDebateCommand(args) {
|
|
|
3555
3844
|
console.log(`- rounds: ${debate.run.roundCount}`);
|
|
3556
3845
|
console.log(`- checkpoint: ${debate.questionRecord.id}`);
|
|
3557
3846
|
}
|
|
3558
|
-
function disabledTeamCommandError() {
|
|
3559
|
-
return new Error("`longtable team` is disabled. Use `longtable panel --prompt <text>` for visible multi-role review, or `longtable ask --prompt \"lt debate: <text>\"` when debate is explicitly requested.");
|
|
3560
|
-
}
|
|
3561
3847
|
async function runDecide(args) {
|
|
3562
3848
|
const workingDirectory = typeof args.cwd === "string" ? args.cwd : cwd();
|
|
3563
3849
|
const answer = typeof args.answer === "string" ? args.answer.trim() : "";
|
|
@@ -3732,7 +4018,7 @@ async function runCodexSubcommand(subcommand, args) {
|
|
|
3732
4018
|
const installed = await installCodexSkills(roles, customDir, skillSurface);
|
|
3733
4019
|
console.log(`Installed ${installed.length} LongTable Codex skills in ${resolveCodexSkillsDir(customDir)} (${skillSurface} surface)`);
|
|
3734
4020
|
console.log("Use them inside Codex with natural-language triggers such as `lt explore: ...` or `lt panel: ...`.");
|
|
3735
|
-
console.log("Use `$longtable` as the general router; compact installs expose
|
|
4021
|
+
console.log("Use `$longtable` as the general router; compact installs expose `$longtable-panel` plus the most common role shortcuts.");
|
|
3736
4022
|
for (const skill of installed) {
|
|
3737
4023
|
console.log(`- ${skill.name}`);
|
|
3738
4024
|
}
|
|
@@ -3936,6 +4222,10 @@ async function main() {
|
|
|
3936
4222
|
await runResume(values);
|
|
3937
4223
|
return;
|
|
3938
4224
|
}
|
|
4225
|
+
if (command === "handoff") {
|
|
4226
|
+
await runHandoff(values);
|
|
4227
|
+
return;
|
|
4228
|
+
}
|
|
3939
4229
|
if (command === "doctor" || command === "status") {
|
|
3940
4230
|
await runDoctor(values);
|
|
3941
4231
|
return;
|
|
@@ -3993,6 +4283,25 @@ async function main() {
|
|
|
3993
4283
|
return;
|
|
3994
4284
|
}
|
|
3995
4285
|
if (command === "panel") {
|
|
4286
|
+
if (subcommand === "record") {
|
|
4287
|
+
await runPanelRecordCommand(values);
|
|
4288
|
+
return;
|
|
4289
|
+
}
|
|
4290
|
+
if (subcommand === "status") {
|
|
4291
|
+
await runPanelStatusCommand(values);
|
|
4292
|
+
return;
|
|
4293
|
+
}
|
|
4294
|
+
if (subcommand === "stop") {
|
|
4295
|
+
await runPanelStopCommand(values);
|
|
4296
|
+
return;
|
|
4297
|
+
}
|
|
4298
|
+
if (subcommand === "resume") {
|
|
4299
|
+
await runPanelResumeCommand(values);
|
|
4300
|
+
return;
|
|
4301
|
+
}
|
|
4302
|
+
if (subcommand) {
|
|
4303
|
+
throw new Error(`Unknown panel subcommand: ${subcommand}`);
|
|
4304
|
+
}
|
|
3996
4305
|
await runPanelCommand(values);
|
|
3997
4306
|
return;
|
|
3998
4307
|
}
|
|
@@ -4000,9 +4309,6 @@ async function main() {
|
|
|
4000
4309
|
await runSentinel(values);
|
|
4001
4310
|
return;
|
|
4002
4311
|
}
|
|
4003
|
-
if (command === "team") {
|
|
4004
|
-
throw disabledTeamCommandError();
|
|
4005
|
-
}
|
|
4006
4312
|
if (command === "decide") {
|
|
4007
4313
|
await runDecide(values);
|
|
4008
4314
|
return;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PanelMemberResult, PanelWorkerRun, PanelWorkerRunStatus } from "@longtable/core";
|
|
2
|
+
import type { PanelFallback } from "./panel.js";
|
|
3
|
+
export declare function panelWorkerRunDirectory(workingDirectory: string, runId: string): string;
|
|
4
|
+
export declare function panelWorkerRunPath(workingDirectory: string, runId: string): string;
|
|
5
|
+
export declare function createPanelWorkerRun(options: {
|
|
6
|
+
workingDirectory: string;
|
|
7
|
+
fallback: PanelFallback;
|
|
8
|
+
initialStatus?: PanelWorkerRunStatus;
|
|
9
|
+
diagnostics?: string[];
|
|
10
|
+
}): Promise<PanelWorkerRun>;
|
|
11
|
+
export declare function readPanelWorkerRun(workingDirectory: string, runId: string): Promise<PanelWorkerRun>;
|
|
12
|
+
export declare function writePanelWorkerRun(run: PanelWorkerRun): Promise<void>;
|
|
13
|
+
export declare function launchPanelWorkerRun(run: PanelWorkerRun): Promise<PanelWorkerRun>;
|
|
14
|
+
export declare function refreshPanelWorkerRun(run: PanelWorkerRun): Promise<{
|
|
15
|
+
run: PanelWorkerRun;
|
|
16
|
+
memberResults: PanelMemberResult[];
|
|
17
|
+
}>;
|
|
18
|
+
export declare function requestPanelWorkerStop(run: PanelWorkerRun): Promise<PanelWorkerRun>;
|
|
19
|
+
export declare function resumePanelWorkerRun(run: PanelWorkerRun): Promise<PanelWorkerRun>;
|
|
20
|
+
export declare function waitForPanelWorkerRun(run: PanelWorkerRun, timeoutMs: number): Promise<PanelWorkerRun>;
|