@longtable/cli 0.1.18 → 0.1.20
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 +4 -5
- package/dist/cli.js +239 -86
- package/dist/project-session.d.ts +6 -0
- package/dist/project-session.js +49 -7
- package/dist/prompt-aliases.js +2 -2
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -27,16 +27,15 @@ approval.
|
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
longtable setup --provider codex
|
|
30
|
-
longtable init --flow interview
|
|
31
30
|
longtable start
|
|
32
31
|
cd "<project-path>"
|
|
33
32
|
codex
|
|
34
33
|
```
|
|
35
34
|
|
|
36
35
|
`longtable setup --provider codex` is the permission-first setup route. It asks
|
|
37
|
-
which runtime surfaces
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
where LongTable may install support, which runtime surfaces it may enable, how
|
|
37
|
+
strongly it may interrupt research decisions, and whether to create a project
|
|
38
|
+
workspace now. `longtable init` remains only as a deprecated compatibility alias.
|
|
40
39
|
|
|
41
40
|
Return later:
|
|
42
41
|
|
|
@@ -85,7 +84,7 @@ This is how LongTable avoids turning tacit knowledge into fake certainty.
|
|
|
85
84
|
## Commands
|
|
86
85
|
|
|
87
86
|
```bash
|
|
88
|
-
longtable
|
|
87
|
+
longtable setup
|
|
89
88
|
longtable start
|
|
90
89
|
longtable resume --cwd "<project-path>"
|
|
91
90
|
longtable roles
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { stdin as input, stdout as output, cwd, exit } from "node:process";
|
|
|
8
8
|
import { dirname, join, resolve } from "node:path";
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
10
|
import { classifyCheckpointTrigger } from "@longtable/checkpoints";
|
|
11
|
-
import { buildProviderChoices, buildQuickSetupFlow, createPersistedSetupOutput, installRuntimeConfigFromStoredSetup, loadSetupOutput, renderInstallSummary, renderSetupSummary, resolveDefaultRuntimeConfigPath, resolveDefaultSetupPath, saveSetupAndRuntimeConfig, serializeSetupOutput, writeRuntimeConfig } from "@longtable/setup";
|
|
11
|
+
import { buildProviderChoices, buildQuickSetupFlow, createPersistedSetupOutput, installRuntimeConfigFromStoredSetup, loadSetupOutput, renderInstallSummary, renderSetupSummary, resolveDefaultRuntimeConfigPath, resolveDefaultSetupPath, saveSetupOutput, saveSetupAndRuntimeConfig, serializeSetupOutput, writeRuntimeConfig } from "@longtable/setup";
|
|
12
12
|
import { buildCodexSkillSpecs, buildCodexThinWrappedPrompt, installCodexSkills, listInstalledCodexSkills, renderQuestionRecordPrompt, removeCodexSkills, resolveCodexSkillsDir, runCodexThinWrapper } from "@longtable/provider-codex";
|
|
13
13
|
import { buildClaudeSkillSpecs, installClaudeSkills, listInstalledClaudeSkills, renderQuestionRecordInput, removeClaudeSkills, resolveClaudeSkillsDir } from "@longtable/provider-claude";
|
|
14
14
|
import { installCodexPromptAliases, listInstalledCodexPromptAliases, removeCodexPromptAliases, resolveCodexPromptsDir } from "./prompt-aliases.js";
|
|
@@ -42,7 +42,7 @@ const ANSI = {
|
|
|
42
42
|
green: "\u001B[32m"
|
|
43
43
|
};
|
|
44
44
|
const LONGTABLE_MCP_SERVER_NAME = "longtable-state";
|
|
45
|
-
const LONGTABLE_MCP_PACKAGE_VERSION = "0.1.
|
|
45
|
+
const LONGTABLE_MCP_PACKAGE_VERSION = "0.1.20";
|
|
46
46
|
const LONGTABLE_MCP_MARKER_START = "# LongTable state MCP START";
|
|
47
47
|
const LONGTABLE_MCP_MARKER_END = "# LongTable state MCP END";
|
|
48
48
|
function style(text, prefix) {
|
|
@@ -78,9 +78,9 @@ function usage() {
|
|
|
78
78
|
" Run `longtable ...` in your terminal, not inside the Codex chat box.",
|
|
79
79
|
" After `longtable start`, move into the created project directory and open `codex` there.",
|
|
80
80
|
"",
|
|
81
|
-
" longtable
|
|
82
|
-
" longtable
|
|
83
|
-
" longtable start [--path <dir>] [--name <project>] [--goal <text>] [--blocker <text>] [--perspectives <role[,role]>] [--disagreement synthesis_only|show_on_conflict|always_visible] [--setup <path>] [--json]",
|
|
81
|
+
" longtable setup [--provider codex|claude] [--install-scope user|project|none] [--surfaces cli_only|skills|skills_mcp|skills_mcp_sentinel] [--intervention advisory|balanced|strong] [--workspace create|later] [--project-dir <path>] [--json] [--dir <path>] [--skills-dir <path>] [--runtime-path <file>] [--setup-path <file>]",
|
|
82
|
+
" longtable init [deprecated alias for setup; full legacy flags still supported for automation]",
|
|
83
|
+
" longtable start [--path <dir>] [--name <project>] [--goal <text>] [--blocker <text>] [--research-object research_question|theory_framework|measurement_instrument|study_design|analysis_plan|manuscript] [--gap-risk known_gap|suspected_tacit_assumptions|diagnose] [--protected-decision theory|measurement|method|evidence_citation|authorship_voice|submission_public_sharing] [--perspectives <role[,role]>] [--disagreement synthesis_only|show_on_conflict|always_visible] [--setup <path>] [--json]",
|
|
84
84
|
" longtable resume [--cwd <path>] [--json]",
|
|
85
85
|
" longtable doctor [--cwd <path>] [--fix] [--json] [--codex-dir <path>] [--claude-dir <path>] [--codex-prompts-dir <path>] [--codex-runtime-path <file>] [--claude-runtime-path <file>]",
|
|
86
86
|
" longtable status [--cwd <path>] [--fix] [--json] [--codex-dir <path>] [--claude-dir <path>] [--codex-prompts-dir <path>] [--codex-runtime-path <file>] [--claude-runtime-path <file>]",
|
|
@@ -109,7 +109,7 @@ function usage() {
|
|
|
109
109
|
" longtable mcp install --provider all",
|
|
110
110
|
"",
|
|
111
111
|
"Examples:",
|
|
112
|
-
" longtable
|
|
112
|
+
" longtable setup --provider codex",
|
|
113
113
|
" longtable start",
|
|
114
114
|
" longtable start --path ~/Research/My-Project --name \"AI Adoption Meta-Analysis\" --goal \"Narrow the review question\"",
|
|
115
115
|
" cd \"<project-path>\" && codex",
|
|
@@ -197,7 +197,7 @@ function renderQuestionHeader(index, total, section, prompt) {
|
|
|
197
197
|
].join("\n");
|
|
198
198
|
}
|
|
199
199
|
function questionSection(questionId) {
|
|
200
|
-
if (questionId === "
|
|
200
|
+
if (questionId === "careerStage" || questionId === "experienceLevel") {
|
|
201
201
|
return "Researcher profile";
|
|
202
202
|
}
|
|
203
203
|
if (questionId === "preferredCheckpointIntensity" || questionId === "preferredEntryMode") {
|
|
@@ -476,7 +476,7 @@ async function promptMultiChoice(rl, prompt, choices) {
|
|
|
476
476
|
});
|
|
477
477
|
}
|
|
478
478
|
function hasCompleteFlagInput(args) {
|
|
479
|
-
const required = ["provider", "
|
|
479
|
+
const required = ["provider", "career-stage", "experience", "checkpoint"];
|
|
480
480
|
return required.every((key) => typeof args[key] === "string" && String(args[key]).trim().length > 0);
|
|
481
481
|
}
|
|
482
482
|
function resolveSetupFlow(args) {
|
|
@@ -484,7 +484,9 @@ function resolveSetupFlow(args) {
|
|
|
484
484
|
}
|
|
485
485
|
function toSetupAnswers(args) {
|
|
486
486
|
return {
|
|
487
|
-
field:
|
|
487
|
+
field: typeof args.field === "string" && args.field.trim().length > 0
|
|
488
|
+
? String(args.field)
|
|
489
|
+
: "unspecified",
|
|
488
490
|
careerStage: String(args["career-stage"]),
|
|
489
491
|
experienceLevel: String(args.experience),
|
|
490
492
|
currentProjectType: typeof args["project-type"] === "string" && args["project-type"].trim().length > 0
|
|
@@ -515,6 +517,7 @@ async function collectInteractiveAnswers(initialFlow) {
|
|
|
515
517
|
console.log("");
|
|
516
518
|
const provider = await promptChoice(rl, "Which provider do you want to configure?", buildProviderChoices());
|
|
517
519
|
const answers = {
|
|
520
|
+
field: "unspecified",
|
|
518
521
|
currentProjectType: "unspecified research task"
|
|
519
522
|
};
|
|
520
523
|
const questions = buildQuickSetupFlow(flow);
|
|
@@ -531,8 +534,6 @@ async function collectInteractiveAnswers(initialFlow) {
|
|
|
531
534
|
if (!value) {
|
|
532
535
|
continue;
|
|
533
536
|
}
|
|
534
|
-
if (question.id === "field")
|
|
535
|
-
answers.field = value;
|
|
536
537
|
if (question.id === "careerStage")
|
|
537
538
|
answers.careerStage = value;
|
|
538
539
|
if (question.id === "experienceLevel")
|
|
@@ -562,77 +563,72 @@ async function collectInteractiveAnswers(initialFlow) {
|
|
|
562
563
|
}
|
|
563
564
|
function buildPermissionSetupChoices() {
|
|
564
565
|
return {
|
|
566
|
+
installScope: [
|
|
567
|
+
{
|
|
568
|
+
id: "user",
|
|
569
|
+
label: "User-level provider config",
|
|
570
|
+
description: "Why: available across projects. What you get: writes to ~/.codex or ~/.claude. Tradeoff: broader machine-level change."
|
|
571
|
+
},
|
|
572
|
+
{
|
|
573
|
+
id: "project",
|
|
574
|
+
label: "Current project only",
|
|
575
|
+
description: "Why: keeps LongTable local to this repository. What you get: project-scoped runtime files when supported. Tradeoff: not available elsewhere."
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
id: "none",
|
|
579
|
+
label: "Do not install provider files",
|
|
580
|
+
description: "Why: safest permission boundary. What you get: CLI setup record only. Tradeoff: no provider-native skills or MCP config."
|
|
581
|
+
}
|
|
582
|
+
],
|
|
565
583
|
surfaces: [
|
|
566
584
|
{
|
|
567
585
|
id: "cli_only",
|
|
568
586
|
label: "CLI only",
|
|
569
|
-
description: "Why: least invasive. Tradeoff: no natural in-provider LongTable entrypoints."
|
|
587
|
+
description: "Why: least invasive. What you get: setup record and CLI commands. Tradeoff: no natural in-provider LongTable entrypoints."
|
|
570
588
|
},
|
|
571
589
|
{
|
|
572
590
|
id: "skills",
|
|
573
591
|
label: "Skills",
|
|
574
|
-
description: "Why: enables natural LongTable skill routing. Tradeoff: writes provider skill files."
|
|
592
|
+
description: "Why: enables natural LongTable skill routing. What you get: provider skills. Tradeoff: writes provider skill files."
|
|
575
593
|
},
|
|
576
594
|
{
|
|
577
595
|
id: "skills_mcp",
|
|
578
596
|
label: "Skills + MCP",
|
|
579
|
-
description: "Why: adds structured state access. Tradeoff: writes provider config for MCP transport."
|
|
597
|
+
description: "Why: adds structured state access. What you get: skills and MCP config. Tradeoff: writes provider config for MCP transport."
|
|
580
598
|
},
|
|
581
599
|
{
|
|
582
600
|
id: "skills_mcp_sentinel",
|
|
583
601
|
label: "Skills + MCP + Sentinel",
|
|
584
|
-
description: "Why: prepares advisory gap/tacit monitoring. Tradeoff: LongTable may nudge research turns."
|
|
602
|
+
description: "Why: prepares advisory gap/tacit monitoring. What you get: skills, MCP, and sentinel approval. Tradeoff: LongTable may nudge research turns."
|
|
585
603
|
}
|
|
586
604
|
],
|
|
587
605
|
intervention: [
|
|
588
606
|
{
|
|
589
607
|
id: "advisory",
|
|
590
608
|
label: "Advisory",
|
|
591
|
-
description: "Why: notices gaps without blocking. Tradeoff: you may still miss hard commitments."
|
|
609
|
+
description: "Why: notices gaps without blocking. What you get: light nudges. Tradeoff: you may still miss hard commitments."
|
|
592
610
|
},
|
|
593
611
|
{
|
|
594
612
|
id: "balanced",
|
|
595
613
|
label: "Balanced",
|
|
596
|
-
description: "Why: blocks clear theory, measurement, method, or evidence commitments. Tradeoff: occasional stops."
|
|
614
|
+
description: "Why: blocks clear theory, measurement, method, or evidence commitments. What you get: recommended checkpoints. Tradeoff: occasional stops."
|
|
597
615
|
},
|
|
598
616
|
{
|
|
599
617
|
id: "strong",
|
|
600
618
|
label: "Strong",
|
|
601
|
-
description: "Why: maximizes judgment protection. Tradeoff: more interruption before closure."
|
|
619
|
+
description: "Why: maximizes judgment protection. What you get: stricter checkpoints. Tradeoff: more interruption before closure."
|
|
602
620
|
}
|
|
603
621
|
],
|
|
604
|
-
|
|
605
|
-
{
|
|
606
|
-
id: "standard",
|
|
607
|
-
label: "Standard chat",
|
|
608
|
-
description: "Why: portable default. Tradeoff: checkpoints and gaps are less persistently visible."
|
|
609
|
-
},
|
|
610
|
-
{
|
|
611
|
-
id: "hud",
|
|
612
|
-
label: "Research HUD",
|
|
613
|
-
description: "Why: keeps goals, blockers, and pending checkpoints visible. Requires tmux."
|
|
614
|
-
},
|
|
615
|
-
{
|
|
616
|
-
id: "console",
|
|
617
|
-
label: "Research console",
|
|
618
|
-
description: "Why: enables a richer tmux layout for HUD and team discussion. Requires tmux."
|
|
619
|
-
}
|
|
620
|
-
],
|
|
621
|
-
team: [
|
|
622
|
-
{
|
|
623
|
-
id: "off",
|
|
624
|
-
label: "Off",
|
|
625
|
-
description: "Why: simplest. Tradeoff: panel disagreement stays inside one LongTable response."
|
|
626
|
-
},
|
|
622
|
+
workspace: [
|
|
627
623
|
{
|
|
628
|
-
id: "
|
|
629
|
-
label: "
|
|
630
|
-
description: "Why:
|
|
624
|
+
id: "create",
|
|
625
|
+
label: "Yes, create one now",
|
|
626
|
+
description: "Why: durable state needs .longtable/. What you get: decision log and CURRENT.md. Tradeoff: asks project-specific questions now."
|
|
631
627
|
},
|
|
632
628
|
{
|
|
633
|
-
id: "
|
|
634
|
-
label: "
|
|
635
|
-
description: "Why:
|
|
629
|
+
id: "later",
|
|
630
|
+
label: "No, prepare runtime only",
|
|
631
|
+
description: "Why: keeps setup short. What you get: runtime support without project state. Tradeoff: no durable research memory until `longtable start`."
|
|
636
632
|
}
|
|
637
633
|
]
|
|
638
634
|
};
|
|
@@ -644,6 +640,65 @@ function checkpointIntensityFromIntervention(choice) {
|
|
|
644
640
|
return "low";
|
|
645
641
|
return "balanced";
|
|
646
642
|
}
|
|
643
|
+
function shouldInstallSkills(scope, surfaces) {
|
|
644
|
+
return scope !== "none" && surfaces !== "cli_only";
|
|
645
|
+
}
|
|
646
|
+
function shouldInstallMcp(scope, surfaces) {
|
|
647
|
+
return scope !== "none" && (surfaces === "skills_mcp" || surfaces === "skills_mcp_sentinel");
|
|
648
|
+
}
|
|
649
|
+
function setupProjectRoot(args) {
|
|
650
|
+
return resolve(normalizeUserPath(typeof args["project-dir"] === "string" && args["project-dir"].trim()
|
|
651
|
+
? args["project-dir"].trim()
|
|
652
|
+
: cwd()));
|
|
653
|
+
}
|
|
654
|
+
function setupInstallDir(provider, scope, customDir, projectRoot) {
|
|
655
|
+
if (customDir)
|
|
656
|
+
return customDir;
|
|
657
|
+
if (scope === "project")
|
|
658
|
+
return join(projectRoot, provider === "codex" ? ".codex" : ".claude", "skills");
|
|
659
|
+
return undefined;
|
|
660
|
+
}
|
|
661
|
+
function setupPathForScope(scope, args, projectRoot) {
|
|
662
|
+
if (typeof args["setup-path"] === "string")
|
|
663
|
+
return args["setup-path"];
|
|
664
|
+
if (scope === "project")
|
|
665
|
+
return join(projectRoot, ".longtable", "setup.json");
|
|
666
|
+
return undefined;
|
|
667
|
+
}
|
|
668
|
+
function runtimePathForScope(provider, scope, args, projectRoot) {
|
|
669
|
+
if (typeof args["runtime-path"] === "string")
|
|
670
|
+
return args["runtime-path"];
|
|
671
|
+
if (scope !== "project")
|
|
672
|
+
return undefined;
|
|
673
|
+
return join(projectRoot, ".longtable", provider === "codex" ? "codex-runtime.toml" : "claude-runtime.json");
|
|
674
|
+
}
|
|
675
|
+
function mcpArgsForScope(provider, scope, args, projectRoot) {
|
|
676
|
+
if (scope !== "project")
|
|
677
|
+
return args;
|
|
678
|
+
return {
|
|
679
|
+
...args,
|
|
680
|
+
...(provider === "codex" && typeof args["codex-config"] !== "string"
|
|
681
|
+
? { "codex-config": join(projectRoot, ".codex", "config.toml") }
|
|
682
|
+
: {}),
|
|
683
|
+
...(provider === "claude" && typeof args["claude-settings"] !== "string"
|
|
684
|
+
? { "claude-settings": join(projectRoot, ".claude", "settings.json") }
|
|
685
|
+
: {})
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
function parseSetupInstallScope(value) {
|
|
689
|
+
return value === "user" || value === "project" || value === "none" ? value : undefined;
|
|
690
|
+
}
|
|
691
|
+
function parseSetupSurface(value) {
|
|
692
|
+
return value === "cli_only" || value === "skills" || value === "skills_mcp" || value === "skills_mcp_sentinel"
|
|
693
|
+
? value
|
|
694
|
+
: undefined;
|
|
695
|
+
}
|
|
696
|
+
function parseSetupIntervention(value) {
|
|
697
|
+
return value === "advisory" || value === "balanced" || value === "strong" ? value : undefined;
|
|
698
|
+
}
|
|
699
|
+
function parseSetupWorkspace(value) {
|
|
700
|
+
return value === "create" || value === "later" ? value : undefined;
|
|
701
|
+
}
|
|
647
702
|
async function runSetup(args) {
|
|
648
703
|
const json = args.json === true;
|
|
649
704
|
const rl = createInterface({ input, output });
|
|
@@ -652,27 +707,30 @@ async function runSetup(args) {
|
|
|
652
707
|
? (args.provider === "claude" ? "claude" : "codex")
|
|
653
708
|
: await promptChoice(rl, "Which provider should LongTable configure?", buildProviderChoices()));
|
|
654
709
|
const choices = buildPermissionSetupChoices();
|
|
655
|
-
const
|
|
710
|
+
const installScope = parseSetupInstallScope(args["install-scope"]) ?? await promptChoice(rl, "Where may LongTable install runtime support?", choices.installScope);
|
|
711
|
+
const surfaces = parseSetupSurface(args.surfaces) ?? await promptChoice(rl, [
|
|
656
712
|
"Which LongTable runtime surfaces should be enabled?",
|
|
657
713
|
"This is a permission choice because skills, MCP, and sentinel support write provider-facing runtime files."
|
|
658
714
|
].join("\n"), choices.surfaces);
|
|
659
|
-
const intervention = await promptChoice(rl, "How strongly may LongTable interrupt research decisions?", choices.intervention);
|
|
660
|
-
const
|
|
661
|
-
const
|
|
715
|
+
const intervention = parseSetupIntervention(args.intervention) ?? await promptChoice(rl, "How strongly may LongTable interrupt research decisions?", choices.intervention);
|
|
716
|
+
const workspacePreference = parseSetupWorkspace(args.workspace) ?? await promptChoice(rl, "Should LongTable create a project workspace now?", choices.workspace);
|
|
717
|
+
const projectRoot = setupProjectRoot(args);
|
|
662
718
|
const outputValue = createPersistedSetupOutput({
|
|
663
719
|
field: "unspecified",
|
|
664
720
|
careerStage: "unspecified",
|
|
665
721
|
experienceLevel: "advanced",
|
|
666
722
|
preferredCheckpointIntensity: checkpointIntensityFromIntervention(intervention),
|
|
667
723
|
preferredEntryMode: "explore",
|
|
668
|
-
panelPreference:
|
|
724
|
+
panelPreference: "show_on_conflict"
|
|
669
725
|
}, provider, "quickstart");
|
|
670
726
|
outputValue.initialState.explicitState = {
|
|
671
727
|
...outputValue.initialState.explicitState,
|
|
728
|
+
installScope,
|
|
672
729
|
runtimeSurfaces: surfaces,
|
|
673
730
|
interventionPosture: intervention,
|
|
674
|
-
|
|
675
|
-
|
|
731
|
+
workspaceCreationPreference: workspacePreference,
|
|
732
|
+
tmuxMode: "standard",
|
|
733
|
+
teamMode: "panel"
|
|
676
734
|
};
|
|
677
735
|
if (surfaces === "skills_mcp_sentinel") {
|
|
678
736
|
outputValue.initialState.inferredHypotheses.push({
|
|
@@ -682,44 +740,64 @@ async function runSetup(args) {
|
|
|
682
740
|
status: "confirmed"
|
|
683
741
|
});
|
|
684
742
|
}
|
|
685
|
-
const
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
743
|
+
const setupPath = setupPathForScope(installScope, args, projectRoot);
|
|
744
|
+
const runtimePath = runtimePathForScope(provider, installScope, args, projectRoot);
|
|
745
|
+
const result = installScope === "none"
|
|
746
|
+
? {
|
|
747
|
+
provider,
|
|
748
|
+
setupTarget: await saveSetupOutput(outputValue, setupPath)
|
|
749
|
+
}
|
|
750
|
+
: await saveSetupAndRuntimeConfig(outputValue, {
|
|
751
|
+
setupPath,
|
|
752
|
+
runtimePath
|
|
753
|
+
});
|
|
754
|
+
const scopedInstallDir = setupInstallDir(provider, installScope, typeof args["skills-dir"] === "string" ? args["skills-dir"] : typeof args.dir === "string" ? args.dir : undefined, projectRoot);
|
|
755
|
+
const installedSkills = !shouldInstallSkills(installScope, surfaces)
|
|
690
756
|
? []
|
|
691
757
|
: provider === "codex"
|
|
692
|
-
? await installCodexSkills(listRoleDefinitions(),
|
|
693
|
-
: await installClaudeSkills(listRoleDefinitions(),
|
|
694
|
-
|
|
695
|
-
if (
|
|
696
|
-
|
|
697
|
-
console.log("MCP setup is approved. To write provider config now, run:");
|
|
698
|
-
console.log(`- longtable mcp install --provider ${provider} --write`);
|
|
758
|
+
? await installCodexSkills(listRoleDefinitions(), scopedInstallDir)
|
|
759
|
+
: await installClaudeSkills(listRoleDefinitions(), scopedInstallDir);
|
|
760
|
+
let mcpInstall;
|
|
761
|
+
if (shouldInstallMcp(installScope, surfaces)) {
|
|
762
|
+
mcpInstall = await installMcpForSetup(provider, mcpArgsForScope(provider, installScope, args, projectRoot));
|
|
699
763
|
}
|
|
700
764
|
if (json) {
|
|
701
765
|
console.log(JSON.stringify({
|
|
702
766
|
setup: outputValue,
|
|
703
767
|
runtime: result,
|
|
704
768
|
installedSkills: installedSkills.map((skill) => skill.name),
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
teamMode
|
|
769
|
+
mcpInstall,
|
|
770
|
+
workspacePreference
|
|
708
771
|
}, null, 2));
|
|
709
772
|
return;
|
|
710
773
|
}
|
|
711
774
|
console.log("");
|
|
712
775
|
console.log(renderSetupSummary(outputValue));
|
|
713
776
|
console.log("");
|
|
714
|
-
|
|
777
|
+
if ("runtimeTarget" in result) {
|
|
778
|
+
console.log(renderInstallSummary(result));
|
|
779
|
+
}
|
|
780
|
+
else {
|
|
781
|
+
console.log("LongTable setup summary");
|
|
782
|
+
console.log(`setup path: ${result.setupTarget.path}`);
|
|
783
|
+
console.log("provider files: not installed by researcher choice");
|
|
784
|
+
}
|
|
715
785
|
console.log(`Installed skills: ${installedSkills.length}`);
|
|
716
|
-
if (
|
|
786
|
+
if (mcpInstall) {
|
|
787
|
+
console.log("");
|
|
788
|
+
console.log(renderMcpInstallSummary(mcpInstall));
|
|
789
|
+
}
|
|
790
|
+
if (surfaces === "skills_mcp_sentinel") {
|
|
717
791
|
console.log("");
|
|
718
|
-
console.log("
|
|
719
|
-
console.log("-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
console.log("
|
|
792
|
+
console.log("Background sentinel approval recorded.");
|
|
793
|
+
console.log("Hook installation remains opt-in; LongTable will not install hooks without an explicit hook command.");
|
|
794
|
+
}
|
|
795
|
+
if (workspacePreference === "create") {
|
|
796
|
+
console.log("");
|
|
797
|
+
console.log("Project workspace requested. LongTable will now run `longtable start` with research-object and gap-risk prompts.");
|
|
798
|
+
await runStart({
|
|
799
|
+
setup: result.setupTarget.path
|
|
800
|
+
});
|
|
723
801
|
}
|
|
724
802
|
}
|
|
725
803
|
finally {
|
|
@@ -733,6 +811,33 @@ function perspectiveChoices() {
|
|
|
733
811
|
description: persona.shortDescription
|
|
734
812
|
}));
|
|
735
813
|
}
|
|
814
|
+
function researchObjectChoices() {
|
|
815
|
+
return [
|
|
816
|
+
{ id: "research_question", label: "Research question", description: "The main question, problem, or contribution boundary." },
|
|
817
|
+
{ id: "theory_framework", label: "Theory framework", description: "Constructs, theory choice, or conceptual model." },
|
|
818
|
+
{ id: "measurement_instrument", label: "Measurement/instrument", description: "Variables, scales, instruments, or operationalization." },
|
|
819
|
+
{ id: "study_design", label: "Study design", description: "Methods, sample, intervention, or data collection design." },
|
|
820
|
+
{ id: "analysis_plan", label: "Analysis plan", description: "Analytic strategy, models, coding, or interpretation plan." },
|
|
821
|
+
{ id: "manuscript", label: "Manuscript", description: "Drafting, revision, voice, evidence, or submission writing." }
|
|
822
|
+
];
|
|
823
|
+
}
|
|
824
|
+
function gapRiskChoices() {
|
|
825
|
+
return [
|
|
826
|
+
{ id: "known_gap", label: "I know the gap", description: "The blocker is explicit and can be tracked directly." },
|
|
827
|
+
{ id: "suspected_tacit_assumptions", label: "I suspect tacit assumptions", description: "There may be hidden commitments or unstated premises." },
|
|
828
|
+
{ id: "diagnose", label: "Ask LongTable to diagnose it", description: "Let LongTable classify likely gaps during the session." }
|
|
829
|
+
];
|
|
830
|
+
}
|
|
831
|
+
function protectedDecisionChoices() {
|
|
832
|
+
return [
|
|
833
|
+
{ id: "theory", label: "Theory", description: "Do not let theory or construct choices settle quietly." },
|
|
834
|
+
{ id: "measurement", label: "Measurement", description: "Do not let variables, scales, or instruments settle quietly." },
|
|
835
|
+
{ id: "method", label: "Method", description: "Do not let design, sampling, or procedure choices settle quietly." },
|
|
836
|
+
{ id: "evidence_citation", label: "Evidence/citation", description: "Do not let unsupported source or citation choices settle quietly." },
|
|
837
|
+
{ id: "authorship_voice", label: "Authorship/voice", description: "Do not let writing voice or authorial judgment disappear quietly." },
|
|
838
|
+
{ id: "submission_public_sharing", label: "Submission/public sharing", description: "Do not let public-facing commitments settle quietly." }
|
|
839
|
+
];
|
|
840
|
+
}
|
|
736
841
|
function normalizePerspectiveList(value) {
|
|
737
842
|
if (!value?.trim()) {
|
|
738
843
|
return [];
|
|
@@ -747,6 +852,9 @@ async function collectProjectInterview(setup, args) {
|
|
|
747
852
|
!(typeof args.path === "string" && args.path.trim()) ||
|
|
748
853
|
!(typeof args.goal === "string" && args.goal.trim()) ||
|
|
749
854
|
typeof args.blocker !== "string" ||
|
|
855
|
+
!(typeof args["research-object"] === "string" && args["research-object"].trim()) ||
|
|
856
|
+
!(typeof args["gap-risk"] === "string" && args["gap-risk"].trim()) ||
|
|
857
|
+
!(typeof args["protected-decision"] === "string" && args["protected-decision"].trim()) ||
|
|
750
858
|
normalizePerspectiveList(typeof args.perspectives === "string" ? args.perspectives : undefined).length === 0 ||
|
|
751
859
|
!(typeof args.disagreement === "string" && args.disagreement.trim());
|
|
752
860
|
const rl = createInterface({ input, output });
|
|
@@ -762,23 +870,29 @@ async function collectProjectInterview(setup, args) {
|
|
|
762
870
|
console.log("");
|
|
763
871
|
}
|
|
764
872
|
const projectName = (typeof args.name === "string" && args.name.trim()) ||
|
|
765
|
-
(await promptText(rl, renderQuestionHeader(1,
|
|
873
|
+
(await promptText(rl, renderQuestionHeader(1, 9, "Project interview", "What should this project be called?"), true));
|
|
766
874
|
const suggestedParentDir = typeof args.path === "string" && args.path.trim()
|
|
767
875
|
? normalizeUserPath(args.path.trim())
|
|
768
876
|
: homedir();
|
|
769
877
|
const suggestedPath = resolveInteractiveProjectPath(suggestedParentDir, projectName);
|
|
770
878
|
const projectPath = (typeof args.path === "string" && args.path.trim()
|
|
771
879
|
? normalizeUserPath(args.path.trim())
|
|
772
|
-
: resolveInteractiveProjectPath((await promptText(rl, renderQuestionHeader(2,
|
|
880
|
+
: resolveInteractiveProjectPath((await promptText(rl, renderQuestionHeader(2, 9, "Project interview", `Which parent directory should contain this project?\nLongTable will create this folder:\n${suggestedPath}`), true)), projectName));
|
|
773
881
|
const currentGoal = (typeof args.goal === "string" && args.goal.trim()) ||
|
|
774
|
-
(await promptText(rl, renderQuestionHeader(3,
|
|
882
|
+
(await promptText(rl, renderQuestionHeader(3, 9, "Current session", "What are you trying to accomplish in this session?"), true));
|
|
775
883
|
const currentBlocker = (typeof args.blocker === "string" && args.blocker.trim()) ||
|
|
776
|
-
(await promptText(rl, renderQuestionHeader(4,
|
|
884
|
+
(await promptText(rl, renderQuestionHeader(4, 9, "Current session", "What is the main blocker or uncertainty right now?"), false));
|
|
885
|
+
const researchObject = (typeof args["research-object"] === "string" && args["research-object"].trim()) ||
|
|
886
|
+
await promptChoice(rl, renderQuestionHeader(5, 9, "Research object", "What kind of research object are we protecting right now?"), researchObjectChoices());
|
|
887
|
+
const gapRisk = (typeof args["gap-risk"] === "string" && args["gap-risk"].trim()) ||
|
|
888
|
+
await promptChoice(rl, renderQuestionHeader(6, 9, "Gap/tacit risk", "What is the most likely gap risk at the start of this workspace?"), gapRiskChoices());
|
|
889
|
+
const protectedDecision = (typeof args["protected-decision"] === "string" && args["protected-decision"].trim()) ||
|
|
890
|
+
await promptChoice(rl, renderQuestionHeader(7, 9, "Protected decision", "Which decision should LongTable not let you settle quietly?"), protectedDecisionChoices());
|
|
777
891
|
const requestedPerspectives = normalizePerspectiveList(typeof args.perspectives === "string" ? args.perspectives : undefined).length > 0
|
|
778
892
|
? normalizePerspectiveList(typeof args.perspectives === "string" ? args.perspectives : undefined)
|
|
779
|
-
: await promptMultiChoice(rl, renderQuestionHeader(
|
|
893
|
+
: await promptMultiChoice(rl, renderQuestionHeader(8, 9, "Perspectives", "Which perspectives do you already know you want at the table? Leave everything unchecked for auto."), perspectiveChoices());
|
|
780
894
|
const disagreementPreference = (typeof args.disagreement === "string" && args.disagreement.trim()) ||
|
|
781
|
-
(await promptChoice(rl, renderQuestionHeader(
|
|
895
|
+
(await promptChoice(rl, renderQuestionHeader(9, 9, "Disagreement", "How visible should disagreement between perspectives be in this project by default?"), [
|
|
782
896
|
{
|
|
783
897
|
id: "synthesis_only",
|
|
784
898
|
label: "Synthesis only",
|
|
@@ -800,6 +914,9 @@ async function collectProjectInterview(setup, args) {
|
|
|
800
914
|
projectPath: projectPath.trim(),
|
|
801
915
|
currentGoal: currentGoal.trim(),
|
|
802
916
|
...(currentBlocker?.trim() ? { currentBlocker: currentBlocker.trim() } : {}),
|
|
917
|
+
researchObject: researchObject.trim(),
|
|
918
|
+
gapRisk: gapRisk.trim(),
|
|
919
|
+
protectedDecision: protectedDecision.trim(),
|
|
803
920
|
requestedPerspectives,
|
|
804
921
|
disagreementPreference: disagreementPreference
|
|
805
922
|
};
|
|
@@ -813,7 +930,7 @@ function normalizePersistAnswers(raw) {
|
|
|
813
930
|
flow: raw.flow === "interview" ? "interview" : "quickstart",
|
|
814
931
|
provider: raw.provider === "claude" ? "claude" : "codex",
|
|
815
932
|
answers: {
|
|
816
|
-
field: raw.field,
|
|
933
|
+
field: raw.field?.trim() ? raw.field.trim() : "unspecified",
|
|
817
934
|
careerStage: raw.careerStage,
|
|
818
935
|
experienceLevel: raw.experienceLevel,
|
|
819
936
|
currentProjectType: "unspecified research task",
|
|
@@ -858,6 +975,11 @@ async function readPersistAnswers(args) {
|
|
|
858
975
|
throw new Error("persist-init requires either --answers-json, --stdin, or the full set of setup flags.");
|
|
859
976
|
}
|
|
860
977
|
async function runInit(args) {
|
|
978
|
+
if (!hasCompleteFlagInput(args)) {
|
|
979
|
+
console.error("`longtable init` is deprecated. Use `longtable setup` for permission-first runtime setup.");
|
|
980
|
+
await runSetup(args);
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
861
983
|
const json = args.json === true;
|
|
862
984
|
const installRuntime = args["no-install"] !== true;
|
|
863
985
|
const installPrompts = args["install-prompts"] === true;
|
|
@@ -1055,6 +1177,34 @@ function renderMcpInstallSummary(result) {
|
|
|
1055
1177
|
}
|
|
1056
1178
|
return lines.join("\n").trimEnd();
|
|
1057
1179
|
}
|
|
1180
|
+
async function installMcpForSetup(provider, args) {
|
|
1181
|
+
const serverName = typeof args.name === "string" && args.name.trim()
|
|
1182
|
+
? args.name.trim()
|
|
1183
|
+
: LONGTABLE_MCP_SERVER_NAME;
|
|
1184
|
+
const packageSpec = resolveMcpPackageSpec(args);
|
|
1185
|
+
const command = typeof args.command === "string" && args.command.trim() ? args.command.trim() : "npx";
|
|
1186
|
+
const mcpArgs = command === "npx" ? ["-y", packageSpec] : [packageSpec];
|
|
1187
|
+
const targets = [];
|
|
1188
|
+
if (provider === "codex") {
|
|
1189
|
+
const path = resolveCodexMcpConfigPath(args);
|
|
1190
|
+
const block = renderCodexMcpBlock(serverName, command, mcpArgs);
|
|
1191
|
+
const content = await writeCodexMcpConfig(path, block, serverName);
|
|
1192
|
+
targets.push({ provider, path, format: "toml", content });
|
|
1193
|
+
}
|
|
1194
|
+
if (provider === "claude") {
|
|
1195
|
+
const path = resolveClaudeMcpSettingsPath(args);
|
|
1196
|
+
const content = await writeClaudeMcpSettings(path, serverName, command, mcpArgs);
|
|
1197
|
+
targets.push({ provider, path, format: "json", content });
|
|
1198
|
+
}
|
|
1199
|
+
return {
|
|
1200
|
+
serverName,
|
|
1201
|
+
packageSpec,
|
|
1202
|
+
command,
|
|
1203
|
+
args: mcpArgs,
|
|
1204
|
+
write: true,
|
|
1205
|
+
targets
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1058
1208
|
async function runMcpSubcommand(subcommand, args) {
|
|
1059
1209
|
if (!subcommand || subcommand === "install" || subcommand === "print-config") {
|
|
1060
1210
|
const serverName = typeof args.name === "string" && args.name.trim()
|
|
@@ -1267,7 +1417,7 @@ function renderDoctorStatus(status) {
|
|
|
1267
1417
|
nextActions.push("longtable doctor --fix");
|
|
1268
1418
|
}
|
|
1269
1419
|
if (!status.setupExists) {
|
|
1270
|
-
nextActions.push("longtable
|
|
1420
|
+
nextActions.push("longtable setup --provider codex");
|
|
1271
1421
|
}
|
|
1272
1422
|
if (!status.workspace.found) {
|
|
1273
1423
|
nextActions.push("longtable start");
|
|
@@ -1359,7 +1509,7 @@ async function repairDoctorStatus(args, status) {
|
|
|
1359
1509
|
repair.removedLegacyPromptFiles = await removeCodexPromptAliases(codexPromptsDir);
|
|
1360
1510
|
}
|
|
1361
1511
|
if (!status.setupExists) {
|
|
1362
|
-
repair.skipped.push("runtime configs require
|
|
1512
|
+
repair.skipped.push("runtime configs require setup approval; run `longtable setup --provider codex` first");
|
|
1363
1513
|
return repair;
|
|
1364
1514
|
}
|
|
1365
1515
|
const setup = await loadSetupOutput(setupOverride);
|
|
@@ -2303,7 +2453,7 @@ async function runStart(args) {
|
|
|
2303
2453
|
const setupPath = typeof args.setup === "string" ? args.setup : undefined;
|
|
2304
2454
|
const existingSetup = await loadOptionalSetup(setupPath);
|
|
2305
2455
|
if (!existingSetup) {
|
|
2306
|
-
throw new Error("LongTable
|
|
2456
|
+
throw new Error("LongTable setup is missing. Run `longtable setup --provider codex` first.");
|
|
2307
2457
|
}
|
|
2308
2458
|
const interview = await collectProjectInterview(existingSetup, args);
|
|
2309
2459
|
await verifyWritableWorkspaceParent(interview.projectPath);
|
|
@@ -2312,6 +2462,9 @@ async function runStart(args) {
|
|
|
2312
2462
|
projectPath: interview.projectPath,
|
|
2313
2463
|
currentGoal: interview.currentGoal,
|
|
2314
2464
|
currentBlocker: interview.currentBlocker,
|
|
2465
|
+
researchObject: interview.researchObject,
|
|
2466
|
+
gapRisk: interview.gapRisk,
|
|
2467
|
+
protectedDecision: interview.protectedDecision,
|
|
2315
2468
|
requestedPerspectives: interview.requestedPerspectives,
|
|
2316
2469
|
disagreementPreference: interview.disagreementPreference,
|
|
2317
2470
|
setup: existingSetup
|
|
@@ -28,6 +28,9 @@ export interface LongTableSessionRecord {
|
|
|
28
28
|
projectPath: string;
|
|
29
29
|
currentGoal: string;
|
|
30
30
|
currentBlocker?: string;
|
|
31
|
+
researchObject?: string;
|
|
32
|
+
gapRisk?: string;
|
|
33
|
+
protectedDecision?: string;
|
|
31
34
|
nextAction?: string;
|
|
32
35
|
openQuestions?: string[];
|
|
33
36
|
requestedPerspectives: string[];
|
|
@@ -150,6 +153,9 @@ export declare function createOrUpdateProjectWorkspace(options: {
|
|
|
150
153
|
projectPath: string;
|
|
151
154
|
currentGoal: string;
|
|
152
155
|
currentBlocker?: string;
|
|
156
|
+
researchObject?: string;
|
|
157
|
+
gapRisk?: string;
|
|
158
|
+
protectedDecision?: string;
|
|
153
159
|
requestedPerspectives: string[];
|
|
154
160
|
disagreementPreference: ProjectDisagreementPreference;
|
|
155
161
|
setup: SetupPersistedOutput;
|
package/dist/project-session.js
CHANGED
|
@@ -99,6 +99,9 @@ function buildCurrentGuide(project, session, recentInvocations = [], pendingQues
|
|
|
99
99
|
"## 지금 초점",
|
|
100
100
|
`- 현재 목표: ${session.currentGoal}`,
|
|
101
101
|
...(session.currentBlocker ? [`- 현재 blocker: ${session.currentBlocker}`] : []),
|
|
102
|
+
...(session.researchObject ? [`- 연구 객체: ${session.researchObject}`] : []),
|
|
103
|
+
...(session.gapRisk ? [`- 공백/암묵지 위험: ${session.gapRisk}`] : []),
|
|
104
|
+
...(session.protectedDecision ? [`- 보호할 결정: ${session.protectedDecision}`] : []),
|
|
102
105
|
`- 다음 액션: ${nextAction}`,
|
|
103
106
|
`- 관점: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
104
107
|
`- disagreement: ${session.disagreementPreference}`,
|
|
@@ -148,6 +151,9 @@ function buildCurrentGuide(project, session, recentInvocations = [], pendingQues
|
|
|
148
151
|
"## Focus Now",
|
|
149
152
|
`- Current goal: ${session.currentGoal}`,
|
|
150
153
|
...(session.currentBlocker ? [`- Current blocker: ${session.currentBlocker}`] : []),
|
|
154
|
+
...(session.researchObject ? [`- Research object: ${session.researchObject}`] : []),
|
|
155
|
+
...(session.gapRisk ? [`- Gap/tacit risk: ${session.gapRisk}`] : []),
|
|
156
|
+
...(session.protectedDecision ? [`- Protected decision: ${session.protectedDecision}`] : []),
|
|
151
157
|
`- Next action: ${nextAction}`,
|
|
152
158
|
`- Perspectives: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
153
159
|
`- Disagreement: ${session.disagreementPreference}`,
|
|
@@ -335,6 +341,9 @@ function buildProjectAgentsMd(project, session) {
|
|
|
335
341
|
`- Project: ${project.projectName}`,
|
|
336
342
|
`- Current goal: ${session.currentGoal}`,
|
|
337
343
|
...(session.currentBlocker ? [`- Current blocker: ${session.currentBlocker}`] : []),
|
|
344
|
+
...(session.researchObject ? [`- Research object: ${session.researchObject}`] : []),
|
|
345
|
+
...(session.gapRisk ? [`- Gap/tacit risk: ${session.gapRisk}`] : []),
|
|
346
|
+
...(session.protectedDecision ? [`- Protected decision: ${session.protectedDecision}`] : []),
|
|
338
347
|
`- Requested perspectives: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
339
348
|
`- Disagreement visibility: ${session.disagreementPreference}`,
|
|
340
349
|
"- These instructions apply to this directory and its children."
|
|
@@ -343,9 +352,9 @@ function buildProjectAgentsMd(project, session) {
|
|
|
343
352
|
function buildStateSeed(project, session, setup) {
|
|
344
353
|
const state = createEmptyResearchState();
|
|
345
354
|
state.explicitState = {
|
|
346
|
-
field: setup.profileSeed.field,
|
|
347
|
-
careerStage: setup.profileSeed.careerStage,
|
|
348
|
-
experienceLevel: setup.profileSeed.experienceLevel,
|
|
355
|
+
field: setup.profileSeed.field ?? "unspecified",
|
|
356
|
+
careerStage: setup.profileSeed.careerStage ?? "unspecified",
|
|
357
|
+
experienceLevel: setup.profileSeed.experienceLevel ?? "advanced",
|
|
349
358
|
projectName: project.projectName,
|
|
350
359
|
disagreementPreference: session.disagreementPreference,
|
|
351
360
|
requestedPerspectives: session.requestedPerspectives
|
|
@@ -353,6 +362,9 @@ function buildStateSeed(project, session, setup) {
|
|
|
353
362
|
state.workingState = {
|
|
354
363
|
currentGoal: session.currentGoal,
|
|
355
364
|
...(session.currentBlocker ? { currentBlocker: session.currentBlocker } : {}),
|
|
365
|
+
...(session.researchObject ? { researchObject: session.researchObject } : {}),
|
|
366
|
+
...(session.gapRisk ? { gapRisk: session.gapRisk } : {}),
|
|
367
|
+
...(session.protectedDecision ? { protectedDecision: session.protectedDecision } : {}),
|
|
356
368
|
...(session.nextAction ? { nextAction: session.nextAction } : {}),
|
|
357
369
|
openQuestions: session.openQuestions ?? [],
|
|
358
370
|
activeModes: session.activeModes ?? [],
|
|
@@ -361,6 +373,9 @@ function buildStateSeed(project, session, setup) {
|
|
|
361
373
|
if (session.currentBlocker) {
|
|
362
374
|
state.openTensions.push(session.currentBlocker);
|
|
363
375
|
}
|
|
376
|
+
if (session.gapRisk) {
|
|
377
|
+
state.openTensions.push(`Gap/tacit risk: ${session.gapRisk}`);
|
|
378
|
+
}
|
|
364
379
|
if (setup.profileSeed.humanAuthorshipSignal) {
|
|
365
380
|
state.explicitState.humanAuthorshipSignal = setup.profileSeed.humanAuthorshipSignal;
|
|
366
381
|
}
|
|
@@ -384,6 +399,21 @@ function buildStateSeed(project, session, setup) {
|
|
|
384
399
|
importance: "high"
|
|
385
400
|
});
|
|
386
401
|
}
|
|
402
|
+
if (session.researchObject || session.gapRisk || session.protectedDecision) {
|
|
403
|
+
state.narrativeTraces.push({
|
|
404
|
+
id: "project-session-risk-profile",
|
|
405
|
+
timestamp: nowIso(),
|
|
406
|
+
source: "longtable-start",
|
|
407
|
+
traceType: "tension",
|
|
408
|
+
summary: [
|
|
409
|
+
session.researchObject ? `Research object: ${session.researchObject}.` : "",
|
|
410
|
+
session.gapRisk ? `Gap/tacit risk: ${session.gapRisk}.` : "",
|
|
411
|
+
session.protectedDecision ? `Protected decision: ${session.protectedDecision}.` : ""
|
|
412
|
+
].filter(Boolean).join(" "),
|
|
413
|
+
visibility: "explicit",
|
|
414
|
+
importance: "high"
|
|
415
|
+
});
|
|
416
|
+
}
|
|
387
417
|
return JSON.stringify(state, null, 2);
|
|
388
418
|
}
|
|
389
419
|
async function removeLegacyRootFiles(projectPath) {
|
|
@@ -907,10 +937,10 @@ export async function createOrUpdateProjectWorkspace(options) {
|
|
|
907
937
|
contractVersion: "workspace-v2",
|
|
908
938
|
locale,
|
|
909
939
|
globalSetupSummary: {
|
|
910
|
-
field: options.setup.profileSeed.field,
|
|
911
|
-
careerStage: options.setup.profileSeed.careerStage,
|
|
912
|
-
experienceLevel: options.setup.profileSeed.experienceLevel,
|
|
913
|
-
checkpointIntensity: options.setup.profileSeed.preferredCheckpointIntensity,
|
|
940
|
+
field: options.setup.profileSeed.field ?? "unspecified",
|
|
941
|
+
careerStage: options.setup.profileSeed.careerStage ?? "unspecified",
|
|
942
|
+
experienceLevel: options.setup.profileSeed.experienceLevel ?? "advanced",
|
|
943
|
+
checkpointIntensity: options.setup.profileSeed.preferredCheckpointIntensity ?? "balanced",
|
|
914
944
|
...(options.setup.profileSeed.humanAuthorshipSignal
|
|
915
945
|
? { humanAuthorshipSignal: options.setup.profileSeed.humanAuthorshipSignal }
|
|
916
946
|
: {}),
|
|
@@ -931,6 +961,9 @@ export async function createOrUpdateProjectWorkspace(options) {
|
|
|
931
961
|
projectPath,
|
|
932
962
|
currentGoal: options.currentGoal,
|
|
933
963
|
...(options.currentBlocker ? { currentBlocker: options.currentBlocker } : {}),
|
|
964
|
+
...(options.researchObject ? { researchObject: options.researchObject } : {}),
|
|
965
|
+
...(options.gapRisk ? { gapRisk: options.gapRisk } : {}),
|
|
966
|
+
...(options.protectedDecision ? { protectedDecision: options.protectedDecision } : {}),
|
|
934
967
|
nextAction: buildNextAction({
|
|
935
968
|
schemaVersion: 1,
|
|
936
969
|
id: sessionId,
|
|
@@ -939,6 +972,9 @@ export async function createOrUpdateProjectWorkspace(options) {
|
|
|
939
972
|
projectPath,
|
|
940
973
|
currentGoal: options.currentGoal,
|
|
941
974
|
...(options.currentBlocker ? { currentBlocker: options.currentBlocker } : {}),
|
|
975
|
+
...(options.researchObject ? { researchObject: options.researchObject } : {}),
|
|
976
|
+
...(options.gapRisk ? { gapRisk: options.gapRisk } : {}),
|
|
977
|
+
...(options.protectedDecision ? { protectedDecision: options.protectedDecision } : {}),
|
|
942
978
|
requestedPerspectives: options.requestedPerspectives,
|
|
943
979
|
disagreementPreference: options.disagreementPreference
|
|
944
980
|
}),
|
|
@@ -950,6 +986,9 @@ export async function createOrUpdateProjectWorkspace(options) {
|
|
|
950
986
|
projectPath,
|
|
951
987
|
currentGoal: options.currentGoal,
|
|
952
988
|
...(options.currentBlocker ? { currentBlocker: options.currentBlocker } : {}),
|
|
989
|
+
...(options.researchObject ? { researchObject: options.researchObject } : {}),
|
|
990
|
+
...(options.gapRisk ? { gapRisk: options.gapRisk } : {}),
|
|
991
|
+
...(options.protectedDecision ? { protectedDecision: options.protectedDecision } : {}),
|
|
953
992
|
requestedPerspectives: options.requestedPerspectives,
|
|
954
993
|
disagreementPreference: options.disagreementPreference
|
|
955
994
|
}),
|
|
@@ -964,6 +1003,9 @@ export async function createOrUpdateProjectWorkspace(options) {
|
|
|
964
1003
|
projectPath,
|
|
965
1004
|
currentGoal: options.currentGoal,
|
|
966
1005
|
...(options.currentBlocker ? { currentBlocker: options.currentBlocker } : {}),
|
|
1006
|
+
...(options.researchObject ? { researchObject: options.researchObject } : {}),
|
|
1007
|
+
...(options.gapRisk ? { gapRisk: options.gapRisk } : {}),
|
|
1008
|
+
...(options.protectedDecision ? { protectedDecision: options.protectedDecision } : {}),
|
|
967
1009
|
requestedPerspectives: options.requestedPerspectives,
|
|
968
1010
|
disagreementPreference: options.disagreementPreference
|
|
969
1011
|
}),
|
package/dist/prompt-aliases.js
CHANGED
|
@@ -33,9 +33,9 @@ function promptSpec() {
|
|
|
33
33
|
"Ask exactly one setup question at a time.",
|
|
34
34
|
"Use numbered choices when possible and include a 'None of the above' option when needed.",
|
|
35
35
|
"Do not move to the next question until the researcher answers the current one.",
|
|
36
|
-
"Quickstart covers: provider,
|
|
36
|
+
"Quickstart covers: provider, career stage, experience level, checkpoint intensity, and human authorship signal. Do not ask for research field during setup unless the researcher volunteers it.",
|
|
37
37
|
"Interview also covers: preferred entry mode, weakest domain, and panel visibility preference.",
|
|
38
|
-
"After collecting all answers, summarize the proposed setup and then output both: 1) the exact `longtable codex persist-init ... --install-skills` command and 2) a strict JSON object with keys provider, flow,
|
|
38
|
+
"After collecting all answers, summarize the proposed setup and then output both: 1) the exact `longtable codex persist-init ... --install-skills` command and 2) a strict JSON object with keys provider, flow, careerStage, experienceLevel, preferredCheckpointIntensity, and optional field, humanAuthorshipSignal, preferredEntryMode, weakestDomain, panelPreference.",
|
|
39
39
|
"If the user prefers paste-based setup, tell them they can pipe the JSON into `longtable codex persist-init --stdin --install-skills`.",
|
|
40
40
|
"If the researcher asks you to stay inside Codex, keep the conversation in numbered form and do not prematurely close.",
|
|
41
41
|
"Frame the setup like a short researcher interview, not a bare config form.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longtable/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Researcher-facing LongTable CLI",
|
|
6
6
|
"type": "module",
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@longtable/checkpoints": "0.1.
|
|
32
|
-
"@longtable/core": "0.1.
|
|
33
|
-
"@longtable/memory": "0.1.
|
|
34
|
-
"@longtable/provider-claude": "0.1.
|
|
35
|
-
"@longtable/provider-codex": "0.1.
|
|
36
|
-
"@longtable/setup": "0.1.
|
|
31
|
+
"@longtable/checkpoints": "0.1.20",
|
|
32
|
+
"@longtable/core": "0.1.20",
|
|
33
|
+
"@longtable/memory": "0.1.20",
|
|
34
|
+
"@longtable/provider-claude": "0.1.20",
|
|
35
|
+
"@longtable/provider-codex": "0.1.20",
|
|
36
|
+
"@longtable/setup": "0.1.20"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^22.10.1",
|