@longtable/cli 0.1.55 → 0.1.57

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 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,13 @@ 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 repair-state [--cwd <path>] [--dry-run] [--json]",
163
+ " 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>]",
164
+ " longtable panel status --run <panel_run_id> [--wait [ms]] [--cwd <path>] [--json]",
165
+ " longtable panel stop --run <panel_run_id> [--cwd <path>] [--json]",
166
+ " longtable panel resume --run <panel_run_id> [--wait [ms]] [--cwd <path>] [--json]",
167
+ " longtable panel record [--invocation <id>] --result-file <json> [--surface sequential_fallback|native_subagents|native_workers] [--cwd <path>] [--json]",
168
+ " longtable handoff [--cwd <path>] [--output <file>] [--print] [--json]",
162
169
  " longtable decide [--question <id>] --answer <value-or-text> [--rationale <text>] [--provider codex|claude] [--cwd <path>] [--json]",
163
170
  " 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
171
  " longtable codex persist-init [--answers-json <json> | --stdin | full setup flags] [--install-skills] [--install-prompts] [--json]",
@@ -194,7 +201,7 @@ function parseArgs(argv) {
194
201
  const values = {};
195
202
  let subcommand = maybeSubcommand;
196
203
  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", "decide", "sentinel", "team", "access", "search", "spec"].includes(command);
204
+ const directCommand = command && ["init", "setup", "start", "resume", "doctor", "status", "audit", "roles", "show", "install", "mcp", "codex", "claude", "ask", "clarify", "question", "clear-question", "repair-state", "prune-questions", "panel", "handoff", "decide", "sentinel", "access", "search", "spec"].includes(command);
198
205
  let startIndex = 1;
199
206
  if (modeCommand) {
200
207
  subcommand = undefined;
@@ -203,7 +210,7 @@ function parseArgs(argv) {
203
210
  else if (command === "codex" || command === "claude" || command === "mcp") {
204
211
  startIndex = 2;
205
212
  }
206
- else if ((command === "access" || command === "search" || command === "spec") && maybeSubcommand && !maybeSubcommand.startsWith("--")) {
213
+ else if ((command === "access" || command === "search" || command === "spec" || command === "panel") && maybeSubcommand && !maybeSubcommand.startsWith("--")) {
207
214
  subcommand = maybeSubcommand;
208
215
  startIndex = 2;
209
216
  }
@@ -1777,6 +1784,10 @@ function renderDoctorStatus(status) {
1777
1784
  if (!status.workspace.found) {
1778
1785
  nextActions.push("longtable start");
1779
1786
  }
1787
+ if ((status.workspace.answerWarnings ?? []).some((warning) => warning.issue.includes("legacy answer shape"))) {
1788
+ const root = status.workspace.rootPath ? ` --cwd "${status.workspace.rootPath}"` : "";
1789
+ nextActions.push(`longtable repair-state${root}`);
1790
+ }
1780
1791
  nextActions.push(...status.hardStop.nextActions);
1781
1792
  const firstQuestion = status.workspace.pendingQuestions?.[0];
1782
1793
  if (firstQuestion && status.hardStop.nextActions.length === 0) {
@@ -2302,6 +2313,132 @@ function parsePanelMode(value) {
2302
2313
  }
2303
2314
  return "review";
2304
2315
  }
2316
+ function requireRunId(args) {
2317
+ if (typeof args.run !== "string" || args.run.trim().length === 0) {
2318
+ throw new Error("A panel run id is required. Pass --run <panel_run_id>.");
2319
+ }
2320
+ return args.run.trim();
2321
+ }
2322
+ function commandAvailable(command) {
2323
+ try {
2324
+ execSync(`command -v ${command}`, { stdio: "ignore" });
2325
+ return true;
2326
+ }
2327
+ catch {
2328
+ return false;
2329
+ }
2330
+ }
2331
+ function parseWaitMs(value) {
2332
+ if (value === undefined || value === false) {
2333
+ return undefined;
2334
+ }
2335
+ if (value === true) {
2336
+ return 30_000;
2337
+ }
2338
+ const trimmed = value.trim();
2339
+ const multiplier = trimmed.endsWith("s") ? 1000 : 1;
2340
+ const numeric = Number.parseInt(trimmed.endsWith("s") ? trimmed.slice(0, -1) : trimmed, 10);
2341
+ if (!Number.isFinite(numeric) || numeric <= 0) {
2342
+ throw new Error(`Invalid --wait value: ${value}. Use milliseconds or a value like 30s.`);
2343
+ }
2344
+ return numeric * multiplier;
2345
+ }
2346
+ function panelWorkerNextCommands(context, runId) {
2347
+ const cwdFlag = `--cwd "${context.project.projectPath}"`;
2348
+ return {
2349
+ status: `longtable panel status ${cwdFlag} --run ${runId}`,
2350
+ stop: `longtable panel stop ${cwdFlag} --run ${runId}`,
2351
+ resume: `longtable panel resume ${cwdFlag} --run ${runId}`
2352
+ };
2353
+ }
2354
+ async function recordTerminalNativeWorkerRun(context, run) {
2355
+ if ((run.status !== "completed" && run.status !== "blocked") || !existsSync(run.aggregateResultPath)) {
2356
+ return null;
2357
+ }
2358
+ const aggregate = JSON.parse(await readFile(run.aggregateResultPath, "utf8"));
2359
+ return recordPanelResultInWorkspace({
2360
+ context,
2361
+ result: {
2362
+ ...aggregate,
2363
+ invocationId: run.invocationId,
2364
+ surface: "native_workers",
2365
+ status: aggregate.status ?? run.status
2366
+ }
2367
+ });
2368
+ }
2369
+ function summarizePanelRecordOutput(result) {
2370
+ if (!result) {
2371
+ return null;
2372
+ }
2373
+ return {
2374
+ invocationId: result.invocation.id,
2375
+ status: result.invocation.status,
2376
+ surface: result.invocation.surface,
2377
+ evidenceRecordIds: result.evidenceRecords.map((record) => record.id)
2378
+ };
2379
+ }
2380
+ async function runPanelStatusCommand(args) {
2381
+ const context = await requireWorkspaceContext(args);
2382
+ const runId = requireRunId(args);
2383
+ const waitMs = parseWaitMs(args.wait);
2384
+ const initial = await refreshPanelWorkerRun(await readPanelWorkerRun(context.project.projectPath, runId));
2385
+ const refreshed = waitMs ? await waitForPanelWorkerRun(initial.run, waitMs) : initial.run;
2386
+ const recordedPanelResult = await recordTerminalNativeWorkerRun(context, refreshed);
2387
+ const nextCommands = panelWorkerNextCommands(context, refreshed.id);
2388
+ if (args.json === true) {
2389
+ console.log(JSON.stringify({ ...refreshed, nextCommands, recordedPanelResult: summarizePanelRecordOutput(recordedPanelResult) }, null, 2));
2390
+ return;
2391
+ }
2392
+ console.log("LongTable panel run status");
2393
+ console.log(`- run: ${refreshed.id}`);
2394
+ console.log(`- status: ${refreshed.status}`);
2395
+ for (const worker of refreshed.workers) {
2396
+ console.log(`- ${worker.label} (${worker.role}): ${worker.status}`);
2397
+ }
2398
+ console.log(`- stop: ${nextCommands.stop}`);
2399
+ console.log(`- resume: ${nextCommands.resume}`);
2400
+ if (recordedPanelResult) {
2401
+ console.log(`- recorded evidence: ${recordedPanelResult.evidenceRecords.length}`);
2402
+ }
2403
+ }
2404
+ async function runPanelStopCommand(args) {
2405
+ const context = await requireWorkspaceContext(args);
2406
+ const runId = requireRunId(args);
2407
+ const stopped = await requestPanelWorkerStop(await readPanelWorkerRun(context.project.projectPath, runId));
2408
+ const nextCommands = panelWorkerNextCommands(context, stopped.id);
2409
+ if (args.json === true) {
2410
+ console.log(JSON.stringify({ ...stopped, nextCommands }, null, 2));
2411
+ return;
2412
+ }
2413
+ console.log("LongTable panel run stop requested");
2414
+ console.log(`- run: ${stopped.id}`);
2415
+ console.log(`- status: ${stopped.status}`);
2416
+ for (const worker of stopped.workers) {
2417
+ console.log(`- ${worker.label} (${worker.role}): ${worker.status}`);
2418
+ }
2419
+ console.log(`- resume: ${nextCommands.resume}`);
2420
+ }
2421
+ async function runPanelResumeCommand(args) {
2422
+ const context = await requireWorkspaceContext(args);
2423
+ const runId = requireRunId(args);
2424
+ const waitMs = parseWaitMs(args.wait);
2425
+ const { run } = await refreshPanelWorkerRun(await readPanelWorkerRun(context.project.projectPath, runId));
2426
+ const resumed = run.status === "completed" ? run : await launchPanelWorkerRun(await resumePanelWorkerRun(run));
2427
+ const finalRun = waitMs ? await waitForPanelWorkerRun(resumed, waitMs) : resumed;
2428
+ const recordedPanelResult = await recordTerminalNativeWorkerRun(context, finalRun);
2429
+ const nextCommands = panelWorkerNextCommands(context, finalRun.id);
2430
+ if (args.json === true) {
2431
+ console.log(JSON.stringify({ ...finalRun, nextCommands, recordedPanelResult: summarizePanelRecordOutput(recordedPanelResult) }, null, 2));
2432
+ return;
2433
+ }
2434
+ console.log("LongTable panel run resume requested");
2435
+ console.log(`- run: ${finalRun.id}`);
2436
+ console.log(`- status: ${finalRun.status}`);
2437
+ console.log(`- status command: ${nextCommands.status}`);
2438
+ if (recordedPanelResult) {
2439
+ console.log(`- recorded evidence: ${recordedPanelResult.evidenceRecords.length}`);
2440
+ }
2441
+ }
2305
2442
  async function loadOptionalSetup(path) {
2306
2443
  try {
2307
2444
  return await loadSetupOutput(path);
@@ -2388,7 +2525,9 @@ async function runPanelCommand(args) {
2388
2525
  await assertWorkspaceNotBlocked(existingContext);
2389
2526
  }
2390
2527
  const projectAware = await buildProjectAwarePrompt(prompt, workingDirectory);
2391
- const provider = setup?.providerSelection.provider;
2528
+ const provider = args.provider === "codex" || args.provider === "claude"
2529
+ ? args.provider
2530
+ : setup?.providerSelection.provider;
2392
2531
  const visibility = parsePanelVisibility(typeof args.visibility === "string" ? args.visibility : undefined) ??
2393
2532
  parsePanelVisibility(setup?.profileSeed.panelPreference) ??
2394
2533
  "always_visible";
@@ -2398,7 +2537,9 @@ async function runPanelCommand(args) {
2398
2537
  mode,
2399
2538
  roleFlag: typeof args.role === "string" ? args.role : undefined,
2400
2539
  provider,
2401
- visibility
2540
+ visibility,
2541
+ nativeSubagents: args["native-subagents"] === true,
2542
+ nativeWorkers: args["native-workers"] === true
2402
2543
  });
2403
2544
  if (projectAware.projectContextFound) {
2404
2545
  const context = await loadProjectContextFromDirectory(workingDirectory);
@@ -2406,6 +2547,30 @@ async function runPanelCommand(args) {
2406
2547
  await appendInvocationRecordToWorkspace(context, fallback.invocationRecord, [fallback.questionRecord]);
2407
2548
  }
2408
2549
  }
2550
+ if (args.print === true) {
2551
+ console.log(fallback.prompt);
2552
+ return;
2553
+ }
2554
+ const waitMs = parseWaitMs(args.wait);
2555
+ const nativeWorkersRequested = args["native-workers"] === true && fallback.plan.preferredSurface === "native_workers";
2556
+ const nativeRunContext = nativeWorkersRequested
2557
+ ? await loadProjectContextFromDirectory(workingDirectory)
2558
+ : null;
2559
+ const nativeRun = nativeWorkersRequested && nativeRunContext
2560
+ ? await launchPanelWorkerRun(await createPanelWorkerRun({
2561
+ workingDirectory: nativeRunContext.project.projectPath,
2562
+ fallback,
2563
+ initialStatus: "planned",
2564
+ diagnostics: [
2565
+ commandAvailable("tmux") ? "tmux:available" : "tmux:unavailable",
2566
+ commandAvailable("codex") ? "codex:available" : "codex:unavailable"
2567
+ ]
2568
+ }))
2569
+ : null;
2570
+ const finalNativeRun = nativeRun && waitMs ? await waitForPanelWorkerRun(nativeRun, waitMs) : nativeRun;
2571
+ const recordedPanelResult = finalNativeRun && nativeRunContext
2572
+ ? await recordTerminalNativeWorkerRun(nativeRunContext, finalNativeRun)
2573
+ : null;
2409
2574
  if (args.json === true) {
2410
2575
  console.log(JSON.stringify({
2411
2576
  intent: fallback.intent,
@@ -2414,22 +2579,51 @@ async function runPanelCommand(args) {
2414
2579
  invocationRecord: fallback.invocationRecord,
2415
2580
  questionRecord: fallback.questionRecord,
2416
2581
  execution: {
2417
- status: "planned",
2582
+ status: finalNativeRun?.status ?? "planned",
2418
2583
  stableSurface: "sequential_fallback",
2419
- nativeParallel: "not_required_for_option_a",
2584
+ preferredSurface: fallback.plan.preferredSurface,
2585
+ nativeParallel: fallback.plan.preferredSurface === "native_workers"
2586
+ ? "longtable_native_workers"
2587
+ : fallback.plan.preferredSurface === "native_subagents"
2588
+ ? "session_dependent"
2589
+ : "not_requested",
2420
2590
  projectContextFound: projectAware.projectContextFound,
2421
- invocationLogged: projectAware.projectContextFound
2591
+ invocationLogged: projectAware.projectContextFound,
2592
+ nativeRunCreated: Boolean(finalNativeRun),
2593
+ waitMs,
2594
+ degradedReason: nativeWorkersRequested && !finalNativeRun
2595
+ ? "native workers require an existing LongTable workspace; sequential fallback prompt returned"
2596
+ : finalNativeRun?.status === "degraded"
2597
+ ? "native workers require local tmux and codex commands; sequential fallback remains available"
2598
+ : undefined
2422
2599
  },
2600
+ nativeRun: finalNativeRun,
2601
+ recordedPanelResult: summarizePanelRecordOutput(recordedPanelResult),
2423
2602
  fallbackPrompt: fallback.prompt
2424
2603
  }, null, 2));
2425
2604
  return;
2426
2605
  }
2427
- if (args.print === true) {
2428
- console.log(fallback.prompt);
2429
- return;
2430
- }
2431
2606
  console.log(renderPanelSummary(fallback.plan));
2432
2607
  console.log("");
2608
+ if (finalNativeRun) {
2609
+ console.log("LongTable native panel worker run created");
2610
+ console.log(`- run: ${finalNativeRun.id}`);
2611
+ console.log(`- status: ${finalNativeRun.status}`);
2612
+ console.log(`- state: ${panelWorkerRunPath(nativeRunContext.project.projectPath, finalNativeRun.id)}`);
2613
+ const nextCommands = panelWorkerNextCommands(nativeRunContext, finalNativeRun.id);
2614
+ console.log(`- next status: ${nextCommands.status}`);
2615
+ console.log(`- stop: ${nextCommands.stop}`);
2616
+ console.log(`- resume: ${nextCommands.resume}`);
2617
+ if (recordedPanelResult) {
2618
+ console.log(`- recorded evidence: ${recordedPanelResult.evidenceRecords.length}`);
2619
+ }
2620
+ if (finalNativeRun.status === "degraded") {
2621
+ console.log("- degraded: native workers are unavailable; use the sequential fallback prompt below.");
2622
+ console.log("");
2623
+ console.log(fallback.prompt);
2624
+ }
2625
+ return;
2626
+ }
2433
2627
  const exitCode = await runCodexThinWrapper({
2434
2628
  prompt: fallback.prompt,
2435
2629
  mode,
@@ -2439,6 +2633,106 @@ async function runPanelCommand(args) {
2439
2633
  });
2440
2634
  exit(exitCode);
2441
2635
  }
2636
+ function parseInvocationSurface(value) {
2637
+ if (value === undefined || value === true) {
2638
+ return undefined;
2639
+ }
2640
+ const allowed = [
2641
+ "native_parallel",
2642
+ "native_subagents",
2643
+ "native_workers",
2644
+ "generated_skill",
2645
+ "prompt_alias",
2646
+ "sequential_fallback",
2647
+ "file_backed_panel_debate",
2648
+ "file_backed_debate",
2649
+ "mcp_transport"
2650
+ ];
2651
+ if (allowed.includes(value)) {
2652
+ return value;
2653
+ }
2654
+ throw new Error(`Invalid panel result surface: ${value}.`);
2655
+ }
2656
+ function parseInvocationStatus(value) {
2657
+ if (value === undefined || value === true) {
2658
+ return undefined;
2659
+ }
2660
+ const allowed = ["planned", "running", "completed", "blocked", "degraded", "error"];
2661
+ if (allowed.includes(value)) {
2662
+ return value;
2663
+ }
2664
+ throw new Error(`Invalid panel result status: ${value}.`);
2665
+ }
2666
+ async function readPanelResultRecordInput(args) {
2667
+ const resultFile = typeof args["result-file"] === "string" ? args["result-file"] : undefined;
2668
+ const baseDirectory = typeof args.cwd === "string" ? args.cwd : cwd();
2669
+ const fromFile = resultFile
2670
+ ? JSON.parse(await readFile(resolve(baseDirectory, resultFile), "utf8"))
2671
+ : {};
2672
+ const result = {
2673
+ ...fromFile,
2674
+ ...(typeof args.invocation === "string" ? { invocationId: args.invocation } : {}),
2675
+ ...(typeof args.synthesis === "string" ? { synthesis: args.synthesis } : {}),
2676
+ ...(typeof args["conflict-summary"] === "string" ? { conflictSummary: args["conflict-summary"] } : {}),
2677
+ ...(typeof args["decision-prompt"] === "string" ? { decisionPrompt: args["decision-prompt"] } : {}),
2678
+ ...(parseInvocationSurface(args.surface) ? { surface: parseInvocationSurface(args.surface) } : {}),
2679
+ ...(parseInvocationStatus(args.status) ? { status: parseInvocationStatus(args.status) } : {})
2680
+ };
2681
+ if (!result.synthesis &&
2682
+ !result.conflictSummary &&
2683
+ !result.decisionPrompt &&
2684
+ (!result.memberResults || result.memberResults.length === 0)) {
2685
+ throw new Error("Panel result content is required. Pass --result-file with synthesis, conflictSummary, decisionPrompt, or memberResults.");
2686
+ }
2687
+ return result;
2688
+ }
2689
+ async function runPanelRecordCommand(args) {
2690
+ const context = await requireWorkspaceContext(args);
2691
+ const resultInput = await readPanelResultRecordInput(args);
2692
+ const result = await recordPanelResultInWorkspace({
2693
+ context,
2694
+ result: resultInput
2695
+ });
2696
+ if (args.json === true) {
2697
+ console.log(JSON.stringify({
2698
+ invocation: result.invocation,
2699
+ evidenceRecords: result.evidenceRecords,
2700
+ files: {
2701
+ state: context.stateFilePath,
2702
+ current: context.currentFilePath
2703
+ }
2704
+ }, null, 2));
2705
+ return;
2706
+ }
2707
+ console.log("LongTable panel result recorded");
2708
+ console.log(`- invocation: ${result.invocation.id}`);
2709
+ console.log(`- status: ${result.invocation.status}`);
2710
+ console.log(`- surface: ${result.invocation.surface}`);
2711
+ console.log(`- evidence records: ${result.evidenceRecords.length}`);
2712
+ console.log(`- unincorporated evidence: longtable spec unincorporated --cwd "${context.project.projectPath}"`);
2713
+ console.log(`- next handoff: longtable handoff --cwd "${context.project.projectPath}"`);
2714
+ }
2715
+ async function runHandoff(args) {
2716
+ const context = await requireWorkspaceContext(args);
2717
+ const result = await createWorkspaceHandoff({
2718
+ context,
2719
+ outputPath: typeof args.output === "string" ? args.output : undefined
2720
+ });
2721
+ if (args.json === true) {
2722
+ console.log(JSON.stringify(result, null, 2));
2723
+ return;
2724
+ }
2725
+ if (args.print === true) {
2726
+ console.log(result.content);
2727
+ return;
2728
+ }
2729
+ console.log("LongTable handoff created");
2730
+ console.log(`- file: ${result.path}`);
2731
+ console.log(`- latest invocation: ${result.latestInvocationId ?? "none"}`);
2732
+ console.log(`- unincorporated evidence: ${result.sourceEvidenceIds.length}`);
2733
+ console.log(`- pending decisions: ${result.pendingQuestionIds.length}`);
2734
+ console.log("Use this handoff directly in Codex/Claude, or paste it into OMX `$ralplan` when OMX is installed.");
2735
+ }
2442
2736
  function parseLimit(value) {
2443
2737
  if (typeof value !== "string") {
2444
2738
  return undefined;
@@ -3142,6 +3436,39 @@ async function runClearQuestion(args) {
3142
3436
  console.log(`- state: ${context.stateFilePath}`);
3143
3437
  console.log(`- current: ${context.currentFilePath}`);
3144
3438
  }
3439
+ async function runRepairState(args) {
3440
+ const workingDirectory = typeof args.cwd === "string" ? args.cwd : cwd();
3441
+ const context = await loadProjectContextFromDirectory(workingDirectory);
3442
+ if (!context) {
3443
+ throw new Error("No LongTable project workspace was found here. Run this inside a project or pass --cwd.");
3444
+ }
3445
+ const result = await repairWorkspaceStateConsistency({
3446
+ context,
3447
+ dryRun: args["dry-run"] === true
3448
+ });
3449
+ if (args.json === true) {
3450
+ console.log(JSON.stringify({
3451
+ dryRun: args["dry-run"] === true,
3452
+ repaired: result.repaired,
3453
+ files: {
3454
+ state: context.stateFilePath,
3455
+ current: context.currentFilePath
3456
+ }
3457
+ }, null, 2));
3458
+ return;
3459
+ }
3460
+ console.log(args["dry-run"] === true ? "LongTable state repair preview" : "LongTable state repaired");
3461
+ if (result.repaired.length === 0) {
3462
+ console.log("- no repairs needed");
3463
+ }
3464
+ else {
3465
+ for (const item of result.repaired) {
3466
+ console.log(`- ${item}`);
3467
+ }
3468
+ }
3469
+ console.log(`- state: ${context.stateFilePath}`);
3470
+ console.log(`- current: ${context.currentFilePath}`);
3471
+ }
3145
3472
  async function runPruneQuestions(args) {
3146
3473
  const workingDirectory = typeof args.cwd === "string" ? args.cwd : cwd();
3147
3474
  const context = await loadProjectContextFromDirectory(workingDirectory);
@@ -3555,9 +3882,6 @@ async function runPanelDebateCommand(args) {
3555
3882
  console.log(`- rounds: ${debate.run.roundCount}`);
3556
3883
  console.log(`- checkpoint: ${debate.questionRecord.id}`);
3557
3884
  }
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
3885
  async function runDecide(args) {
3562
3886
  const workingDirectory = typeof args.cwd === "string" ? args.cwd : cwd();
3563
3887
  const answer = typeof args.answer === "string" ? args.answer.trim() : "";
@@ -3732,7 +4056,7 @@ async function runCodexSubcommand(subcommand, args) {
3732
4056
  const installed = await installCodexSkills(roles, customDir, skillSurface);
3733
4057
  console.log(`Installed ${installed.length} LongTable Codex skills in ${resolveCodexSkillsDir(customDir)} (${skillSurface} surface)`);
3734
4058
  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 only the most common role shortcuts.");
4059
+ console.log("Use `$longtable` as the general router; compact installs expose `$longtable-panel` plus the most common role shortcuts.");
3736
4060
  for (const skill of installed) {
3737
4061
  console.log(`- ${skill.name}`);
3738
4062
  }
@@ -3936,6 +4260,10 @@ async function main() {
3936
4260
  await runResume(values);
3937
4261
  return;
3938
4262
  }
4263
+ if (command === "handoff") {
4264
+ await runHandoff(values);
4265
+ return;
4266
+ }
3939
4267
  if (command === "doctor" || command === "status") {
3940
4268
  await runDoctor(values);
3941
4269
  return;
@@ -3988,11 +4316,34 @@ async function main() {
3988
4316
  await runClearQuestion(values);
3989
4317
  return;
3990
4318
  }
4319
+ if (command === "repair-state") {
4320
+ await runRepairState(values);
4321
+ return;
4322
+ }
3991
4323
  if (command === "prune-questions") {
3992
4324
  await runPruneQuestions(values);
3993
4325
  return;
3994
4326
  }
3995
4327
  if (command === "panel") {
4328
+ if (subcommand === "record") {
4329
+ await runPanelRecordCommand(values);
4330
+ return;
4331
+ }
4332
+ if (subcommand === "status") {
4333
+ await runPanelStatusCommand(values);
4334
+ return;
4335
+ }
4336
+ if (subcommand === "stop") {
4337
+ await runPanelStopCommand(values);
4338
+ return;
4339
+ }
4340
+ if (subcommand === "resume") {
4341
+ await runPanelResumeCommand(values);
4342
+ return;
4343
+ }
4344
+ if (subcommand) {
4345
+ throw new Error(`Unknown panel subcommand: ${subcommand}`);
4346
+ }
3996
4347
  await runPanelCommand(values);
3997
4348
  return;
3998
4349
  }
@@ -4000,9 +4351,6 @@ async function main() {
4000
4351
  await runSentinel(values);
4001
4352
  return;
4002
4353
  }
4003
- if (command === "team") {
4004
- throw disabledTeamCommandError();
4005
- }
4006
4354
  if (command === "decide") {
4007
4355
  await runDecide(values);
4008
4356
  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>;