@longtable/cli 0.1.8 → 0.1.9
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 +55 -91
- package/dist/cli.js +43 -39
- package/dist/persona-router.d.ts +1 -1
- package/dist/persona-router.js +6 -6
- package/dist/project-session.d.ts +13 -2
- package/dist/project-session.js +232 -150
- package/dist/prompt-aliases.js +32 -32
- package/package.json +10 -7
package/README.md
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
# @longtable/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Researcher-facing CLI for LongTable.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
LongTable is designed around a simple contract:
|
|
6
6
|
|
|
7
|
-
1.
|
|
8
|
-
2.
|
|
9
|
-
|
|
10
|
-
중요한 점:
|
|
11
|
-
|
|
12
|
-
- 이 두 명령은 **터미널에서 실행하는 셸 명령**입니다.
|
|
13
|
-
- Codex 채팅창에 `longtable start`를 입력하는 것이 아닙니다.
|
|
14
|
-
- `longtable start`로 프로젝트 작업공간을 만든 뒤, 그 디렉토리에서 `codex`를 여는 것이 기본 경로입니다.
|
|
7
|
+
1. seed the researcher profile once
|
|
8
|
+
2. create a workspace for each project
|
|
9
|
+
3. continue the research conversation inside that workspace
|
|
15
10
|
|
|
16
11
|
## Install
|
|
17
12
|
|
|
@@ -19,47 +14,7 @@ Long Table의 researcher-facing CLI입니다.
|
|
|
19
14
|
npm install -g @longtable/cli
|
|
20
15
|
```
|
|
21
16
|
|
|
22
|
-
##
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
longtable init --flow interview
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
여기서는 연구자 프로필과 기본 선호를 묻습니다.
|
|
29
|
-
|
|
30
|
-
- 연구 분야
|
|
31
|
-
- 연구자 역할
|
|
32
|
-
- challenge 강도
|
|
33
|
-
- 저자성/서사 관련 기본값
|
|
34
|
-
- Long Table이 보통 어디서부터 시작해야 하는지
|
|
35
|
-
|
|
36
|
-
## 2. Project start
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
longtable start
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
여기서는 실제 작업공간을 만듭니다.
|
|
43
|
-
|
|
44
|
-
- 프로젝트 이름
|
|
45
|
-
- 프로젝트 디렉토리 위치
|
|
46
|
-
- 현재 세션 목표
|
|
47
|
-
- 현재 blocker
|
|
48
|
-
- 필요한 관점
|
|
49
|
-
- disagreement 가시성
|
|
50
|
-
|
|
51
|
-
그리고 Long Table은:
|
|
52
|
-
|
|
53
|
-
- 프로젝트 디렉토리 생성
|
|
54
|
-
- `.longtable/` 메모리 파일 생성
|
|
55
|
-
- 프로젝트용 `AGENTS.md` 생성
|
|
56
|
-
- `START-HERE.md` 생성
|
|
57
|
-
- `NEXT-STEPS.md` 생성
|
|
58
|
-
- `SESSION-SNAPSHOT.md` 생성
|
|
59
|
-
|
|
60
|
-
을 수행합니다.
|
|
61
|
-
|
|
62
|
-
## Recommended flow
|
|
17
|
+
## Primary Flow
|
|
63
18
|
|
|
64
19
|
```bash
|
|
65
20
|
longtable init --flow interview
|
|
@@ -68,9 +23,7 @@ cd "<project-path>"
|
|
|
68
23
|
codex
|
|
69
24
|
```
|
|
70
25
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
돌아와서 다시 이어갈 때는:
|
|
26
|
+
Return later:
|
|
74
27
|
|
|
75
28
|
```bash
|
|
76
29
|
cd "<project-path>"
|
|
@@ -78,58 +31,69 @@ longtable resume
|
|
|
78
31
|
codex
|
|
79
32
|
```
|
|
80
33
|
|
|
81
|
-
##
|
|
82
|
-
|
|
83
|
-
프로젝트 디렉토리 안에서는 보통 그냥 `codex`를 열고 자연어로 연구를 시작하면 됩니다.
|
|
84
|
-
|
|
85
|
-
Codex 안에서 더 명시적으로 부르고 싶다면, 아래처럼 짧은 문법도 사용할 수 있습니다.
|
|
34
|
+
## What `longtable start` Creates
|
|
86
35
|
|
|
87
36
|
```text
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
37
|
+
<project>/
|
|
38
|
+
AGENTS.md
|
|
39
|
+
CURRENT.md
|
|
40
|
+
.longtable/
|
|
41
|
+
project.json
|
|
42
|
+
current-session.json
|
|
43
|
+
state.json
|
|
44
|
+
sessions/
|
|
93
45
|
```
|
|
94
46
|
|
|
95
|
-
|
|
47
|
+
## Artifact Contract
|
|
96
48
|
|
|
97
|
-
|
|
49
|
+
- `AGENTS.md`: runtime guidance for Codex
|
|
50
|
+
- `CURRENT.md`: human-facing current view regenerated from state
|
|
51
|
+
- `.longtable/project.json`: stable project identity
|
|
52
|
+
- `.longtable/current-session.json`: current session cursor
|
|
53
|
+
- `.longtable/state.json`: layered memory state
|
|
54
|
+
- `.longtable/sessions/`: historical snapshots
|
|
98
55
|
|
|
99
|
-
|
|
100
|
-
longtable roles
|
|
101
|
-
longtable resume --cwd "<project-path>"
|
|
102
|
-
longtable ask --cwd "<project-path>" --prompt "연구 질문을 어디서부터 좁혀야 할지 모르겠어."
|
|
103
|
-
longtable review --cwd "<project-path>" --prompt "방법론적으로 어디가 취약한지 말해줘." --role methods_critic
|
|
104
|
-
```
|
|
56
|
+
## Why This Shape
|
|
105
57
|
|
|
106
|
-
|
|
58
|
+
The CLI tries to keep the root simple for novice researchers while preserving enough structure for power users and downstream tooling.
|
|
107
59
|
|
|
108
|
-
|
|
109
|
-
longtable roles
|
|
110
|
-
```
|
|
60
|
+
The memory model distinguishes:
|
|
111
61
|
|
|
112
|
-
|
|
62
|
+
- explicit state
|
|
63
|
+
- working state
|
|
64
|
+
- inferred hypotheses
|
|
65
|
+
- open tensions
|
|
66
|
+
- narrative traces
|
|
113
67
|
|
|
114
|
-
|
|
115
|
-
- `reviewer`
|
|
116
|
-
- `methods_critic`
|
|
117
|
-
- `voice_keeper`
|
|
68
|
+
This is how LongTable avoids turning tacit knowledge into fake certainty.
|
|
118
69
|
|
|
119
|
-
##
|
|
70
|
+
## Commands
|
|
120
71
|
|
|
121
72
|
```bash
|
|
122
|
-
longtable
|
|
123
|
-
longtable
|
|
73
|
+
longtable init
|
|
74
|
+
longtable start
|
|
75
|
+
longtable resume --cwd "<project-path>"
|
|
76
|
+
longtable roles
|
|
77
|
+
longtable ask --cwd "<project-path>" --prompt "..."
|
|
124
78
|
```
|
|
125
79
|
|
|
126
|
-
|
|
127
|
-
사용자에게 약속하는 주 경로는 아닙니다.
|
|
80
|
+
## Inside Codex
|
|
128
81
|
|
|
129
|
-
|
|
82
|
+
Natural language should be the default.
|
|
130
83
|
|
|
131
|
-
|
|
132
|
-
- `longtable start`
|
|
133
|
-
- 프로젝트 디렉토리에서 `codex`
|
|
84
|
+
Explicit short forms are available when needed:
|
|
134
85
|
|
|
135
|
-
|
|
86
|
+
```text
|
|
87
|
+
lt explore: Where should I narrow the question first?
|
|
88
|
+
lt review: What is weak in this claim?
|
|
89
|
+
lt panel: Show me the disagreement before I commit.
|
|
90
|
+
lt methods: Where is the design vulnerable?
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Validation
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm install
|
|
97
|
+
npm run typecheck
|
|
98
|
+
npm run build
|
|
99
|
+
```
|
package/dist/cli.js
CHANGED
|
@@ -6,12 +6,12 @@ import { createInterface } from "node:readline/promises";
|
|
|
6
6
|
import { stdin as input, stdout as output, cwd, exit } from "node:process";
|
|
7
7
|
import { dirname, resolve } from "node:path";
|
|
8
8
|
import { homedir } from "node:os";
|
|
9
|
-
import { buildProviderChoices, buildQuickSetupFlow, createPersistedSetupOutput, installRuntimeConfigFromStoredSetup, loadSetupOutput, renderInstallSummary, renderSetupSummary, resolveDefaultRuntimeConfigPath, resolveDefaultSetupPath, saveSetupAndRuntimeConfig, serializeSetupOutput } from "@
|
|
10
|
-
import { buildCodexThinWrappedPrompt, runCodexThinWrapper } from "@
|
|
9
|
+
import { buildProviderChoices, buildQuickSetupFlow, createPersistedSetupOutput, installRuntimeConfigFromStoredSetup, loadSetupOutput, renderInstallSummary, renderSetupSummary, resolveDefaultRuntimeConfigPath, resolveDefaultSetupPath, saveSetupAndRuntimeConfig, serializeSetupOutput } from "@longtable/setup";
|
|
10
|
+
import { buildCodexThinWrappedPrompt, runCodexThinWrapper } from "@longtable/provider-codex";
|
|
11
11
|
import { installCodexPromptAliases, listInstalledCodexPromptAliases, removeCodexPromptAliases, resolveCodexPromptsDir } from "./prompt-aliases.js";
|
|
12
12
|
import { buildPersonaGuidance, parseInvocationDirective } from "./persona-router.js";
|
|
13
13
|
import { PERSONA_DEFINITIONS } from "./personas.js";
|
|
14
|
-
import { createOrUpdateProjectWorkspace, loadProjectContextFromDirectory, renderProjectWorkspaceSummary } from "./project-session.js";
|
|
14
|
+
import { createOrUpdateProjectWorkspace, loadProjectContextFromDirectory, renderProjectWorkspaceSummary, syncCurrentWorkspaceView } from "./project-session.js";
|
|
15
15
|
const VALID_MODES = new Set([
|
|
16
16
|
"explore",
|
|
17
17
|
"review",
|
|
@@ -155,11 +155,11 @@ function buildSetupFlowChoices() {
|
|
|
155
155
|
];
|
|
156
156
|
}
|
|
157
157
|
function renderSetupHeader(flow) {
|
|
158
|
-
const title = flow === "interview" ? "
|
|
158
|
+
const title = flow === "interview" ? "LongTable Setup Interview" : "LongTable Quickstart";
|
|
159
159
|
const subtitle = flow === "interview"
|
|
160
160
|
? "We will ask about your research persona, challenge preferences, and authorship defaults."
|
|
161
|
-
: "We will capture the minimum profile needed to start using
|
|
162
|
-
return [renderBrandBanner("
|
|
161
|
+
: "We will capture the minimum profile needed to start using LongTable.";
|
|
162
|
+
return [renderBrandBanner("LongTable", "Research workspace setup"), "", renderSectionCard(title, [subtitle])].join("\n");
|
|
163
163
|
}
|
|
164
164
|
function renderQuestionHeader(index, total, section, prompt) {
|
|
165
165
|
return [
|
|
@@ -176,7 +176,7 @@ function questionSection(questionId) {
|
|
|
176
176
|
return "Interaction style";
|
|
177
177
|
}
|
|
178
178
|
if (questionId === "weakestDomain" || questionId === "panelPreference") {
|
|
179
|
-
return "How
|
|
179
|
+
return "How LongTable should challenge you";
|
|
180
180
|
}
|
|
181
181
|
return "Authorship and voice";
|
|
182
182
|
}
|
|
@@ -253,14 +253,14 @@ async function verifyWritableWorkspaceParent(projectPath) {
|
|
|
253
253
|
catch (error) {
|
|
254
254
|
const message = error instanceof Error ? error.message : String(error);
|
|
255
255
|
throw new Error([
|
|
256
|
-
`
|
|
256
|
+
`LongTable could not create a project workspace under: ${parentDir}`,
|
|
257
257
|
"Reason: your current shell process cannot write to that parent directory.",
|
|
258
258
|
"",
|
|
259
259
|
"What to try next:",
|
|
260
260
|
`- test it directly: mkdir -p "${resolve(parentDir, "_longtable_write_test")}"`,
|
|
261
|
-
"- if that fails too, this is an OS/disk permission problem rather than a
|
|
261
|
+
"- if that fails too, this is an OS/disk permission problem rather than a LongTable command problem",
|
|
262
262
|
"- try a known-writable path such as ~/Research",
|
|
263
|
-
"- or choose a different existing parent directory when
|
|
263
|
+
"- or choose a different existing parent directory when LongTable asks where the project should live",
|
|
264
264
|
"",
|
|
265
265
|
`Original error: ${message}`
|
|
266
266
|
].join("\n"));
|
|
@@ -481,7 +481,7 @@ async function collectInteractiveAnswers(initialFlow) {
|
|
|
481
481
|
const rl = createInterface({ input, output });
|
|
482
482
|
try {
|
|
483
483
|
const flow = initialFlow ??
|
|
484
|
-
(await promptChoice(rl, "How would you like to set up
|
|
484
|
+
(await promptChoice(rl, "How would you like to set up LongTable?", buildSetupFlowChoices()));
|
|
485
485
|
console.log("");
|
|
486
486
|
console.log(renderSetupHeader(flow));
|
|
487
487
|
console.log("");
|
|
@@ -559,11 +559,11 @@ async function collectProjectInterview(setup, args) {
|
|
|
559
559
|
try {
|
|
560
560
|
if (needsInteractivePrompts) {
|
|
561
561
|
console.log("");
|
|
562
|
-
console.log(renderBrandBanner("
|
|
562
|
+
console.log(renderBrandBanner("LongTable", "Project workspace interview"));
|
|
563
563
|
console.log("");
|
|
564
|
-
console.log(renderSectionCard("
|
|
564
|
+
console.log(renderSectionCard("LongTable Project Start", [
|
|
565
565
|
"We will create a project workspace and a session memory seed for today's work.",
|
|
566
|
-
"At the end,
|
|
566
|
+
"At the end, LongTable will tell you exactly which directory to open in Codex."
|
|
567
567
|
]));
|
|
568
568
|
console.log("");
|
|
569
569
|
}
|
|
@@ -575,7 +575,7 @@ async function collectProjectInterview(setup, args) {
|
|
|
575
575
|
const suggestedPath = resolveInteractiveProjectPath(suggestedParentDir, projectName);
|
|
576
576
|
const projectPath = (typeof args.path === "string" && args.path.trim()
|
|
577
577
|
? normalizeUserPath(args.path.trim())
|
|
578
|
-
: resolveInteractiveProjectPath((await promptText(rl, renderQuestionHeader(2, 6, "Project interview", `Which parent directory should contain this project?\
|
|
578
|
+
: resolveInteractiveProjectPath((await promptText(rl, renderQuestionHeader(2, 6, "Project interview", `Which parent directory should contain this project?\nLongTable will create this folder:\n${suggestedPath}`), true)), projectName));
|
|
579
579
|
const currentGoal = (typeof args.goal === "string" && args.goal.trim()) ||
|
|
580
580
|
(await promptText(rl, renderQuestionHeader(3, 6, "Current session", "What are you trying to accomplish in this session?"), true));
|
|
581
581
|
const currentBlocker = (typeof args.blocker === "string" && args.blocker.trim()) ||
|
|
@@ -588,7 +588,7 @@ async function collectProjectInterview(setup, args) {
|
|
|
588
588
|
{
|
|
589
589
|
id: "synthesis_only",
|
|
590
590
|
label: "Synthesis only",
|
|
591
|
-
description: "Show one
|
|
591
|
+
description: "Show one LongTable answer unless I ask for more."
|
|
592
592
|
},
|
|
593
593
|
{
|
|
594
594
|
id: "show_on_conflict",
|
|
@@ -709,7 +709,7 @@ async function runInit(args) {
|
|
|
709
709
|
console.log("- Start here: `longtable start`.");
|
|
710
710
|
console.log("- If you want a direct natural-language entry: `longtable ask --prompt \"...\"`.");
|
|
711
711
|
console.log("- Codex prompt files are available as an experimental integration, not the primary path.");
|
|
712
|
-
console.log("- Suggested next action: create a project workspace and let
|
|
712
|
+
console.log("- Suggested next action: create a project workspace and let LongTable interview the current session.");
|
|
713
713
|
}
|
|
714
714
|
}
|
|
715
715
|
async function runShow(args) {
|
|
@@ -767,7 +767,7 @@ async function runCodexPersistInit(args) {
|
|
|
767
767
|
console.log("- Start here: `longtable start`.");
|
|
768
768
|
console.log("- If you want a direct natural-language entry: `longtable ask --prompt \"...\"`.");
|
|
769
769
|
console.log("- Codex prompt files are available as an experimental integration, not the primary path.");
|
|
770
|
-
console.log("- Suggested next action: create a project workspace and let
|
|
770
|
+
console.log("- Suggested next action: create a project workspace and let LongTable interview the current session.");
|
|
771
771
|
}
|
|
772
772
|
}
|
|
773
773
|
async function resolvePrompt(prompt) {
|
|
@@ -779,7 +779,7 @@ async function resolvePrompt(prompt) {
|
|
|
779
779
|
}
|
|
780
780
|
const rl = createInterface({ input, output });
|
|
781
781
|
try {
|
|
782
|
-
return (await rl.question("What should
|
|
782
|
+
return (await rl.question("What should LongTable help with?\n> ")).trim();
|
|
783
783
|
}
|
|
784
784
|
finally {
|
|
785
785
|
rl.close();
|
|
@@ -842,7 +842,7 @@ async function buildProjectAwarePrompt(prompt, workingDirectory) {
|
|
|
842
842
|
return { prompt, projectContextFound: false };
|
|
843
843
|
}
|
|
844
844
|
const lines = [
|
|
845
|
-
"
|
|
845
|
+
"LongTable project context",
|
|
846
846
|
`project: ${context.project.projectName}`,
|
|
847
847
|
`current session goal: ${context.session.currentGoal}`,
|
|
848
848
|
...(context.session.currentBlocker ? [`current blocker: ${context.session.currentBlocker}`] : []),
|
|
@@ -936,8 +936,8 @@ async function runRoles(args) {
|
|
|
936
936
|
console.log(JSON.stringify(payload, null, 2));
|
|
937
937
|
return;
|
|
938
938
|
}
|
|
939
|
-
console.log("
|
|
940
|
-
console.log("These are perspectives
|
|
939
|
+
console.log("LongTable roles");
|
|
940
|
+
console.log("These are perspectives LongTable can consult when relevant.");
|
|
941
941
|
console.log("Inside Codex, explicit forms like `lt editor: ...` and `lt methods: ...` are stronger than plain natural language.");
|
|
942
942
|
console.log("");
|
|
943
943
|
for (const persona of payload) {
|
|
@@ -951,7 +951,7 @@ async function runStart(args) {
|
|
|
951
951
|
const setupPath = typeof args.setup === "string" ? args.setup : undefined;
|
|
952
952
|
const existingSetup = await loadOptionalSetup(setupPath);
|
|
953
953
|
if (!existingSetup) {
|
|
954
|
-
throw new Error("
|
|
954
|
+
throw new Error("LongTable global setup is missing. Run `longtable init --flow interview` first.");
|
|
955
955
|
}
|
|
956
956
|
const interview = await collectProjectInterview(existingSetup, args);
|
|
957
957
|
await verifyWritableWorkspaceParent(interview.projectPath);
|
|
@@ -968,8 +968,12 @@ async function runStart(args) {
|
|
|
968
968
|
console.log(JSON.stringify({
|
|
969
969
|
project: context.project,
|
|
970
970
|
session: context.session,
|
|
971
|
-
|
|
972
|
-
|
|
971
|
+
files: {
|
|
972
|
+
project: context.projectFilePath,
|
|
973
|
+
session: context.sessionFilePath,
|
|
974
|
+
state: context.stateFilePath,
|
|
975
|
+
current: context.currentFilePath
|
|
976
|
+
}
|
|
973
977
|
}, null, 2));
|
|
974
978
|
return;
|
|
975
979
|
}
|
|
@@ -979,7 +983,7 @@ async function runStart(args) {
|
|
|
979
983
|
`1. cd "${context.project.projectPath}"`,
|
|
980
984
|
"2. run `codex` in that directory",
|
|
981
985
|
"3. begin with your current goal in natural language",
|
|
982
|
-
"4. if you return later,
|
|
986
|
+
"4. if you return later, open `CURRENT.md` or run `longtable resume`",
|
|
983
987
|
"",
|
|
984
988
|
`Suggested first message: ${context.session.currentBlocker ? `"I want to work on ${context.session.currentGoal}. My current blocker is ${context.session.currentBlocker}."` : `"I want to work on ${context.session.currentGoal}."`}`,
|
|
985
989
|
"",
|
|
@@ -990,22 +994,24 @@ async function runResume(args) {
|
|
|
990
994
|
const workingDirectory = typeof args.cwd === "string" ? args.cwd : cwd();
|
|
991
995
|
const context = await loadProjectContextFromDirectory(workingDirectory);
|
|
992
996
|
if (!context) {
|
|
993
|
-
throw new Error("No
|
|
997
|
+
throw new Error("No LongTable project workspace was found here. Run `longtable start` first or pass --cwd.");
|
|
994
998
|
}
|
|
999
|
+
await syncCurrentWorkspaceView(context);
|
|
995
1000
|
const payload = {
|
|
996
1001
|
project: context.project,
|
|
997
1002
|
session: context.session,
|
|
998
1003
|
files: {
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1004
|
+
current: resolve(context.project.projectPath, "CURRENT.md"),
|
|
1005
|
+
project: context.projectFilePath,
|
|
1006
|
+
session: context.sessionFilePath,
|
|
1007
|
+
state: context.stateFilePath
|
|
1002
1008
|
}
|
|
1003
1009
|
};
|
|
1004
1010
|
if (args.json === true) {
|
|
1005
1011
|
console.log(JSON.stringify(payload, null, 2));
|
|
1006
1012
|
return;
|
|
1007
1013
|
}
|
|
1008
|
-
console.log(renderSectionCard("
|
|
1014
|
+
console.log(renderSectionCard("LongTable Resume", [
|
|
1009
1015
|
`Project: ${context.project.projectName}`,
|
|
1010
1016
|
`Path: ${context.project.projectPath}`,
|
|
1011
1017
|
`Current goal: ${context.session.currentGoal}`,
|
|
@@ -1013,19 +1019,17 @@ async function runResume(args) {
|
|
|
1013
1019
|
`Requested perspectives: ${context.session.requestedPerspectives.length > 0 ? context.session.requestedPerspectives.join(", ") : "auto"}`,
|
|
1014
1020
|
`Disagreement: ${context.session.disagreementPreference}`,
|
|
1015
1021
|
"",
|
|
1016
|
-
"
|
|
1017
|
-
`- ${payload.files.
|
|
1018
|
-
`- ${payload.files.nextSteps}`,
|
|
1019
|
-
`- ${payload.files.sessionSnapshot}`,
|
|
1022
|
+
"Current file:",
|
|
1023
|
+
`- ${payload.files.current}`,
|
|
1020
1024
|
"",
|
|
1021
|
-
`Suggested restart message: ${context.session.currentBlocker ? `
|
|
1025
|
+
`Suggested restart message: "${context.session.resumeHint ?? (context.session.currentBlocker ? `I want to continue ${context.session.currentGoal}. The unresolved blocker is ${context.session.currentBlocker}.` : `I want to continue ${context.session.currentGoal}.`)}"`
|
|
1022
1026
|
]));
|
|
1023
1027
|
}
|
|
1024
1028
|
async function runCodexSubcommand(subcommand, args) {
|
|
1025
1029
|
const customDir = typeof args.dir === "string" ? args.dir : undefined;
|
|
1026
1030
|
if (subcommand === "install-prompts") {
|
|
1027
1031
|
const installed = await installCodexPromptAliases(customDir);
|
|
1028
|
-
console.log(`Installed ${installed.length}
|
|
1032
|
+
console.log(`Installed ${installed.length} LongTable prompt aliases in ${resolveCodexPromptsDir(customDir)}`);
|
|
1029
1033
|
console.log("Note: prompt-file discovery depends on the Codex build. Treat this as an experimental integration.");
|
|
1030
1034
|
for (const prompt of installed) {
|
|
1031
1035
|
console.log(`- /prompts:${prompt.name}`);
|
|
@@ -1038,7 +1042,7 @@ async function runCodexSubcommand(subcommand, args) {
|
|
|
1038
1042
|
}
|
|
1039
1043
|
if (subcommand === "remove-prompts") {
|
|
1040
1044
|
const removed = await removeCodexPromptAliases(customDir);
|
|
1041
|
-
console.log(`Removed ${removed.length}
|
|
1045
|
+
console.log(`Removed ${removed.length} LongTable prompt aliases from ${resolveCodexPromptsDir(customDir)}`);
|
|
1042
1046
|
return;
|
|
1043
1047
|
}
|
|
1044
1048
|
if (subcommand === "status") {
|
|
@@ -1057,7 +1061,7 @@ async function runCodexSubcommand(subcommand, args) {
|
|
|
1057
1061
|
console.log(JSON.stringify(status, null, 2));
|
|
1058
1062
|
return;
|
|
1059
1063
|
}
|
|
1060
|
-
console.log("
|
|
1064
|
+
console.log("LongTable Codex status");
|
|
1061
1065
|
console.log(`- setup: ${status.setupExists ? "present" : "missing"} (${setupPath})`);
|
|
1062
1066
|
console.log(`- codex runtime artifact: ${status.runtimeExists ? "present" : "missing"} (${runtimePath})`);
|
|
1063
1067
|
console.log(`- prompt aliases dir: ${status.promptsDir}`);
|
package/dist/persona-router.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CanonicalPersona } from "./personas.js";
|
|
2
|
-
import type { InteractionMode } from "@
|
|
2
|
+
import type { InteractionMode } from "@longtable/core";
|
|
3
3
|
export type OutputLanguage = "ko" | "en";
|
|
4
4
|
export interface PersonaRoutingResult {
|
|
5
5
|
outputLanguage: OutputLanguage;
|
package/dist/persona-router.js
CHANGED
|
@@ -118,8 +118,8 @@ export function renderDisclosure(roles, language) {
|
|
|
118
118
|
}
|
|
119
119
|
const labels = roles.map((role) => getPersonaDefinition(role).label);
|
|
120
120
|
return language === "ko"
|
|
121
|
-
? `
|
|
122
|
-
: `
|
|
121
|
+
? `LongTable consulted: ${labels.join(", ")}`
|
|
122
|
+
: `LongTable consulted: ${labels.join(", ")}`;
|
|
123
123
|
}
|
|
124
124
|
export function buildPersonaGuidance(options) {
|
|
125
125
|
const directive = parseInvocationDirective(options.prompt);
|
|
@@ -129,8 +129,8 @@ export function buildPersonaGuidance(options) {
|
|
|
129
129
|
const disclosure = renderDisclosure(routing.consultedRoles, routing.outputLanguage);
|
|
130
130
|
const lines = [];
|
|
131
131
|
lines.push(routing.outputLanguage === "ko"
|
|
132
|
-
? `
|
|
133
|
-
: `
|
|
132
|
+
? `LongTable mode: ${options.mode[0].toUpperCase()}${options.mode.slice(1)}`
|
|
133
|
+
: `LongTable mode: ${options.mode[0].toUpperCase()}${options.mode.slice(1)}`);
|
|
134
134
|
if (disclosure) {
|
|
135
135
|
lines.push(disclosure);
|
|
136
136
|
}
|
|
@@ -141,8 +141,8 @@ export function buildPersonaGuidance(options) {
|
|
|
141
141
|
}
|
|
142
142
|
if (options.panel || directive.panel) {
|
|
143
143
|
lines.push(routing.outputLanguage === "ko"
|
|
144
|
-
? "Return format: 1)
|
|
145
|
-
: "Return format: 1)
|
|
144
|
+
? "Return format: 1) LongTable synthesis 2) panel opinions by role 3) decision prompt to the researcher."
|
|
145
|
+
: "Return format: 1) LongTable synthesis 2) panel opinions by role 3) decision prompt to the researcher.");
|
|
146
146
|
}
|
|
147
147
|
if (options.showConflicts || directive.showConflicts) {
|
|
148
148
|
lines.push(routing.outputLanguage === "ko"
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import type { SetupPersistedOutput } from "@
|
|
1
|
+
import type { SetupPersistedOutput } from "@longtable/setup";
|
|
2
2
|
export type ProjectDisagreementPreference = "synthesis_only" | "show_on_conflict" | "always_visible";
|
|
3
3
|
export interface LongTableProjectRecord {
|
|
4
4
|
schemaVersion: 1;
|
|
5
|
-
product: "
|
|
5
|
+
product: "LongTable";
|
|
6
6
|
projectName: string;
|
|
7
7
|
projectPath: string;
|
|
8
8
|
createdAt: string;
|
|
9
|
+
contractVersion?: "workspace-v2";
|
|
10
|
+
locale?: string;
|
|
9
11
|
globalSetupSummary: {
|
|
10
12
|
field: string;
|
|
11
13
|
careerStage: string;
|
|
@@ -20,20 +22,29 @@ export interface LongTableSessionRecord {
|
|
|
20
22
|
schemaVersion: 1;
|
|
21
23
|
id: string;
|
|
22
24
|
createdAt: string;
|
|
25
|
+
lastUpdatedAt?: string;
|
|
23
26
|
projectName: string;
|
|
24
27
|
projectPath: string;
|
|
25
28
|
currentGoal: string;
|
|
26
29
|
currentBlocker?: string;
|
|
30
|
+
nextAction?: string;
|
|
31
|
+
openQuestions?: string[];
|
|
27
32
|
requestedPerspectives: string[];
|
|
28
33
|
disagreementPreference: ProjectDisagreementPreference;
|
|
34
|
+
activeModes?: string[];
|
|
35
|
+
resumeHint?: string;
|
|
36
|
+
locale?: string;
|
|
29
37
|
}
|
|
30
38
|
export interface LongTableProjectContext {
|
|
31
39
|
project: LongTableProjectRecord;
|
|
32
40
|
session: LongTableSessionRecord;
|
|
33
41
|
projectFilePath: string;
|
|
34
42
|
sessionFilePath: string;
|
|
43
|
+
stateFilePath: string;
|
|
44
|
+
currentFilePath: string;
|
|
35
45
|
metaDir: string;
|
|
36
46
|
}
|
|
47
|
+
export declare function syncCurrentWorkspaceView(context: LongTableProjectContext): Promise<string>;
|
|
37
48
|
export declare function createOrUpdateProjectWorkspace(options: {
|
|
38
49
|
projectName: string;
|
|
39
50
|
projectPath: string;
|
package/dist/project-session.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
1
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
3
4
|
import { dirname, join, resolve } from "node:path";
|
|
4
|
-
import { createEmptyResearchState } from "@
|
|
5
|
+
import { createEmptyResearchState } from "@longtable/memory";
|
|
6
|
+
const CURRENT_FILE_NAME = "CURRENT.md";
|
|
7
|
+
const LEGACY_ROOT_FILES = ["LONGTABLE.md", "START-HERE.md", "NEXT-STEPS.md", "SESSION-SNAPSHOT.md"];
|
|
5
8
|
function nowIso() {
|
|
6
9
|
return new Date().toISOString();
|
|
7
10
|
}
|
|
@@ -16,160 +19,168 @@ function slugify(input) {
|
|
|
16
19
|
function resolveMetaDir(projectPath) {
|
|
17
20
|
return join(projectPath, ".longtable");
|
|
18
21
|
}
|
|
19
|
-
function
|
|
20
|
-
|
|
21
|
-
"# Long Table Workspace",
|
|
22
|
-
"",
|
|
23
|
-
"This directory is a Long Table research workspace.",
|
|
24
|
-
"",
|
|
25
|
-
"## Current project",
|
|
26
|
-
`- Project: ${project.projectName}`,
|
|
27
|
-
`- Goal right now: ${session.currentGoal}`,
|
|
28
|
-
...(session.currentBlocker ? [`- Current blocker: ${session.currentBlocker}`] : []),
|
|
29
|
-
`- Disagreement visibility: ${session.disagreementPreference}`,
|
|
30
|
-
`- Requested perspectives: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
31
|
-
"",
|
|
32
|
-
"## How Codex should behave here",
|
|
33
|
-
"- Treat this as a researcher-facing Long Table session, not a generic coding task.",
|
|
34
|
-
"- Ask clarifying or tension questions before closing too early.",
|
|
35
|
-
"- If you foreground specific roles, disclose them with `Long Table consulted: ...`.",
|
|
36
|
-
"- Keep one accountable synthesis, but keep disagreement visible by default when it matters.",
|
|
37
|
-
"- For factual, current, or external claims, attach source links or local file references whenever possible.",
|
|
38
|
-
"- If you cannot source a statement, label it as an inference or estimate.",
|
|
39
|
-
"- Do not expose internal tool logs or process commentary in researcher-facing answers.",
|
|
40
|
-
"",
|
|
41
|
-
"## Session files",
|
|
42
|
-
"- `.longtable/project.json` contains project-level metadata.",
|
|
43
|
-
"- `.longtable/current-session.json` contains the current session goal and blocker."
|
|
44
|
-
];
|
|
45
|
-
return lines.join("\n");
|
|
22
|
+
function resolveStateFilePath(projectPath) {
|
|
23
|
+
return join(resolveMetaDir(projectPath), "state.json");
|
|
46
24
|
}
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
"# Start Here",
|
|
50
|
-
"",
|
|
51
|
-
`Project: ${project.projectName}`,
|
|
52
|
-
"",
|
|
53
|
-
"This workspace was created by Long Table for a single research project.",
|
|
54
|
-
"",
|
|
55
|
-
"## What to do now",
|
|
56
|
-
"1. Open Codex in this directory.",
|
|
57
|
-
"2. Start with your current goal, not a shell command.",
|
|
58
|
-
"3. Let Long Table keep disagreement visible when it matters.",
|
|
59
|
-
"4. If you ask for factual or current external information, expect sources or an explicit inference label.",
|
|
60
|
-
"",
|
|
61
|
-
"## Suggested first message",
|
|
62
|
-
session.currentBlocker
|
|
63
|
-
? `"I want to work on ${session.currentGoal}. My current blocker is: ${session.currentBlocker}."`
|
|
64
|
-
: `"I want to work on ${session.currentGoal}."`,
|
|
65
|
-
"",
|
|
66
|
-
"## Explicit Long Table invocation inside Codex",
|
|
67
|
-
"- `lt explore: <question>`",
|
|
68
|
-
"- `lt review: <claim or plan>`",
|
|
69
|
-
"- `lt panel: <claim or plan>`",
|
|
70
|
-
"- `lt editor: <draft or positioning question>`",
|
|
71
|
-
"- `lt reviewer: <claim or section>`",
|
|
72
|
-
"- `lt methods: <design, measure, or analysis plan>`",
|
|
73
|
-
"- `lt commit: <decision that needs commitment>`",
|
|
74
|
-
"",
|
|
75
|
-
"## What Long Table already knows in this directory",
|
|
76
|
-
`- Current goal: ${session.currentGoal}`,
|
|
77
|
-
...(session.currentBlocker ? [`- Current blocker: ${session.currentBlocker}`] : []),
|
|
78
|
-
`- Requested perspectives: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
79
|
-
`- Disagreement visibility: ${session.disagreementPreference}`,
|
|
80
|
-
"",
|
|
81
|
-
"## Files",
|
|
82
|
-
"- `AGENTS.md` tells Codex how to behave in this workspace.",
|
|
83
|
-
"- `.longtable/current-session.json` stores the current session goal and blocker.",
|
|
84
|
-
"- `.longtable/project.json` stores the project-level record.",
|
|
85
|
-
"- `NEXT-STEPS.md` stores the immediate next actions.",
|
|
86
|
-
"- `SESSION-SNAPSHOT.md` stores the short resume snapshot."
|
|
87
|
-
];
|
|
88
|
-
return lines.join("\n");
|
|
25
|
+
function resolveCurrentFilePath(projectPath) {
|
|
26
|
+
return join(projectPath, CURRENT_FILE_NAME);
|
|
89
27
|
}
|
|
90
|
-
function
|
|
91
|
-
|
|
28
|
+
function normalizeLocale(locale) {
|
|
29
|
+
if ((locale ?? "").toLowerCase().startsWith("ko")) {
|
|
30
|
+
return "ko";
|
|
31
|
+
}
|
|
32
|
+
return "en";
|
|
33
|
+
}
|
|
34
|
+
function resolveUserLocale() {
|
|
35
|
+
const envLocale = process.env.LC_ALL ??
|
|
36
|
+
process.env.LC_MESSAGES ??
|
|
37
|
+
process.env.LANG ??
|
|
38
|
+
"";
|
|
39
|
+
if (envLocale && !["c", "c.utf-8", "posix"].includes(envLocale.toLowerCase())) {
|
|
40
|
+
return normalizeLocale(envLocale);
|
|
41
|
+
}
|
|
42
|
+
if (process.platform === "darwin") {
|
|
43
|
+
try {
|
|
44
|
+
const appleLocale = execSync("defaults read -g AppleLocale", { encoding: "utf8" }).trim();
|
|
45
|
+
if (appleLocale) {
|
|
46
|
+
return normalizeLocale(appleLocale);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Ignore and fall back to Intl below.
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return normalizeLocale(Intl.DateTimeFormat().resolvedOptions().locale);
|
|
54
|
+
}
|
|
55
|
+
function buildFirstQuestion(session) {
|
|
56
|
+
return session.currentBlocker
|
|
92
57
|
? `What would reduce the uncertainty around "${session.currentBlocker}" first?`
|
|
93
58
|
: `What is the first concrete question that would move "${session.currentGoal}" forward?`;
|
|
59
|
+
}
|
|
60
|
+
function buildOpenQuestions(session) {
|
|
61
|
+
const firstQuestion = buildFirstQuestion(session);
|
|
62
|
+
return session.currentBlocker
|
|
63
|
+
? [
|
|
64
|
+
firstQuestion,
|
|
65
|
+
`What evidence would let you decide whether "${session.currentBlocker}" is a knowledge gap, a coding rule gap, or a data gap?`
|
|
66
|
+
]
|
|
67
|
+
: [
|
|
68
|
+
firstQuestion,
|
|
69
|
+
`What would count as a good first outcome for "${session.currentGoal}" in this session?`
|
|
70
|
+
];
|
|
71
|
+
}
|
|
72
|
+
function buildNextAction(session) {
|
|
73
|
+
return session.currentBlocker
|
|
74
|
+
? `Open with the blocker, then ask LongTable to surface the first high-leverage uncertainty around "${session.currentBlocker}".`
|
|
75
|
+
: "Open with your current goal in one sentence, then ask LongTable for the first concrete research move.";
|
|
76
|
+
}
|
|
77
|
+
function buildResumeHint(session) {
|
|
78
|
+
return session.currentBlocker
|
|
79
|
+
? `I want to continue ${session.currentGoal}. The unresolved blocker is ${session.currentBlocker}.`
|
|
80
|
+
: `I want to continue ${session.currentGoal}.`;
|
|
81
|
+
}
|
|
82
|
+
function buildCurrentGuide(project, session) {
|
|
83
|
+
const locale = normalizeLocale(session.locale ?? project.locale);
|
|
84
|
+
const openQuestions = session.openQuestions && session.openQuestions.length > 0
|
|
85
|
+
? session.openQuestions
|
|
86
|
+
: buildOpenQuestions(session);
|
|
87
|
+
const nextAction = session.nextAction ?? buildNextAction(session);
|
|
88
|
+
const resumeHint = session.resumeHint ?? buildResumeHint(session);
|
|
89
|
+
const suggestedPrompt = `lt explore: ${openQuestions[0]}`;
|
|
90
|
+
if (locale === "ko") {
|
|
91
|
+
return [
|
|
92
|
+
"# CURRENT",
|
|
93
|
+
"",
|
|
94
|
+
`Project: ${project.projectName}`,
|
|
95
|
+
"",
|
|
96
|
+
"이 파일은 `.longtable/current-session.json`과 `.longtable/state.json`에서 재생성되는 현재 작업 뷰입니다.",
|
|
97
|
+
"",
|
|
98
|
+
"## 지금 초점",
|
|
99
|
+
`- 현재 목표: ${session.currentGoal}`,
|
|
100
|
+
...(session.currentBlocker ? [`- 현재 blocker: ${session.currentBlocker}`] : []),
|
|
101
|
+
`- 다음 액션: ${nextAction}`,
|
|
102
|
+
`- 관점: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
103
|
+
`- disagreement: ${session.disagreementPreference}`,
|
|
104
|
+
"",
|
|
105
|
+
"## 열린 질문",
|
|
106
|
+
...openQuestions.map((question) => `- ${question}`),
|
|
107
|
+
"",
|
|
108
|
+
"## 다시 시작 문장",
|
|
109
|
+
`- "${resumeHint}"`,
|
|
110
|
+
"",
|
|
111
|
+
"## 빠른 시작",
|
|
112
|
+
"- 이 디렉토리에서 `codex`를 엽니다.",
|
|
113
|
+
`- 첫 메시지는 보통 \`${suggestedPrompt}\` 정도면 충분합니다.`,
|
|
114
|
+
"",
|
|
115
|
+
"## 증거 규칙",
|
|
116
|
+
"- 외부 사실이나 현재 정보는 source를 붙이거나 inference로 낮춥니다."
|
|
117
|
+
].join("\n");
|
|
118
|
+
}
|
|
94
119
|
return [
|
|
95
|
-
"#
|
|
120
|
+
"# CURRENT",
|
|
96
121
|
"",
|
|
97
122
|
`Project: ${project.projectName}`,
|
|
98
123
|
"",
|
|
99
|
-
"
|
|
100
|
-
"1. Open Codex in this directory.",
|
|
101
|
-
"2. State your current goal in one sentence.",
|
|
102
|
-
"3. Ask Long Table to surface disagreement before closing on a plan.",
|
|
124
|
+
"This file is regenerated from `.longtable/current-session.json` and `.longtable/state.json`.",
|
|
103
125
|
"",
|
|
104
|
-
"##
|
|
105
|
-
`-
|
|
106
|
-
`-
|
|
107
|
-
`-
|
|
108
|
-
""
|
|
109
|
-
|
|
110
|
-
"- Read `SESSION-SNAPSHOT.md` first.",
|
|
111
|
-
"- Continue from the unresolved blocker rather than restating the whole project.",
|
|
126
|
+
"## Focus Now",
|
|
127
|
+
`- Current goal: ${session.currentGoal}`,
|
|
128
|
+
...(session.currentBlocker ? [`- Current blocker: ${session.currentBlocker}`] : []),
|
|
129
|
+
`- Next action: ${nextAction}`,
|
|
130
|
+
`- Perspectives: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
131
|
+
`- Disagreement: ${session.disagreementPreference}`,
|
|
112
132
|
"",
|
|
113
|
-
"##
|
|
114
|
-
|
|
115
|
-
].join("\n");
|
|
116
|
-
}
|
|
117
|
-
function buildSessionSnapshot(project, session) {
|
|
118
|
-
return [
|
|
119
|
-
"# Session Snapshot",
|
|
133
|
+
"## Open Questions",
|
|
134
|
+
...openQuestions.map((question) => `- ${question}`),
|
|
120
135
|
"",
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
...(session.currentBlocker ? [`Current blocker: ${session.currentBlocker}`] : []),
|
|
124
|
-
`Requested perspectives: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
125
|
-
`Disagreement visibility: ${session.disagreementPreference}`,
|
|
136
|
+
"## Restart Prompt",
|
|
137
|
+
`- "${resumeHint}"`,
|
|
126
138
|
"",
|
|
127
|
-
"##
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
: `"I want to continue ${session.currentGoal}."`,
|
|
139
|
+
"## Quick Start",
|
|
140
|
+
"- Open `codex` in this directory.",
|
|
141
|
+
`- A good first message is usually \`${suggestedPrompt}\`.`,
|
|
131
142
|
"",
|
|
132
|
-
"##
|
|
133
|
-
"-
|
|
134
|
-
"- If factual or external claims matter, Long Table should cite sources or mark them as inference."
|
|
143
|
+
"## Evidence Rule",
|
|
144
|
+
"- External or current claims should carry a source link or be labeled as inference."
|
|
135
145
|
].join("\n");
|
|
136
146
|
}
|
|
137
147
|
function buildProjectAgentsMd(project, session) {
|
|
138
148
|
return [
|
|
139
149
|
"# AGENTS.md",
|
|
140
150
|
"",
|
|
141
|
-
"This directory is a
|
|
151
|
+
"This directory is a LongTable research workspace.",
|
|
142
152
|
"",
|
|
143
|
-
"##
|
|
144
|
-
`- Project name: ${project.projectName}`,
|
|
145
|
-
`- Current goal: ${session.currentGoal}`,
|
|
146
|
-
...(session.currentBlocker ? [`- Current blocker: ${session.currentBlocker}`] : []),
|
|
147
|
-
`- Requested perspectives: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
148
|
-
`- Disagreement visibility: ${session.disagreementPreference}`,
|
|
149
|
-
"",
|
|
150
|
-
"## Research-facing behavior",
|
|
153
|
+
"## Runtime Contract",
|
|
151
154
|
"- Treat researcher interaction as the primary task.",
|
|
152
|
-
"-
|
|
155
|
+
"- Read `.longtable/current-session.json` before giving substantial guidance.",
|
|
156
|
+
"- Use `.longtable/project.json` as stable project context.",
|
|
157
|
+
"- Use `.longtable/state.json` as layered working memory.",
|
|
158
|
+
"- Prefer `currentGoal`, `currentBlocker`, `nextAction`, and `openQuestions` over generic assumptions.",
|
|
159
|
+
"- Treat `AGENTS.md` as runtime guidance, not as the researcher-facing resume artifact.",
|
|
160
|
+
"",
|
|
161
|
+
"## Invocation Rules",
|
|
162
|
+
"- If the user message starts with `lt `, `longtable `, `long table `, or `롱테이블 ` followed by a directive and `:`, treat it as an explicit LongTable invocation.",
|
|
153
163
|
"- Supported explicit directives are: explore, review, critique, draft, commit, panel, status, editor, reviewer, methods, theory, measurement, ethics, voice, venue.",
|
|
154
|
-
"- For explicit
|
|
155
|
-
"- For general research requests in this workspace, prefer
|
|
164
|
+
"- For explicit LongTable invocations, do not begin by scanning the workspace. Use the current session files first and answer as LongTable immediately.",
|
|
165
|
+
"- For general research requests in this workspace, prefer LongTable behavior before generic coding behavior.",
|
|
166
|
+
"",
|
|
167
|
+
"## Research Behavior",
|
|
156
168
|
"- Begin exploratory work with clarifying or tension questions before recommending a direction.",
|
|
157
|
-
"- If you foreground role perspectives, disclose them with `
|
|
169
|
+
"- If you foreground role perspectives, disclose them with `LongTable consulted: ...`.",
|
|
158
170
|
"- Keep one accountable synthesis, but do not hide meaningful disagreement.",
|
|
159
|
-
"- For factual, current, or external claims, provide source links or file references when possible.",
|
|
160
|
-
"- If a statement cannot be sourced, label it as an inference or estimate instead of presenting it as a fact.",
|
|
161
171
|
...(session.disagreementPreference === "always_visible"
|
|
162
|
-
? ["-
|
|
172
|
+
? ["- Panel disagreement should be visible by default rather than hidden behind a single synthesis."]
|
|
163
173
|
: []),
|
|
174
|
+
"- For factual, current, or external claims, provide source links or file references when possible.",
|
|
175
|
+
"- If a statement cannot be sourced, label it as an inference or estimate instead of presenting it as a fact.",
|
|
164
176
|
"- Do not expose internal tool logs, file-search traces, or process commentary in the researcher-facing answer.",
|
|
165
177
|
"",
|
|
166
|
-
"## Session memory",
|
|
167
|
-
"- Read `.longtable/current-session.json` before giving substantial guidance.",
|
|
168
|
-
"- Use `.longtable/project.json` as the project-level context.",
|
|
169
|
-
"- Prefer the current goal and blocker over generic assumptions.",
|
|
170
|
-
"- Do not recursively search unrelated files unless the researcher explicitly asks for file analysis or code changes.",
|
|
171
|
-
"",
|
|
172
178
|
"## Scope",
|
|
179
|
+
`- Project: ${project.projectName}`,
|
|
180
|
+
`- Current goal: ${session.currentGoal}`,
|
|
181
|
+
...(session.currentBlocker ? [`- Current blocker: ${session.currentBlocker}`] : []),
|
|
182
|
+
`- Requested perspectives: ${session.requestedPerspectives.length > 0 ? session.requestedPerspectives.join(", ") : "auto"}`,
|
|
183
|
+
`- Disagreement visibility: ${session.disagreementPreference}`,
|
|
173
184
|
"- These instructions apply to this directory and its children."
|
|
174
185
|
].join("\n");
|
|
175
186
|
}
|
|
@@ -180,12 +191,18 @@ function buildStateSeed(project, session, setup) {
|
|
|
180
191
|
careerStage: setup.profileSeed.careerStage,
|
|
181
192
|
experienceLevel: setup.profileSeed.experienceLevel,
|
|
182
193
|
projectName: project.projectName,
|
|
183
|
-
currentGoal: session.currentGoal,
|
|
184
194
|
disagreementPreference: session.disagreementPreference,
|
|
185
195
|
requestedPerspectives: session.requestedPerspectives
|
|
186
196
|
};
|
|
197
|
+
state.workingState = {
|
|
198
|
+
currentGoal: session.currentGoal,
|
|
199
|
+
...(session.currentBlocker ? { currentBlocker: session.currentBlocker } : {}),
|
|
200
|
+
...(session.nextAction ? { nextAction: session.nextAction } : {}),
|
|
201
|
+
openQuestions: session.openQuestions ?? [],
|
|
202
|
+
activeModes: session.activeModes ?? [],
|
|
203
|
+
...(session.resumeHint ? { resumeHint: session.resumeHint } : {})
|
|
204
|
+
};
|
|
187
205
|
if (session.currentBlocker) {
|
|
188
|
-
state.explicitState.currentBlocker = session.currentBlocker;
|
|
189
206
|
state.openTensions.push(session.currentBlocker);
|
|
190
207
|
}
|
|
191
208
|
if (setup.profileSeed.humanAuthorshipSignal) {
|
|
@@ -213,24 +230,42 @@ function buildStateSeed(project, session, setup) {
|
|
|
213
230
|
}
|
|
214
231
|
return JSON.stringify(state, null, 2);
|
|
215
232
|
}
|
|
233
|
+
async function removeLegacyRootFiles(projectPath) {
|
|
234
|
+
await Promise.all(LEGACY_ROOT_FILES.map((file) => rm(join(projectPath, file), { force: true })));
|
|
235
|
+
}
|
|
236
|
+
export async function syncCurrentWorkspaceView(context) {
|
|
237
|
+
const body = buildCurrentGuide(context.project, context.session);
|
|
238
|
+
await writeFile(context.currentFilePath, body, "utf8");
|
|
239
|
+
return context.currentFilePath;
|
|
240
|
+
}
|
|
216
241
|
export async function createOrUpdateProjectWorkspace(options) {
|
|
217
242
|
const projectPath = resolve(options.projectPath);
|
|
218
243
|
const metaDir = resolveMetaDir(projectPath);
|
|
219
244
|
const sessionsDir = join(metaDir, "sessions");
|
|
220
245
|
const projectFilePath = join(metaDir, "project.json");
|
|
221
246
|
const sessionFilePath = join(metaDir, "current-session.json");
|
|
247
|
+
const stateFilePath = resolveStateFilePath(projectPath);
|
|
248
|
+
const currentFilePath = resolveCurrentFilePath(projectPath);
|
|
222
249
|
const sessionId = slugify(`${options.projectName}-${Date.now()}`);
|
|
250
|
+
const locale = resolveUserLocale();
|
|
251
|
+
const timestamp = nowIso();
|
|
223
252
|
await mkdir(projectPath, { recursive: true });
|
|
224
253
|
await mkdir(metaDir, { recursive: true });
|
|
225
254
|
await mkdir(sessionsDir, { recursive: true });
|
|
226
255
|
const project = existsSync(projectFilePath)
|
|
227
|
-
?
|
|
256
|
+
? {
|
|
257
|
+
...JSON.parse(await readFile(projectFilePath, "utf8")),
|
|
258
|
+
contractVersion: "workspace-v2",
|
|
259
|
+
locale
|
|
260
|
+
}
|
|
228
261
|
: {
|
|
229
262
|
schemaVersion: 1,
|
|
230
|
-
product: "
|
|
263
|
+
product: "LongTable",
|
|
231
264
|
projectName: options.projectName,
|
|
232
265
|
projectPath,
|
|
233
|
-
createdAt:
|
|
266
|
+
createdAt: timestamp,
|
|
267
|
+
contractVersion: "workspace-v2",
|
|
268
|
+
locale,
|
|
234
269
|
globalSetupSummary: {
|
|
235
270
|
field: options.setup.profileSeed.field,
|
|
236
271
|
careerStage: options.setup.profileSeed.careerStage,
|
|
@@ -250,30 +285,67 @@ export async function createOrUpdateProjectWorkspace(options) {
|
|
|
250
285
|
const session = {
|
|
251
286
|
schemaVersion: 1,
|
|
252
287
|
id: sessionId,
|
|
253
|
-
createdAt:
|
|
288
|
+
createdAt: timestamp,
|
|
289
|
+
lastUpdatedAt: timestamp,
|
|
254
290
|
projectName: project.projectName,
|
|
255
291
|
projectPath,
|
|
256
292
|
currentGoal: options.currentGoal,
|
|
257
293
|
...(options.currentBlocker ? { currentBlocker: options.currentBlocker } : {}),
|
|
294
|
+
nextAction: buildNextAction({
|
|
295
|
+
schemaVersion: 1,
|
|
296
|
+
id: sessionId,
|
|
297
|
+
createdAt: timestamp,
|
|
298
|
+
projectName: project.projectName,
|
|
299
|
+
projectPath,
|
|
300
|
+
currentGoal: options.currentGoal,
|
|
301
|
+
...(options.currentBlocker ? { currentBlocker: options.currentBlocker } : {}),
|
|
302
|
+
requestedPerspectives: options.requestedPerspectives,
|
|
303
|
+
disagreementPreference: options.disagreementPreference
|
|
304
|
+
}),
|
|
305
|
+
openQuestions: buildOpenQuestions({
|
|
306
|
+
schemaVersion: 1,
|
|
307
|
+
id: sessionId,
|
|
308
|
+
createdAt: timestamp,
|
|
309
|
+
projectName: project.projectName,
|
|
310
|
+
projectPath,
|
|
311
|
+
currentGoal: options.currentGoal,
|
|
312
|
+
...(options.currentBlocker ? { currentBlocker: options.currentBlocker } : {}),
|
|
313
|
+
requestedPerspectives: options.requestedPerspectives,
|
|
314
|
+
disagreementPreference: options.disagreementPreference
|
|
315
|
+
}),
|
|
258
316
|
requestedPerspectives: options.requestedPerspectives,
|
|
259
|
-
disagreementPreference: options.disagreementPreference
|
|
317
|
+
disagreementPreference: options.disagreementPreference,
|
|
318
|
+
activeModes: ["explore"],
|
|
319
|
+
resumeHint: buildResumeHint({
|
|
320
|
+
schemaVersion: 1,
|
|
321
|
+
id: sessionId,
|
|
322
|
+
createdAt: timestamp,
|
|
323
|
+
projectName: project.projectName,
|
|
324
|
+
projectPath,
|
|
325
|
+
currentGoal: options.currentGoal,
|
|
326
|
+
...(options.currentBlocker ? { currentBlocker: options.currentBlocker } : {}),
|
|
327
|
+
requestedPerspectives: options.requestedPerspectives,
|
|
328
|
+
disagreementPreference: options.disagreementPreference
|
|
329
|
+
}),
|
|
330
|
+
locale
|
|
260
331
|
};
|
|
261
|
-
|
|
262
|
-
await writeFile(sessionFilePath, JSON.stringify(session, null, 2), "utf8");
|
|
263
|
-
await writeFile(join(sessionsDir, `${sessionId}.json`), JSON.stringify(session, null, 2), "utf8");
|
|
264
|
-
await writeFile(join(metaDir, "state.json"), buildStateSeed(project, session, options.setup), "utf8");
|
|
265
|
-
await writeFile(join(projectPath, "LONGTABLE.md"), buildWorkspaceGuide(project, session), "utf8");
|
|
266
|
-
await writeFile(join(projectPath, "START-HERE.md"), buildStartHereGuide(project, session), "utf8");
|
|
267
|
-
await writeFile(join(projectPath, "NEXT-STEPS.md"), buildNextStepsGuide(project, session), "utf8");
|
|
268
|
-
await writeFile(join(projectPath, "SESSION-SNAPSHOT.md"), buildSessionSnapshot(project, session), "utf8");
|
|
269
|
-
await writeFile(join(projectPath, "AGENTS.md"), buildProjectAgentsMd(project, session), "utf8");
|
|
270
|
-
return {
|
|
332
|
+
const context = {
|
|
271
333
|
project,
|
|
272
334
|
session,
|
|
273
335
|
projectFilePath,
|
|
274
336
|
sessionFilePath,
|
|
337
|
+
stateFilePath,
|
|
338
|
+
currentFilePath,
|
|
275
339
|
metaDir
|
|
276
340
|
};
|
|
341
|
+
await writeFile(projectFilePath, JSON.stringify(project, null, 2), "utf8");
|
|
342
|
+
await writeFile(sessionFilePath, JSON.stringify(session, null, 2), "utf8");
|
|
343
|
+
await writeFile(join(sessionsDir, `${sessionId}.json`), JSON.stringify(session, null, 2), "utf8");
|
|
344
|
+
await writeFile(stateFilePath, buildStateSeed(project, session, options.setup), "utf8");
|
|
345
|
+
await writeFile(join(projectPath, "AGENTS.md"), buildProjectAgentsMd(project, session), "utf8");
|
|
346
|
+
await syncCurrentWorkspaceView(context);
|
|
347
|
+
await removeLegacyRootFiles(projectPath);
|
|
348
|
+
return context;
|
|
277
349
|
}
|
|
278
350
|
export async function loadProjectContextFromDirectory(startPath) {
|
|
279
351
|
let current = resolve(startPath);
|
|
@@ -282,11 +354,22 @@ export async function loadProjectContextFromDirectory(startPath) {
|
|
|
282
354
|
const projectFilePath = join(metaDir, "project.json");
|
|
283
355
|
const sessionFilePath = join(metaDir, "current-session.json");
|
|
284
356
|
if (existsSync(projectFilePath) && existsSync(sessionFilePath)) {
|
|
357
|
+
const project = JSON.parse(await readFile(projectFilePath, "utf8"));
|
|
358
|
+
const session = JSON.parse(await readFile(sessionFilePath, "utf8"));
|
|
285
359
|
return {
|
|
286
|
-
project
|
|
287
|
-
session:
|
|
360
|
+
project,
|
|
361
|
+
session: {
|
|
362
|
+
...session,
|
|
363
|
+
locale: session.locale ?? project.locale ?? resolveUserLocale(),
|
|
364
|
+
openQuestions: session.openQuestions ?? buildOpenQuestions(session),
|
|
365
|
+
nextAction: session.nextAction ?? buildNextAction(session),
|
|
366
|
+
resumeHint: session.resumeHint ?? buildResumeHint(session),
|
|
367
|
+
activeModes: session.activeModes ?? ["explore"]
|
|
368
|
+
},
|
|
288
369
|
projectFilePath,
|
|
289
370
|
sessionFilePath,
|
|
371
|
+
stateFilePath: resolveStateFilePath(project.projectPath),
|
|
372
|
+
currentFilePath: resolveCurrentFilePath(project.projectPath),
|
|
290
373
|
metaDir
|
|
291
374
|
};
|
|
292
375
|
}
|
|
@@ -300,7 +383,7 @@ export async function loadProjectContextFromDirectory(startPath) {
|
|
|
300
383
|
export function renderProjectWorkspaceSummary(context) {
|
|
301
384
|
return [
|
|
302
385
|
"┌──────────────────────────────────────────────┐",
|
|
303
|
-
"│
|
|
386
|
+
"│ LongTable Project Workspace │",
|
|
304
387
|
"└──────────────────────────────────────────────┘",
|
|
305
388
|
`Project: ${context.project.projectName}`,
|
|
306
389
|
`Path: ${context.project.projectPath}`,
|
|
@@ -312,9 +395,8 @@ export function renderProjectWorkspaceSummary(context) {
|
|
|
312
395
|
"Created files:",
|
|
313
396
|
`- ${context.projectFilePath}`,
|
|
314
397
|
`- ${context.sessionFilePath}`,
|
|
315
|
-
`- ${
|
|
316
|
-
`- ${
|
|
317
|
-
`- ${join(context.project.projectPath, "SESSION-SNAPSHOT.md")}`,
|
|
398
|
+
`- ${context.stateFilePath}`,
|
|
399
|
+
`- ${context.currentFilePath}`,
|
|
318
400
|
`- ${join(context.project.projectPath, "AGENTS.md")}`
|
|
319
401
|
].join("\n");
|
|
320
402
|
}
|
package/dist/prompt-aliases.js
CHANGED
|
@@ -9,26 +9,26 @@ function promptSpec() {
|
|
|
9
9
|
return [
|
|
10
10
|
{
|
|
11
11
|
name: "longtable",
|
|
12
|
-
description: "Single-entry
|
|
12
|
+
description: "Single-entry LongTable router for research conversations",
|
|
13
13
|
argumentHint: "<natural language research request>",
|
|
14
14
|
body: [
|
|
15
|
-
"You are
|
|
15
|
+
"You are LongTable.",
|
|
16
16
|
"Classify the user's request into one of these modes: explore, review, critique, draft, commit, panel, or status.",
|
|
17
17
|
"If the request is ambiguous, ask one short clarifying question before closing.",
|
|
18
|
-
"Always begin with `
|
|
19
|
-
"Always disclose consulted roles with `
|
|
18
|
+
"Always begin with `LongTable mode: <Mode>`.",
|
|
19
|
+
"Always disclose consulted roles with `LongTable consulted: ...` when any role is foregrounded.",
|
|
20
20
|
"In explore mode, ask at least two clarifying or tension questions before any recommendation.",
|
|
21
|
-
"In panel mode, return 1)
|
|
21
|
+
"In panel mode, return 1) LongTable synthesis 2) visible panel opinions by role 3) conflict summary if needed 4) a decision prompt for the researcher.",
|
|
22
22
|
"Do not expose internal tool logs, file searches, or process notes in the researcher-facing answer.",
|
|
23
23
|
"Treat any slash-command arguments as the current research object."
|
|
24
24
|
]
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
name: "longtable-init",
|
|
28
|
-
description: "Run
|
|
28
|
+
description: "Run LongTable researcher onboarding inside Codex",
|
|
29
29
|
argumentHint: "[project context or current uncertainty]",
|
|
30
30
|
body: [
|
|
31
|
-
"You are
|
|
31
|
+
"You are LongTable onboarding inside Codex.",
|
|
32
32
|
"First ask whether the researcher wants Quickstart or Interview setup.",
|
|
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.",
|
|
@@ -45,11 +45,11 @@ function promptSpec() {
|
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
name: "longtable-explore",
|
|
48
|
-
description: "
|
|
48
|
+
description: "LongTable explore mode for open research questions",
|
|
49
49
|
argumentHint: "<topic or research problem>",
|
|
50
50
|
body: [
|
|
51
|
-
"You are
|
|
52
|
-
"Always begin with `
|
|
51
|
+
"You are LongTable in explore mode.",
|
|
52
|
+
"Always begin with `LongTable mode: Explore`.",
|
|
53
53
|
"Ask at least two clarifying or tension questions before any recommendation.",
|
|
54
54
|
"Keep unresolved tensions visible.",
|
|
55
55
|
"Do not rush to synthesis.",
|
|
@@ -59,11 +59,11 @@ function promptSpec() {
|
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
name: "longtable-review",
|
|
62
|
-
description: "
|
|
62
|
+
description: "LongTable review mode for critical evaluation",
|
|
63
63
|
argumentHint: "<claim, paragraph, design, or plan>",
|
|
64
64
|
body: [
|
|
65
|
-
"You are
|
|
66
|
-
"Always begin with `
|
|
65
|
+
"You are LongTable in review mode.",
|
|
66
|
+
"Always begin with `LongTable mode: Review`.",
|
|
67
67
|
"Surface why this may be wrong before synthesis.",
|
|
68
68
|
"Preserve the researcher's own language where possible.",
|
|
69
69
|
"Treat any slash-command arguments as the object to review."
|
|
@@ -71,12 +71,12 @@ function promptSpec() {
|
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
73
|
name: "longtable-panel",
|
|
74
|
-
description: "
|
|
74
|
+
description: "LongTable panel mode with visible role disagreement",
|
|
75
75
|
argumentHint: "<claim, plan, or draft for multi-role review>",
|
|
76
76
|
body: [
|
|
77
|
-
"You are
|
|
78
|
-
"Always begin with `
|
|
79
|
-
"Return 1) a
|
|
77
|
+
"You are LongTable in panel mode.",
|
|
78
|
+
"Always begin with `LongTable mode: Panel`.",
|
|
79
|
+
"Return 1) a LongTable synthesis 2) visible panel opinions by role 3) a decision prompt for the researcher.",
|
|
80
80
|
"If roles disagree, do not collapse them too early.",
|
|
81
81
|
"Disclose which roles were consulted.",
|
|
82
82
|
"Treat any slash-command arguments as the object under discussion."
|
|
@@ -84,10 +84,10 @@ function promptSpec() {
|
|
|
84
84
|
},
|
|
85
85
|
{
|
|
86
86
|
name: "longtable-editor",
|
|
87
|
-
description: "
|
|
87
|
+
description: "LongTable editor view",
|
|
88
88
|
argumentHint: "<claim, draft, or paper positioning>",
|
|
89
89
|
body: [
|
|
90
|
-
"You are
|
|
90
|
+
"You are LongTable with the Journal Editor role foregrounded.",
|
|
91
91
|
"Prioritize venue fit, framing clarity, contribution shape, and likely editorial concerns.",
|
|
92
92
|
"Disclose that the editor role was consulted.",
|
|
93
93
|
"Treat any slash-command arguments as the editorial object."
|
|
@@ -95,10 +95,10 @@ function promptSpec() {
|
|
|
95
95
|
},
|
|
96
96
|
{
|
|
97
97
|
name: "longtable-reviewer",
|
|
98
|
-
description: "
|
|
98
|
+
description: "LongTable reviewer view",
|
|
99
99
|
argumentHint: "<claim, method, or manuscript section>",
|
|
100
100
|
body: [
|
|
101
|
-
"You are
|
|
101
|
+
"You are LongTable with the Reviewer role foregrounded.",
|
|
102
102
|
"Prioritize likely objections, missing evidence, weak claims, and points needing clarification.",
|
|
103
103
|
"Disclose that the reviewer role was consulted.",
|
|
104
104
|
"Treat any slash-command arguments as the review object."
|
|
@@ -106,10 +106,10 @@ function promptSpec() {
|
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
108
|
name: "longtable-methods",
|
|
109
|
-
description: "
|
|
109
|
+
description: "LongTable methods-critic view",
|
|
110
110
|
argumentHint: "<study design, measure, or analysis plan>",
|
|
111
111
|
body: [
|
|
112
|
-
"You are
|
|
112
|
+
"You are LongTable with the Methods Critic role foregrounded.",
|
|
113
113
|
"Prioritize design fit, methodological defensibility, and mismatches between question, measure, and analysis.",
|
|
114
114
|
"Disclose that the methods critic role was consulted.",
|
|
115
115
|
"Treat any slash-command arguments as the methodological object."
|
|
@@ -117,10 +117,10 @@ function promptSpec() {
|
|
|
117
117
|
},
|
|
118
118
|
{
|
|
119
119
|
name: "longtable-critique",
|
|
120
|
-
description: "
|
|
120
|
+
description: "LongTable critique mode for stronger counterarguments",
|
|
121
121
|
argumentHint: "<claim or draft to challenge>",
|
|
122
122
|
body: [
|
|
123
|
-
"You are
|
|
123
|
+
"You are LongTable in critique mode.",
|
|
124
124
|
"Prioritize counterarguments, blind spots, and hidden assumptions.",
|
|
125
125
|
"Do not smooth over uncertainty.",
|
|
126
126
|
"Treat any slash-command arguments as the object to challenge."
|
|
@@ -128,10 +128,10 @@ function promptSpec() {
|
|
|
128
128
|
},
|
|
129
129
|
{
|
|
130
130
|
name: "longtable-draft",
|
|
131
|
-
description: "
|
|
131
|
+
description: "LongTable draft mode with narrative-trace preservation",
|
|
132
132
|
argumentHint: "<draft goal or section request>",
|
|
133
133
|
body: [
|
|
134
|
-
"You are
|
|
134
|
+
"You are LongTable in draft mode.",
|
|
135
135
|
"Preserve narrative trace and avoid generic fluency.",
|
|
136
136
|
"Keep the researcher's voice recognizable.",
|
|
137
137
|
"Treat any slash-command arguments as the drafting target."
|
|
@@ -139,10 +139,10 @@ function promptSpec() {
|
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
141
|
name: "longtable-commit",
|
|
142
|
-
description: "
|
|
142
|
+
description: "LongTable commit mode for explicit human decisions",
|
|
143
143
|
argumentHint: "<decision or choice that needs commitment>",
|
|
144
144
|
body: [
|
|
145
|
-
"You are
|
|
145
|
+
"You are LongTable in commit mode.",
|
|
146
146
|
"Before making any recommendation, ask for the human commitment that is actually at stake.",
|
|
147
147
|
"Make the trade-offs explicit.",
|
|
148
148
|
"Treat any slash-command arguments as the decision under consideration."
|
|
@@ -150,11 +150,11 @@ function promptSpec() {
|
|
|
150
150
|
},
|
|
151
151
|
{
|
|
152
152
|
name: "longtable-status",
|
|
153
|
-
description: "Inspect
|
|
153
|
+
description: "Inspect LongTable setup and Codex alias status",
|
|
154
154
|
argumentHint: "[optional concern]",
|
|
155
155
|
body: [
|
|
156
|
-
"You are
|
|
157
|
-
"Inspect whether setup and runtime artifacts appear to exist under `~/.
|
|
156
|
+
"You are LongTable status mode.",
|
|
157
|
+
"Inspect whether setup and runtime artifacts appear to exist under `~/.longtable/` and whether LongTable prompt aliases appear to be installed under `~/.codex/prompts/`.",
|
|
158
158
|
"Summarize what is configured, what is missing, and the next minimal action.",
|
|
159
159
|
"Treat any slash-command arguments as the user's concern."
|
|
160
160
|
]
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longtable/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "Researcher-facing
|
|
5
|
+
"description": "Researcher-facing LongTable CLI",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
"import": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"longtable": "./bin/longtable"
|
|
17
|
+
},
|
|
15
18
|
"directories": {
|
|
16
19
|
"bin": "./bin"
|
|
17
20
|
},
|
|
@@ -25,9 +28,9 @@
|
|
|
25
28
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
26
29
|
},
|
|
27
30
|
"dependencies": {
|
|
28
|
-
"@
|
|
29
|
-
"@
|
|
30
|
-
"@
|
|
31
|
+
"@longtable/memory": "0.1.9",
|
|
32
|
+
"@longtable/provider-codex": "0.1.9",
|
|
33
|
+
"@longtable/setup": "0.1.9"
|
|
31
34
|
},
|
|
32
35
|
"devDependencies": {
|
|
33
36
|
"@types/node": "^22.10.1",
|
|
@@ -44,9 +47,9 @@
|
|
|
44
47
|
"license": "MIT",
|
|
45
48
|
"repository": {
|
|
46
49
|
"type": "git",
|
|
47
|
-
"url": "git+https://github.com/HosungYou/
|
|
50
|
+
"url": "git+https://github.com/HosungYou/LongTable.git"
|
|
48
51
|
},
|
|
49
|
-
"homepage": "https://github.com/HosungYou/
|
|
52
|
+
"homepage": "https://github.com/HosungYou/LongTable#readme",
|
|
50
53
|
"publishConfig": {
|
|
51
54
|
"access": "public"
|
|
52
55
|
},
|