@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 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", "decide", "sentinel", "team", "access", "search", "spec"].includes(command);
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 = setup?.providerSelection.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
- nativeParallel: "not_required_for_option_a",
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 only the most common role shortcuts.");
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>;