@longtable/cli 0.1.31 → 0.1.32
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 +16 -13
- package/dist/cli.js +71 -28
- package/dist/project-session.d.ts +84 -2
- package/dist/project-session.js +240 -6
- package/dist/prompt-aliases.js +5 -5
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -8,9 +8,9 @@ Claude skills, and future MCP surfaces remain generated adapter artifacts.
|
|
|
8
8
|
|
|
9
9
|
The basic contract is:
|
|
10
10
|
|
|
11
|
-
1.
|
|
12
|
-
2.
|
|
13
|
-
3.
|
|
11
|
+
1. approve provider/runtime support once
|
|
12
|
+
2. start each project inside the provider with `$longtable-interview`
|
|
13
|
+
3. create or resume a workspace from that interview
|
|
14
14
|
4. preserve decisions, tensions, and evidence as durable project state
|
|
15
15
|
|
|
16
16
|
## Install
|
|
@@ -26,15 +26,17 @@ config, hooks, or provider runtime files without explicit setup approval.
|
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
28
|
longtable setup --provider codex
|
|
29
|
-
|
|
30
|
-
cd "<project-path>"
|
|
29
|
+
cd "<research-folder>"
|
|
31
30
|
codex
|
|
32
31
|
```
|
|
33
32
|
|
|
33
|
+
Then invoke `$longtable-interview` inside Codex.
|
|
34
|
+
|
|
34
35
|
`longtable setup --provider codex` is the permission-first setup route. It asks
|
|
35
36
|
where LongTable may install support, which runtime surfaces it may enable, how
|
|
36
|
-
strongly it may interrupt research decisions, and whether to
|
|
37
|
-
|
|
37
|
+
strongly it may interrupt research decisions, and whether to show the
|
|
38
|
+
provider-native interview launch steps. `longtable init` remains only as a
|
|
39
|
+
deprecated compatibility alias.
|
|
38
40
|
|
|
39
41
|
Return later:
|
|
40
42
|
|
|
@@ -44,7 +46,7 @@ longtable resume
|
|
|
44
46
|
codex
|
|
45
47
|
```
|
|
46
48
|
|
|
47
|
-
## What
|
|
49
|
+
## What `$longtable-interview` Creates
|
|
48
50
|
|
|
49
51
|
```text
|
|
50
52
|
<project>/
|
|
@@ -84,7 +86,6 @@ This is how LongTable avoids turning tacit knowledge into fake certainty.
|
|
|
84
86
|
|
|
85
87
|
```bash
|
|
86
88
|
longtable setup
|
|
87
|
-
longtable start
|
|
88
89
|
longtable resume --cwd "<project-path>"
|
|
89
90
|
longtable roles
|
|
90
91
|
longtable ask --cwd "<project-path>" --prompt "..."
|
|
@@ -136,12 +137,14 @@ longtable claude install-skills
|
|
|
136
137
|
|
|
137
138
|
Codex skills include `longtable`, `longtable-panel`, and generated role-specific
|
|
138
139
|
skills such as `longtable-methods-critic`. If your Codex build exposes explicit
|
|
139
|
-
skill shortcuts, `$longtable` is the
|
|
140
|
-
|
|
140
|
+
skill shortcuts, `$longtable-interview` is the research-start entry and
|
|
141
|
+
`$longtable` is the general router. Do not depend on `/prompts`; current Codex
|
|
142
|
+
builds may reject it.
|
|
141
143
|
|
|
142
144
|
Claude Code skills include `longtable`, `longtable-panel`, and generated
|
|
143
|
-
role-specific skills such as `longtable-methods-critic`. They
|
|
144
|
-
|
|
145
|
+
role-specific skills such as `longtable-methods-critic`. They also include
|
|
146
|
+
`longtable-interview` for the First Research Shape workflow. They are adapter
|
|
147
|
+
files generated from the LongTable role registry.
|
|
145
148
|
|
|
146
149
|
## Panel Orchestration
|
|
147
150
|
|
package/dist/cli.js
CHANGED
|
@@ -43,7 +43,7 @@ const ANSI = {
|
|
|
43
43
|
green: "\u001B[32m"
|
|
44
44
|
};
|
|
45
45
|
const LONGTABLE_MCP_SERVER_NAME = "longtable-state";
|
|
46
|
-
const LONGTABLE_MCP_PACKAGE_VERSION = "0.1.
|
|
46
|
+
const LONGTABLE_MCP_PACKAGE_VERSION = "0.1.32";
|
|
47
47
|
const LONGTABLE_MCP_MARKER_START = "# LongTable state MCP START";
|
|
48
48
|
const LONGTABLE_MCP_MARKER_END = "# LongTable state MCP END";
|
|
49
49
|
function style(text, prefix) {
|
|
@@ -68,6 +68,20 @@ function renderBrandBanner(title, subtitle) {
|
|
|
68
68
|
}
|
|
69
69
|
return lines.join("\n");
|
|
70
70
|
}
|
|
71
|
+
function renderInterviewLaunchSteps(provider) {
|
|
72
|
+
const command = provider === "codex" ? "codex" : "claude";
|
|
73
|
+
return renderSectionCard("LongTable Interview", [
|
|
74
|
+
"Setup is permission and runtime calibration, not the research interview.",
|
|
75
|
+
"The first research conversation now happens inside the provider so the model can listen, reflect, and ask one natural-language follow-up at a time.",
|
|
76
|
+
"",
|
|
77
|
+
"Next:",
|
|
78
|
+
"1. cd \"<research-folder>\"",
|
|
79
|
+
`2. run \`${command}\``,
|
|
80
|
+
"3. invoke `$longtable-interview`",
|
|
81
|
+
"",
|
|
82
|
+
"The interview will create or resume `.longtable/`, build a First Research Shape, and use option UI only for the final confirmation."
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
71
85
|
function renderProgressBar(current, total) {
|
|
72
86
|
const width = 10;
|
|
73
87
|
const filled = Math.max(1, Math.round((current / total) * width));
|
|
@@ -77,11 +91,11 @@ function usage() {
|
|
|
77
91
|
return [
|
|
78
92
|
"Usage:",
|
|
79
93
|
" Run `longtable ...` in your terminal, not inside the Codex chat box.",
|
|
80
|
-
"
|
|
94
|
+
" LongTable research starts inside Codex or Claude with `$longtable-interview` after setup.",
|
|
81
95
|
"",
|
|
82
96
|
" longtable setup [--provider codex|claude] [--install-scope user|project|none] [--surfaces cli_only|skills|skills_mcp|skills_mcp_sentinel] [--intervention advisory|balanced|strong] [--checkpoint-ui off|interactive|strong] [--workspace create|later] [--project-dir <path>] [--json] [--dir <path>] [--skills-dir <path>] [--runtime-path <file>] [--setup-path <file>]",
|
|
83
97
|
" longtable init [deprecated alias for setup; full legacy flags still supported for automation]",
|
|
84
|
-
" 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]",
|
|
98
|
+
" longtable start [deprecated fallback] [--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] [--no-interview]",
|
|
85
99
|
" longtable resume [--cwd <path>] [--json]",
|
|
86
100
|
" longtable doctor [--cwd <path>] [--fix] [--json] [--codex-dir <path>] [--codex-config <path>] [--claude-dir <path>] [--codex-prompts-dir <path>] [--codex-runtime-path <file>] [--claude-runtime-path <file>]",
|
|
87
101
|
" longtable status [--cwd <path>] [--fix] [--json] [--codex-dir <path>] [--codex-config <path>] [--claude-dir <path>] [--codex-prompts-dir <path>] [--codex-runtime-path <file>] [--claude-runtime-path <file>]",
|
|
@@ -114,9 +128,9 @@ function usage() {
|
|
|
114
128
|
"",
|
|
115
129
|
"Examples:",
|
|
116
130
|
" longtable setup --provider codex",
|
|
117
|
-
"
|
|
118
|
-
" longtable
|
|
119
|
-
"
|
|
131
|
+
" cd \"<research-folder>\" && codex",
|
|
132
|
+
" $longtable-interview",
|
|
133
|
+
" longtable start --no-interview --path ~/Research/My-Project --name \"AI Adoption Meta-Analysis\" --goal \"Narrow the review question\"",
|
|
120
134
|
" longtable doctor",
|
|
121
135
|
" longtable roles",
|
|
122
136
|
" longtable ask --prompt \"연구를 시작하고 싶어. 지금 어디서부터 좁혀야 할지 모르겠어.\"",
|
|
@@ -447,13 +461,13 @@ function buildPermissionSetupChoices() {
|
|
|
447
461
|
workspace: [
|
|
448
462
|
{
|
|
449
463
|
id: "create",
|
|
450
|
-
label: "
|
|
451
|
-
description: "Why:
|
|
464
|
+
label: "Show interview launch steps",
|
|
465
|
+
description: "Why: research should start inside the provider. What you get: setup finishes with Codex/Claude + $longtable-interview steps. Tradeoff: workspace creation waits for the in-provider interview."
|
|
452
466
|
},
|
|
453
467
|
{
|
|
454
468
|
id: "later",
|
|
455
469
|
label: "No, prepare runtime only",
|
|
456
|
-
description: "Why: keeps setup short. What you get: runtime support without project state. Tradeoff: no durable research memory until `
|
|
470
|
+
description: "Why: keeps setup short. What you get: runtime support without project state. Tradeoff: no durable research memory until `$longtable-interview` creates or resumes a workspace."
|
|
457
471
|
}
|
|
458
472
|
]
|
|
459
473
|
};
|
|
@@ -575,6 +589,8 @@ async function runSetup(args) {
|
|
|
575
589
|
interventionPosture: effectiveIntervention,
|
|
576
590
|
checkpointUiMode: checkpointUi,
|
|
577
591
|
workspaceCreationPreference: workspacePreference,
|
|
592
|
+
officialStartSurface: "$longtable-interview",
|
|
593
|
+
setupPosture: "permission_first",
|
|
578
594
|
teamMode: "panel"
|
|
579
595
|
};
|
|
580
596
|
if (surfaces === "skills_mcp_sentinel") {
|
|
@@ -617,7 +633,12 @@ async function runSetup(args) {
|
|
|
617
633
|
runtime: result,
|
|
618
634
|
installedSkills: installedSkills.map((skill) => skill.name),
|
|
619
635
|
mcpInstall,
|
|
620
|
-
workspacePreference
|
|
636
|
+
workspacePreference,
|
|
637
|
+
nextStep: {
|
|
638
|
+
surface: "$longtable-interview",
|
|
639
|
+
command: provider === "codex" ? "codex" : "claude",
|
|
640
|
+
description: "Open the provider in the research folder and invoke `$longtable-interview`."
|
|
641
|
+
}
|
|
621
642
|
}, null, 2));
|
|
622
643
|
return;
|
|
623
644
|
}
|
|
@@ -646,12 +667,11 @@ async function runSetup(args) {
|
|
|
646
667
|
console.log("Background sentinel approval recorded.");
|
|
647
668
|
console.log("Hook installation remains opt-in; LongTable will not install hooks without an explicit hook command.");
|
|
648
669
|
}
|
|
670
|
+
console.log("");
|
|
671
|
+
console.log(renderInterviewLaunchSteps(provider));
|
|
649
672
|
if (workspacePreference === "create") {
|
|
650
673
|
console.log("");
|
|
651
|
-
console.log("
|
|
652
|
-
await runStart({
|
|
653
|
-
setup: result.setupTarget.path
|
|
654
|
-
});
|
|
674
|
+
console.log("Workspace launch requested. Open the provider in your research folder and run `$longtable-interview`; the interview will create `.longtable/` there.");
|
|
655
675
|
}
|
|
656
676
|
}
|
|
657
677
|
function perspectiveChoices() {
|
|
@@ -849,6 +869,7 @@ function normalizePerspectiveList(value) {
|
|
|
849
869
|
.filter(Boolean);
|
|
850
870
|
}
|
|
851
871
|
async function collectProjectInterview(setup, args) {
|
|
872
|
+
const skipResearchInterview = args["no-interview"] === true;
|
|
852
873
|
const providedPerspectives = normalizePerspectiveList(typeof args.perspectives === "string" ? args.perspectives : undefined);
|
|
853
874
|
const providedGoal = typeof args.goal === "string" && args.goal.trim() ? args.goal.trim() : undefined;
|
|
854
875
|
const providedBlocker = typeof args.blocker === "string" && args.blocker.trim() ? args.blocker.trim() : undefined;
|
|
@@ -863,11 +884,11 @@ async function collectProjectInterview(setup, args) {
|
|
|
863
884
|
: undefined;
|
|
864
885
|
const needsInteractivePrompts = !(typeof args.name === "string" && args.name.trim()) ||
|
|
865
886
|
!(typeof args.path === "string" && args.path.trim()) ||
|
|
866
|
-
!providedGoal ||
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
887
|
+
(!skipResearchInterview && (!providedGoal ||
|
|
888
|
+
!providedBlocker ||
|
|
889
|
+
!providedResearchObject ||
|
|
890
|
+
!providedGapRisk ||
|
|
891
|
+
!providedProtectedDecision));
|
|
871
892
|
if (needsInteractivePrompts) {
|
|
872
893
|
console.log("");
|
|
873
894
|
console.log(renderBrandBanner("LongTable", "Project workspace interview"));
|
|
@@ -887,15 +908,17 @@ async function collectProjectInterview(setup, args) {
|
|
|
887
908
|
const projectPath = (typeof args.path === "string" && args.path.trim()
|
|
888
909
|
? normalizeUserPath(args.path.trim())
|
|
889
910
|
: resolveInteractiveProjectPath((await promptText(renderQuestionHeader(2, 2, "Workspace", `Which parent directory should contain this project?\nLongTable will create this folder:\n${suggestedPath}`), true)), projectName));
|
|
890
|
-
const adaptive =
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
!
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
911
|
+
const adaptive = skipResearchInterview
|
|
912
|
+
? {}
|
|
913
|
+
: await collectAdaptiveStartInterview({
|
|
914
|
+
currentGoal: providedGoal,
|
|
915
|
+
currentBlocker: providedBlocker,
|
|
916
|
+
needsResearchSeed: !providedGoal ||
|
|
917
|
+
!providedBlocker ||
|
|
918
|
+
!providedResearchObject ||
|
|
919
|
+
!providedGapRisk ||
|
|
920
|
+
!providedProtectedDecision
|
|
921
|
+
});
|
|
899
922
|
const currentGoal = providedGoal ?? adaptive.currentGoal;
|
|
900
923
|
if (!currentGoal?.trim()) {
|
|
901
924
|
throw new Error("LongTable start needs a current research goal or an opening interview answer.");
|
|
@@ -2773,6 +2796,26 @@ async function runRoles(args) {
|
|
|
2773
2796
|
}
|
|
2774
2797
|
}
|
|
2775
2798
|
async function runStart(args) {
|
|
2799
|
+
const hasMinimalFallbackArgs = typeof args.name === "string" &&
|
|
2800
|
+
typeof args.path === "string" &&
|
|
2801
|
+
typeof args.goal === "string";
|
|
2802
|
+
const hasFallbackIntent = args["no-interview"] === true ||
|
|
2803
|
+
hasMinimalFallbackArgs;
|
|
2804
|
+
if (!hasFallbackIntent) {
|
|
2805
|
+
console.log(renderSectionCard("LongTable Start Has Moved", [
|
|
2806
|
+
"`longtable start` is now a fallback for automation and scripted workspace creation.",
|
|
2807
|
+
"The primary research-start experience is provider-native so LongTable can run a real interview instead of a terminal questionnaire.",
|
|
2808
|
+
"",
|
|
2809
|
+
"Use:",
|
|
2810
|
+
"1. longtable setup --provider codex",
|
|
2811
|
+
"2. cd \"<research-folder>\"",
|
|
2812
|
+
"3. codex",
|
|
2813
|
+
"4. $longtable-interview",
|
|
2814
|
+
"",
|
|
2815
|
+
"For automation, pass `--no-interview --json` with `--name`, `--path`, and `--goal`."
|
|
2816
|
+
]));
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2776
2819
|
const setupPath = typeof args.setup === "string" ? args.setup : undefined;
|
|
2777
2820
|
const existingSetup = await loadOptionalSetup(setupPath);
|
|
2778
2821
|
if (!existingSetup) {
|
|
@@ -19,6 +19,53 @@ export interface StartInterviewSession {
|
|
|
19
19
|
inferredSignals: StartInterviewSignal[];
|
|
20
20
|
summary: string;
|
|
21
21
|
}
|
|
22
|
+
export type InterviewTurnQuality = "thin" | "usable" | "rich";
|
|
23
|
+
export type InterviewDepth = "gathering_context" | "forming_first_handle" | "ready_to_summarize";
|
|
24
|
+
export interface FirstResearchShape {
|
|
25
|
+
handle: string;
|
|
26
|
+
currentGoal: string;
|
|
27
|
+
currentBlocker?: string;
|
|
28
|
+
researchObject?: string;
|
|
29
|
+
gapRisk?: string;
|
|
30
|
+
protectedDecision?: string;
|
|
31
|
+
openQuestions: string[];
|
|
32
|
+
nextAction: string;
|
|
33
|
+
confidence: "low" | "medium" | "high";
|
|
34
|
+
sourceHookId?: string;
|
|
35
|
+
confirmedAt?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface LongTableInterviewTurn {
|
|
38
|
+
id: string;
|
|
39
|
+
index: number;
|
|
40
|
+
createdAt: string;
|
|
41
|
+
question: string;
|
|
42
|
+
answer: string;
|
|
43
|
+
reflection?: string;
|
|
44
|
+
quality: InterviewTurnQuality;
|
|
45
|
+
needsFollowUp: boolean;
|
|
46
|
+
followUpQuestion?: string;
|
|
47
|
+
rationale?: string[];
|
|
48
|
+
}
|
|
49
|
+
export interface LongTableHookRun {
|
|
50
|
+
id: string;
|
|
51
|
+
kind: "longtable_interview" | "quality_probe" | "checkpoint" | "panel_decision";
|
|
52
|
+
status: "pending" | "active" | "ready_to_confirm" | "confirmed" | "deferred" | "cancelled";
|
|
53
|
+
createdAt: string;
|
|
54
|
+
updatedAt: string;
|
|
55
|
+
targetOutcome?: "first_research_handle" | string;
|
|
56
|
+
depth?: InterviewDepth;
|
|
57
|
+
provider?: ProviderKind;
|
|
58
|
+
turns?: LongTableInterviewTurn[];
|
|
59
|
+
firstResearchShape?: FirstResearchShape;
|
|
60
|
+
qualityNotes?: string[];
|
|
61
|
+
rationale?: string[];
|
|
62
|
+
linkedQuestionRecordIds?: string[];
|
|
63
|
+
linkedDecisionRecordIds?: string[];
|
|
64
|
+
}
|
|
65
|
+
export type LongTableWorkspaceState = ResearchState & {
|
|
66
|
+
hooks?: LongTableHookRun[];
|
|
67
|
+
firstResearchShape?: FirstResearchShape;
|
|
68
|
+
};
|
|
22
69
|
export interface LongTableProjectRecord {
|
|
23
70
|
schemaVersion: 1;
|
|
24
71
|
product: "LongTable";
|
|
@@ -52,6 +99,7 @@ export interface LongTableSessionRecord {
|
|
|
52
99
|
nextAction?: string;
|
|
53
100
|
openQuestions?: string[];
|
|
54
101
|
startInterview?: StartInterviewSession;
|
|
102
|
+
firstResearchShape?: FirstResearchShape;
|
|
55
103
|
requestedPerspectives: string[];
|
|
56
104
|
disagreementPreference: ProjectDisagreementPreference;
|
|
57
105
|
activeModes?: string[];
|
|
@@ -127,9 +175,43 @@ export interface LongTableWorkspaceInspection {
|
|
|
127
175
|
suggestion?: string;
|
|
128
176
|
}>;
|
|
129
177
|
}
|
|
130
|
-
export declare function loadWorkspaceState(context: LongTableProjectContext): Promise<
|
|
178
|
+
export declare function loadWorkspaceState(context: LongTableProjectContext): Promise<LongTableWorkspaceState>;
|
|
131
179
|
export declare function syncCurrentWorkspaceView(context: LongTableProjectContext): Promise<string>;
|
|
132
|
-
export declare function appendInvocationRecordToWorkspace(context: LongTableProjectContext, invocation: InvocationRecord, questions?: QuestionRecord[]): Promise<
|
|
180
|
+
export declare function appendInvocationRecordToWorkspace(context: LongTableProjectContext, invocation: InvocationRecord, questions?: QuestionRecord[]): Promise<LongTableWorkspaceState>;
|
|
181
|
+
export declare function beginLongTableInterview(options: {
|
|
182
|
+
context: LongTableProjectContext;
|
|
183
|
+
provider?: ProviderKind;
|
|
184
|
+
openingQuestion?: string;
|
|
185
|
+
seedAnswer?: string;
|
|
186
|
+
}): Promise<{
|
|
187
|
+
hook: LongTableHookRun;
|
|
188
|
+
state: LongTableWorkspaceState;
|
|
189
|
+
}>;
|
|
190
|
+
export declare function appendLongTableInterviewTurn(options: {
|
|
191
|
+
context: LongTableProjectContext;
|
|
192
|
+
hookId?: string;
|
|
193
|
+
question: string;
|
|
194
|
+
answer: string;
|
|
195
|
+
reflection?: string;
|
|
196
|
+
quality?: InterviewTurnQuality;
|
|
197
|
+
needsFollowUp?: boolean;
|
|
198
|
+
followUpQuestion?: string;
|
|
199
|
+
rationale?: string[];
|
|
200
|
+
}): Promise<{
|
|
201
|
+
hook: LongTableHookRun;
|
|
202
|
+
turn: NonNullable<LongTableHookRun["turns"]>[number];
|
|
203
|
+
state: LongTableWorkspaceState;
|
|
204
|
+
}>;
|
|
205
|
+
export declare function summarizeLongTableInterview(options: {
|
|
206
|
+
context: LongTableProjectContext;
|
|
207
|
+
hookId?: string;
|
|
208
|
+
shape: FirstResearchShape;
|
|
209
|
+
}): Promise<{
|
|
210
|
+
hook: LongTableHookRun;
|
|
211
|
+
shape: FirstResearchShape;
|
|
212
|
+
state: LongTableWorkspaceState;
|
|
213
|
+
session: LongTableSessionRecord;
|
|
214
|
+
}>;
|
|
133
215
|
export declare function listBlockingWorkspaceQuestions(context: LongTableProjectContext): Promise<QuestionRecord[]>;
|
|
134
216
|
export declare function assertWorkspaceNotBlocked(context: LongTableProjectContext): Promise<void>;
|
|
135
217
|
export declare function createWorkspaceFollowUpQuestions(options: {
|
package/dist/project-session.js
CHANGED
|
@@ -54,6 +54,9 @@ function resolveUserLocale() {
|
|
|
54
54
|
return normalizeLocale(Intl.DateTimeFormat().resolvedOptions().locale);
|
|
55
55
|
}
|
|
56
56
|
function buildFirstQuestion(session) {
|
|
57
|
+
if (session.firstResearchShape?.openQuestions?.[0]) {
|
|
58
|
+
return session.firstResearchShape.openQuestions[0];
|
|
59
|
+
}
|
|
57
60
|
return session.currentBlocker
|
|
58
61
|
? `Where does "${session.currentBlocker}" show up most concretely in the scene, material, or evidence?`
|
|
59
62
|
: `What scene, case, text, data, or draft would make "${session.currentGoal}" easiest to inspect first?`;
|
|
@@ -63,20 +66,23 @@ function buildOpenQuestions(session) {
|
|
|
63
66
|
if (session.startInterview) {
|
|
64
67
|
return [
|
|
65
68
|
firstQuestion,
|
|
66
|
-
`What
|
|
69
|
+
`What still feels hardest to name or make concrete in "${session.currentGoal}"?`
|
|
67
70
|
];
|
|
68
71
|
}
|
|
69
72
|
return session.currentBlocker
|
|
70
73
|
? [
|
|
71
74
|
firstQuestion,
|
|
72
|
-
`What would
|
|
75
|
+
`What would give "${session.currentBlocker}" a usable first research handle without forcing a final research question yet?`
|
|
73
76
|
]
|
|
74
77
|
: [
|
|
75
78
|
firstQuestion,
|
|
76
|
-
`What would
|
|
79
|
+
`What would give this project a usable first research handle without pretending the question is settled?`
|
|
77
80
|
];
|
|
78
81
|
}
|
|
79
82
|
function buildNextAction(session) {
|
|
83
|
+
if (session.firstResearchShape) {
|
|
84
|
+
return session.firstResearchShape.nextAction;
|
|
85
|
+
}
|
|
80
86
|
if (session.startInterview) {
|
|
81
87
|
return session.currentBlocker
|
|
82
88
|
? `Begin from the start-interview brief, then make "${session.currentBlocker}" concrete with one scene, source, case, or dataset.`
|
|
@@ -87,6 +93,9 @@ function buildNextAction(session) {
|
|
|
87
93
|
: "Open with your current goal in one sentence, then ask LongTable for the first concrete research move.";
|
|
88
94
|
}
|
|
89
95
|
function buildResumeHint(session) {
|
|
96
|
+
if (session.firstResearchShape) {
|
|
97
|
+
return `I want to continue from the First Research Shape: ${session.firstResearchShape.handle}.`;
|
|
98
|
+
}
|
|
90
99
|
if (session.startInterview) {
|
|
91
100
|
return session.currentBlocker
|
|
92
101
|
? `I want to continue from the LongTable start interview. The first unresolved issue is ${session.currentBlocker}.`
|
|
@@ -118,6 +127,7 @@ function buildCurrentGuide(project, session, recentInvocations = [], pendingQues
|
|
|
118
127
|
...(session.researchObject ? [`- 연구 객체: ${session.researchObject}`] : []),
|
|
119
128
|
...(session.gapRisk ? [`- 공백/암묵지 위험: ${session.gapRisk}`] : []),
|
|
120
129
|
...(session.protectedDecision ? [`- 보호할 결정: ${session.protectedDecision}`] : []),
|
|
130
|
+
...(session.firstResearchShape ? [`- First Research Shape: ${session.firstResearchShape.handle}`] : []),
|
|
121
131
|
...(session.startInterview ? [`- start interview: ${session.startInterview.summary}`] : []),
|
|
122
132
|
`- 다음 액션: ${nextAction}`,
|
|
123
133
|
`- 관점: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
@@ -149,10 +159,19 @@ function buildCurrentGuide(project, session, recentInvocations = [], pendingQues
|
|
|
149
159
|
"",
|
|
150
160
|
"## 다시 시작 문장",
|
|
151
161
|
`- "${resumeHint}"`,
|
|
162
|
+
...(session.firstResearchShape
|
|
163
|
+
? [
|
|
164
|
+
"",
|
|
165
|
+
"## First Research Shape",
|
|
166
|
+
`- Handle: ${session.firstResearchShape.handle}`,
|
|
167
|
+
`- Confidence: ${session.firstResearchShape.confidence}`,
|
|
168
|
+
...session.firstResearchShape.openQuestions.map((question) => `- Open question: ${question}`)
|
|
169
|
+
]
|
|
170
|
+
: []),
|
|
152
171
|
"",
|
|
153
172
|
"## 빠른 시작",
|
|
154
173
|
"- 이 디렉토리에서 `codex`를 엽니다.",
|
|
155
|
-
`- 첫 메시지는 보통 \`${suggestedPrompt}\` 정도면 충분합니다.`,
|
|
174
|
+
`- 첫 메시지는 보통 \`${session.firstResearchShape ? suggestedPrompt : "$longtable-interview"}\` 정도면 충분합니다.`,
|
|
156
175
|
"",
|
|
157
176
|
"## 증거 규칙",
|
|
158
177
|
"- 외부 사실이나 현재 정보는 source를 붙이거나 inference로 낮춥니다."
|
|
@@ -171,6 +190,7 @@ function buildCurrentGuide(project, session, recentInvocations = [], pendingQues
|
|
|
171
190
|
...(session.researchObject ? [`- Research object: ${session.researchObject}`] : []),
|
|
172
191
|
...(session.gapRisk ? [`- Gap/tacit risk: ${session.gapRisk}`] : []),
|
|
173
192
|
...(session.protectedDecision ? [`- Protected decision: ${session.protectedDecision}`] : []),
|
|
193
|
+
...(session.firstResearchShape ? [`- First Research Shape: ${session.firstResearchShape.handle}`] : []),
|
|
174
194
|
...(session.startInterview ? [`- Start interview: ${session.startInterview.summary}`] : []),
|
|
175
195
|
`- Next action: ${nextAction}`,
|
|
176
196
|
`- Perspectives: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
@@ -202,10 +222,19 @@ function buildCurrentGuide(project, session, recentInvocations = [], pendingQues
|
|
|
202
222
|
"",
|
|
203
223
|
"## Restart Prompt",
|
|
204
224
|
`- "${resumeHint}"`,
|
|
225
|
+
...(session.firstResearchShape
|
|
226
|
+
? [
|
|
227
|
+
"",
|
|
228
|
+
"## First Research Shape",
|
|
229
|
+
`- Handle: ${session.firstResearchShape.handle}`,
|
|
230
|
+
`- Confidence: ${session.firstResearchShape.confidence}`,
|
|
231
|
+
...session.firstResearchShape.openQuestions.map((question) => `- Open question: ${question}`)
|
|
232
|
+
]
|
|
233
|
+
: []),
|
|
205
234
|
"",
|
|
206
235
|
"## Quick Start",
|
|
207
236
|
"- Open `codex` in this directory.",
|
|
208
|
-
`- A good first message is usually \`${suggestedPrompt}\`.`,
|
|
237
|
+
`- A good first message is usually \`${session.firstResearchShape ? suggestedPrompt : "$longtable-interview"}\`.`,
|
|
209
238
|
"",
|
|
210
239
|
"## Evidence Rule",
|
|
211
240
|
"- External or current claims should carry a source link or be labeled as inference."
|
|
@@ -220,6 +249,8 @@ async function loadResearchState(stateFilePath) {
|
|
|
220
249
|
...parsed,
|
|
221
250
|
explicitState: parsed.explicitState ?? {},
|
|
222
251
|
workingState: parsed.workingState ?? {},
|
|
252
|
+
hooks: parsed.hooks ?? [],
|
|
253
|
+
...(parsed.firstResearchShape ? { firstResearchShape: parsed.firstResearchShape } : {}),
|
|
223
254
|
inferredHypotheses: parsed.inferredHypotheses ?? [],
|
|
224
255
|
openTensions: parsed.openTensions ?? [],
|
|
225
256
|
decisionLog: parsed.decisionLog ?? [],
|
|
@@ -339,13 +370,16 @@ function buildProjectAgentsMd(project, session) {
|
|
|
339
370
|
"- Treat `AGENTS.md` as runtime guidance, not as the researcher-facing resume artifact.",
|
|
340
371
|
"",
|
|
341
372
|
"## Invocation Rules",
|
|
373
|
+
"- If the user message starts with `$longtable-interview`, run the LongTable interview flow before generic research advice.",
|
|
342
374
|
"- If the user message starts with `lt `, `longtable `, `long table `, or `롱테이블 ` followed by a directive and `:`, treat it as an explicit LongTable invocation.",
|
|
343
|
-
"- Supported explicit directives are: explore, review, critique, draft, commit, panel, status, editor, reviewer, methods, theory, measurement, ethics, voice, venue.",
|
|
375
|
+
"- Supported explicit directives are: interview, explore, review, critique, draft, commit, panel, status, editor, reviewer, methods, theory, measurement, ethics, voice, venue.",
|
|
344
376
|
"- For explicit LongTable invocations, do not begin by scanning the workspace. Use the current session files first and answer as LongTable immediately.",
|
|
345
377
|
"- For general research requests in this workspace, prefer LongTable behavior before generic coding behavior.",
|
|
346
378
|
"",
|
|
347
379
|
"## Research Behavior",
|
|
348
380
|
"- Begin exploratory work with clarifying or tension questions before recommending a direction.",
|
|
381
|
+
"- For `$longtable-interview`, ask one natural-language question at a time, reflect with `LongTable hears: ...`, and avoid early reader/reviewer or theory/method/measurement classification.",
|
|
382
|
+
"- Use structured options only at the final First Research Shape confirmation or at true checkpoint boundaries.",
|
|
349
383
|
"- If you foreground role perspectives, disclose them with `LongTable consulted: ...`.",
|
|
350
384
|
"- Keep one accountable synthesis, but do not hide meaningful disagreement.",
|
|
351
385
|
...(session.disagreementPreference === "always_visible"
|
|
@@ -362,6 +396,7 @@ function buildProjectAgentsMd(project, session) {
|
|
|
362
396
|
...(session.researchObject ? [`- Research object: ${session.researchObject}`] : []),
|
|
363
397
|
...(session.gapRisk ? [`- Gap/tacit risk: ${session.gapRisk}`] : []),
|
|
364
398
|
...(session.protectedDecision ? [`- Protected decision: ${session.protectedDecision}`] : []),
|
|
399
|
+
...(session.firstResearchShape ? [`- First Research Shape: ${session.firstResearchShape.handle}`] : []),
|
|
365
400
|
...(session.startInterview ? [`- Start interview summary: ${session.startInterview.summary}`] : []),
|
|
366
401
|
`- Requested perspectives: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
367
402
|
`- Disagreement visibility: ${session.disagreementPreference}`,
|
|
@@ -390,6 +425,10 @@ function buildStateSeed(project, session, setup) {
|
|
|
390
425
|
...(session.startInterview ? { startInterview: session.startInterview } : {}),
|
|
391
426
|
...(session.resumeHint ? { resumeHint: session.resumeHint } : {})
|
|
392
427
|
};
|
|
428
|
+
if (session.firstResearchShape) {
|
|
429
|
+
state.firstResearchShape = session.firstResearchShape;
|
|
430
|
+
state.workingState.firstResearchShape = session.firstResearchShape;
|
|
431
|
+
}
|
|
393
432
|
if (session.currentBlocker) {
|
|
394
433
|
state.openTensions.push(session.currentBlocker);
|
|
395
434
|
}
|
|
@@ -477,6 +516,200 @@ export async function appendInvocationRecordToWorkspace(context, invocation, que
|
|
|
477
516
|
function createId(prefix) {
|
|
478
517
|
return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
479
518
|
}
|
|
519
|
+
function normalizeInterviewQuality(answer, quality) {
|
|
520
|
+
if (quality) {
|
|
521
|
+
return quality;
|
|
522
|
+
}
|
|
523
|
+
const trimmed = answer.trim();
|
|
524
|
+
const wordCount = trimmed.split(/\s+/).filter(Boolean).length;
|
|
525
|
+
if (trimmed.length < 12 || wordCount < 3) {
|
|
526
|
+
return "thin";
|
|
527
|
+
}
|
|
528
|
+
if (trimmed.length > 80 || wordCount >= 12) {
|
|
529
|
+
return "rich";
|
|
530
|
+
}
|
|
531
|
+
return "usable";
|
|
532
|
+
}
|
|
533
|
+
function defaultFollowUpQuestion(answer) {
|
|
534
|
+
const trimmed = answer.trim();
|
|
535
|
+
if (trimmed.length < 12) {
|
|
536
|
+
return "Say one more sentence about where this problem appears or why it matters before LongTable tries to classify it.";
|
|
537
|
+
}
|
|
538
|
+
return "What concrete scene, case, material, text, dataset, or decision would make that problem easier to inspect first?";
|
|
539
|
+
}
|
|
540
|
+
function depthForInterview(turns = []) {
|
|
541
|
+
const usableTurns = turns.filter((turn) => turn.quality !== "thin").length;
|
|
542
|
+
if (usableTurns >= 3) {
|
|
543
|
+
return "ready_to_summarize";
|
|
544
|
+
}
|
|
545
|
+
if (usableTurns >= 1) {
|
|
546
|
+
return "forming_first_handle";
|
|
547
|
+
}
|
|
548
|
+
return "gathering_context";
|
|
549
|
+
}
|
|
550
|
+
function activeInterviewHook(state, hookId) {
|
|
551
|
+
const hooks = state.hooks ?? [];
|
|
552
|
+
if (hookId) {
|
|
553
|
+
return hooks.find((hook) => hook.id === hookId);
|
|
554
|
+
}
|
|
555
|
+
return [...hooks].reverse().find((hook) => hook.kind === "longtable_interview" &&
|
|
556
|
+
(hook.status === "pending" || hook.status === "active" || hook.status === "ready_to_confirm"));
|
|
557
|
+
}
|
|
558
|
+
function upsertHook(state, hook) {
|
|
559
|
+
const hooks = state.hooks ?? [];
|
|
560
|
+
const existingIndex = hooks.findIndex((candidate) => candidate.id === hook.id);
|
|
561
|
+
const nextHooks = existingIndex >= 0
|
|
562
|
+
? hooks.map((candidate) => candidate.id === hook.id ? hook : candidate)
|
|
563
|
+
: [...hooks, hook];
|
|
564
|
+
return {
|
|
565
|
+
...state,
|
|
566
|
+
hooks: nextHooks
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
export async function beginLongTableInterview(options) {
|
|
570
|
+
const state = await loadResearchState(options.context.stateFilePath);
|
|
571
|
+
const existing = activeInterviewHook(state);
|
|
572
|
+
if (existing) {
|
|
573
|
+
return { hook: existing, state };
|
|
574
|
+
}
|
|
575
|
+
const timestamp = nowIso();
|
|
576
|
+
const hook = {
|
|
577
|
+
id: createId("hook_interview"),
|
|
578
|
+
kind: "longtable_interview",
|
|
579
|
+
status: "active",
|
|
580
|
+
createdAt: timestamp,
|
|
581
|
+
updatedAt: timestamp,
|
|
582
|
+
targetOutcome: "first_research_handle",
|
|
583
|
+
depth: "gathering_context",
|
|
584
|
+
provider: options.provider,
|
|
585
|
+
turns: [],
|
|
586
|
+
qualityNotes: [],
|
|
587
|
+
rationale: [
|
|
588
|
+
"Official LongTable research start surface is provider-native `$longtable-interview`, not the CLI start questionnaire.",
|
|
589
|
+
"The hook keeps early research ambiguity open until a first research handle can be summarized."
|
|
590
|
+
]
|
|
591
|
+
};
|
|
592
|
+
let updated = upsertHook(state, hook);
|
|
593
|
+
updated.workingState = {
|
|
594
|
+
...updated.workingState,
|
|
595
|
+
activeInterviewHookId: hook.id,
|
|
596
|
+
interviewSurface: "$longtable-interview",
|
|
597
|
+
...(options.openingQuestion ? { interviewOpeningQuestion: options.openingQuestion } : {}),
|
|
598
|
+
...(options.seedAnswer ? { interviewSeedAnswer: options.seedAnswer } : {})
|
|
599
|
+
};
|
|
600
|
+
await writeFile(options.context.stateFilePath, JSON.stringify(updated, null, 2), "utf8");
|
|
601
|
+
await syncCurrentWorkspaceView(options.context);
|
|
602
|
+
return { hook, state: updated };
|
|
603
|
+
}
|
|
604
|
+
export async function appendLongTableInterviewTurn(options) {
|
|
605
|
+
const state = await loadResearchState(options.context.stateFilePath);
|
|
606
|
+
const existing = activeInterviewHook(state, options.hookId);
|
|
607
|
+
if (!existing) {
|
|
608
|
+
throw new Error("No active LongTable interview hook was found. Run begin_interview first.");
|
|
609
|
+
}
|
|
610
|
+
const quality = normalizeInterviewQuality(options.answer, options.quality);
|
|
611
|
+
const needsFollowUp = options.needsFollowUp ?? quality === "thin";
|
|
612
|
+
const followUpQuestion = needsFollowUp
|
|
613
|
+
? options.followUpQuestion ?? defaultFollowUpQuestion(options.answer)
|
|
614
|
+
: options.followUpQuestion;
|
|
615
|
+
const timestamp = nowIso();
|
|
616
|
+
const turns = existing.turns ?? [];
|
|
617
|
+
const turn = {
|
|
618
|
+
id: createId("interview_turn"),
|
|
619
|
+
index: turns.length + 1,
|
|
620
|
+
createdAt: timestamp,
|
|
621
|
+
question: options.question.trim(),
|
|
622
|
+
answer: options.answer.trim(),
|
|
623
|
+
...(options.reflection?.trim() ? { reflection: options.reflection.trim() } : {}),
|
|
624
|
+
quality,
|
|
625
|
+
needsFollowUp,
|
|
626
|
+
...(followUpQuestion?.trim() ? { followUpQuestion: followUpQuestion.trim() } : {}),
|
|
627
|
+
...(options.rationale && options.rationale.length > 0 ? { rationale: options.rationale } : {})
|
|
628
|
+
};
|
|
629
|
+
const nextTurns = [...turns, turn];
|
|
630
|
+
const depth = depthForInterview(nextTurns);
|
|
631
|
+
const hook = {
|
|
632
|
+
...existing,
|
|
633
|
+
status: depth === "ready_to_summarize" ? "ready_to_confirm" : "active",
|
|
634
|
+
updatedAt: timestamp,
|
|
635
|
+
depth,
|
|
636
|
+
turns: nextTurns,
|
|
637
|
+
qualityNotes: [
|
|
638
|
+
...(existing.qualityNotes ?? []),
|
|
639
|
+
...(needsFollowUp ? [`Turn ${turn.index} needs follow-up: ${followUpQuestion}`] : [])
|
|
640
|
+
]
|
|
641
|
+
};
|
|
642
|
+
const updated = upsertHook(state, hook);
|
|
643
|
+
await writeFile(options.context.stateFilePath, JSON.stringify(updated, null, 2), "utf8");
|
|
644
|
+
await syncCurrentWorkspaceView(options.context);
|
|
645
|
+
return { hook, turn, state: updated };
|
|
646
|
+
}
|
|
647
|
+
export async function summarizeLongTableInterview(options) {
|
|
648
|
+
const state = await loadResearchState(options.context.stateFilePath);
|
|
649
|
+
const existing = activeInterviewHook(state, options.hookId);
|
|
650
|
+
if (!existing) {
|
|
651
|
+
throw new Error("No active LongTable interview hook was found. Run begin_interview first.");
|
|
652
|
+
}
|
|
653
|
+
const timestamp = nowIso();
|
|
654
|
+
const shape = {
|
|
655
|
+
...options.shape,
|
|
656
|
+
handle: options.shape.handle.trim(),
|
|
657
|
+
currentGoal: options.shape.currentGoal.trim(),
|
|
658
|
+
openQuestions: options.shape.openQuestions.map((question) => question.trim()).filter(Boolean),
|
|
659
|
+
nextAction: options.shape.nextAction.trim(),
|
|
660
|
+
sourceHookId: existing.id
|
|
661
|
+
};
|
|
662
|
+
const hook = {
|
|
663
|
+
...existing,
|
|
664
|
+
status: "ready_to_confirm",
|
|
665
|
+
updatedAt: timestamp,
|
|
666
|
+
depth: "ready_to_summarize",
|
|
667
|
+
firstResearchShape: shape
|
|
668
|
+
};
|
|
669
|
+
const session = {
|
|
670
|
+
...options.context.session,
|
|
671
|
+
lastUpdatedAt: timestamp,
|
|
672
|
+
currentGoal: shape.currentGoal,
|
|
673
|
+
...(shape.currentBlocker ? { currentBlocker: shape.currentBlocker } : {}),
|
|
674
|
+
...(shape.researchObject ? { researchObject: shape.researchObject } : {}),
|
|
675
|
+
...(shape.gapRisk ? { gapRisk: shape.gapRisk } : {}),
|
|
676
|
+
...(shape.protectedDecision ? { protectedDecision: shape.protectedDecision } : {}),
|
|
677
|
+
nextAction: shape.nextAction,
|
|
678
|
+
openQuestions: shape.openQuestions,
|
|
679
|
+
firstResearchShape: shape,
|
|
680
|
+
resumeHint: `I want to continue from the First Research Shape: ${shape.handle}.`
|
|
681
|
+
};
|
|
682
|
+
options.context.session = session;
|
|
683
|
+
let updated = upsertHook(state, hook);
|
|
684
|
+
updated.firstResearchShape = shape;
|
|
685
|
+
updated.workingState = {
|
|
686
|
+
...updated.workingState,
|
|
687
|
+
currentGoal: shape.currentGoal,
|
|
688
|
+
...(shape.currentBlocker ? { currentBlocker: shape.currentBlocker } : {}),
|
|
689
|
+
...(shape.researchObject ? { researchObject: shape.researchObject } : {}),
|
|
690
|
+
...(shape.gapRisk ? { gapRisk: shape.gapRisk } : {}),
|
|
691
|
+
...(shape.protectedDecision ? { protectedDecision: shape.protectedDecision } : {}),
|
|
692
|
+
openQuestions: shape.openQuestions,
|
|
693
|
+
nextAction: shape.nextAction,
|
|
694
|
+
firstResearchShape: shape
|
|
695
|
+
};
|
|
696
|
+
if (shape.currentBlocker && !updated.openTensions.includes(shape.currentBlocker)) {
|
|
697
|
+
updated.openTensions.push(shape.currentBlocker);
|
|
698
|
+
}
|
|
699
|
+
updated.narrativeTraces.push({
|
|
700
|
+
id: createId("narrative_trace"),
|
|
701
|
+
timestamp,
|
|
702
|
+
source: "$longtable-interview",
|
|
703
|
+
traceType: "judgment",
|
|
704
|
+
summary: `First Research Shape: ${shape.handle}.`,
|
|
705
|
+
visibility: "explicit",
|
|
706
|
+
importance: shape.confidence
|
|
707
|
+
});
|
|
708
|
+
await writeFile(options.context.sessionFilePath, JSON.stringify(session, null, 2), "utf8");
|
|
709
|
+
await writeFile(options.context.stateFilePath, JSON.stringify(updated, null, 2), "utf8");
|
|
710
|
+
await syncCurrentWorkspaceView(options.context);
|
|
711
|
+
return { hook, shape, state: updated, session };
|
|
712
|
+
}
|
|
480
713
|
function findQuestionForDecision(state, questionId) {
|
|
481
714
|
const pending = (state.questionLog ?? []).filter((record) => record.status === "pending");
|
|
482
715
|
if (questionId) {
|
|
@@ -1175,6 +1408,7 @@ export function renderProjectWorkspaceSummary(context) {
|
|
|
1175
1408
|
`Goal: ${context.session.currentGoal}`,
|
|
1176
1409
|
...(context.session.currentBlocker ? [`Blocker: ${context.session.currentBlocker}`] : []),
|
|
1177
1410
|
...(context.session.researchObject ? [`Working object: ${context.session.researchObject}`] : []),
|
|
1411
|
+
...(context.session.firstResearchShape ? [`First Research Shape: ${context.session.firstResearchShape.handle}`] : []),
|
|
1178
1412
|
...(context.session.startInterview ? [`Start interview: ${context.session.startInterview.summary}`] : []),
|
|
1179
1413
|
"└───────────────────────────────────────────────────────┘",
|
|
1180
1414
|
"",
|
package/dist/prompt-aliases.js
CHANGED
|
@@ -29,18 +29,18 @@ function promptSpec() {
|
|
|
29
29
|
argumentHint: "[project context or current uncertainty]",
|
|
30
30
|
body: [
|
|
31
31
|
"You are LongTable setup guidance inside Codex.",
|
|
32
|
-
"Treat `longtable init` as deprecated. Prefer `longtable setup --provider codex` for runtime permissions, then
|
|
32
|
+
"Treat `longtable init` as deprecated. Prefer `longtable setup --provider codex` for runtime permissions, then `$longtable-interview` inside Codex for the project interview.",
|
|
33
33
|
"Ask exactly one setup question at a time.",
|
|
34
34
|
"Use numbered choices and include a concise Why / What you get / Tradeoff for each option.",
|
|
35
35
|
"Do not move to the next question until the researcher answers the current one.",
|
|
36
|
-
"Runtime setup covers only: provider, install scope, runtime surfaces, intervention strength, and whether to
|
|
36
|
+
"Runtime setup covers only: provider, install scope, runtime surfaces, intervention strength, and whether to show interview launch steps.",
|
|
37
37
|
"Do not ask for field, career stage, experience level, authorship signal, weakest domain, or panel preference during runtime setup.",
|
|
38
|
-
"Project
|
|
38
|
+
"Project interview covers: the first research handle, early uncertainty, first inspectable material, and final structured confirmation.",
|
|
39
39
|
"After collecting runtime answers, summarize the proposed setup and output the exact `longtable setup --provider codex ...` command.",
|
|
40
|
-
"If the researcher is ready to create a project workspace,
|
|
40
|
+
"If the researcher is ready to create a project workspace, tell them to open Codex in the research folder and invoke `$longtable-interview`.",
|
|
41
41
|
"If the researcher asks you to stay inside Codex, keep the conversation in numbered form and do not prematurely close.",
|
|
42
42
|
"Frame setup as permission and intervention calibration, not a researcher profile interview.",
|
|
43
|
-
"Do not pretend setup is the full project-start interview. The project-start interview happens in
|
|
43
|
+
"Do not pretend setup is the full project-start interview. The project-start interview happens in `$longtable-interview`.",
|
|
44
44
|
"Treat any slash-command arguments as context for why setup is being done now."
|
|
45
45
|
]
|
|
46
46
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longtable/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.32",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Researcher-facing LongTable CLI",
|
|
6
6
|
"type": "module",
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@clack/prompts": "^1.2.0",
|
|
32
|
-
"@longtable/checkpoints": "0.1.
|
|
33
|
-
"@longtable/core": "0.1.
|
|
34
|
-
"@longtable/memory": "0.1.
|
|
35
|
-
"@longtable/provider-claude": "0.1.
|
|
36
|
-
"@longtable/provider-codex": "0.1.
|
|
37
|
-
"@longtable/setup": "0.1.
|
|
32
|
+
"@longtable/checkpoints": "0.1.32",
|
|
33
|
+
"@longtable/core": "0.1.32",
|
|
34
|
+
"@longtable/memory": "0.1.32",
|
|
35
|
+
"@longtable/provider-claude": "0.1.32",
|
|
36
|
+
"@longtable/provider-codex": "0.1.32",
|
|
37
|
+
"@longtable/setup": "0.1.32"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^22.10.1",
|