@longtable/cli 0.1.9 → 0.1.10
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 +82 -1
- package/dist/cli.js +673 -32
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/panel.d.ts +40 -0
- package/dist/panel.js +268 -0
- package/dist/personas.d.ts +5 -0
- package/dist/personas.js +44 -8
- package/dist/project-session.d.ts +81 -0
- package/dist/project-session.js +364 -3
- package/dist/prompt-aliases.js +3 -3
- package/package.json +7 -4
package/dist/cli.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
3
3
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
4
|
+
import { execSync } from "node:child_process";
|
|
4
5
|
import { emitKeypressEvents } from "node:readline";
|
|
5
6
|
import { createInterface } from "node:readline/promises";
|
|
6
7
|
import { stdin as input, stdout as output, cwd, exit } from "node:process";
|
|
7
8
|
import { dirname, resolve } from "node:path";
|
|
8
9
|
import { homedir } from "node:os";
|
|
9
|
-
import { buildProviderChoices, buildQuickSetupFlow, createPersistedSetupOutput, installRuntimeConfigFromStoredSetup, loadSetupOutput, renderInstallSummary, renderSetupSummary, resolveDefaultRuntimeConfigPath, resolveDefaultSetupPath, saveSetupAndRuntimeConfig, serializeSetupOutput } from "@longtable/setup";
|
|
10
|
-
import { buildCodexThinWrappedPrompt, runCodexThinWrapper } from "@longtable/provider-codex";
|
|
10
|
+
import { buildProviderChoices, buildQuickSetupFlow, createPersistedSetupOutput, installRuntimeConfigFromStoredSetup, loadSetupOutput, renderInstallSummary, renderSetupSummary, resolveDefaultRuntimeConfigPath, resolveDefaultSetupPath, saveSetupAndRuntimeConfig, serializeSetupOutput, writeRuntimeConfig } from "@longtable/setup";
|
|
11
|
+
import { buildCodexSkillSpecs, buildCodexThinWrappedPrompt, installCodexSkills, listInstalledCodexSkills, renderQuestionRecordPrompt, removeCodexSkills, resolveCodexSkillsDir, runCodexThinWrapper } from "@longtable/provider-codex";
|
|
12
|
+
import { buildClaudeSkillSpecs, installClaudeSkills, listInstalledClaudeSkills, renderQuestionRecordInput, removeClaudeSkills, resolveClaudeSkillsDir } from "@longtable/provider-claude";
|
|
11
13
|
import { installCodexPromptAliases, listInstalledCodexPromptAliases, removeCodexPromptAliases, resolveCodexPromptsDir } from "./prompt-aliases.js";
|
|
12
14
|
import { buildPersonaGuidance, parseInvocationDirective } from "./persona-router.js";
|
|
13
|
-
import { PERSONA_DEFINITIONS } from "./personas.js";
|
|
14
|
-
import {
|
|
15
|
+
import { PERSONA_DEFINITIONS, listRoleDefinitions } from "./personas.js";
|
|
16
|
+
import { buildPanelFallback, renderPanelSummary } from "./panel.js";
|
|
17
|
+
import { appendInvocationRecordToWorkspace, assertWorkspaceNotBlocked, answerWorkspaceQuestion, createWorkspaceQuestion, createOrUpdateProjectWorkspace, inspectProjectWorkspace, loadProjectContextFromDirectory, renderProjectWorkspaceSummary, syncCurrentWorkspaceView } from "./project-session.js";
|
|
15
18
|
const VALID_MODES = new Set([
|
|
16
19
|
"explore",
|
|
17
20
|
"review",
|
|
@@ -69,28 +72,40 @@ function usage() {
|
|
|
69
72
|
" Run `longtable ...` in your terminal, not inside the Codex chat box.",
|
|
70
73
|
" After `longtable start`, move into the created project directory and open `codex` there.",
|
|
71
74
|
"",
|
|
72
|
-
" longtable init [--flow quickstart|interview] [--provider codex|claude] [--field <field>] [--career-stage <stage>] [--experience novice|intermediate|advanced] [--checkpoint low|balanced|high] [--authorship-signal <text>] [--entry-mode explore|review|critique|draft|commit] [--weakest-domain theory|methodology|measurement|analysis|writing] [--panel-preference synthesis_only|show_on_conflict|always_visible] [--json] [--no-install] [--install-prompts]",
|
|
75
|
+
" longtable init [--flow quickstart|interview] [--provider codex|claude] [--field <field>] [--career-stage <stage>] [--experience novice|intermediate|advanced] [--checkpoint low|balanced|high] [--authorship-signal <text>] [--entry-mode explore|review|critique|draft|commit] [--weakest-domain theory|methodology|measurement|analysis|writing] [--panel-preference synthesis_only|show_on_conflict|always_visible] [--json] [--no-install] [--install-skills] [--install-prompts]",
|
|
73
76
|
" longtable start [--path <dir>] [--name <project>] [--goal <text>] [--blocker <text>] [--perspectives <role[,role]>] [--disagreement synthesis_only|show_on_conflict|always_visible] [--setup <path>] [--json]",
|
|
74
77
|
" longtable resume [--cwd <path>] [--json]",
|
|
78
|
+
" longtable doctor [--cwd <path>] [--fix] [--json] [--codex-dir <path>] [--claude-dir <path>] [--codex-prompts-dir <path>] [--codex-runtime-path <file>] [--claude-runtime-path <file>]",
|
|
79
|
+
" longtable status [--cwd <path>] [--fix] [--json] [--codex-dir <path>] [--claude-dir <path>] [--codex-prompts-dir <path>] [--codex-runtime-path <file>] [--claude-runtime-path <file>]",
|
|
75
80
|
" longtable roles [--json]",
|
|
76
81
|
" longtable show [--json] [--path <file>]",
|
|
77
82
|
" longtable install [--json] [--path <file>] [--runtime-path <file>]",
|
|
78
83
|
" longtable ask [--prompt <text>] [--print] [--json] [--setup <path>] [--cwd <path>]",
|
|
84
|
+
" longtable question --prompt <decision-context> [--title <text>] [--text <question>] [--provider codex|claude] [--required|--advisory] [--print] [--cwd <path>] [--json]",
|
|
85
|
+
" 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>]",
|
|
86
|
+
" longtable decide [--question <id>] --answer <value-or-text> [--rationale <text>] [--provider codex|claude] [--cwd <path>] [--json]",
|
|
79
87
|
" 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>]",
|
|
80
|
-
" longtable codex persist-init [--answers-json <json> | --stdin | full setup flags] [--install-prompts] [--json]",
|
|
88
|
+
" longtable codex persist-init [--answers-json <json> | --stdin | full setup flags] [--install-skills] [--install-prompts] [--json]",
|
|
89
|
+
" longtable codex install-skills [--dir <path>]",
|
|
90
|
+
" longtable codex remove-skills [--dir <path>]",
|
|
81
91
|
" longtable codex install-prompts [--dir <path>]",
|
|
82
92
|
" longtable codex remove-prompts [--dir <path>]",
|
|
83
93
|
" longtable codex status [--dir <path>] [--json]",
|
|
94
|
+
" longtable claude install-skills [--dir <path>]",
|
|
95
|
+
" longtable claude remove-skills [--dir <path>]",
|
|
96
|
+
" longtable claude status [--dir <path>] [--json]",
|
|
84
97
|
"",
|
|
85
98
|
"Examples:",
|
|
86
|
-
" longtable init --flow interview --install-
|
|
99
|
+
" longtable init --flow interview --provider codex --install-skills",
|
|
87
100
|
" longtable start",
|
|
88
101
|
" longtable start --path ~/Research/My-Project --name \"AI Adoption Meta-Analysis\" --goal \"Narrow the review question\"",
|
|
89
102
|
" cd \"<project-path>\" && codex",
|
|
103
|
+
" longtable doctor",
|
|
90
104
|
" longtable roles",
|
|
91
105
|
" longtable ask --prompt \"연구를 시작하고 싶어. 지금 어디서부터 좁혀야 할지 모르겠어.\"",
|
|
92
|
-
" printf '{\"provider\":\"codex\",...}' | longtable codex persist-init --stdin --install-
|
|
93
|
-
" longtable codex install-
|
|
106
|
+
" printf '{\"provider\":\"codex\",...}' | longtable codex persist-init --stdin --install-skills",
|
|
107
|
+
" longtable codex install-skills",
|
|
108
|
+
" longtable claude install-skills"
|
|
94
109
|
].join("\n");
|
|
95
110
|
}
|
|
96
111
|
function parseArgs(argv) {
|
|
@@ -98,13 +113,13 @@ function parseArgs(argv) {
|
|
|
98
113
|
const values = {};
|
|
99
114
|
let subcommand = maybeSubcommand;
|
|
100
115
|
const modeCommand = command && VALID_MODES.has(command);
|
|
101
|
-
const directCommand = command && ["init", "start", "resume", "roles", "show", "install", "codex", "ask"].includes(command);
|
|
116
|
+
const directCommand = command && ["init", "start", "resume", "doctor", "status", "roles", "show", "install", "codex", "claude", "ask", "question", "panel", "decide"].includes(command);
|
|
102
117
|
let startIndex = 1;
|
|
103
118
|
if (modeCommand) {
|
|
104
119
|
subcommand = undefined;
|
|
105
120
|
startIndex = 1;
|
|
106
121
|
}
|
|
107
|
-
else if (command === "codex") {
|
|
122
|
+
else if (command === "codex" || command === "claude") {
|
|
108
123
|
startIndex = 2;
|
|
109
124
|
}
|
|
110
125
|
else if (directCommand) {
|
|
@@ -667,9 +682,11 @@ async function runInit(args) {
|
|
|
667
682
|
const json = args.json === true;
|
|
668
683
|
const installRuntime = args["no-install"] !== true;
|
|
669
684
|
const installPrompts = args["install-prompts"] === true;
|
|
685
|
+
const installSkills = args["install-skills"] === true;
|
|
670
686
|
const customPath = typeof args.path === "string" ? args.path : undefined;
|
|
671
687
|
const runtimePath = typeof args["runtime-path"] === "string" ? args["runtime-path"] : undefined;
|
|
672
688
|
const promptsDir = typeof args.dir === "string" ? args.dir : undefined;
|
|
689
|
+
const skillsDir = typeof args["skills-dir"] === "string" ? args["skills-dir"] : promptsDir;
|
|
673
690
|
const { flow, provider, answers } = hasCompleteFlagInput(args)
|
|
674
691
|
? {
|
|
675
692
|
flow: resolveSetupFlow(args),
|
|
@@ -686,8 +703,23 @@ async function runInit(args) {
|
|
|
686
703
|
if (provider === "codex" && installPrompts) {
|
|
687
704
|
installedPrompts = await installCodexPromptAliases(promptsDir);
|
|
688
705
|
}
|
|
706
|
+
let installedSkills = [];
|
|
707
|
+
if (provider === "codex" && installSkills) {
|
|
708
|
+
installedSkills = await installCodexSkills(listRoleDefinitions(), skillsDir);
|
|
709
|
+
}
|
|
710
|
+
if (provider === "claude" && installSkills) {
|
|
711
|
+
installedSkills = await installClaudeSkills(listRoleDefinitions(), skillsDir);
|
|
712
|
+
}
|
|
689
713
|
if (json) {
|
|
690
|
-
|
|
714
|
+
if (installedPrompts.length === 0 && installedSkills.length === 0) {
|
|
715
|
+
console.log(serializeSetupOutput(outputValue));
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
console.log(JSON.stringify({
|
|
719
|
+
setup: outputValue,
|
|
720
|
+
installedPrompts: installedPrompts.map((prompt) => prompt.name),
|
|
721
|
+
installedSkills: installedSkills.map((skill) => skill.name)
|
|
722
|
+
}, null, 2));
|
|
691
723
|
return;
|
|
692
724
|
}
|
|
693
725
|
console.log(renderSetupSummary(outputValue));
|
|
@@ -699,18 +731,33 @@ async function runInit(args) {
|
|
|
699
731
|
console.log("");
|
|
700
732
|
console.log("Installed Codex prompt files:");
|
|
701
733
|
for (const prompt of installedPrompts) {
|
|
702
|
-
console.log(`-
|
|
734
|
+
console.log(`- ${prompt.name}`);
|
|
735
|
+
}
|
|
736
|
+
console.log(" Note: prompt files are legacy and may not be exposed by your Codex build.");
|
|
737
|
+
}
|
|
738
|
+
if (installedSkills.length > 0) {
|
|
739
|
+
console.log("");
|
|
740
|
+
console.log(`Installed ${provider === "codex" ? "Codex" : "Claude"} skill files:`);
|
|
741
|
+
for (const skill of installedSkills) {
|
|
742
|
+
console.log(`- ${skill.name}`);
|
|
703
743
|
}
|
|
704
|
-
console.log("
|
|
744
|
+
console.log(" Use these by naming LongTable naturally, e.g. `lt panel: ...`.");
|
|
705
745
|
}
|
|
706
746
|
if (provider === "codex") {
|
|
707
747
|
console.log("");
|
|
708
748
|
console.log("Next step:");
|
|
709
749
|
console.log("- Start here: `longtable start`.");
|
|
710
750
|
console.log("- If you want a direct natural-language entry: `longtable ask --prompt \"...\"`.");
|
|
711
|
-
console.log("- Codex
|
|
751
|
+
console.log("- Codex skills are the preferred native surface. Prompt files are legacy and may not expose slash commands.");
|
|
712
752
|
console.log("- Suggested next action: create a project workspace and let LongTable interview the current session.");
|
|
713
753
|
}
|
|
754
|
+
if (provider === "claude") {
|
|
755
|
+
console.log("");
|
|
756
|
+
console.log("Next step:");
|
|
757
|
+
console.log("- Start here: `longtable start`.");
|
|
758
|
+
console.log("- In Claude Code, use natural language such as `lt explore: ...` or `lt panel: ...`.");
|
|
759
|
+
console.log("- Claude skills are adapter output from LongTable roles, not the source of truth.");
|
|
760
|
+
}
|
|
714
761
|
}
|
|
715
762
|
async function runShow(args) {
|
|
716
763
|
const outputValue = await loadSetupOutput(typeof args.path === "string" ? args.path : undefined);
|
|
@@ -731,6 +778,300 @@ async function runInstall(args) {
|
|
|
731
778
|
}
|
|
732
779
|
console.log(renderInstallSummary(result));
|
|
733
780
|
}
|
|
781
|
+
function commandOnPath(command) {
|
|
782
|
+
try {
|
|
783
|
+
execSync(`command -v ${command}`, { stdio: "ignore" });
|
|
784
|
+
return true;
|
|
785
|
+
}
|
|
786
|
+
catch {
|
|
787
|
+
return false;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
function missingNames(expected, installed) {
|
|
791
|
+
const installedSet = new Set(installed);
|
|
792
|
+
return expected.filter((name) => !installedSet.has(name));
|
|
793
|
+
}
|
|
794
|
+
function setupForProvider(setup, provider) {
|
|
795
|
+
return {
|
|
796
|
+
...setup,
|
|
797
|
+
providerSelection: provider === "claude"
|
|
798
|
+
? {
|
|
799
|
+
provider,
|
|
800
|
+
checkpointProtocol: "native_structured",
|
|
801
|
+
supportsStructuredQuestions: true
|
|
802
|
+
}
|
|
803
|
+
: {
|
|
804
|
+
provider,
|
|
805
|
+
checkpointProtocol: "numbered",
|
|
806
|
+
supportsStructuredQuestions: false
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
async function collectDoctorStatus(args) {
|
|
811
|
+
const roles = listRoleDefinitions();
|
|
812
|
+
const setupOverride = typeof args.setup === "string"
|
|
813
|
+
? args.setup
|
|
814
|
+
: typeof args.path === "string"
|
|
815
|
+
? args.path
|
|
816
|
+
: undefined;
|
|
817
|
+
const setupPath = resolveDefaultSetupPath(setupOverride).path;
|
|
818
|
+
const codexRuntimeOverride = typeof args["codex-runtime-path"] === "string"
|
|
819
|
+
? args["codex-runtime-path"]
|
|
820
|
+
: undefined;
|
|
821
|
+
const claudeRuntimeOverride = typeof args["claude-runtime-path"] === "string"
|
|
822
|
+
? args["claude-runtime-path"]
|
|
823
|
+
: undefined;
|
|
824
|
+
const codexDir = typeof args["codex-dir"] === "string"
|
|
825
|
+
? args["codex-dir"]
|
|
826
|
+
: typeof args.dir === "string"
|
|
827
|
+
? args.dir
|
|
828
|
+
: undefined;
|
|
829
|
+
const codexPromptsDir = typeof args["codex-prompts-dir"] === "string"
|
|
830
|
+
? args["codex-prompts-dir"]
|
|
831
|
+
: typeof args["prompts-dir"] === "string"
|
|
832
|
+
? args["prompts-dir"]
|
|
833
|
+
: typeof args.dir === "string"
|
|
834
|
+
? args.dir
|
|
835
|
+
: undefined;
|
|
836
|
+
const claudeDir = typeof args["claude-dir"] === "string"
|
|
837
|
+
? args["claude-dir"]
|
|
838
|
+
: typeof args.dir === "string"
|
|
839
|
+
? args.dir
|
|
840
|
+
: undefined;
|
|
841
|
+
const codexRuntimePath = resolveDefaultRuntimeConfigPath("codex", codexRuntimeOverride).path;
|
|
842
|
+
const claudeRuntimePath = resolveDefaultRuntimeConfigPath("claude", claudeRuntimeOverride).path;
|
|
843
|
+
const expectedCodexSkills = buildCodexSkillSpecs(roles).map((skill) => skill.name);
|
|
844
|
+
const expectedClaudeSkills = buildClaudeSkillSpecs(roles).map((skill) => skill.name);
|
|
845
|
+
const [codexSkills, claudeSkills, codexAliases, workspace] = await Promise.all([
|
|
846
|
+
listInstalledCodexSkills(roles, codexDir),
|
|
847
|
+
listInstalledClaudeSkills(roles, claudeDir),
|
|
848
|
+
listInstalledCodexPromptAliases(codexPromptsDir),
|
|
849
|
+
inspectProjectWorkspace(typeof args.cwd === "string" ? args.cwd : cwd())
|
|
850
|
+
]);
|
|
851
|
+
const installedCodexSkills = codexSkills.map((skill) => skill.name);
|
|
852
|
+
const installedClaudeSkills = claudeSkills.map((skill) => skill.name);
|
|
853
|
+
return {
|
|
854
|
+
setupPath,
|
|
855
|
+
setupExists: existsSync(setupPath),
|
|
856
|
+
providers: {
|
|
857
|
+
codex: {
|
|
858
|
+
command: "codex",
|
|
859
|
+
commandOnPath: commandOnPath("codex"),
|
|
860
|
+
runtimePath: codexRuntimePath,
|
|
861
|
+
runtimeExists: existsSync(codexRuntimePath),
|
|
862
|
+
skillsDir: resolveCodexSkillsDir(codexDir),
|
|
863
|
+
expectedSkills: expectedCodexSkills,
|
|
864
|
+
installedSkills: installedCodexSkills,
|
|
865
|
+
missingSkills: missingNames(expectedCodexSkills, installedCodexSkills),
|
|
866
|
+
promptsDir: resolveCodexPromptsDir(codexPromptsDir),
|
|
867
|
+
legacyPromptFilesInstalled: codexAliases.map((alias) => alias.name)
|
|
868
|
+
},
|
|
869
|
+
claude: {
|
|
870
|
+
command: "claude",
|
|
871
|
+
commandOnPath: commandOnPath("claude"),
|
|
872
|
+
runtimePath: claudeRuntimePath,
|
|
873
|
+
runtimeExists: existsSync(claudeRuntimePath),
|
|
874
|
+
skillsDir: resolveClaudeSkillsDir(claudeDir),
|
|
875
|
+
expectedSkills: expectedClaudeSkills,
|
|
876
|
+
installedSkills: installedClaudeSkills,
|
|
877
|
+
missingSkills: missingNames(expectedClaudeSkills, installedClaudeSkills)
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
workspace
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
function renderProviderDoctorBlock(label, provider) {
|
|
884
|
+
const expectedCount = provider.expectedSkills.length;
|
|
885
|
+
const installedCount = provider.installedSkills.length;
|
|
886
|
+
return [
|
|
887
|
+
`${label}:`,
|
|
888
|
+
`- command: ${provider.commandOnPath ? "present" : "missing"} (${provider.command})`,
|
|
889
|
+
`- runtime artifact: ${provider.runtimeExists ? "present" : "missing"} (${provider.runtimePath})`,
|
|
890
|
+
`- skills: ${installedCount}/${expectedCount} installed (${provider.skillsDir})`,
|
|
891
|
+
...(provider.missingSkills.length > 0
|
|
892
|
+
? [`- missing skills: ${provider.missingSkills.join(", ")}`]
|
|
893
|
+
: ["- missing skills: none"])
|
|
894
|
+
];
|
|
895
|
+
}
|
|
896
|
+
function renderDoctorStatus(status) {
|
|
897
|
+
const lines = [
|
|
898
|
+
"LongTable doctor",
|
|
899
|
+
`- setup: ${status.setupExists ? "present" : "missing"} (${status.setupPath})`,
|
|
900
|
+
"",
|
|
901
|
+
...renderProviderDoctorBlock("Codex", status.providers.codex),
|
|
902
|
+
`- legacy prompt files: ${status.providers.codex.legacyPromptFilesInstalled.length}`,
|
|
903
|
+
...(status.providers.codex.legacyPromptFilesInstalled.length > 0
|
|
904
|
+
? [`- legacy prompt names: ${status.providers.codex.legacyPromptFilesInstalled.join(", ")}`]
|
|
905
|
+
: []),
|
|
906
|
+
"",
|
|
907
|
+
...renderProviderDoctorBlock("Claude", status.providers.claude),
|
|
908
|
+
"",
|
|
909
|
+
"Workspace:"
|
|
910
|
+
];
|
|
911
|
+
if (!status.workspace.found) {
|
|
912
|
+
lines.push("- project: not found from current directory");
|
|
913
|
+
}
|
|
914
|
+
else {
|
|
915
|
+
const workspace = status.workspace;
|
|
916
|
+
lines.push(`- project: ${workspace.project?.name ?? "unknown"}`, `- root: ${workspace.rootPath ?? "unknown"}`, `- goal: ${workspace.session?.currentGoal ?? "unknown"}`, `- invocations: ${workspace.counts?.invocations ?? 0}`, `- questions: ${workspace.counts?.questions ?? 0} (${workspace.counts?.pendingQuestions ?? 0} pending, ${workspace.counts?.answeredQuestions ?? 0} answered)`, `- decisions: ${workspace.counts?.decisions ?? 0}`);
|
|
917
|
+
if ((workspace.recentInvocations ?? []).length > 0) {
|
|
918
|
+
lines.push("- recent invocations:");
|
|
919
|
+
for (const invocation of workspace.recentInvocations ?? []) {
|
|
920
|
+
const roles = invocation.roles.length > 0 ? invocation.roles.join(",") : "auto";
|
|
921
|
+
lines.push(` - ${invocation.kind}/${invocation.mode} via ${invocation.surface}: ${roles} (${invocation.status})`);
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
if ((workspace.pendingQuestions ?? []).length > 0) {
|
|
925
|
+
lines.push("- pending questions:");
|
|
926
|
+
for (const question of workspace.pendingQuestions ?? []) {
|
|
927
|
+
lines.push(` - ${question.id}: ${question.question} (${question.options.join("/")})`);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
const nextActions = [];
|
|
932
|
+
const canFix = status.providers.codex.missingSkills.length > 0 ||
|
|
933
|
+
status.providers.claude.missingSkills.length > 0 ||
|
|
934
|
+
status.providers.codex.legacyPromptFilesInstalled.length > 0 ||
|
|
935
|
+
(status.setupExists &&
|
|
936
|
+
(!status.providers.codex.runtimeExists || !status.providers.claude.runtimeExists));
|
|
937
|
+
if (canFix) {
|
|
938
|
+
nextActions.push("longtable doctor --fix");
|
|
939
|
+
}
|
|
940
|
+
if (!status.setupExists) {
|
|
941
|
+
nextActions.push("longtable init --flow interview --provider codex --install-skills");
|
|
942
|
+
}
|
|
943
|
+
if (!status.workspace.found) {
|
|
944
|
+
nextActions.push("longtable start");
|
|
945
|
+
}
|
|
946
|
+
const firstQuestion = status.workspace.pendingQuestions?.[0];
|
|
947
|
+
if (firstQuestion) {
|
|
948
|
+
nextActions.push(`longtable decide --question ${firstQuestion.id} --answer <value>`);
|
|
949
|
+
}
|
|
950
|
+
if (nextActions.length > 0) {
|
|
951
|
+
lines.push("", "Next actions:");
|
|
952
|
+
for (const action of nextActions) {
|
|
953
|
+
lines.push(`- ${action}`);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
return lines.join("\n");
|
|
957
|
+
}
|
|
958
|
+
function renderRepairSummary(repair) {
|
|
959
|
+
const lines = ["LongTable doctor repair"];
|
|
960
|
+
if (repair.installedCodexSkills.length > 0) {
|
|
961
|
+
lines.push(`- installed Codex skills: ${repair.installedCodexSkills.length}`);
|
|
962
|
+
}
|
|
963
|
+
if (repair.installedClaudeSkills.length > 0) {
|
|
964
|
+
lines.push(`- installed Claude skills: ${repair.installedClaudeSkills.length}`);
|
|
965
|
+
}
|
|
966
|
+
if (repair.removedLegacyPromptFiles.length > 0) {
|
|
967
|
+
lines.push(`- removed legacy prompt files: ${repair.removedLegacyPromptFiles.length}`);
|
|
968
|
+
}
|
|
969
|
+
if (repair.writtenRuntimeConfigs.length > 0) {
|
|
970
|
+
lines.push("- wrote runtime configs:");
|
|
971
|
+
for (const target of repair.writtenRuntimeConfigs) {
|
|
972
|
+
lines.push(` - ${target.provider}: ${target.path}`);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
if (repair.skipped.length > 0) {
|
|
976
|
+
lines.push("- skipped:");
|
|
977
|
+
for (const item of repair.skipped) {
|
|
978
|
+
lines.push(` - ${item}`);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
if (lines.length === 1) {
|
|
982
|
+
lines.push("- no repairs needed");
|
|
983
|
+
}
|
|
984
|
+
return lines.join("\n");
|
|
985
|
+
}
|
|
986
|
+
async function repairDoctorStatus(args, status) {
|
|
987
|
+
const roles = listRoleDefinitions();
|
|
988
|
+
const codexDir = typeof args["codex-dir"] === "string"
|
|
989
|
+
? args["codex-dir"]
|
|
990
|
+
: typeof args.dir === "string"
|
|
991
|
+
? args.dir
|
|
992
|
+
: undefined;
|
|
993
|
+
const codexPromptsDir = typeof args["codex-prompts-dir"] === "string"
|
|
994
|
+
? args["codex-prompts-dir"]
|
|
995
|
+
: typeof args["prompts-dir"] === "string"
|
|
996
|
+
? args["prompts-dir"]
|
|
997
|
+
: typeof args.dir === "string"
|
|
998
|
+
? args.dir
|
|
999
|
+
: undefined;
|
|
1000
|
+
const claudeDir = typeof args["claude-dir"] === "string"
|
|
1001
|
+
? args["claude-dir"]
|
|
1002
|
+
: typeof args.dir === "string"
|
|
1003
|
+
? args.dir
|
|
1004
|
+
: undefined;
|
|
1005
|
+
const setupOverride = typeof args.setup === "string"
|
|
1006
|
+
? args.setup
|
|
1007
|
+
: typeof args.path === "string"
|
|
1008
|
+
? args.path
|
|
1009
|
+
: undefined;
|
|
1010
|
+
const codexRuntimeOverride = typeof args["codex-runtime-path"] === "string"
|
|
1011
|
+
? args["codex-runtime-path"]
|
|
1012
|
+
: undefined;
|
|
1013
|
+
const claudeRuntimeOverride = typeof args["claude-runtime-path"] === "string"
|
|
1014
|
+
? args["claude-runtime-path"]
|
|
1015
|
+
: undefined;
|
|
1016
|
+
const repair = {
|
|
1017
|
+
installedCodexSkills: [],
|
|
1018
|
+
installedClaudeSkills: [],
|
|
1019
|
+
removedLegacyPromptFiles: [],
|
|
1020
|
+
writtenRuntimeConfigs: [],
|
|
1021
|
+
skipped: []
|
|
1022
|
+
};
|
|
1023
|
+
if (status.providers.codex.missingSkills.length > 0) {
|
|
1024
|
+
repair.installedCodexSkills = (await installCodexSkills(roles, codexDir)).map((skill) => skill.name);
|
|
1025
|
+
}
|
|
1026
|
+
if (status.providers.claude.missingSkills.length > 0) {
|
|
1027
|
+
repair.installedClaudeSkills = (await installClaudeSkills(roles, claudeDir)).map((skill) => skill.name);
|
|
1028
|
+
}
|
|
1029
|
+
if (status.providers.codex.legacyPromptFilesInstalled.length > 0) {
|
|
1030
|
+
repair.removedLegacyPromptFiles = await removeCodexPromptAliases(codexPromptsDir);
|
|
1031
|
+
}
|
|
1032
|
+
if (!status.setupExists) {
|
|
1033
|
+
repair.skipped.push("runtime configs require a researcher setup; run `longtable init --flow interview --provider codex` first");
|
|
1034
|
+
return repair;
|
|
1035
|
+
}
|
|
1036
|
+
const setup = await loadSetupOutput(setupOverride);
|
|
1037
|
+
if (!status.providers.codex.runtimeExists) {
|
|
1038
|
+
const target = await writeRuntimeConfig(setupForProvider(setup, "codex"), status.setupPath, codexRuntimeOverride);
|
|
1039
|
+
repair.writtenRuntimeConfigs.push({
|
|
1040
|
+
provider: target.provider,
|
|
1041
|
+
path: target.path,
|
|
1042
|
+
format: target.format
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
if (!status.providers.claude.runtimeExists) {
|
|
1046
|
+
const target = await writeRuntimeConfig(setupForProvider(setup, "claude"), status.setupPath, claudeRuntimeOverride);
|
|
1047
|
+
repair.writtenRuntimeConfigs.push({
|
|
1048
|
+
provider: target.provider,
|
|
1049
|
+
path: target.path,
|
|
1050
|
+
format: target.format
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
return repair;
|
|
1054
|
+
}
|
|
1055
|
+
async function runDoctor(args) {
|
|
1056
|
+
const status = await collectDoctorStatus(args);
|
|
1057
|
+
if (args.fix === true) {
|
|
1058
|
+
const repair = await repairDoctorStatus(args, status);
|
|
1059
|
+
const updatedStatus = await collectDoctorStatus(args);
|
|
1060
|
+
if (args.json === true) {
|
|
1061
|
+
console.log(JSON.stringify({ repair, status: updatedStatus }, null, 2));
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
console.log(renderRepairSummary(repair));
|
|
1065
|
+
console.log("");
|
|
1066
|
+
console.log(renderDoctorStatus(updatedStatus));
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
if (args.json === true) {
|
|
1070
|
+
console.log(JSON.stringify(status, null, 2));
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1073
|
+
console.log(renderDoctorStatus(status));
|
|
1074
|
+
}
|
|
734
1075
|
async function runCodexPersistInit(args) {
|
|
735
1076
|
const { flow, provider, answers } = await readPersistAnswers(args);
|
|
736
1077
|
const outputValue = createPersistedSetupOutput(answers, provider, flow);
|
|
@@ -742,11 +1083,16 @@ async function runCodexPersistInit(args) {
|
|
|
742
1083
|
if (provider === "codex" && args["install-prompts"] === true) {
|
|
743
1084
|
installedPrompts = await installCodexPromptAliases(typeof args.dir === "string" ? args.dir : undefined);
|
|
744
1085
|
}
|
|
1086
|
+
let installedSkills = [];
|
|
1087
|
+
if (provider === "codex" && args["install-skills"] === true) {
|
|
1088
|
+
installedSkills = await installCodexSkills(listRoleDefinitions(), typeof args.dir === "string" ? args.dir : undefined);
|
|
1089
|
+
}
|
|
745
1090
|
if (args.json === true) {
|
|
746
1091
|
console.log(JSON.stringify({
|
|
747
1092
|
setup: outputValue,
|
|
748
1093
|
install: result,
|
|
749
|
-
installedPrompts: installedPrompts.map((prompt) => prompt.name)
|
|
1094
|
+
installedPrompts: installedPrompts.map((prompt) => prompt.name),
|
|
1095
|
+
installedSkills: installedSkills.map((skill) => skill.name)
|
|
750
1096
|
}, null, 2));
|
|
751
1097
|
return;
|
|
752
1098
|
}
|
|
@@ -757,16 +1103,24 @@ async function runCodexPersistInit(args) {
|
|
|
757
1103
|
console.log("");
|
|
758
1104
|
console.log("Installed Codex prompt files:");
|
|
759
1105
|
for (const prompt of installedPrompts) {
|
|
760
|
-
console.log(`-
|
|
1106
|
+
console.log(`- ${prompt.name}`);
|
|
1107
|
+
}
|
|
1108
|
+
console.log(" Note: prompt files are legacy and may not be exposed by your Codex build.");
|
|
1109
|
+
}
|
|
1110
|
+
if (installedSkills.length > 0) {
|
|
1111
|
+
console.log("");
|
|
1112
|
+
console.log("Installed Codex skill files:");
|
|
1113
|
+
for (const skill of installedSkills) {
|
|
1114
|
+
console.log(`- ${skill.name}`);
|
|
761
1115
|
}
|
|
762
|
-
console.log("
|
|
1116
|
+
console.log(" Use these inside Codex by naming LongTable naturally, e.g. `lt panel: ...`.");
|
|
763
1117
|
}
|
|
764
1118
|
if (provider === "codex") {
|
|
765
1119
|
console.log("");
|
|
766
1120
|
console.log("Next step:");
|
|
767
1121
|
console.log("- Start here: `longtable start`.");
|
|
768
1122
|
console.log("- If you want a direct natural-language entry: `longtable ask --prompt \"...\"`.");
|
|
769
|
-
console.log("- Codex
|
|
1123
|
+
console.log("- Codex skills are the preferred native surface. Prompt files are legacy and may not expose slash commands.");
|
|
770
1124
|
console.log("- Suggested next action: create a project workspace and let LongTable interview the current session.");
|
|
771
1125
|
}
|
|
772
1126
|
}
|
|
@@ -828,6 +1182,20 @@ function inferModeFromPrompt(prompt) {
|
|
|
828
1182
|
}
|
|
829
1183
|
return "explore";
|
|
830
1184
|
}
|
|
1185
|
+
function parsePanelVisibility(value) {
|
|
1186
|
+
if (value === "synthesis_only" ||
|
|
1187
|
+
value === "show_on_conflict" ||
|
|
1188
|
+
value === "always_visible") {
|
|
1189
|
+
return value;
|
|
1190
|
+
}
|
|
1191
|
+
return undefined;
|
|
1192
|
+
}
|
|
1193
|
+
function parsePanelMode(value) {
|
|
1194
|
+
if (value && VALID_MODES.has(value) && value !== "explore" && value !== "submit") {
|
|
1195
|
+
return value;
|
|
1196
|
+
}
|
|
1197
|
+
return "review";
|
|
1198
|
+
}
|
|
831
1199
|
async function loadOptionalSetup(path) {
|
|
832
1200
|
try {
|
|
833
1201
|
return await loadSetupOutput(path);
|
|
@@ -864,6 +1232,10 @@ async function runModeCommand(mode, args) {
|
|
|
864
1232
|
throw new Error(`Invalid stage: ${stage}`);
|
|
865
1233
|
}
|
|
866
1234
|
const setup = await loadOptionalSetup(typeof args.setup === "string" ? args.setup : undefined);
|
|
1235
|
+
const projectContext = await loadProjectContextFromDirectory(workingDirectory);
|
|
1236
|
+
if (projectContext) {
|
|
1237
|
+
await assertWorkspaceNotBlocked(projectContext);
|
|
1238
|
+
}
|
|
867
1239
|
const projectAware = await buildProjectAwarePrompt(prompt, workingDirectory);
|
|
868
1240
|
const panelPreference = setup?.profileSeed.panelPreference;
|
|
869
1241
|
const panelRequested = args.panel === true ||
|
|
@@ -898,6 +1270,125 @@ async function runModeCommand(mode, args) {
|
|
|
898
1270
|
});
|
|
899
1271
|
exit(exitCode);
|
|
900
1272
|
}
|
|
1273
|
+
async function runPanelCommand(args) {
|
|
1274
|
+
const workingDirectory = typeof args.cwd === "string" ? args.cwd : cwd();
|
|
1275
|
+
const prompt = await resolvePrompt(typeof args.prompt === "string" ? args.prompt : undefined);
|
|
1276
|
+
if (!prompt) {
|
|
1277
|
+
throw new Error("A prompt is required.");
|
|
1278
|
+
}
|
|
1279
|
+
const setup = await loadOptionalSetup(typeof args.setup === "string" ? args.setup : undefined);
|
|
1280
|
+
const existingContext = await loadProjectContextFromDirectory(workingDirectory);
|
|
1281
|
+
if (existingContext) {
|
|
1282
|
+
await assertWorkspaceNotBlocked(existingContext);
|
|
1283
|
+
}
|
|
1284
|
+
const projectAware = await buildProjectAwarePrompt(prompt, workingDirectory);
|
|
1285
|
+
const provider = setup?.providerSelection.provider;
|
|
1286
|
+
const visibility = parsePanelVisibility(typeof args.visibility === "string" ? args.visibility : undefined) ??
|
|
1287
|
+
parsePanelVisibility(setup?.profileSeed.panelPreference) ??
|
|
1288
|
+
"always_visible";
|
|
1289
|
+
const mode = parsePanelMode(typeof args.mode === "string" ? args.mode : undefined);
|
|
1290
|
+
const fallback = buildPanelFallback({
|
|
1291
|
+
prompt: projectAware.prompt,
|
|
1292
|
+
mode,
|
|
1293
|
+
roleFlag: typeof args.role === "string" ? args.role : undefined,
|
|
1294
|
+
provider,
|
|
1295
|
+
visibility
|
|
1296
|
+
});
|
|
1297
|
+
if (projectAware.projectContextFound) {
|
|
1298
|
+
const context = await loadProjectContextFromDirectory(workingDirectory);
|
|
1299
|
+
if (context) {
|
|
1300
|
+
await appendInvocationRecordToWorkspace(context, fallback.invocationRecord, [fallback.questionRecord]);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
if (args.json === true) {
|
|
1304
|
+
console.log(JSON.stringify({
|
|
1305
|
+
intent: fallback.intent,
|
|
1306
|
+
plan: fallback.plan,
|
|
1307
|
+
result: fallback.result,
|
|
1308
|
+
invocationRecord: fallback.invocationRecord,
|
|
1309
|
+
questionRecord: fallback.questionRecord,
|
|
1310
|
+
execution: {
|
|
1311
|
+
status: "planned",
|
|
1312
|
+
stableSurface: "sequential_fallback",
|
|
1313
|
+
nativeParallel: "not_required_for_option_a",
|
|
1314
|
+
projectContextFound: projectAware.projectContextFound,
|
|
1315
|
+
invocationLogged: projectAware.projectContextFound
|
|
1316
|
+
},
|
|
1317
|
+
fallbackPrompt: fallback.prompt
|
|
1318
|
+
}, null, 2));
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
if (args.print === true) {
|
|
1322
|
+
console.log(fallback.prompt);
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
console.log(renderPanelSummary(fallback.plan));
|
|
1326
|
+
console.log("");
|
|
1327
|
+
const exitCode = await runCodexThinWrapper({
|
|
1328
|
+
prompt: fallback.prompt,
|
|
1329
|
+
mode,
|
|
1330
|
+
setupPath: typeof args.setup === "string" ? args.setup : undefined,
|
|
1331
|
+
workingDirectory,
|
|
1332
|
+
json: false
|
|
1333
|
+
});
|
|
1334
|
+
exit(exitCode);
|
|
1335
|
+
}
|
|
1336
|
+
async function runQuestion(args) {
|
|
1337
|
+
const workingDirectory = typeof args.cwd === "string" ? args.cwd : cwd();
|
|
1338
|
+
const prompt = await resolvePrompt(typeof args.prompt === "string" ? args.prompt : undefined);
|
|
1339
|
+
if (!prompt) {
|
|
1340
|
+
throw new Error("A decision context is required. Pass --prompt <text>.");
|
|
1341
|
+
}
|
|
1342
|
+
const context = await loadProjectContextFromDirectory(workingDirectory);
|
|
1343
|
+
if (!context) {
|
|
1344
|
+
throw new Error("No LongTable project workspace was found here. Run this inside a project or pass --cwd.");
|
|
1345
|
+
}
|
|
1346
|
+
const provider = args.provider === "claude" ? "claude" : args.provider === "codex" ? "codex" : undefined;
|
|
1347
|
+
const required = args.required === true ? true : args.advisory === true ? false : undefined;
|
|
1348
|
+
const result = await createWorkspaceQuestion({
|
|
1349
|
+
context,
|
|
1350
|
+
prompt,
|
|
1351
|
+
title: typeof args.title === "string" ? args.title : undefined,
|
|
1352
|
+
question: typeof args.text === "string" ? args.text : undefined,
|
|
1353
|
+
provider,
|
|
1354
|
+
required
|
|
1355
|
+
});
|
|
1356
|
+
const transport = provider === "claude"
|
|
1357
|
+
? renderQuestionRecordInput(result.question)
|
|
1358
|
+
: renderQuestionRecordPrompt(result.question);
|
|
1359
|
+
if (args.json === true) {
|
|
1360
|
+
console.log(JSON.stringify({
|
|
1361
|
+
question: result.question,
|
|
1362
|
+
transport,
|
|
1363
|
+
files: {
|
|
1364
|
+
state: context.stateFilePath,
|
|
1365
|
+
current: context.currentFilePath
|
|
1366
|
+
},
|
|
1367
|
+
nextAction: `longtable decide --question ${result.question.id} --answer <value>`
|
|
1368
|
+
}, null, 2));
|
|
1369
|
+
return;
|
|
1370
|
+
}
|
|
1371
|
+
if (args.print === true) {
|
|
1372
|
+
if (provider === "claude") {
|
|
1373
|
+
console.log(JSON.stringify(transport, null, 2));
|
|
1374
|
+
}
|
|
1375
|
+
else {
|
|
1376
|
+
console.log("prompt" in transport ? transport.prompt : JSON.stringify(transport, null, 2));
|
|
1377
|
+
}
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
const optionValues = [
|
|
1381
|
+
...result.question.prompt.options.map((option) => option.value),
|
|
1382
|
+
...(result.question.prompt.allowOther ? ["other"] : [])
|
|
1383
|
+
];
|
|
1384
|
+
console.log(result.question.prompt.required ? "LongTable required Researcher Checkpoint recorded" : "LongTable advisory Researcher Checkpoint recorded");
|
|
1385
|
+
console.log(`- question: ${result.question.id}`);
|
|
1386
|
+
console.log(`- checkpoint: ${result.question.prompt.checkpointKey ?? "manual"}`);
|
|
1387
|
+
console.log(`- prompt: ${result.question.prompt.question}`);
|
|
1388
|
+
console.log(`- options: ${optionValues.join("/")}`);
|
|
1389
|
+
console.log(`- answer: longtable decide --question ${result.question.id} --answer <value>`);
|
|
1390
|
+
console.log(`- current: ${context.currentFilePath}`);
|
|
1391
|
+
}
|
|
901
1392
|
async function runAsk(args) {
|
|
902
1393
|
const prompt = await resolvePrompt(typeof args.prompt === "string" ? args.prompt : undefined);
|
|
903
1394
|
if (!prompt) {
|
|
@@ -907,7 +1398,7 @@ async function runAsk(args) {
|
|
|
907
1398
|
const effectivePrompt = directive.cleanedPrompt;
|
|
908
1399
|
const inferred = directive.mode ?? inferModeFromPrompt(effectivePrompt);
|
|
909
1400
|
if (inferred === "status") {
|
|
910
|
-
await
|
|
1401
|
+
await runDoctor(args);
|
|
911
1402
|
return;
|
|
912
1403
|
}
|
|
913
1404
|
const mode = inferred === "panel" ? "review" : inferred;
|
|
@@ -918,18 +1409,60 @@ async function runAsk(args) {
|
|
|
918
1409
|
if (directive.roles.length > 0 && typeof delegatedArgs.role !== "string") {
|
|
919
1410
|
delegatedArgs.role = directive.roles.join(",");
|
|
920
1411
|
}
|
|
921
|
-
if (
|
|
922
|
-
|
|
923
|
-
|
|
1412
|
+
if (inferred === "panel" || directive.panel || delegatedArgs.panel === true) {
|
|
1413
|
+
await runPanelCommand({
|
|
1414
|
+
...delegatedArgs,
|
|
1415
|
+
visibility: "always_visible"
|
|
1416
|
+
});
|
|
1417
|
+
return;
|
|
924
1418
|
}
|
|
925
1419
|
await runModeCommand(mode, delegatedArgs);
|
|
926
1420
|
}
|
|
1421
|
+
async function runDecide(args) {
|
|
1422
|
+
const workingDirectory = typeof args.cwd === "string" ? args.cwd : cwd();
|
|
1423
|
+
const answer = typeof args.answer === "string" ? args.answer.trim() : "";
|
|
1424
|
+
if (!answer) {
|
|
1425
|
+
throw new Error("A decision answer is required. Pass --answer <value-or-text>.");
|
|
1426
|
+
}
|
|
1427
|
+
const context = await loadProjectContextFromDirectory(workingDirectory);
|
|
1428
|
+
if (!context) {
|
|
1429
|
+
throw new Error("No LongTable project workspace was found here. Run this inside a project or pass --cwd.");
|
|
1430
|
+
}
|
|
1431
|
+
const provider = args.provider === "claude" ? "claude" : args.provider === "codex" ? "codex" : undefined;
|
|
1432
|
+
const result = await answerWorkspaceQuestion({
|
|
1433
|
+
context,
|
|
1434
|
+
questionId: typeof args.question === "string" ? args.question : undefined,
|
|
1435
|
+
answer,
|
|
1436
|
+
rationale: typeof args.rationale === "string" ? args.rationale : undefined,
|
|
1437
|
+
provider
|
|
1438
|
+
});
|
|
1439
|
+
if (args.json === true) {
|
|
1440
|
+
console.log(JSON.stringify({
|
|
1441
|
+
question: result.question,
|
|
1442
|
+
decision: result.decision,
|
|
1443
|
+
files: {
|
|
1444
|
+
state: context.stateFilePath,
|
|
1445
|
+
current: context.currentFilePath
|
|
1446
|
+
}
|
|
1447
|
+
}, null, 2));
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
console.log("LongTable decision recorded");
|
|
1451
|
+
console.log(`- question: ${result.question.id}`);
|
|
1452
|
+
console.log(`- decision: ${result.decision.id}`);
|
|
1453
|
+
console.log(`- answer: ${result.decision.selectedOption ?? answer}`);
|
|
1454
|
+
console.log(`- state: ${context.stateFilePath}`);
|
|
1455
|
+
console.log(`- current: ${context.currentFilePath}`);
|
|
1456
|
+
}
|
|
927
1457
|
async function runRoles(args) {
|
|
928
1458
|
const payload = PERSONA_DEFINITIONS.map((persona) => ({
|
|
929
1459
|
key: persona.key,
|
|
930
1460
|
label: persona.label,
|
|
931
1461
|
description: persona.shortDescription,
|
|
932
1462
|
triggerMode: persona.triggerMode,
|
|
1463
|
+
defaultPanelMember: persona.defaultPanelMember,
|
|
1464
|
+
checkpointSensitivity: persona.checkpointSensitivity,
|
|
1465
|
+
supportedModes: persona.supportedModes,
|
|
933
1466
|
exampleTriggers: persona.synonyms.slice(0, 4)
|
|
934
1467
|
}));
|
|
935
1468
|
if (args.json === true) {
|
|
@@ -944,6 +1477,8 @@ async function runRoles(args) {
|
|
|
944
1477
|
console.log(`- ${persona.label} (${persona.key})`);
|
|
945
1478
|
console.log(` ${persona.description}`);
|
|
946
1479
|
console.log(` Trigger: ${persona.triggerMode === "auto-callable" ? "auto-callable when your language strongly implies it" : "explicit request only"}`);
|
|
1480
|
+
console.log(` Panel: ${persona.defaultPanelMember ? "default member" : "contextual member"}`);
|
|
1481
|
+
console.log(` Checkpoint sensitivity: ${persona.checkpointSensitivity}`);
|
|
947
1482
|
console.log(` Examples: ${persona.exampleTriggers.join(", ")}`);
|
|
948
1483
|
}
|
|
949
1484
|
}
|
|
@@ -1027,12 +1562,28 @@ async function runResume(args) {
|
|
|
1027
1562
|
}
|
|
1028
1563
|
async function runCodexSubcommand(subcommand, args) {
|
|
1029
1564
|
const customDir = typeof args.dir === "string" ? args.dir : undefined;
|
|
1565
|
+
const roles = listRoleDefinitions();
|
|
1566
|
+
if (subcommand === "install-skills") {
|
|
1567
|
+
const installed = await installCodexSkills(roles, customDir);
|
|
1568
|
+
console.log(`Installed ${installed.length} LongTable Codex skills in ${resolveCodexSkillsDir(customDir)}`);
|
|
1569
|
+
console.log("Use them inside Codex with natural-language triggers such as `lt explore: ...` or `lt panel: ...`.");
|
|
1570
|
+
console.log("If you want an explicit trigger, use `$longtable` when your Codex build exposes skills that way.");
|
|
1571
|
+
for (const skill of installed) {
|
|
1572
|
+
console.log(`- ${skill.name}`);
|
|
1573
|
+
}
|
|
1574
|
+
return;
|
|
1575
|
+
}
|
|
1576
|
+
if (subcommand === "remove-skills") {
|
|
1577
|
+
const removed = await removeCodexSkills(roles, customDir);
|
|
1578
|
+
console.log(`Removed ${removed.length} LongTable Codex skills from ${resolveCodexSkillsDir(customDir)}`);
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1030
1581
|
if (subcommand === "install-prompts") {
|
|
1031
1582
|
const installed = await installCodexPromptAliases(customDir);
|
|
1032
|
-
console.log(`Installed ${installed.length} LongTable prompt
|
|
1033
|
-
console.log("Note:
|
|
1583
|
+
console.log(`Installed ${installed.length} legacy LongTable prompt files in ${resolveCodexPromptsDir(customDir)}`);
|
|
1584
|
+
console.log("Note: current Codex builds may not expose these files as slash commands. Prefer `longtable codex install-skills`.");
|
|
1034
1585
|
for (const prompt of installed) {
|
|
1035
|
-
console.log(`-
|
|
1586
|
+
console.log(`- ${prompt.name}`);
|
|
1036
1587
|
}
|
|
1037
1588
|
return;
|
|
1038
1589
|
}
|
|
@@ -1042,11 +1593,12 @@ async function runCodexSubcommand(subcommand, args) {
|
|
|
1042
1593
|
}
|
|
1043
1594
|
if (subcommand === "remove-prompts") {
|
|
1044
1595
|
const removed = await removeCodexPromptAliases(customDir);
|
|
1045
|
-
console.log(`Removed ${removed.length} LongTable prompt
|
|
1596
|
+
console.log(`Removed ${removed.length} legacy LongTable prompt files from ${resolveCodexPromptsDir(customDir)}`);
|
|
1046
1597
|
return;
|
|
1047
1598
|
}
|
|
1048
1599
|
if (subcommand === "status") {
|
|
1049
1600
|
const aliases = await listInstalledCodexPromptAliases(customDir);
|
|
1601
|
+
const skills = await listInstalledCodexSkills(roles, customDir);
|
|
1050
1602
|
const setupPath = resolveDefaultSetupPath(typeof args.path === "string" ? args.path : undefined).path;
|
|
1051
1603
|
const runtimePath = resolveDefaultRuntimeConfigPath("codex", typeof args["runtime-path"] === "string" ? args["runtime-path"] : undefined).path;
|
|
1052
1604
|
const status = {
|
|
@@ -1054,8 +1606,10 @@ async function runCodexSubcommand(subcommand, args) {
|
|
|
1054
1606
|
setupExists: existsSync(setupPath),
|
|
1055
1607
|
runtimePath,
|
|
1056
1608
|
runtimeExists: existsSync(runtimePath),
|
|
1609
|
+
skillsDir: resolveCodexSkillsDir(customDir),
|
|
1610
|
+
skillsInstalled: skills.map((skill) => skill.name),
|
|
1057
1611
|
promptsDir: resolveCodexPromptsDir(customDir),
|
|
1058
|
-
|
|
1612
|
+
legacyPromptFilesInstalled: aliases.map((alias) => alias.name)
|
|
1059
1613
|
};
|
|
1060
1614
|
if (args.json === true) {
|
|
1061
1615
|
console.log(JSON.stringify(status, null, 2));
|
|
@@ -1064,21 +1618,81 @@ async function runCodexSubcommand(subcommand, args) {
|
|
|
1064
1618
|
console.log("LongTable Codex status");
|
|
1065
1619
|
console.log(`- setup: ${status.setupExists ? "present" : "missing"} (${setupPath})`);
|
|
1066
1620
|
console.log(`- codex runtime artifact: ${status.runtimeExists ? "present" : "missing"} (${runtimePath})`);
|
|
1621
|
+
console.log(`- skills dir: ${status.skillsDir}`);
|
|
1622
|
+
if (skills.length === 0) {
|
|
1623
|
+
console.log("- skills: none");
|
|
1624
|
+
}
|
|
1625
|
+
else {
|
|
1626
|
+
console.log("- skills:");
|
|
1627
|
+
for (const skill of skills) {
|
|
1628
|
+
console.log(` - ${skill.name}`);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1067
1631
|
console.log(`- prompt aliases dir: ${status.promptsDir}`);
|
|
1068
|
-
console.log("- prompt
|
|
1632
|
+
console.log("- prompt files: legacy; current Codex builds may not expose these as slash commands");
|
|
1069
1633
|
if (aliases.length === 0) {
|
|
1070
|
-
console.log("- prompt
|
|
1634
|
+
console.log("- legacy prompt files: none");
|
|
1071
1635
|
}
|
|
1072
1636
|
else {
|
|
1073
|
-
console.log("- prompt
|
|
1637
|
+
console.log("- legacy prompt files:");
|
|
1074
1638
|
for (const alias of aliases) {
|
|
1075
|
-
console.log(` -
|
|
1639
|
+
console.log(` - ${alias.name}`);
|
|
1076
1640
|
}
|
|
1077
1641
|
}
|
|
1078
1642
|
return;
|
|
1079
1643
|
}
|
|
1080
1644
|
throw new Error("Unknown codex subcommand.");
|
|
1081
1645
|
}
|
|
1646
|
+
async function runClaudeSubcommand(subcommand, args) {
|
|
1647
|
+
const customDir = typeof args.dir === "string" ? args.dir : undefined;
|
|
1648
|
+
const roles = listRoleDefinitions();
|
|
1649
|
+
if (subcommand === "install-skills") {
|
|
1650
|
+
const installed = await installClaudeSkills(roles, customDir);
|
|
1651
|
+
console.log(`Installed ${installed.length} LongTable Claude skills in ${resolveClaudeSkillsDir(customDir)}`);
|
|
1652
|
+
console.log("Use them inside Claude Code with natural-language triggers such as `lt explore: ...` or `lt panel: ...`.");
|
|
1653
|
+
for (const skill of installed) {
|
|
1654
|
+
console.log(`- ${skill.name}`);
|
|
1655
|
+
}
|
|
1656
|
+
return;
|
|
1657
|
+
}
|
|
1658
|
+
if (subcommand === "remove-skills") {
|
|
1659
|
+
const removed = await removeClaudeSkills(roles, customDir);
|
|
1660
|
+
console.log(`Removed ${removed.length} LongTable Claude skills from ${resolveClaudeSkillsDir(customDir)}`);
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
if (subcommand === "status") {
|
|
1664
|
+
const skills = await listInstalledClaudeSkills(roles, customDir);
|
|
1665
|
+
const setupPath = resolveDefaultSetupPath(typeof args.path === "string" ? args.path : undefined).path;
|
|
1666
|
+
const runtimePath = resolveDefaultRuntimeConfigPath("claude", typeof args["runtime-path"] === "string" ? args["runtime-path"] : undefined).path;
|
|
1667
|
+
const status = {
|
|
1668
|
+
setupPath,
|
|
1669
|
+
setupExists: existsSync(setupPath),
|
|
1670
|
+
runtimePath,
|
|
1671
|
+
runtimeExists: existsSync(runtimePath),
|
|
1672
|
+
skillsDir: resolveClaudeSkillsDir(customDir),
|
|
1673
|
+
skillsInstalled: skills.map((skill) => skill.name)
|
|
1674
|
+
};
|
|
1675
|
+
if (args.json === true) {
|
|
1676
|
+
console.log(JSON.stringify(status, null, 2));
|
|
1677
|
+
return;
|
|
1678
|
+
}
|
|
1679
|
+
console.log("LongTable Claude status");
|
|
1680
|
+
console.log(`- setup: ${status.setupExists ? "present" : "missing"} (${setupPath})`);
|
|
1681
|
+
console.log(`- claude runtime artifact: ${status.runtimeExists ? "present" : "missing"} (${runtimePath})`);
|
|
1682
|
+
console.log(`- skills dir: ${status.skillsDir}`);
|
|
1683
|
+
if (skills.length === 0) {
|
|
1684
|
+
console.log("- skills: none");
|
|
1685
|
+
}
|
|
1686
|
+
else {
|
|
1687
|
+
console.log("- skills:");
|
|
1688
|
+
for (const skill of skills) {
|
|
1689
|
+
console.log(` - ${skill.name}`);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1694
|
+
throw new Error("Unknown claude subcommand.");
|
|
1695
|
+
}
|
|
1082
1696
|
async function main() {
|
|
1083
1697
|
const parsed = parseArgs(process.argv.slice(2));
|
|
1084
1698
|
const { command, subcommand, values } = parsed;
|
|
@@ -1098,6 +1712,10 @@ async function main() {
|
|
|
1098
1712
|
await runResume(values);
|
|
1099
1713
|
return;
|
|
1100
1714
|
}
|
|
1715
|
+
if (command === "doctor" || command === "status") {
|
|
1716
|
+
await runDoctor(values);
|
|
1717
|
+
return;
|
|
1718
|
+
}
|
|
1101
1719
|
if (command === "roles") {
|
|
1102
1720
|
await runRoles(values);
|
|
1103
1721
|
return;
|
|
@@ -1114,11 +1732,34 @@ async function main() {
|
|
|
1114
1732
|
await runAsk(values);
|
|
1115
1733
|
return;
|
|
1116
1734
|
}
|
|
1735
|
+
if (command === "question") {
|
|
1736
|
+
await runQuestion(values);
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
if (command === "panel") {
|
|
1740
|
+
await runPanelCommand(values);
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
if (command === "decide") {
|
|
1744
|
+
await runDecide(values);
|
|
1745
|
+
return;
|
|
1746
|
+
}
|
|
1117
1747
|
if (command === "codex") {
|
|
1118
1748
|
await runCodexSubcommand(subcommand, values);
|
|
1119
1749
|
return;
|
|
1120
1750
|
}
|
|
1751
|
+
if (command === "claude") {
|
|
1752
|
+
await runClaudeSubcommand(subcommand, values);
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1121
1755
|
if (VALID_MODES.has(command)) {
|
|
1756
|
+
if (values.panel === true) {
|
|
1757
|
+
await runPanelCommand({
|
|
1758
|
+
...values,
|
|
1759
|
+
mode: command
|
|
1760
|
+
});
|
|
1761
|
+
return;
|
|
1762
|
+
}
|
|
1122
1763
|
await runModeCommand(command, values);
|
|
1123
1764
|
return;
|
|
1124
1765
|
}
|