@longtable/cli 0.1.41 → 0.1.43
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 +12 -0
- package/dist/cli.js +4 -1
- package/dist/longtable-codex-native-hook.js +124 -58
- package/dist/project-session.d.ts +4 -0
- package/dist/project-session.js +206 -5
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -188,6 +188,12 @@ Inside a LongTable project workspace, panel planning also appends an
|
|
|
188
188
|
`InvocationRecord` to `.longtable/state.json`, creates a pending follow-up
|
|
189
189
|
`QuestionRecord`, and refreshes `CURRENT.md`.
|
|
190
190
|
|
|
191
|
+
Panel output should remain inspectable. A panel or debate result is expected to
|
|
192
|
+
show the consulted roles, each role's main claim or objection, the disagreement
|
|
193
|
+
map, decision options, a defensible recommendation when one exists, and the
|
|
194
|
+
exact researcher-facing question before a high-stakes decision is treated as
|
|
195
|
+
settled.
|
|
196
|
+
|
|
191
197
|
Default panel roles include:
|
|
192
198
|
|
|
193
199
|
- `reviewer`
|
|
@@ -204,6 +210,12 @@ measurement, theory, method, evidence, authorship, or tacit-assumption risks.
|
|
|
204
210
|
Use `--record` inside a LongTable workspace to store the finding as an
|
|
205
211
|
unconfirmed inferred hypothesis.
|
|
206
212
|
|
|
213
|
+
The Codex hook stays quiet for advisory-only questions. Required hook context is
|
|
214
|
+
reserved for durable Researcher Checkpoints, especially when a prompt would
|
|
215
|
+
change the research question/scope, theory frame, measurement/coding standard,
|
|
216
|
+
method design, or analysis strategy. Low-risk reversible work should proceed
|
|
217
|
+
with visible assumptions rather than a noisy hook interruption.
|
|
218
|
+
|
|
207
219
|
`longtable team` creates a file-backed agent-team review under
|
|
208
220
|
`.longtable/team/<id>/`: independent review, cross-review, and
|
|
209
221
|
synthesis/checkpoint. Use it when roles should inspect each other's concerns
|
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,7 @@ import { existsSync, readFileSync, statSync } from "node:fs";
|
|
|
3
3
|
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import { execSync } from "node:child_process";
|
|
5
5
|
import { createInterface } from "node:readline/promises";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
6
7
|
import { stdin as input, stdout as output, cwd, env, exit } from "node:process";
|
|
7
8
|
import { dirname, join, resolve } from "node:path";
|
|
8
9
|
import { homedir } from "node:os";
|
|
@@ -44,8 +45,10 @@ const ANSI = {
|
|
|
44
45
|
cyan: "\u001B[36m",
|
|
45
46
|
green: "\u001B[32m"
|
|
46
47
|
};
|
|
48
|
+
const require = createRequire(import.meta.url);
|
|
49
|
+
const LONGTABLE_PACKAGE_VERSION = String(require("../package.json").version ?? "0.0.0");
|
|
47
50
|
const LONGTABLE_MCP_SERVER_NAME = "longtable-state";
|
|
48
|
-
const LONGTABLE_MCP_PACKAGE_VERSION =
|
|
51
|
+
const LONGTABLE_MCP_PACKAGE_VERSION = LONGTABLE_PACKAGE_VERSION;
|
|
49
52
|
const LONGTABLE_MCP_MARKER_START = "# LongTable state MCP START";
|
|
50
53
|
const LONGTABLE_MCP_MARKER_END = "# LongTable state MCP END";
|
|
51
54
|
function style(text, prefix) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { pathToFileURL } from "node:url";
|
|
2
|
-
import {
|
|
2
|
+
import { createWorkspaceFollowUpQuestions, loadProjectContextFromDirectory, loadWorkspaceState, pendingQuestionObligations } from "./index.js";
|
|
3
3
|
function safeString(value) {
|
|
4
4
|
return typeof value === "string" ? value : "";
|
|
5
5
|
}
|
|
@@ -115,7 +115,7 @@ function looksLikeLongTableProductOrToolingPrompt(prompt) {
|
|
|
115
115
|
if (!normalized) {
|
|
116
116
|
return false;
|
|
117
117
|
}
|
|
118
|
-
return /\b(longlongtable|hook|checkpoint|mcp|agents?|skills?|ux|interface|setup|install|cli|npm|version|global|release|deploy|git|github|readme|docs?|documentation|workflow|package|router|autocomplete|simulation test)\b/i.test(normalized)
|
|
118
|
+
return /\b(longtable|longlongtable|hook|checkpoint|mcp|agents?|skills?|ux|interface|setup|install|cli|npm|version|global|release|deploy|git|github|readme|docs?|documentation|workflow|package|router|autocomplete|simulation test)\b/i.test(normalized)
|
|
119
119
|
|| /롱테이블|훅|체크포인트|에이전트|스킬|사용성|인터페이스|설치|세팅|글로벌|배포|버전|릴리즈|깃|깃허브|문서화된\s*절차|패키지|라우터|자동완성|시뮬레이션\s*테스트/.test(normalized);
|
|
120
120
|
}
|
|
121
121
|
function looksLikeResearchDomainPrompt(prompt) {
|
|
@@ -123,34 +123,74 @@ function looksLikeResearchDomainPrompt(prompt) {
|
|
|
123
123
|
if (!normalized) {
|
|
124
124
|
return false;
|
|
125
125
|
}
|
|
126
|
-
return /\b(research|study|paper|manuscript|journal|article|method|methodology|measurement|construct|theory|analysis|model|data|participant|sample|scale|survey|instrument|validity|hypothesis|literature|meta[- ]?analysis|gold standard|coding|trust|reliance|calibration)\b/i.test(normalized)
|
|
127
|
-
||
|
|
126
|
+
return /\b(research|research question|research direction|scope|boundary|study|paper|manuscript|journal|article|method|methodology|measurement|construct|theory|framework|analysis|analysis plan|model|data|participant|sample|scale|survey|instrument|validity|hypothesis|literature|meta[- ]?analysis|gold standard|coding|criteria|trust|reliance|calibration)\b/i.test(normalized)
|
|
127
|
+
|| /연구|연구\s*질문|연구\s*방향|범위|경계|논문|원고|저널|방법론|방법|연구\s*설계|측정|구성개념|개념|이론|프레임워크|분석|분석\s*계획|모형|모델|데이터|참가자|표본|샘플|척도|설문|도구|타당도|가설|문헌|메타\s*분석|골드\s*스탠더드|코딩|기준|신뢰|의존|캘리브레이션|교정|보정/.test(normalized);
|
|
128
128
|
}
|
|
129
129
|
function looksLikeResearchCommitmentPrompt(prompt) {
|
|
130
|
-
return looksLikeResearchDomainPrompt(prompt) && looksLikeClosurePrompt(prompt)
|
|
130
|
+
return looksLikeResearchDomainPrompt(prompt) && (looksLikeClosurePrompt(prompt) ||
|
|
131
|
+
/\b(change|revise|update|replace|reframe|modify|alter)\b/i.test(prompt) ||
|
|
132
|
+
/바꾸|변경|수정|교체|전환|재설정/.test(prompt));
|
|
131
133
|
}
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
|
|
134
|
+
function looksLikeQuestionGenerationPrompt(prompt) {
|
|
135
|
+
return /\b(needed questions?|necessary questions?|question generation|clarifying questions?|ask questions?)\b/i.test(prompt)
|
|
136
|
+
|| /필요한\s*질문|질문을\s*(모두|많이|생성)|질문\s*생성|물어봐|질문해/.test(prompt);
|
|
137
|
+
}
|
|
138
|
+
function looksLikeMultiCommitmentChangePrompt(prompt) {
|
|
139
|
+
const normalized = prompt.trim();
|
|
140
|
+
const actionCue = /\b(change|revise|update|replace|reframe|modify|alter)\b/i.test(normalized)
|
|
141
|
+
|| /바꾸|변경|수정|교체|전환|재설정/.test(normalized);
|
|
142
|
+
if (!actionCue) {
|
|
143
|
+
return false;
|
|
135
144
|
}
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
145
|
+
const categories = [
|
|
146
|
+
/\b(research question|research direction|scope|boundary|inclusion criteria|exclusion criteria)\b/i.test(normalized)
|
|
147
|
+
|| /연구\s*질문|연구\s*문제|연구\s*방향|범위|경계|포함\s*기준|제외\s*기준/.test(normalized),
|
|
148
|
+
/\b(theory|framework|conceptual model|construct map)\b/i.test(normalized)
|
|
149
|
+
|| /이론|프레임워크|개념\s*모형|구성개념\s*지도|컨스트럭트/.test(normalized),
|
|
150
|
+
/\b(measure|measurement|scale|instrument|coding|coding rule|extraction rule|operationali[sz]ation)\b/i.test(normalized)
|
|
151
|
+
|| /측정|척도|도구|코딩|코딩\s*규칙|코딩\s*기준|추출\s*규칙|추출\s*기준|조작화/.test(normalized),
|
|
152
|
+
/\b(method|methodology|study design|sampling|sample)\b/i.test(normalized)
|
|
153
|
+
|| /방법론|방법|연구\s*설계|표본|샘플링/.test(normalized),
|
|
154
|
+
/\b(analysis plan|analysis method|meta[- ]?analysis|masem|(?:statistical|structural|path|analysis) model|moderator|random[- ]?effects)\b/i.test(normalized)
|
|
155
|
+
|| /분석\s*계획|분석\s*방법|메타\s*분석|분석\s*(?:모형|모델)|통계\s*(?:모형|모델)|구조\s*방정식|경로\s*모형|조절효과|랜덤\s*효과/.test(normalized)
|
|
156
|
+
];
|
|
157
|
+
return categories.filter(Boolean).length >= 2;
|
|
158
|
+
}
|
|
159
|
+
function looksLikeExplicitInterviewPrompt(prompt) {
|
|
160
|
+
const normalized = prompt.trim();
|
|
161
|
+
if (!normalized) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
if (/\$longtable-interview\b/i.test(normalized)) {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
if (looksLikeLongTableProductOrToolingPrompt(normalized)) {
|
|
168
|
+
return false;
|
|
142
169
|
}
|
|
143
|
-
|
|
144
|
-
|
|
170
|
+
return /\bLongTable\b.*\binterview\b/i.test(normalized)
|
|
171
|
+
|| /\bfirst research shape\b/i.test(normalized)
|
|
172
|
+
|| /롱테이블.*인터뷰|LongTable.*인터뷰|First Research Shape/i.test(normalized);
|
|
173
|
+
}
|
|
174
|
+
function looksLikeResearchStateConfirmationPrompt(prompt) {
|
|
175
|
+
if (looksLikeLongTableProductOrToolingPrompt(prompt) && !looksLikeExplicitInterviewPrompt(prompt)) {
|
|
176
|
+
return false;
|
|
145
177
|
}
|
|
146
|
-
return
|
|
178
|
+
return looksLikeResearchCommitmentPrompt(prompt)
|
|
179
|
+
|| (looksLikeExplicitInterviewPrompt(prompt) && looksLikeClosurePrompt(prompt))
|
|
180
|
+
|| /\b(confirm|summarize|save|store|record)\b.*\b(first research shape|research direction|research shape)\b/i.test(prompt)
|
|
181
|
+
|| /(First Research Shape|연구\s*방향|연구\s*형태).*(확정|저장|기록|요약)/.test(prompt);
|
|
182
|
+
}
|
|
183
|
+
function shouldSurfaceInterviewContext(prompt) {
|
|
184
|
+
return looksLikeExplicitInterviewPrompt(prompt) || looksLikeResearchStateConfirmationPrompt(prompt);
|
|
147
185
|
}
|
|
148
186
|
function shouldCreateRequiredQuestionsForPrompt(prompt) {
|
|
149
187
|
return !looksLikeLongTableProductOrToolingPrompt(prompt) && looksLikeResearchCommitmentPrompt(prompt);
|
|
150
188
|
}
|
|
151
189
|
function shouldApplyProtectedDecisionClosure(runtime, prompt) {
|
|
152
190
|
return Boolean(runtime.context.session.protectedDecision) &&
|
|
153
|
-
shouldCreateRequiredQuestionsForPrompt(prompt)
|
|
191
|
+
shouldCreateRequiredQuestionsForPrompt(prompt) &&
|
|
192
|
+
!looksLikeQuestionGenerationPrompt(prompt) &&
|
|
193
|
+
!looksLikeMultiCommitmentChangePrompt(prompt);
|
|
154
194
|
}
|
|
155
195
|
function protectedDecisionClosurePrompt(prompt) {
|
|
156
196
|
return [
|
|
@@ -167,6 +207,14 @@ function isStateChangingBash(command) {
|
|
|
167
207
|
return /\b(git\s+commit|npm\s+version|mv|cp|rm|sed\s+-i|perl\s+-i|tee|touch|mkdir|rmdir|apply_patch|patch)\b/.test(normalized)
|
|
168
208
|
|| />\s*\S+/.test(normalized);
|
|
169
209
|
}
|
|
210
|
+
function mutatesLongTableResearchState(command) {
|
|
211
|
+
const normalized = command.trim();
|
|
212
|
+
if (!normalized) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
return /\.longtable(?:\/|\b)|\bCURRENT\.md\b/.test(normalized)
|
|
216
|
+
|| /\blongtable\s+(?:start|question|clear-question|prune-questions|ask|clarify|panel|team)\b/.test(normalized);
|
|
217
|
+
}
|
|
170
218
|
async function loadLongTableRuntime(startPath) {
|
|
171
219
|
const context = await loadProjectContextFromDirectory(startPath);
|
|
172
220
|
if (!context) {
|
|
@@ -206,6 +254,13 @@ function buildPendingQuestionContext(question) {
|
|
|
206
254
|
"Do not choose or record an answer unless the researcher explicitly provides the selection."
|
|
207
255
|
].join("\n");
|
|
208
256
|
}
|
|
257
|
+
function buildSeparatePendingQuestionNotice(question) {
|
|
258
|
+
return [
|
|
259
|
+
`Separate unresolved Researcher Checkpoint: ${question.prompt.title}.`,
|
|
260
|
+
`Question: ${question.prompt.question}`,
|
|
261
|
+
"This is not part of the active interview. Keep it visible, but do not answer or record it unless the researcher explicitly provides the selection."
|
|
262
|
+
].join("\n");
|
|
263
|
+
}
|
|
209
264
|
function buildGeneratedQuestionsContext(questions, created) {
|
|
210
265
|
const lines = [
|
|
211
266
|
created
|
|
@@ -220,16 +275,6 @@ function buildGeneratedQuestionsContext(questions, created) {
|
|
|
220
275
|
lines.push("Do not choose or record answers for these checkpoints unless the researcher explicitly provides the selections.");
|
|
221
276
|
return lines.join("\n");
|
|
222
277
|
}
|
|
223
|
-
function buildAdvisoryQuestionsContext(questions) {
|
|
224
|
-
const lines = [
|
|
225
|
-
`LongTable surfaced ${questions.length} response-only advisory question${questions.length === 1 ? "" : "s"} for this prompt.`,
|
|
226
|
-
"Use these only if they help the reply. Do not create QuestionRecord entries, call longtable decide, or answer for the researcher unless the prompt explicitly asks to commit a research decision."
|
|
227
|
-
];
|
|
228
|
-
for (const question of questions) {
|
|
229
|
-
lines.push(`- ${question.title}: ${question.question}`);
|
|
230
|
-
}
|
|
231
|
-
return lines.join("\n");
|
|
232
|
-
}
|
|
233
278
|
function buildPendingObligationContext(obligation) {
|
|
234
279
|
return [
|
|
235
280
|
`Pending LongTable research obligation: ${obligation.prompt}`,
|
|
@@ -239,6 +284,12 @@ function buildPendingObligationContext(obligation) {
|
|
|
239
284
|
: "Resume the LongTable interview and let it ask the next research-facing checkpoint before settling the direction."
|
|
240
285
|
].join("\n");
|
|
241
286
|
}
|
|
287
|
+
function buildSeparatePendingObligationNotice(obligation) {
|
|
288
|
+
return [
|
|
289
|
+
`Separate unresolved LongTable obligation: ${obligation.prompt}`,
|
|
290
|
+
"This is not part of the active interview. Keep it visible only when the researcher is settling or saving the research direction."
|
|
291
|
+
].join("\n");
|
|
292
|
+
}
|
|
242
293
|
function buildActiveInterviewContext(hook) {
|
|
243
294
|
const turnCount = hook.turns?.length ?? 0;
|
|
244
295
|
return [
|
|
@@ -254,64 +305,78 @@ function sessionStartContext(runtime) {
|
|
|
254
305
|
const interview = activeInterviewHook(runtime.state);
|
|
255
306
|
const needsDetailedSummary = Boolean(blockingQuestion || blockingObligation);
|
|
256
307
|
const sections = [buildWorkspaceSummary(runtime, needsDetailedSummary ? "full" : "compact").join("\n")];
|
|
257
|
-
if (
|
|
308
|
+
if (interview) {
|
|
309
|
+
sections.push(buildActiveInterviewContext(interview));
|
|
310
|
+
if (blockingQuestion) {
|
|
311
|
+
sections.push(buildSeparatePendingQuestionNotice(blockingQuestion));
|
|
312
|
+
}
|
|
313
|
+
else if (blockingObligation) {
|
|
314
|
+
sections.push(buildSeparatePendingObligationNotice(blockingObligation));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
else if (blockingQuestion) {
|
|
258
318
|
sections.push(buildPendingQuestionContext(blockingQuestion));
|
|
259
319
|
}
|
|
260
320
|
else if (blockingObligation) {
|
|
261
321
|
sections.push(buildPendingObligationContext(blockingObligation));
|
|
262
322
|
}
|
|
263
|
-
else if (interview) {
|
|
264
|
-
sections.push(buildActiveInterviewContext(interview));
|
|
265
|
-
}
|
|
266
323
|
sections.push("Treat `.longtable/` state and `CURRENT.md` as the source of truth for this workspace.");
|
|
267
324
|
return sections.filter(Boolean).join("\n\n");
|
|
268
325
|
}
|
|
269
326
|
async function userPromptSubmitContext(runtime, prompt) {
|
|
270
327
|
const blockingQuestion = pendingRequiredQuestions(runtime.state)[0];
|
|
271
|
-
|
|
328
|
+
const blockingObligation = pendingObligations(runtime.state)[0];
|
|
329
|
+
const interview = activeInterviewHook(runtime.state);
|
|
330
|
+
const shouldSurfaceInterview = shouldSurfaceInterviewContext(prompt);
|
|
331
|
+
const shouldSurfaceBlockingState = looksLikeResearchStateConfirmationPrompt(prompt);
|
|
332
|
+
if (interview && shouldSurfaceInterview) {
|
|
333
|
+
const sections = [buildActiveInterviewContext(interview)];
|
|
334
|
+
if (blockingQuestion) {
|
|
335
|
+
sections.push(buildSeparatePendingQuestionNotice(blockingQuestion));
|
|
336
|
+
}
|
|
337
|
+
else if (blockingObligation) {
|
|
338
|
+
sections.push(buildSeparatePendingObligationNotice(blockingObligation));
|
|
339
|
+
}
|
|
340
|
+
return sections.join("\n\n");
|
|
341
|
+
}
|
|
342
|
+
if (blockingQuestion && shouldSurfaceBlockingState) {
|
|
272
343
|
return buildPendingQuestionContext(blockingQuestion);
|
|
273
344
|
}
|
|
274
|
-
|
|
275
|
-
if (blockingObligation) {
|
|
345
|
+
if (blockingObligation && shouldSurfaceBlockingState) {
|
|
276
346
|
return buildPendingObligationContext(blockingObligation);
|
|
277
347
|
}
|
|
278
|
-
const interview = activeInterviewHook(runtime.state);
|
|
279
348
|
if (interview) {
|
|
280
|
-
return
|
|
349
|
+
return null;
|
|
281
350
|
}
|
|
282
351
|
const generatedQuestions = [];
|
|
283
352
|
let createdQuestions = false;
|
|
284
|
-
if (
|
|
285
|
-
const
|
|
353
|
+
if (shouldApplyProtectedDecisionClosure(runtime, prompt)) {
|
|
354
|
+
const protectedGenerated = await createWorkspaceFollowUpQuestions({
|
|
286
355
|
context: runtime.context,
|
|
287
|
-
prompt,
|
|
356
|
+
prompt: protectedDecisionClosurePrompt(prompt),
|
|
288
357
|
provider: "codex",
|
|
289
358
|
required: true,
|
|
290
359
|
auto: true,
|
|
291
360
|
requiredOnly: true
|
|
292
361
|
});
|
|
293
|
-
generatedQuestions.push(...
|
|
294
|
-
createdQuestions = createdQuestions ||
|
|
362
|
+
generatedQuestions.push(...protectedGenerated.questions);
|
|
363
|
+
createdQuestions = createdQuestions || protectedGenerated.created;
|
|
295
364
|
}
|
|
296
|
-
if (
|
|
297
|
-
const
|
|
365
|
+
else if (shouldCreateRequiredQuestionsForPrompt(prompt)) {
|
|
366
|
+
const generated = await createWorkspaceFollowUpQuestions({
|
|
298
367
|
context: runtime.context,
|
|
299
|
-
prompt
|
|
368
|
+
prompt,
|
|
300
369
|
provider: "codex",
|
|
301
370
|
required: true,
|
|
302
371
|
auto: true,
|
|
303
372
|
requiredOnly: true
|
|
304
373
|
});
|
|
305
|
-
generatedQuestions.push(...
|
|
306
|
-
createdQuestions = createdQuestions ||
|
|
374
|
+
generatedQuestions.push(...generated.questions);
|
|
375
|
+
createdQuestions = createdQuestions || generated.created;
|
|
307
376
|
}
|
|
308
377
|
if (generatedQuestions.length > 0) {
|
|
309
378
|
return buildGeneratedQuestionsContext(generatedQuestions, createdQuestions);
|
|
310
379
|
}
|
|
311
|
-
const advisoryQuestions = buildResponseOnlyAdvisoryQuestions(prompt);
|
|
312
|
-
if (advisoryQuestions.length > 0) {
|
|
313
|
-
return buildAdvisoryQuestionsContext(advisoryQuestions);
|
|
314
|
-
}
|
|
315
380
|
return null;
|
|
316
381
|
}
|
|
317
382
|
function preToolUseOutput(runtime, payload) {
|
|
@@ -319,16 +384,17 @@ function preToolUseOutput(runtime, payload) {
|
|
|
319
384
|
return null;
|
|
320
385
|
}
|
|
321
386
|
const command = readCommandText(payload);
|
|
322
|
-
|
|
387
|
+
const stateChangingCommand = isStateChangingBash(command) || mutatesLongTableResearchState(command);
|
|
388
|
+
if (!stateChangingCommand) {
|
|
323
389
|
return null;
|
|
324
390
|
}
|
|
325
391
|
const blockingQuestion = pendingRequiredQuestions(runtime.state)[0];
|
|
326
|
-
if (blockingQuestion) {
|
|
327
|
-
return buildBlockOutput("PreToolUse", "A required LongTable checkpoint is still pending before a state
|
|
392
|
+
if (blockingQuestion && mutatesLongTableResearchState(command)) {
|
|
393
|
+
return buildBlockOutput("PreToolUse", "A required LongTable checkpoint is still pending before a research-state Bash command.", buildPendingQuestionContext(blockingQuestion));
|
|
328
394
|
}
|
|
329
395
|
const blockingObligation = pendingObligations(runtime.state)[0];
|
|
330
|
-
if (blockingObligation) {
|
|
331
|
-
return buildBlockOutput("PreToolUse", "A LongTable research obligation is still pending before a state
|
|
396
|
+
if (blockingObligation && mutatesLongTableResearchState(command)) {
|
|
397
|
+
return buildBlockOutput("PreToolUse", "A LongTable research obligation is still pending before a research-state Bash command.", buildPendingObligationContext(blockingObligation));
|
|
332
398
|
}
|
|
333
399
|
return null;
|
|
334
400
|
}
|
|
@@ -341,8 +407,8 @@ function postToolUseOutput(runtime, payload) {
|
|
|
341
407
|
const output = readCombinedOutput(payload);
|
|
342
408
|
const blockingQuestion = pendingRequiredQuestions(runtime.state)[0];
|
|
343
409
|
const blockingObligation = pendingObligations(runtime.state)[0];
|
|
344
|
-
if ((blockingQuestion || blockingObligation) &&
|
|
345
|
-
return buildBlockOutput("PostToolUse", "A state
|
|
410
|
+
if ((blockingQuestion || blockingObligation) && mutatesLongTableResearchState(command)) {
|
|
411
|
+
return buildBlockOutput("PostToolUse", "A research-state Bash command completed while LongTable still had an unresolved checkpoint or obligation.", blockingQuestion
|
|
346
412
|
? buildPendingQuestionContext(blockingQuestion)
|
|
347
413
|
: buildPendingObligationContext(blockingObligation));
|
|
348
414
|
}
|
|
@@ -44,6 +44,8 @@ export interface LongTableInterviewTurn {
|
|
|
44
44
|
quality: InterviewTurnQuality;
|
|
45
45
|
needsFollowUp: boolean;
|
|
46
46
|
followUpQuestion?: string;
|
|
47
|
+
readyToSummarize?: boolean;
|
|
48
|
+
readinessRationale?: string[];
|
|
47
49
|
rationale?: string[];
|
|
48
50
|
}
|
|
49
51
|
export interface LongTableHookRun {
|
|
@@ -204,6 +206,8 @@ export declare function appendLongTableInterviewTurn(options: {
|
|
|
204
206
|
quality?: InterviewTurnQuality;
|
|
205
207
|
needsFollowUp?: boolean;
|
|
206
208
|
followUpQuestion?: string;
|
|
209
|
+
readyToSummarize?: boolean;
|
|
210
|
+
readinessRationale?: string[];
|
|
207
211
|
rationale?: string[];
|
|
208
212
|
}): Promise<{
|
|
209
213
|
hook: LongTableHookRun;
|
package/dist/project-session.js
CHANGED
|
@@ -420,7 +420,9 @@ function buildProjectAgentsMd(project, session) {
|
|
|
420
420
|
"",
|
|
421
421
|
"## Research Behavior",
|
|
422
422
|
"- Begin exploratory work with clarifying or tension questions before recommending a direction.",
|
|
423
|
-
"- For `$longtable-interview`, ask one natural-language question at a time, reflect with `LongTable hears: ...`, and avoid early reader/reviewer or theory/method/measurement classification.",
|
|
423
|
+
"- For `$longtable-interview`, ask one natural-language question at a time, reflect with `LongTable hears: ...`, record turns when MCP is available, and avoid early reader/reviewer or theory/method/measurement classification.",
|
|
424
|
+
"- Do not summarize `$longtable-interview` because a fixed number of turns has passed; wait for content-based readiness around research object, focal uncertainty, boundary, evidence/material, protected decision, and next action.",
|
|
425
|
+
"- Do not let unrelated pending Researcher Checkpoints interrupt `$longtable-interview`; mention them only as separate unresolved checkpoints unless the researcher is confirming, saving, or recording a research decision.",
|
|
424
426
|
"- Use structured options only at the final First Research Shape confirmation or at true checkpoint boundaries.",
|
|
425
427
|
"- If you foreground role perspectives, disclose them with `LongTable consulted: ...`.",
|
|
426
428
|
"- Keep one accountable synthesis, but do not hide meaningful disagreement.",
|
|
@@ -580,10 +582,10 @@ function defaultFollowUpQuestion(answer) {
|
|
|
580
582
|
return "What concrete scene, case, material, text, dataset, or decision would make that problem easier to inspect first?";
|
|
581
583
|
}
|
|
582
584
|
function depthForInterview(turns = []) {
|
|
583
|
-
|
|
584
|
-
if (usableTurns >= 3) {
|
|
585
|
+
if (turns.some((turn) => turn.readyToSummarize === true && turn.quality !== "thin")) {
|
|
585
586
|
return "ready_to_summarize";
|
|
586
587
|
}
|
|
588
|
+
const usableTurns = turns.filter((turn) => turn.quality !== "thin").length;
|
|
587
589
|
if (usableTurns >= 1) {
|
|
588
590
|
return "forming_first_handle";
|
|
589
591
|
}
|
|
@@ -614,6 +616,15 @@ export async function beginLongTableInterview(options) {
|
|
|
614
616
|
if (existing) {
|
|
615
617
|
return { hook: existing, state };
|
|
616
618
|
}
|
|
619
|
+
const confirmedShape = state.firstResearchShape?.confirmedAt ? state.firstResearchShape : undefined;
|
|
620
|
+
if (confirmedShape) {
|
|
621
|
+
const confirmedHook = [...(state.hooks ?? [])].reverse().find((hook) => hook.kind === "longtable_interview" &&
|
|
622
|
+
hook.status === "confirmed" &&
|
|
623
|
+
hook.firstResearchShape?.handle === confirmedShape.handle);
|
|
624
|
+
if (confirmedHook) {
|
|
625
|
+
return { hook: confirmedHook, state };
|
|
626
|
+
}
|
|
627
|
+
}
|
|
617
628
|
const timestamp = nowIso();
|
|
618
629
|
const hook = {
|
|
619
630
|
id: createId("hook_interview"),
|
|
@@ -654,6 +665,10 @@ export async function appendLongTableInterviewTurn(options) {
|
|
|
654
665
|
const followUpQuestion = needsFollowUp
|
|
655
666
|
? options.followUpQuestion ?? defaultFollowUpQuestion(options.answer)
|
|
656
667
|
: options.followUpQuestion;
|
|
668
|
+
const readyToSummarize = options.readyToSummarize === true && quality !== "thin";
|
|
669
|
+
const readinessRationale = options.readinessRationale
|
|
670
|
+
?.map((rationale) => rationale.trim())
|
|
671
|
+
.filter(Boolean);
|
|
657
672
|
const timestamp = nowIso();
|
|
658
673
|
const turns = existing.turns ?? [];
|
|
659
674
|
const turn = {
|
|
@@ -666,6 +681,8 @@ export async function appendLongTableInterviewTurn(options) {
|
|
|
666
681
|
quality,
|
|
667
682
|
needsFollowUp,
|
|
668
683
|
...(followUpQuestion?.trim() ? { followUpQuestion: followUpQuestion.trim() } : {}),
|
|
684
|
+
...(readyToSummarize ? { readyToSummarize } : {}),
|
|
685
|
+
...(readinessRationale && readinessRationale.length > 0 ? { readinessRationale } : {}),
|
|
669
686
|
...(options.rationale && options.rationale.length > 0 ? { rationale: options.rationale } : {})
|
|
670
687
|
};
|
|
671
688
|
const nextTurns = [...turns, turn];
|
|
@@ -678,7 +695,10 @@ export async function appendLongTableInterviewTurn(options) {
|
|
|
678
695
|
turns: nextTurns,
|
|
679
696
|
qualityNotes: [
|
|
680
697
|
...(existing.qualityNotes ?? []),
|
|
681
|
-
...(needsFollowUp ? [`Turn ${turn.index} needs follow-up: ${followUpQuestion}`] : [])
|
|
698
|
+
...(needsFollowUp ? [`Turn ${turn.index} needs follow-up: ${followUpQuestion}`] : []),
|
|
699
|
+
...(readyToSummarize
|
|
700
|
+
? [`Turn ${turn.index} marked ready to summarize: ${(readinessRationale ?? ["content-based readiness signal"]).join("; ")}`]
|
|
701
|
+
: [])
|
|
682
702
|
]
|
|
683
703
|
};
|
|
684
704
|
const updated = upsertHook(state, hook);
|
|
@@ -981,6 +1001,29 @@ function optionsForCheckpointTrigger(family, checkpointKey) {
|
|
|
981
1001
|
function includesAny(prompt, patterns) {
|
|
982
1002
|
return patterns.some((pattern) => pattern.test(prompt));
|
|
983
1003
|
}
|
|
1004
|
+
function questionPriority(spec) {
|
|
1005
|
+
const byKey = {
|
|
1006
|
+
protected_decision_closure: 100,
|
|
1007
|
+
research_direction_change_commitment: 96,
|
|
1008
|
+
construct_boundary_commitment: 94,
|
|
1009
|
+
measurement_coding_standard: 92,
|
|
1010
|
+
analysis_strategy_commitment: 90,
|
|
1011
|
+
theory_frame_commitment: 88,
|
|
1012
|
+
method_design_commitment: 86,
|
|
1013
|
+
research_scope_boundary: 84,
|
|
1014
|
+
epistemic_alignment_boundary: 82,
|
|
1015
|
+
value_conflict_boundary: 80,
|
|
1016
|
+
source_authority: 70,
|
|
1017
|
+
knowledge_gap_probe: 68,
|
|
1018
|
+
tacit_assumption_probe: 66,
|
|
1019
|
+
needed_question_policy: 60,
|
|
1020
|
+
philosophical_checkpoint_boundary: 58,
|
|
1021
|
+
harness_question_harness: 55
|
|
1022
|
+
};
|
|
1023
|
+
const confidenceWeight = spec.confidence === "high" ? 10 : spec.confidence === "medium" ? 5 : 0;
|
|
1024
|
+
const requiredWeight = spec.kind === "research_commitment" || spec.required ? 20 : 0;
|
|
1025
|
+
return (byKey[spec.key] ?? 0) + confidenceWeight + requiredWeight;
|
|
1026
|
+
}
|
|
984
1027
|
function followUpQuestionOptions(first, second, third, fourth) {
|
|
985
1028
|
return [first, second, third, ...(fourth ? [fourth] : [])];
|
|
986
1029
|
}
|
|
@@ -998,6 +1041,158 @@ export function buildQuestionOpportunitySpecs(prompt, options = {}) {
|
|
|
998
1041
|
});
|
|
999
1042
|
}
|
|
1000
1043
|
}
|
|
1044
|
+
const decisionActionCue = includesAny(normalized, [
|
|
1045
|
+
/\b(final|finalize|commit|decide|settle|freeze|lock|record|apply|incorporate|change|revise|update|replace|reframe|modify|alter)\b/i,
|
|
1046
|
+
/최종|확정|결정|고정|기록|반영|바꾸|변경|수정|교체|전환|재설정/
|
|
1047
|
+
]);
|
|
1048
|
+
const scopeCue = includesAny(normalized, [
|
|
1049
|
+
/\bresearch question\b/i,
|
|
1050
|
+
/\bresearch direction\b/i,
|
|
1051
|
+
/\bscope\b/i,
|
|
1052
|
+
/\bboundary\b/i,
|
|
1053
|
+
/\binclusion criteria\b/i,
|
|
1054
|
+
/\bexclusion criteria\b/i,
|
|
1055
|
+
/연구\s*질문|연구\s*문제|연구\s*방향|범위|경계|포함\s*기준|제외\s*기준/
|
|
1056
|
+
]);
|
|
1057
|
+
const theoryCue = includesAny(normalized, [
|
|
1058
|
+
/\btheory\b/i,
|
|
1059
|
+
/\bframework\b/i,
|
|
1060
|
+
/\bconceptual model\b/i,
|
|
1061
|
+
/\bconstruct map\b/i,
|
|
1062
|
+
/이론|프레임워크|개념\s*모형|구성개념\s*지도|컨스트럭트/
|
|
1063
|
+
]);
|
|
1064
|
+
const measurementCodingCue = includesAny(normalized, [
|
|
1065
|
+
/\bmeasure\b/i,
|
|
1066
|
+
/\bmeasurement\b/i,
|
|
1067
|
+
/\bscale\b/i,
|
|
1068
|
+
/\binstrument\b/i,
|
|
1069
|
+
/\bcoding\b/i,
|
|
1070
|
+
/\bcoding rule\b/i,
|
|
1071
|
+
/\bextraction rule\b/i,
|
|
1072
|
+
/\boperationali[sz]ation\b/i,
|
|
1073
|
+
/측정|척도|도구|코딩|코딩\s*규칙|코딩\s*기준|추출\s*규칙|추출\s*기준|조작화/
|
|
1074
|
+
]);
|
|
1075
|
+
const methodCue = includesAny(normalized, [
|
|
1076
|
+
/\bmethod\b/i,
|
|
1077
|
+
/\bmethodology\b/i,
|
|
1078
|
+
/\bstudy design\b/i,
|
|
1079
|
+
/\bsampling\b/i,
|
|
1080
|
+
/\bsample\b/i,
|
|
1081
|
+
/방법론|방법|연구\s*설계|표본|샘플링/
|
|
1082
|
+
]);
|
|
1083
|
+
const analysisCue = includesAny(normalized, [
|
|
1084
|
+
/\banalysis plan\b/i,
|
|
1085
|
+
/\banalysis method\b/i,
|
|
1086
|
+
/\bmeta[- ]?analysis\b/i,
|
|
1087
|
+
/\bmasem\b/i,
|
|
1088
|
+
/\b(statistical|structural|path|analysis) model\b/i,
|
|
1089
|
+
/\bmoderator\b/i,
|
|
1090
|
+
/\brandom[- ]?effects\b/i,
|
|
1091
|
+
/분석\s*계획|분석\s*방법|메타\s*분석|분석\s*(?:모형|모델)|통계\s*(?:모형|모델)|구조\s*방정식|경로\s*모형|조절효과|랜덤\s*효과/
|
|
1092
|
+
]);
|
|
1093
|
+
const decisionFamilyCount = [scopeCue, theoryCue, measurementCodingCue, methodCue, analysisCue]
|
|
1094
|
+
.filter(Boolean).length;
|
|
1095
|
+
if (decisionActionCue && decisionFamilyCount >= 2) {
|
|
1096
|
+
push({
|
|
1097
|
+
key: "research_direction_change_commitment",
|
|
1098
|
+
kind: "research_commitment",
|
|
1099
|
+
title: "Research direction change",
|
|
1100
|
+
question: "Which high-risk research commitment should LongTable clarify first before changing the project direction?",
|
|
1101
|
+
whyNow: "The prompt touches multiple protected research commitments; proceeding silently would let LongTable choose the priority order for the researcher.",
|
|
1102
|
+
options: followUpQuestionOptions({ value: "scope_first", label: "Scope or research question first", description: "Clarify what the study includes, excludes, or asks before changing downstream work.", recommended: true }, { value: "theory_first", label: "Theory or construct frame first", description: "Clarify the conceptual frame before changing methods or analysis." }, { value: "method_analysis_first", label: "Method or analysis first", description: "Clarify design, data, or analysis implications before changing the artifact." }, { value: "defer", label: "Keep the direction open", description: "Do not change the research direction until the commitment order is explicit." }),
|
|
1103
|
+
confidence: "high",
|
|
1104
|
+
autoEligible: true,
|
|
1105
|
+
required: true,
|
|
1106
|
+
cues: ["research_direction", "multi_commitment_change"]
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
if (decisionActionCue && scopeCue) {
|
|
1110
|
+
push({
|
|
1111
|
+
key: "research_scope_boundary",
|
|
1112
|
+
kind: "research_commitment",
|
|
1113
|
+
title: "Research scope boundary",
|
|
1114
|
+
question: "What scope boundary should LongTable keep explicit before treating the research direction as changed?",
|
|
1115
|
+
whyNow: "Scope changes can redefine the population, domain, corpus, or research question before the researcher has explicitly chosen the boundary.",
|
|
1116
|
+
options: followUpQuestionOptions({ value: "revise_scope", label: "Revise the scope", description: "Change the inclusion boundary before downstream work continues.", recommended: true }, { value: "compare_boundaries", label: "Compare boundaries first", description: "Keep candidate scopes visible before choosing one." }, { value: "proceed_with_scope_assumption", label: "Proceed with scope assumption", description: "Continue only after stating the assumed boundary." }, { value: "defer", label: "Keep scope open", description: "Do not settle the scope yet." }),
|
|
1117
|
+
confidence: "high",
|
|
1118
|
+
autoEligible: true,
|
|
1119
|
+
cues: ["research_scope", "boundary"]
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
if (decisionActionCue && theoryCue) {
|
|
1123
|
+
push({
|
|
1124
|
+
key: "theory_frame_commitment",
|
|
1125
|
+
kind: "research_commitment",
|
|
1126
|
+
title: "Theory frame",
|
|
1127
|
+
question: "Which theory or construct frame should LongTable treat as the candidate commitment before revising the model?",
|
|
1128
|
+
whyNow: "Theory-frame changes can make later measurement, coding, and analysis choices look settled when they are only inferred.",
|
|
1129
|
+
options: followUpQuestionOptions({ value: "compare_theories", label: "Compare theory frames first", description: "Keep competing theoretical anchors visible before choosing one.", recommended: true }, { value: "revise_theory", label: "Revise the frame", description: "Change the framework and record the conceptual tradeoff." }, { value: "use_current_frame", label: "Use current frame tentatively", description: "Proceed but mark the theory choice as provisional." }, { value: "defer", label: "Keep theory open", description: "Do not settle the theory frame yet." }),
|
|
1130
|
+
confidence: "high",
|
|
1131
|
+
autoEligible: true,
|
|
1132
|
+
cues: ["theory", "framework", "construct"]
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
if (decisionActionCue && measurementCodingCue) {
|
|
1136
|
+
push({
|
|
1137
|
+
key: "measurement_coding_standard",
|
|
1138
|
+
kind: "research_commitment",
|
|
1139
|
+
title: "Measurement and coding standard",
|
|
1140
|
+
question: "What measurement or coding rule should LongTable ask you to fix before extracting or revising data?",
|
|
1141
|
+
whyNow: "Measurement and coding rules decide what counts as evidence; changing them silently can make later synthesis non-reproducible.",
|
|
1142
|
+
options: followUpQuestionOptions({ value: "define_construct_rule", label: "Define construct rule first", description: "Clarify what counts as the construct or variable before extraction.", recommended: true }, { value: "define_extraction_rule", label: "Define extraction rule first", description: "Clarify correlation, path, beta, or qualitative evidence extraction rules." }, { value: "pilot_code", label: "Pilot the coding rule", description: "Test the rule on a small sample before committing." }, { value: "defer", label: "Keep coding open", description: "Do not settle measurement or coding yet." }),
|
|
1143
|
+
confidence: "high",
|
|
1144
|
+
autoEligible: true,
|
|
1145
|
+
cues: ["measurement", "coding", "extraction"]
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
if (decisionActionCue && methodCue) {
|
|
1149
|
+
push({
|
|
1150
|
+
key: "method_design_commitment",
|
|
1151
|
+
kind: "research_commitment",
|
|
1152
|
+
title: "Method design",
|
|
1153
|
+
question: "Which method-design choice should LongTable keep explicit before changing the study plan?",
|
|
1154
|
+
whyNow: "Method changes affect the defensible claim, sample, evidence standard, and ethics boundary.",
|
|
1155
|
+
options: followUpQuestionOptions({ value: "revise_design", label: "Revise design first", description: "Change the design or sample boundary before proceeding.", recommended: true }, { value: "check_feasibility", label: "Check feasibility first", description: "Inspect whether data, evidence, and access support the method." }, { value: "proceed_with_method_assumption", label: "Proceed with method assumption", description: "Continue only after stating the assumed method." }, { value: "defer", label: "Keep method open", description: "Do not commit the method yet." }),
|
|
1156
|
+
confidence: "high",
|
|
1157
|
+
autoEligible: true,
|
|
1158
|
+
cues: ["method", "study_design", "sample"]
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
if (decisionActionCue && analysisCue) {
|
|
1162
|
+
push({
|
|
1163
|
+
key: "analysis_strategy_commitment",
|
|
1164
|
+
kind: "research_commitment",
|
|
1165
|
+
title: "Analysis strategy",
|
|
1166
|
+
question: "What analysis strategy should LongTable treat as unsettled before revising or running the synthesis?",
|
|
1167
|
+
whyNow: "Analysis choices determine what effect sizes, moderators, and interpretations become defensible.",
|
|
1168
|
+
options: followUpQuestionOptions({ value: "choose_analysis_family", label: "Choose analysis family first", description: "Clarify MASEM, family-level meta-analysis, moderator analysis, or narrative synthesis.", recommended: true }, { value: "check_data_sufficiency", label: "Check data sufficiency first", description: "Inspect whether primary quantitative effects support the analysis." }, { value: "proceed_with_analysis_assumption", label: "Proceed with assumption", description: "Continue only after stating the analysis assumption." }, { value: "defer", label: "Keep analysis open", description: "Do not settle the analysis plan yet." }),
|
|
1169
|
+
confidence: "high",
|
|
1170
|
+
autoEligible: true,
|
|
1171
|
+
cues: ["analysis", "model", "meta_analysis"]
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
if (decisionActionCue && includesAny(normalized, [
|
|
1175
|
+
/\bconflict\b/i,
|
|
1176
|
+
/\bcontradict/i,
|
|
1177
|
+
/\bontology\b/i,
|
|
1178
|
+
/\bepistem/i,
|
|
1179
|
+
/\bhuman knowledge\b/i,
|
|
1180
|
+
/\bai knowledge\b/i,
|
|
1181
|
+
/\balignment\b/i,
|
|
1182
|
+
/충돌|상충|모순|존재론|인식론|지식|인간의\s*지식|ai의\s*지식|정렬|방향성/
|
|
1183
|
+
])) {
|
|
1184
|
+
push({
|
|
1185
|
+
key: "epistemic_alignment_boundary",
|
|
1186
|
+
kind: "value_conflict",
|
|
1187
|
+
title: "Knowledge alignment",
|
|
1188
|
+
question: "When researcher knowledge, AI inference, and project state conflict, what should LongTable privilege before acting?",
|
|
1189
|
+
whyNow: "The prompt asks LongTable to mediate knowledge conflict; that mediation should be visible rather than hidden inside an implementation choice.",
|
|
1190
|
+
options: followUpQuestionOptions({ value: "ask_researcher", label: "Ask researcher clarity first", description: "Pause when human meaning or priority is underspecified.", recommended: true }, { value: "inspect_project_state", label: "Inspect project state first", description: "Use durable files and prior decisions before inferring intent." }, { value: "proceed_with_trace", label: "Proceed with explicit trace", description: "Continue only after naming the conflict and assumption." }, { value: "defer", label: "Keep conflict open", description: "Do not collapse the conflict into one answer yet." }),
|
|
1191
|
+
confidence: "high",
|
|
1192
|
+
autoEligible: true,
|
|
1193
|
+
cues: ["knowledge_conflict", "epistemic_alignment"]
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1001
1196
|
if (includesAny(normalized, [
|
|
1002
1197
|
/\blongtable\b/,
|
|
1003
1198
|
/\bharness\b/,
|
|
@@ -1231,7 +1426,13 @@ export function buildQuestionOpportunitySpecs(prompt, options = {}) {
|
|
|
1231
1426
|
if (options.requiredOnly === true) {
|
|
1232
1427
|
selected = selected.filter((spec) => spec.kind === "research_commitment");
|
|
1233
1428
|
}
|
|
1234
|
-
|
|
1429
|
+
if (normalized.includes("protected decision closure pressure")) {
|
|
1430
|
+
selected = selected.filter((spec) => spec.key === "protected_decision_closure");
|
|
1431
|
+
}
|
|
1432
|
+
else if (options.requiredOnly === true && selected.some((spec) => spec.key === "research_direction_change_commitment")) {
|
|
1433
|
+
selected = selected.filter((spec) => spec.key === "research_direction_change_commitment");
|
|
1434
|
+
}
|
|
1435
|
+
return selected.sort((a, b) => questionPriority(b) - questionPriority(a));
|
|
1235
1436
|
}
|
|
1236
1437
|
function buildFollowUpQuestionSpecs(prompt) {
|
|
1237
1438
|
return buildQuestionOpportunitySpecs(prompt);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longtable/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.43",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Researcher-facing LongTable CLI",
|
|
6
6
|
"type": "module",
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@clack/prompts": "^1.2.0",
|
|
32
|
-
"@longtable/checkpoints": "0.1.
|
|
33
|
-
"@longtable/core": "0.1.
|
|
34
|
-
"@longtable/memory": "0.1.
|
|
35
|
-
"@longtable/provider-claude": "0.1.
|
|
36
|
-
"@longtable/provider-codex": "0.1.
|
|
37
|
-
"@longtable/setup": "0.1.
|
|
32
|
+
"@longtable/checkpoints": "0.1.43",
|
|
33
|
+
"@longtable/core": "0.1.43",
|
|
34
|
+
"@longtable/memory": "0.1.43",
|
|
35
|
+
"@longtable/provider-claude": "0.1.43",
|
|
36
|
+
"@longtable/provider-codex": "0.1.43",
|
|
37
|
+
"@longtable/setup": "0.1.43"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^22.10.1",
|