@longtable/cli 0.1.1 → 0.1.3
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 +54 -54
- package/dist/cli.js +423 -15
- package/dist/persona-router.d.ts +2 -0
- package/dist/persona-router.js +6 -0
- package/dist/prompt-aliases.js +25 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,101 +1,101 @@
|
|
|
1
1
|
# @longtable/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Long Table의 researcher-facing CLI입니다.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
이 패키지는 연구자가 아래처럼 시작할 수 있게 만드는 것이 목표입니다.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
- `longtable init`
|
|
8
|
+
- `longtable start`
|
|
9
|
+
- `longtable ask --prompt "..."`
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
```
|
|
11
|
+
긴 내부 명령이나 legacy package 이름을 알 필요 없이,
|
|
12
|
+
연구자가 `오늘 무엇이 필요한가`에서 바로 출발할 수 있게 하는 표면입니다.
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
## Install
|
|
16
15
|
|
|
17
16
|
```bash
|
|
18
|
-
npm install
|
|
19
|
-
npm run build
|
|
20
|
-
node packages/longtable/dist/cli.js --help
|
|
17
|
+
npm install -g @longtable/cli
|
|
21
18
|
```
|
|
22
19
|
|
|
23
20
|
## Recommended flow
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
### 1. Setup once
|
|
26
23
|
|
|
27
24
|
```bash
|
|
28
|
-
longtable init --
|
|
25
|
+
longtable init --flow interview
|
|
29
26
|
```
|
|
30
27
|
|
|
31
|
-
|
|
28
|
+
이 인터뷰 setup은 연구자의
|
|
29
|
+
|
|
30
|
+
- 현재 주제
|
|
31
|
+
- 현재 막힘
|
|
32
|
+
- 선호하는 첫 진입 모드
|
|
33
|
+
- 가장 많이 도전받고 싶은 영역
|
|
34
|
+
- 역할 간 의견 충돌 가시성
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
까지 저장합니다.
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
### 2. Start from today’s work
|
|
36
39
|
|
|
37
40
|
```bash
|
|
38
|
-
longtable
|
|
39
|
-
longtable review --prompt "BJET 편집자 관점에서 봐줘." --role editor
|
|
40
|
-
longtable review --prompt "방법론적으로 어디가 취약한지 말해줘." --panel --show-conflicts
|
|
41
|
+
longtable start
|
|
41
42
|
```
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
`longtable start`는 가장 단순한 진입점입니다.
|
|
45
|
+
오늘 필요한 작업을 먼저 고르고, 그 다음 자연어로 상황을 말하면 됩니다.
|
|
44
46
|
|
|
45
|
-
|
|
46
|
-
- `/prompts:longtable-explore`
|
|
47
|
-
- `/prompts:longtable-review`
|
|
48
|
-
- `/prompts:longtable-critique`
|
|
49
|
-
- `/prompts:longtable-draft`
|
|
50
|
-
- `/prompts:longtable-commit`
|
|
51
|
-
- `/prompts:longtable-status`
|
|
52
|
-
|
|
53
|
-
## Core commands
|
|
47
|
+
### 3. Or jump straight in
|
|
54
48
|
|
|
55
49
|
```bash
|
|
56
|
-
longtable
|
|
57
|
-
longtable show --json
|
|
58
|
-
longtable install --json
|
|
59
|
-
longtable explore --prompt "Help me stay exploratory."
|
|
60
|
-
longtable review --prompt "Review this claim critically."
|
|
61
|
-
longtable commit --prompt "Help me make this decision carefully."
|
|
50
|
+
longtable ask --prompt "연구를 시작하고 싶은데 어디서부터 좁혀야 할지 모르겠어."
|
|
62
51
|
```
|
|
63
52
|
|
|
64
|
-
##
|
|
65
|
-
|
|
66
|
-
Install Codex prompt aliases:
|
|
53
|
+
## Useful commands
|
|
67
54
|
|
|
68
55
|
```bash
|
|
69
|
-
longtable
|
|
56
|
+
longtable start
|
|
57
|
+
longtable roles
|
|
58
|
+
longtable ask --prompt "이 연구 아이디어를 어디서부터 열어야 할지 모르겠어."
|
|
59
|
+
longtable review --prompt "BJET 편집자 관점에서 봐줘." --role editor
|
|
60
|
+
longtable review --prompt "방법론적으로 어디가 취약한지 말해줘." --role methods_critic
|
|
61
|
+
longtable review --prompt "의견 충돌까지 보여줘." --panel --show-conflicts
|
|
62
|
+
longtable show --json
|
|
70
63
|
```
|
|
71
64
|
|
|
72
|
-
|
|
65
|
+
## What `roles` means
|
|
73
66
|
|
|
74
67
|
```bash
|
|
75
|
-
longtable
|
|
68
|
+
longtable roles
|
|
76
69
|
```
|
|
77
70
|
|
|
78
|
-
|
|
71
|
+
Long Table이 어떤 관점을 호출할 수 있는지 짧게 보여줍니다.
|
|
79
72
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
73
|
+
예:
|
|
74
|
+
|
|
75
|
+
- `editor`
|
|
76
|
+
- `reviewer`
|
|
77
|
+
- `methods_critic`
|
|
78
|
+
- `voice_keeper`
|
|
83
79
|
|
|
84
|
-
|
|
80
|
+
기본값은 하나의 Long Table synthesis이지만, 필요하면 panel과 conflict도 드러낼 수 있습니다.
|
|
81
|
+
|
|
82
|
+
## Codex integration
|
|
83
|
+
|
|
84
|
+
Long Table은 Codex prompt file 설치도 지원합니다.
|
|
85
85
|
|
|
86
86
|
```bash
|
|
87
|
+
longtable codex install-prompts
|
|
87
88
|
longtable codex status
|
|
88
89
|
```
|
|
89
90
|
|
|
90
|
-
|
|
91
|
+
하지만 이 경로는 현재 `실험적`입니다.
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
longtable
|
|
94
|
-
```
|
|
93
|
+
- Codex 버전/빌드에 따라 prompt file이 slash command로 바로 노출되지 않을 수 있습니다.
|
|
94
|
+
- 그래서 기본 사용자 경로는 `/prompts:...`가 아니라 `longtable start`와 `longtable ask`입니다.
|
|
95
95
|
|
|
96
96
|
## Why this package exists
|
|
97
97
|
|
|
98
|
-
Long Table
|
|
99
|
-
`Diverga
|
|
98
|
+
Long Table은 제품명입니다.
|
|
99
|
+
`Diverga`는 아직 일부 하위 패키지와 runtime path에서만 남아 있는 호환성 레이어입니다.
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
이 패키지는 연구자가 `longtable`만 알면 되게 하기 위해 존재합니다.
|
package/dist/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ import { buildProviderChoices, buildQuickSetupFlow, createPersistedSetupOutput,
|
|
|
7
7
|
import { buildCodexThinWrappedPrompt, runCodexThinWrapper } from "@diverga/provider-codex";
|
|
8
8
|
import { installCodexPromptAliases, listInstalledCodexPromptAliases, removeCodexPromptAliases, resolveCodexPromptsDir } from "./prompt-aliases.js";
|
|
9
9
|
import { buildPersonaGuidance } from "./persona-router.js";
|
|
10
|
+
import { PERSONA_DEFINITIONS } from "./personas.js";
|
|
10
11
|
const VALID_MODES = new Set([
|
|
11
12
|
"explore",
|
|
12
13
|
"review",
|
|
@@ -27,9 +28,12 @@ const VALID_STAGES = new Set([
|
|
|
27
28
|
function usage() {
|
|
28
29
|
return [
|
|
29
30
|
"Usage:",
|
|
30
|
-
" longtable init [--provider codex|claude] [--field <field>] [--career-stage <stage>] [--experience novice|intermediate|advanced] [--project-type <type>] [--checkpoint low|balanced|high] [--authorship-signal <text>] [--json] [--no-install] [--install-prompts]",
|
|
31
|
+
" longtable init [--flow quickstart|interview] [--provider codex|claude] [--field <field>] [--career-stage <stage>] [--experience novice|intermediate|advanced] [--project-type <type>] [--checkpoint low|balanced|high] [--authorship-signal <text>] [--topic <text>] [--blocker <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]",
|
|
32
|
+
" longtable start [--prompt <text>] [--setup <path>] [--cwd <path>] [--print] [--json]",
|
|
33
|
+
" longtable roles [--json]",
|
|
31
34
|
" longtable show [--json] [--path <file>]",
|
|
32
35
|
" longtable install [--json] [--path <file>] [--runtime-path <file>]",
|
|
36
|
+
" longtable ask [--prompt <text>] [--print] [--json] [--setup <path>] [--cwd <path>]",
|
|
33
37
|
" 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>]",
|
|
34
38
|
" longtable codex persist-init [--answers-json <json> | --stdin | full setup flags] [--install-prompts] [--json]",
|
|
35
39
|
" longtable codex install-prompts [--dir <path>]",
|
|
@@ -37,7 +41,10 @@ function usage() {
|
|
|
37
41
|
" longtable codex status [--dir <path>] [--json]",
|
|
38
42
|
"",
|
|
39
43
|
"Examples:",
|
|
40
|
-
" longtable init --install-prompts",
|
|
44
|
+
" longtable init --flow interview --install-prompts",
|
|
45
|
+
" longtable start",
|
|
46
|
+
" longtable roles",
|
|
47
|
+
" longtable ask --prompt \"연구를 시작하고 싶어. 지금 어디서부터 좁혀야 할지 모르겠어.\"",
|
|
41
48
|
" longtable review --prompt \"Review this claim critically.\" --panel --show-conflicts",
|
|
42
49
|
" longtable review --role editor --prompt \"BJET 편집자 관점에서 봐줘.\"",
|
|
43
50
|
" printf '{\"provider\":\"codex\",...}' | longtable codex persist-init --stdin --install-prompts",
|
|
@@ -49,7 +56,7 @@ function parseArgs(argv) {
|
|
|
49
56
|
const values = {};
|
|
50
57
|
let subcommand = maybeSubcommand;
|
|
51
58
|
const modeCommand = command && VALID_MODES.has(command);
|
|
52
|
-
const directCommand = command && ["init", "show", "install", "codex"].includes(command);
|
|
59
|
+
const directCommand = command && ["init", "start", "roles", "show", "install", "codex", "ask"].includes(command);
|
|
53
60
|
let startIndex = 1;
|
|
54
61
|
if (modeCommand) {
|
|
55
62
|
subcommand = undefined;
|
|
@@ -91,6 +98,53 @@ function renderChoices(choices) {
|
|
|
91
98
|
.map((choice, index) => `${index + 1}. ${choice.label} — ${choice.description}`)
|
|
92
99
|
.join("\n");
|
|
93
100
|
}
|
|
101
|
+
function buildSetupFlowChoices() {
|
|
102
|
+
return [
|
|
103
|
+
{
|
|
104
|
+
id: "quickstart",
|
|
105
|
+
label: "Quickstart",
|
|
106
|
+
description: "Minimal setup for the fastest first win."
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: "interview",
|
|
110
|
+
label: "Interview",
|
|
111
|
+
description: "A more detailed researcher profile interview for better first guidance."
|
|
112
|
+
}
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
function renderSetupHeader(flow) {
|
|
116
|
+
const title = flow === "interview" ? "Long Table Setup Interview" : "Long Table Quickstart";
|
|
117
|
+
const subtitle = flow === "interview"
|
|
118
|
+
? "We will ask about your research persona, current topic, blocker, and preferred kind of challenge."
|
|
119
|
+
: "We will capture the minimum profile needed to start using Long Table.";
|
|
120
|
+
return [
|
|
121
|
+
"┌──────────────────────────────────────────────┐",
|
|
122
|
+
`│ ${title.padEnd(44, " ")}│`,
|
|
123
|
+
"└──────────────────────────────────────────────┘",
|
|
124
|
+
subtitle
|
|
125
|
+
].join("\n");
|
|
126
|
+
}
|
|
127
|
+
function renderQuestionHeader(index, total, section, prompt) {
|
|
128
|
+
return [``, `[${index}/${total}] ${section}`, prompt].join("\n");
|
|
129
|
+
}
|
|
130
|
+
function questionSection(questionId) {
|
|
131
|
+
if (questionId === "field" || questionId === "careerStage" || questionId === "experienceLevel") {
|
|
132
|
+
return "Researcher profile";
|
|
133
|
+
}
|
|
134
|
+
if (questionId === "currentProjectType" || questionId === "currentResearchTopic" || questionId === "currentBlocker") {
|
|
135
|
+
return "Current work";
|
|
136
|
+
}
|
|
137
|
+
if (questionId === "preferredCheckpointIntensity" || questionId === "preferredEntryMode") {
|
|
138
|
+
return "Interaction style";
|
|
139
|
+
}
|
|
140
|
+
if (questionId === "weakestDomain" || questionId === "panelPreference") {
|
|
141
|
+
return "How Long Table should challenge you";
|
|
142
|
+
}
|
|
143
|
+
return "Authorship and voice";
|
|
144
|
+
}
|
|
145
|
+
function formatModeLabel(mode) {
|
|
146
|
+
return `${mode[0].toUpperCase()}${mode.slice(1)}`;
|
|
147
|
+
}
|
|
94
148
|
function moveCursorUp(lines) {
|
|
95
149
|
return lines > 0 ? `\u001B[${lines}A` : "";
|
|
96
150
|
}
|
|
@@ -125,6 +179,18 @@ async function promptChoiceByNumber(rl, prompt, choices) {
|
|
|
125
179
|
return choice.id;
|
|
126
180
|
}
|
|
127
181
|
}
|
|
182
|
+
async function promptText(rl, prompt, required) {
|
|
183
|
+
while (true) {
|
|
184
|
+
const answer = (await rl.question(`${prompt}\n> `)).trim();
|
|
185
|
+
if (!required) {
|
|
186
|
+
return answer || undefined;
|
|
187
|
+
}
|
|
188
|
+
if (answer) {
|
|
189
|
+
return answer;
|
|
190
|
+
}
|
|
191
|
+
console.log("This answer cannot be empty.");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
128
194
|
async function promptChoiceWithArrows(rl, prompt, choices) {
|
|
129
195
|
const stream = input;
|
|
130
196
|
if (!stream.isTTY || !output.isTTY) {
|
|
@@ -194,10 +260,59 @@ async function promptChoiceWithArrows(rl, prompt, choices) {
|
|
|
194
260
|
async function promptChoice(rl, prompt, choices) {
|
|
195
261
|
return promptChoiceWithArrows(rl, prompt, choices);
|
|
196
262
|
}
|
|
263
|
+
async function promptStartAction(rl, blocker) {
|
|
264
|
+
return (await promptChoice(rl, blocker?.trim()
|
|
265
|
+
? `What do you want to do with this first?\nCurrent blocker: ${blocker.trim()}`
|
|
266
|
+
: "What do you want Long Table to help you do first?", [
|
|
267
|
+
{
|
|
268
|
+
id: "explore",
|
|
269
|
+
label: "Open the problem",
|
|
270
|
+
description: "Start with questions, tensions, and a clearer research direction."
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
id: "review",
|
|
274
|
+
label: "Review something",
|
|
275
|
+
description: "Critically inspect a claim, outline, or draft."
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: "critique",
|
|
279
|
+
label: "Challenge me hard",
|
|
280
|
+
description: "Push back, stress-test assumptions, and surface hidden risks."
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
id: "editor",
|
|
284
|
+
label: "Journal editor view",
|
|
285
|
+
description: "See how an editor might judge framing, fit, and contribution."
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: "methods",
|
|
289
|
+
label: "Methods check",
|
|
290
|
+
description: "Focus on design fit, defensibility, and methodological weakness."
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
id: "panel",
|
|
294
|
+
label: "Show disagreement",
|
|
295
|
+
description: "Let multiple roles disagree instead of forcing one answer."
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
id: "status",
|
|
299
|
+
label: "Check my setup",
|
|
300
|
+
description: "See what Long Table knows and what is installed."
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
id: "roles",
|
|
304
|
+
label: "What roles exist?",
|
|
305
|
+
description: "See what perspectives Long Table can bring into the conversation."
|
|
306
|
+
}
|
|
307
|
+
]));
|
|
308
|
+
}
|
|
197
309
|
function hasCompleteFlagInput(args) {
|
|
198
310
|
const required = ["provider", "field", "career-stage", "experience", "project-type", "checkpoint"];
|
|
199
311
|
return required.every((key) => typeof args[key] === "string" && String(args[key]).trim().length > 0);
|
|
200
312
|
}
|
|
313
|
+
function resolveSetupFlow(args) {
|
|
314
|
+
return String(args.flow) === "interview" ? "interview" : "quickstart";
|
|
315
|
+
}
|
|
201
316
|
function toSetupAnswers(args) {
|
|
202
317
|
return {
|
|
203
318
|
field: String(args.field),
|
|
@@ -207,19 +322,43 @@ function toSetupAnswers(args) {
|
|
|
207
322
|
preferredCheckpointIntensity: String(args.checkpoint),
|
|
208
323
|
humanAuthorshipSignal: typeof args["authorship-signal"] === "string" && args["authorship-signal"].trim().length > 0
|
|
209
324
|
? args["authorship-signal"].trim()
|
|
325
|
+
: undefined,
|
|
326
|
+
currentResearchTopic: typeof args.topic === "string" && args.topic.trim().length > 0 ? args.topic.trim() : undefined,
|
|
327
|
+
currentBlocker: typeof args.blocker === "string" && args.blocker.trim().length > 0 ? args.blocker.trim() : undefined,
|
|
328
|
+
preferredEntryMode: typeof args["entry-mode"] === "string" && VALID_MODES.has(String(args["entry-mode"]))
|
|
329
|
+
? String(args["entry-mode"])
|
|
330
|
+
: undefined,
|
|
331
|
+
weakestDomain: typeof args["weakest-domain"] === "string"
|
|
332
|
+
? String(args["weakest-domain"])
|
|
333
|
+
: undefined,
|
|
334
|
+
panelPreference: typeof args["panel-preference"] === "string"
|
|
335
|
+
? String(args["panel-preference"])
|
|
210
336
|
: undefined
|
|
211
337
|
};
|
|
212
338
|
}
|
|
213
339
|
async function collectInteractiveAnswers() {
|
|
214
340
|
const rl = createInterface({ input, output });
|
|
215
341
|
try {
|
|
342
|
+
const flow = (await promptChoice(rl, "How would you like to set up Long Table?", buildSetupFlowChoices()));
|
|
343
|
+
console.log("");
|
|
344
|
+
console.log(renderSetupHeader(flow));
|
|
345
|
+
console.log("");
|
|
216
346
|
const provider = await promptChoice(rl, "Which provider do you want to configure?", buildProviderChoices());
|
|
217
347
|
const answers = {};
|
|
218
|
-
|
|
219
|
-
|
|
348
|
+
const questions = buildQuickSetupFlow(flow);
|
|
349
|
+
for (let index = 0; index < questions.length; index += 1) {
|
|
350
|
+
const question = questions[index];
|
|
351
|
+
const prompt = renderQuestionHeader(index + 1, questions.length, questionSection(question.id), question.prompt);
|
|
352
|
+
let value;
|
|
353
|
+
if (question.kind === "text") {
|
|
354
|
+
value = await promptText(rl, prompt, question.required);
|
|
355
|
+
}
|
|
356
|
+
else if (question.choices) {
|
|
357
|
+
value = await promptChoice(rl, prompt, question.choices);
|
|
358
|
+
}
|
|
359
|
+
if (!value) {
|
|
220
360
|
continue;
|
|
221
361
|
}
|
|
222
|
-
const value = await promptChoice(rl, question.prompt, question.choices);
|
|
223
362
|
if (question.id === "field")
|
|
224
363
|
answers.field = value;
|
|
225
364
|
if (question.id === "careerStage")
|
|
@@ -234,8 +373,19 @@ async function collectInteractiveAnswers() {
|
|
|
234
373
|
if (question.id === "humanAuthorshipSignal" && value !== "other") {
|
|
235
374
|
answers.humanAuthorshipSignal = value;
|
|
236
375
|
}
|
|
376
|
+
if (question.id === "currentResearchTopic")
|
|
377
|
+
answers.currentResearchTopic = value;
|
|
378
|
+
if (question.id === "currentBlocker")
|
|
379
|
+
answers.currentBlocker = value;
|
|
380
|
+
if (question.id === "preferredEntryMode")
|
|
381
|
+
answers.preferredEntryMode = value;
|
|
382
|
+
if (question.id === "weakestDomain")
|
|
383
|
+
answers.weakestDomain = value;
|
|
384
|
+
if (question.id === "panelPreference")
|
|
385
|
+
answers.panelPreference = value;
|
|
237
386
|
}
|
|
238
387
|
return {
|
|
388
|
+
flow,
|
|
239
389
|
provider,
|
|
240
390
|
answers: answers
|
|
241
391
|
};
|
|
@@ -246,6 +396,7 @@ async function collectInteractiveAnswers() {
|
|
|
246
396
|
}
|
|
247
397
|
function normalizePersistAnswers(raw) {
|
|
248
398
|
return {
|
|
399
|
+
flow: raw.flow === "interview" ? "interview" : "quickstart",
|
|
249
400
|
provider: raw.provider === "claude" ? "claude" : "codex",
|
|
250
401
|
answers: {
|
|
251
402
|
field: raw.field,
|
|
@@ -255,13 +406,32 @@ function normalizePersistAnswers(raw) {
|
|
|
255
406
|
preferredCheckpointIntensity: raw.preferredCheckpointIntensity,
|
|
256
407
|
...(raw.humanAuthorshipSignal?.trim()
|
|
257
408
|
? { humanAuthorshipSignal: raw.humanAuthorshipSignal.trim() }
|
|
409
|
+
: {}),
|
|
410
|
+
...(raw.currentResearchTopic?.trim()
|
|
411
|
+
? { currentResearchTopic: raw.currentResearchTopic.trim() }
|
|
412
|
+
: {}),
|
|
413
|
+
...(raw.currentBlocker?.trim()
|
|
414
|
+
? { currentBlocker: raw.currentBlocker.trim() }
|
|
415
|
+
: {}),
|
|
416
|
+
...(raw.preferredEntryMode
|
|
417
|
+
? { preferredEntryMode: raw.preferredEntryMode }
|
|
418
|
+
: {}),
|
|
419
|
+
...(raw.weakestDomain
|
|
420
|
+
? { weakestDomain: raw.weakestDomain }
|
|
421
|
+
: {}),
|
|
422
|
+
...(raw.panelPreference
|
|
423
|
+
? { panelPreference: raw.panelPreference }
|
|
258
424
|
: {})
|
|
259
425
|
}
|
|
260
426
|
};
|
|
261
427
|
}
|
|
262
428
|
async function readPersistAnswers(args) {
|
|
263
429
|
if (typeof args["answers-json"] === "string") {
|
|
264
|
-
|
|
430
|
+
const normalized = normalizePersistAnswers(JSON.parse(args["answers-json"]));
|
|
431
|
+
return {
|
|
432
|
+
...normalized,
|
|
433
|
+
flow: typeof args.flow === "string" ? resolveSetupFlow(args) : normalized.flow
|
|
434
|
+
};
|
|
265
435
|
}
|
|
266
436
|
if (args.stdin === true) {
|
|
267
437
|
const raw = readFileSync(0, "utf8").trim();
|
|
@@ -272,6 +442,7 @@ async function readPersistAnswers(args) {
|
|
|
272
442
|
}
|
|
273
443
|
if (hasCompleteFlagInput(args)) {
|
|
274
444
|
return {
|
|
445
|
+
flow: resolveSetupFlow(args),
|
|
275
446
|
provider: String(args.provider) === "claude" ? "claude" : "codex",
|
|
276
447
|
answers: toSetupAnswers(args)
|
|
277
448
|
};
|
|
@@ -285,13 +456,14 @@ async function runInit(args) {
|
|
|
285
456
|
const customPath = typeof args.path === "string" ? args.path : undefined;
|
|
286
457
|
const runtimePath = typeof args["runtime-path"] === "string" ? args["runtime-path"] : undefined;
|
|
287
458
|
const promptsDir = typeof args.dir === "string" ? args.dir : undefined;
|
|
288
|
-
const { provider, answers } = hasCompleteFlagInput(args)
|
|
459
|
+
const { flow, provider, answers } = hasCompleteFlagInput(args)
|
|
289
460
|
? {
|
|
461
|
+
flow: resolveSetupFlow(args),
|
|
290
462
|
provider: String(args.provider) === "claude" ? "claude" : "codex",
|
|
291
463
|
answers: toSetupAnswers(args)
|
|
292
464
|
}
|
|
293
465
|
: await collectInteractiveAnswers();
|
|
294
|
-
const outputValue = createPersistedSetupOutput(answers, provider);
|
|
466
|
+
const outputValue = createPersistedSetupOutput(answers, provider, flow);
|
|
295
467
|
const result = await saveSetupAndRuntimeConfig(outputValue, {
|
|
296
468
|
setupPath: customPath,
|
|
297
469
|
runtimePath
|
|
@@ -311,10 +483,27 @@ async function runInit(args) {
|
|
|
311
483
|
}
|
|
312
484
|
if (installedPrompts.length > 0) {
|
|
313
485
|
console.log("");
|
|
314
|
-
console.log("Installed Codex prompt
|
|
486
|
+
console.log("Installed Codex prompt files:");
|
|
315
487
|
for (const prompt of installedPrompts) {
|
|
316
488
|
console.log(`- /prompts:${prompt.name}`);
|
|
317
489
|
}
|
|
490
|
+
console.log(" Note: whether Codex exposes these as slash commands depends on your Codex build.");
|
|
491
|
+
}
|
|
492
|
+
if (provider === "codex") {
|
|
493
|
+
console.log("");
|
|
494
|
+
console.log("Next step:");
|
|
495
|
+
console.log("- Start here: `longtable start`.");
|
|
496
|
+
console.log("- If you want a direct natural-language entry: `longtable ask --prompt \"...\"`.");
|
|
497
|
+
console.log("- Codex prompt files are available as an experimental integration, not the primary path.");
|
|
498
|
+
if (answers.currentBlocker) {
|
|
499
|
+
console.log(`- Suggested first message: ${answers.currentBlocker}`);
|
|
500
|
+
}
|
|
501
|
+
else if (answers.currentResearchTopic) {
|
|
502
|
+
console.log(`- Suggested first message: Help me open the problem around ${answers.currentResearchTopic}.`);
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
console.log("- Suggested first message: I want to start my research and need help opening the problem.");
|
|
506
|
+
}
|
|
318
507
|
}
|
|
319
508
|
}
|
|
320
509
|
async function runShow(args) {
|
|
@@ -337,8 +526,8 @@ async function runInstall(args) {
|
|
|
337
526
|
console.log(renderInstallSummary(result));
|
|
338
527
|
}
|
|
339
528
|
async function runCodexPersistInit(args) {
|
|
340
|
-
const { provider, answers } = await readPersistAnswers(args);
|
|
341
|
-
const outputValue = createPersistedSetupOutput(answers, provider);
|
|
529
|
+
const { flow, provider, answers } = await readPersistAnswers(args);
|
|
530
|
+
const outputValue = createPersistedSetupOutput(answers, provider, flow);
|
|
342
531
|
const result = await saveSetupAndRuntimeConfig(outputValue, {
|
|
343
532
|
setupPath: typeof args.path === "string" ? args.path : undefined,
|
|
344
533
|
runtimePath: typeof args["runtime-path"] === "string" ? args["runtime-path"] : undefined
|
|
@@ -360,10 +549,27 @@ async function runCodexPersistInit(args) {
|
|
|
360
549
|
console.log(renderInstallSummary(result));
|
|
361
550
|
if (installedPrompts.length > 0) {
|
|
362
551
|
console.log("");
|
|
363
|
-
console.log("Installed Codex prompt
|
|
552
|
+
console.log("Installed Codex prompt files:");
|
|
364
553
|
for (const prompt of installedPrompts) {
|
|
365
554
|
console.log(`- /prompts:${prompt.name}`);
|
|
366
555
|
}
|
|
556
|
+
console.log(" Note: whether Codex exposes these as slash commands depends on your Codex build.");
|
|
557
|
+
}
|
|
558
|
+
if (provider === "codex") {
|
|
559
|
+
console.log("");
|
|
560
|
+
console.log("Next step:");
|
|
561
|
+
console.log("- Start here: `longtable start`.");
|
|
562
|
+
console.log("- If you want a direct natural-language entry: `longtable ask --prompt \"...\"`.");
|
|
563
|
+
console.log("- Codex prompt files are available as an experimental integration, not the primary path.");
|
|
564
|
+
if (answers.currentBlocker) {
|
|
565
|
+
console.log(`- Suggested first message: ${answers.currentBlocker}`);
|
|
566
|
+
}
|
|
567
|
+
else if (answers.currentResearchTopic) {
|
|
568
|
+
console.log(`- Suggested first message: Help me think through ${answers.currentResearchTopic}.`);
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
console.log("- Suggested first message: I want to start my research and I am not sure where to open the problem.");
|
|
572
|
+
}
|
|
367
573
|
}
|
|
368
574
|
}
|
|
369
575
|
async function resolvePrompt(prompt) {
|
|
@@ -381,6 +587,57 @@ async function resolvePrompt(prompt) {
|
|
|
381
587
|
rl.close();
|
|
382
588
|
}
|
|
383
589
|
}
|
|
590
|
+
function inferModeFromPrompt(prompt) {
|
|
591
|
+
const normalized = prompt.toLowerCase();
|
|
592
|
+
if (normalized.includes("status") ||
|
|
593
|
+
normalized.includes("설정") ||
|
|
594
|
+
normalized.includes("상태") ||
|
|
595
|
+
normalized.includes("롱테이블 상태")) {
|
|
596
|
+
return "status";
|
|
597
|
+
}
|
|
598
|
+
if (normalized.includes("패널") ||
|
|
599
|
+
normalized.includes("의견 충돌") ||
|
|
600
|
+
normalized.includes("conflict") ||
|
|
601
|
+
normalized.includes("disagree") ||
|
|
602
|
+
normalized.includes("panel")) {
|
|
603
|
+
return "panel";
|
|
604
|
+
}
|
|
605
|
+
if (normalized.includes("결정") ||
|
|
606
|
+
normalized.includes("고를") ||
|
|
607
|
+
normalized.includes("선택") ||
|
|
608
|
+
normalized.includes("commit")) {
|
|
609
|
+
return "commit";
|
|
610
|
+
}
|
|
611
|
+
if (normalized.includes("초안") ||
|
|
612
|
+
normalized.includes("써줘") ||
|
|
613
|
+
normalized.includes("문단") ||
|
|
614
|
+
normalized.includes("draft") ||
|
|
615
|
+
normalized.includes("write")) {
|
|
616
|
+
return "draft";
|
|
617
|
+
}
|
|
618
|
+
if (normalized.includes("비판") ||
|
|
619
|
+
normalized.includes("반론") ||
|
|
620
|
+
normalized.includes("critique") ||
|
|
621
|
+
normalized.includes("challenge")) {
|
|
622
|
+
return "critique";
|
|
623
|
+
}
|
|
624
|
+
if (normalized.includes("검토") ||
|
|
625
|
+
normalized.includes("review") ||
|
|
626
|
+
normalized.includes("편집자") ||
|
|
627
|
+
normalized.includes("리뷰어") ||
|
|
628
|
+
normalized.includes("judge")) {
|
|
629
|
+
return "review";
|
|
630
|
+
}
|
|
631
|
+
return "explore";
|
|
632
|
+
}
|
|
633
|
+
async function loadOptionalSetup(path) {
|
|
634
|
+
try {
|
|
635
|
+
return await loadSetupOutput(path);
|
|
636
|
+
}
|
|
637
|
+
catch {
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
384
641
|
async function runModeCommand(mode, args) {
|
|
385
642
|
const prompt = await resolvePrompt(typeof args.prompt === "string" ? args.prompt : undefined);
|
|
386
643
|
if (!prompt) {
|
|
@@ -390,10 +647,16 @@ async function runModeCommand(mode, args) {
|
|
|
390
647
|
if (stage && !VALID_STAGES.has(stage)) {
|
|
391
648
|
throw new Error(`Invalid stage: ${stage}`);
|
|
392
649
|
}
|
|
650
|
+
const setup = await loadOptionalSetup(typeof args.setup === "string" ? args.setup : undefined);
|
|
651
|
+
const panelPreference = setup?.profileSeed.panelPreference;
|
|
652
|
+
const panelRequested = args.panel === true ||
|
|
653
|
+
panelPreference === "always_visible" ||
|
|
654
|
+
(panelPreference === "show_on_conflict" && args["show-conflicts"] === true);
|
|
393
655
|
const { guidedPrompt } = buildPersonaGuidance({
|
|
656
|
+
mode,
|
|
394
657
|
prompt,
|
|
395
658
|
roleFlag: typeof args.role === "string" ? args.role : undefined,
|
|
396
|
-
panel:
|
|
659
|
+
panel: panelRequested,
|
|
397
660
|
showConflicts: args["show-conflicts"] === true,
|
|
398
661
|
showDeliberation: args["show-deliberation"] === true
|
|
399
662
|
});
|
|
@@ -418,11 +681,139 @@ async function runModeCommand(mode, args) {
|
|
|
418
681
|
});
|
|
419
682
|
exit(exitCode);
|
|
420
683
|
}
|
|
684
|
+
async function runAsk(args) {
|
|
685
|
+
const prompt = await resolvePrompt(typeof args.prompt === "string" ? args.prompt : undefined);
|
|
686
|
+
if (!prompt) {
|
|
687
|
+
throw new Error("A prompt is required.");
|
|
688
|
+
}
|
|
689
|
+
const inferred = inferModeFromPrompt(prompt);
|
|
690
|
+
if (inferred === "status") {
|
|
691
|
+
await runCodexSubcommand("status", args);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
const mode = inferred === "panel" ? "review" : inferred;
|
|
695
|
+
const delegatedArgs = {
|
|
696
|
+
...args,
|
|
697
|
+
prompt
|
|
698
|
+
};
|
|
699
|
+
if (inferred === "panel" && delegatedArgs.panel !== true) {
|
|
700
|
+
delegatedArgs.panel = true;
|
|
701
|
+
delegatedArgs["show-conflicts"] = true;
|
|
702
|
+
}
|
|
703
|
+
await runModeCommand(mode, delegatedArgs);
|
|
704
|
+
}
|
|
705
|
+
async function runRoles(args) {
|
|
706
|
+
const payload = PERSONA_DEFINITIONS.map((persona) => ({
|
|
707
|
+
key: persona.key,
|
|
708
|
+
label: persona.label,
|
|
709
|
+
description: persona.shortDescription,
|
|
710
|
+
triggerMode: persona.triggerMode,
|
|
711
|
+
exampleTriggers: persona.synonyms.slice(0, 4)
|
|
712
|
+
}));
|
|
713
|
+
if (args.json === true) {
|
|
714
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
console.log("Long Table roles");
|
|
718
|
+
console.log("These are perspectives Long Table can consult when relevant.");
|
|
719
|
+
console.log("");
|
|
720
|
+
for (const persona of payload) {
|
|
721
|
+
console.log(`- ${persona.label} (${persona.key})`);
|
|
722
|
+
console.log(` ${persona.description}`);
|
|
723
|
+
console.log(` Trigger: ${persona.triggerMode === "auto-callable" ? "auto-callable when your language strongly implies it" : "explicit request only"}`);
|
|
724
|
+
console.log(` Examples: ${persona.exampleTriggers.join(", ")}`);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
async function runStart(args) {
|
|
728
|
+
const setupPath = typeof args.setup === "string" ? args.setup : undefined;
|
|
729
|
+
const existingSetup = await loadOptionalSetup(setupPath);
|
|
730
|
+
if (!existingSetup) {
|
|
731
|
+
console.log("Long Table is not set up yet. Starting the interview flow first.");
|
|
732
|
+
console.log("");
|
|
733
|
+
await runInit({
|
|
734
|
+
...args,
|
|
735
|
+
flow: typeof args.flow === "string" ? args.flow : "interview",
|
|
736
|
+
"install-prompts": true
|
|
737
|
+
});
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
const directPrompt = typeof args.prompt === "string" ? args.prompt.trim() : "";
|
|
741
|
+
if (directPrompt) {
|
|
742
|
+
await runAsk({
|
|
743
|
+
...args,
|
|
744
|
+
prompt: directPrompt,
|
|
745
|
+
...(setupPath ? { setup: setupPath } : {})
|
|
746
|
+
});
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
const rl = createInterface({ input, output });
|
|
750
|
+
try {
|
|
751
|
+
const action = await promptStartAction(rl, existingSetup.profileSeed.currentBlocker ?? existingSetup.profileSeed.currentResearchTopic);
|
|
752
|
+
if (action === "status") {
|
|
753
|
+
rl.close();
|
|
754
|
+
await runCodexSubcommand("status", args);
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
if (action === "roles") {
|
|
758
|
+
rl.close();
|
|
759
|
+
await runRoles(args);
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
const defaultPrompt = existingSetup.profileSeed.currentBlocker ??
|
|
763
|
+
existingSetup.profileSeed.currentResearchTopic ??
|
|
764
|
+
"";
|
|
765
|
+
const prompt = (await rl.question(defaultPrompt
|
|
766
|
+
? `What are you working on today?\nPress Enter to use: ${defaultPrompt}\n> `
|
|
767
|
+
: "What are you working on today?\n> ")).trim() || defaultPrompt;
|
|
768
|
+
rl.close();
|
|
769
|
+
if (!prompt) {
|
|
770
|
+
throw new Error("A prompt is required.");
|
|
771
|
+
}
|
|
772
|
+
if (action === "editor") {
|
|
773
|
+
await runModeCommand("review", {
|
|
774
|
+
...args,
|
|
775
|
+
prompt,
|
|
776
|
+
role: "editor",
|
|
777
|
+
...(setupPath ? { setup: setupPath } : {})
|
|
778
|
+
});
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
if (action === "methods") {
|
|
782
|
+
await runModeCommand("review", {
|
|
783
|
+
...args,
|
|
784
|
+
prompt,
|
|
785
|
+
role: "methods_critic",
|
|
786
|
+
...(setupPath ? { setup: setupPath } : {})
|
|
787
|
+
});
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
if (action === "panel") {
|
|
791
|
+
await runModeCommand("review", {
|
|
792
|
+
...args,
|
|
793
|
+
prompt,
|
|
794
|
+
panel: true,
|
|
795
|
+
"show-conflicts": true,
|
|
796
|
+
...(setupPath ? { setup: setupPath } : {})
|
|
797
|
+
});
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
const mode = action;
|
|
801
|
+
await runModeCommand(mode, {
|
|
802
|
+
...args,
|
|
803
|
+
prompt,
|
|
804
|
+
...(setupPath ? { setup: setupPath } : {})
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
finally {
|
|
808
|
+
rl.close();
|
|
809
|
+
}
|
|
810
|
+
}
|
|
421
811
|
async function runCodexSubcommand(subcommand, args) {
|
|
422
812
|
const customDir = typeof args.dir === "string" ? args.dir : undefined;
|
|
423
813
|
if (subcommand === "install-prompts") {
|
|
424
814
|
const installed = await installCodexPromptAliases(customDir);
|
|
425
815
|
console.log(`Installed ${installed.length} Long Table prompt aliases in ${resolveCodexPromptsDir(customDir)}`);
|
|
816
|
+
console.log("Note: prompt-file discovery depends on the Codex build. Treat this as an experimental integration.");
|
|
426
817
|
for (const prompt of installed) {
|
|
427
818
|
console.log(`- /prompts:${prompt.name}`);
|
|
428
819
|
}
|
|
@@ -457,6 +848,7 @@ async function runCodexSubcommand(subcommand, args) {
|
|
|
457
848
|
console.log(`- setup: ${status.setupExists ? "present" : "missing"} (${setupPath})`);
|
|
458
849
|
console.log(`- codex runtime artifact: ${status.runtimeExists ? "present" : "missing"} (${runtimePath})`);
|
|
459
850
|
console.log(`- prompt aliases dir: ${status.promptsDir}`);
|
|
851
|
+
console.log("- prompt-file integration: experimental (your Codex build may not expose these as slash commands)");
|
|
460
852
|
if (aliases.length === 0) {
|
|
461
853
|
console.log("- prompt aliases: none");
|
|
462
854
|
}
|
|
@@ -481,6 +873,14 @@ async function main() {
|
|
|
481
873
|
await runInit(values);
|
|
482
874
|
return;
|
|
483
875
|
}
|
|
876
|
+
if (command === "start") {
|
|
877
|
+
await runStart(values);
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
if (command === "roles") {
|
|
881
|
+
await runRoles(values);
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
484
884
|
if (command === "show") {
|
|
485
885
|
await runShow(values);
|
|
486
886
|
return;
|
|
@@ -489,6 +889,10 @@ async function main() {
|
|
|
489
889
|
await runInstall(values);
|
|
490
890
|
return;
|
|
491
891
|
}
|
|
892
|
+
if (command === "ask") {
|
|
893
|
+
await runAsk(values);
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
492
896
|
if (command === "codex") {
|
|
493
897
|
await runCodexSubcommand(subcommand, values);
|
|
494
898
|
return;
|
|
@@ -500,7 +904,11 @@ async function main() {
|
|
|
500
904
|
throw new Error(`Unknown command: ${command}`);
|
|
501
905
|
}
|
|
502
906
|
main().catch((error) => {
|
|
503
|
-
|
|
907
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
908
|
+
console.error(message);
|
|
909
|
+
if (message === "Setup cancelled.") {
|
|
910
|
+
exit(1);
|
|
911
|
+
}
|
|
504
912
|
console.error("");
|
|
505
913
|
console.error(usage());
|
|
506
914
|
exit(1);
|
package/dist/persona-router.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CanonicalPersona } from "./personas.js";
|
|
2
|
+
import type { InteractionMode } from "@diverga/core";
|
|
2
3
|
export type OutputLanguage = "ko" | "en";
|
|
3
4
|
export interface PersonaRoutingResult {
|
|
4
5
|
outputLanguage: OutputLanguage;
|
|
@@ -12,6 +13,7 @@ export declare function parseRoleFlag(value?: string): CanonicalPersona[];
|
|
|
12
13
|
export declare function routePersonas(prompt: string, explicitRoleFlag?: string): PersonaRoutingResult;
|
|
13
14
|
export declare function renderDisclosure(roles: CanonicalPersona[], language: OutputLanguage): string | null;
|
|
14
15
|
export declare function buildPersonaGuidance(options: {
|
|
16
|
+
mode: InteractionMode;
|
|
15
17
|
prompt: string;
|
|
16
18
|
roleFlag?: string;
|
|
17
19
|
panel?: boolean;
|
package/dist/persona-router.js
CHANGED
|
@@ -63,6 +63,9 @@ export function buildPersonaGuidance(options) {
|
|
|
63
63
|
const routing = routePersonas(options.prompt, options.roleFlag);
|
|
64
64
|
const disclosure = renderDisclosure(routing.consultedRoles, routing.outputLanguage);
|
|
65
65
|
const lines = [];
|
|
66
|
+
lines.push(routing.outputLanguage === "ko"
|
|
67
|
+
? `Long Table mode: ${options.mode[0].toUpperCase()}${options.mode.slice(1)}`
|
|
68
|
+
: `Long Table mode: ${options.mode[0].toUpperCase()}${options.mode.slice(1)}`);
|
|
66
69
|
if (disclosure) {
|
|
67
70
|
lines.push(disclosure);
|
|
68
71
|
}
|
|
@@ -86,6 +89,9 @@ export function buildPersonaGuidance(options) {
|
|
|
86
89
|
? "Include a short deliberation trace showing why the roles diverged."
|
|
87
90
|
: "Include a short deliberation trace showing why the roles diverged.");
|
|
88
91
|
}
|
|
92
|
+
lines.push(routing.outputLanguage === "ko"
|
|
93
|
+
? "Do not show internal file-search logs, tool traces, or process commentary in the researcher-facing answer."
|
|
94
|
+
: "Do not show internal file-search logs, tool traces, or process commentary in the researcher-facing answer.");
|
|
89
95
|
lines.push(options.prompt.trim());
|
|
90
96
|
return {
|
|
91
97
|
guidedPrompt: lines.join("\n\n"),
|
package/dist/prompt-aliases.js
CHANGED
|
@@ -7,19 +7,38 @@ export function resolveCodexPromptsDir(customDir) {
|
|
|
7
7
|
}
|
|
8
8
|
function promptSpec() {
|
|
9
9
|
return [
|
|
10
|
+
{
|
|
11
|
+
name: "longtable",
|
|
12
|
+
description: "Single-entry Long Table router for research conversations",
|
|
13
|
+
argumentHint: "<natural language research request>",
|
|
14
|
+
body: [
|
|
15
|
+
"You are Long Table.",
|
|
16
|
+
"Classify the user's request into one of these modes: explore, review, critique, draft, commit, panel, or status.",
|
|
17
|
+
"If the request is ambiguous, ask one short clarifying question before closing.",
|
|
18
|
+
"Always begin with `Long Table mode: <Mode>`.",
|
|
19
|
+
"Always disclose consulted roles with `Long Table consulted: ...` when any role is foregrounded.",
|
|
20
|
+
"In explore mode, ask at least two clarifying or tension questions before any recommendation.",
|
|
21
|
+
"In panel mode, return 1) Long Table synthesis 2) visible panel opinions by role 3) conflict summary if needed 4) a decision prompt for the researcher.",
|
|
22
|
+
"Do not expose internal tool logs, file searches, or process notes in the researcher-facing answer.",
|
|
23
|
+
"Treat any slash-command arguments as the current research object."
|
|
24
|
+
]
|
|
25
|
+
},
|
|
10
26
|
{
|
|
11
27
|
name: "longtable-init",
|
|
12
28
|
description: "Run Long Table researcher onboarding inside Codex",
|
|
13
29
|
argumentHint: "[project context or current uncertainty]",
|
|
14
30
|
body: [
|
|
15
31
|
"You are Long Table onboarding inside Codex.",
|
|
32
|
+
"First ask whether the researcher wants Quickstart or Interview setup.",
|
|
16
33
|
"Ask exactly one setup question at a time.",
|
|
17
34
|
"Use numbered choices when possible and include a 'None of the above' option when needed.",
|
|
18
35
|
"Do not move to the next question until the researcher answers the current one.",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
36
|
+
"Quickstart covers: provider, field, career stage, experience level, current project type, checkpoint intensity, and human authorship signal.",
|
|
37
|
+
"Interview also covers: current research topic, current blocker, 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-prompts` command and 2) a strict JSON object with keys provider, flow, field, careerStage, experienceLevel, currentProjectType, preferredCheckpointIntensity, and optional humanAuthorshipSignal, currentResearchTopic, currentBlocker, preferredEntryMode, weakestDomain, panelPreference.",
|
|
21
39
|
"If the user prefers paste-based setup, tell them they can pipe the JSON into `longtable codex persist-init --stdin --install-prompts`.",
|
|
22
40
|
"If the researcher asks you to stay inside Codex, keep the conversation in numbered form and do not prematurely close.",
|
|
41
|
+
"Frame the setup like a short researcher interview, not a bare config form.",
|
|
23
42
|
"Treat any slash-command arguments as context for why setup is being done now."
|
|
24
43
|
]
|
|
25
44
|
},
|
|
@@ -29,9 +48,11 @@ function promptSpec() {
|
|
|
29
48
|
argumentHint: "<topic or research problem>",
|
|
30
49
|
body: [
|
|
31
50
|
"You are Long Table in explore mode.",
|
|
51
|
+
"Always begin with `Long Table mode: Explore`.",
|
|
32
52
|
"Ask at least two clarifying or tension questions before any recommendation.",
|
|
33
53
|
"Keep unresolved tensions visible.",
|
|
34
54
|
"Do not rush to synthesis.",
|
|
55
|
+
"Do not expose internal process notes or file-search summaries.",
|
|
35
56
|
"Treat any slash-command arguments as the current research object."
|
|
36
57
|
]
|
|
37
58
|
},
|
|
@@ -41,6 +62,7 @@ function promptSpec() {
|
|
|
41
62
|
argumentHint: "<claim, paragraph, design, or plan>",
|
|
42
63
|
body: [
|
|
43
64
|
"You are Long Table in review mode.",
|
|
65
|
+
"Always begin with `Long Table mode: Review`.",
|
|
44
66
|
"Surface why this may be wrong before synthesis.",
|
|
45
67
|
"Preserve the researcher's own language where possible.",
|
|
46
68
|
"Treat any slash-command arguments as the object to review."
|
|
@@ -52,6 +74,7 @@ function promptSpec() {
|
|
|
52
74
|
argumentHint: "<claim, plan, or draft for multi-role review>",
|
|
53
75
|
body: [
|
|
54
76
|
"You are Long Table in panel mode.",
|
|
77
|
+
"Always begin with `Long Table mode: Panel`.",
|
|
55
78
|
"Return 1) a Long Table synthesis 2) visible panel opinions by role 3) a decision prompt for the researcher.",
|
|
56
79
|
"If roles disagree, do not collapse them too early.",
|
|
57
80
|
"Disclose which roles were consulted.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longtable/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Researcher-facing Long Table CLI on top of the legacy Diverga package surface",
|
|
6
6
|
"type": "module",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@diverga/provider-codex": "0.1.1",
|
|
29
|
-
"@diverga/setup": "0.1.
|
|
29
|
+
"@diverga/setup": "0.1.3"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^22.10.1",
|