@longtable/cli 0.1.39 → 0.1.41

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/dist/cli.js CHANGED
@@ -2853,10 +2853,24 @@ async function runClarify(args) {
2853
2853
  console.log(`- state: ${context.stateFilePath}`);
2854
2854
  console.log(`- current: ${context.currentFilePath}`);
2855
2855
  }
2856
+ function looksLikeProductOrToolingPrompt(prompt) {
2857
+ 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(prompt)
2858
+ || /롱테이블|훅|체크포인트|에이전트|스킬|사용성|인터페이스|설치|세팅|글로벌|배포|버전|릴리즈|깃|깃허브|문서화된\s*절차|패키지|라우터|자동완성|시뮬레이션\s*테스트/.test(prompt);
2859
+ }
2860
+ function looksLikeResearchCommitmentPrompt(prompt) {
2861
+ const researchCue = /\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(prompt)
2862
+ || /연구|논문|원고|저널|방법론|방법|연구\s*설계|측정|구성개념|개념|이론|분석|모형|모델|데이터|참가자|표본|샘플|척도|설문|도구|타당도|가설|문헌|메타\s*분석|골드\s*스탠더드|코딩|신뢰|의존|캘리브레이션|교정|보정/.test(prompt);
2863
+ const closureCue = /\b(final|finalize|commit|ship|submit|publish|freeze|settle|decide|lock|record|apply|incorporate)\b/i.test(prompt)
2864
+ || /최종|확정|커밋|제출|투고|고정|결정|기록|반영/.test(prompt);
2865
+ return researchCue && closureCue;
2866
+ }
2856
2867
  async function runAutomaticFollowUpIfNeeded(prompt, args) {
2857
2868
  if (args["no-clarify"] === true || args.print === true || args.json === true) {
2858
2869
  return false;
2859
2870
  }
2871
+ if (looksLikeProductOrToolingPrompt(prompt) || !looksLikeResearchCommitmentPrompt(prompt)) {
2872
+ return false;
2873
+ }
2860
2874
  const workingDirectory = typeof args.cwd === "string" ? args.cwd : cwd();
2861
2875
  const context = await loadProjectContextFromDirectory(workingDirectory);
2862
2876
  if (!context) {
@@ -2868,7 +2882,8 @@ async function runAutomaticFollowUpIfNeeded(prompt, args) {
2868
2882
  prompt,
2869
2883
  provider,
2870
2884
  required: true,
2871
- auto: true
2885
+ auto: true,
2886
+ requiredOnly: true
2872
2887
  });
2873
2888
  if (result.questions.length === 0) {
2874
2889
  return false;
@@ -1,5 +1,5 @@
1
1
  import { pathToFileURL } from "node:url";
2
- import { createWorkspaceFollowUpQuestions, loadProjectContextFromDirectory, loadWorkspaceState, pendingQuestionObligations } from "./index.js";
2
+ import { buildQuestionOpportunitySpecs, createWorkspaceFollowUpQuestions, loadProjectContextFromDirectory, loadWorkspaceState, pendingQuestionObligations } from "./index.js";
3
3
  function safeString(value) {
4
4
  return typeof value === "string" ? value : "";
5
5
  }
@@ -107,24 +107,50 @@ function looksLikeClosurePrompt(prompt) {
107
107
  if (!normalized) {
108
108
  return false;
109
109
  }
110
- return /\b(final|finalize|commit|ship|submit|revise|rewrite|draft|publish|implement|fix)\b/i.test(normalized)
111
- || /최종|확정|커밋|제출|수정|초안|구현|진행|고쳐/.test(normalized);
110
+ return /\b(final|finalize|commit|ship|submit|publish|freeze|settle|decide|lock|record|apply|incorporate)\b/i.test(normalized)
111
+ || /최종|확정|커밋|제출|투고|고정|결정|기록|반영/.test(normalized);
112
112
  }
113
- function looksLikeLongTableEngineeringPrompt(prompt) {
113
+ function looksLikeLongTableProductOrToolingPrompt(prompt) {
114
114
  const normalized = prompt.trim();
115
115
  if (!normalized) {
116
116
  return false;
117
117
  }
118
- return /\b(longtable|hook|checkpoint|mcp|agent|skill|skills|ux|interface|setup|install|cli|npm|version|global|publish|release|deploy|git)\b/i.test(normalized)
119
- || /롱테이블|훅|체크포인트|에이전트|스킬|사용성|인터페이스|설치|세팅|글로벌|배포|버전|릴리즈|깃|깃허브/.test(normalized);
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)
119
+ || /롱테이블|훅|체크포인트|에이전트|스킬|사용성|인터페이스|설치|세팅|글로벌|배포|버전|릴리즈|깃|깃허브|문서화된\s*절차|패키지|라우터|자동완성|시뮬레이션\s*테스트/.test(normalized);
120
120
  }
121
- function shouldAutoCreateQuestionsForPrompt(prompt) {
122
- return !looksLikeLongTableEngineeringPrompt(prompt);
121
+ function looksLikeResearchDomainPrompt(prompt) {
122
+ const normalized = prompt.trim();
123
+ if (!normalized) {
124
+ return false;
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
+ || /연구|논문|원고|저널|방법론|방법|연구\s*설계|측정|구성개념|개념|이론|분석|모형|모델|데이터|참가자|표본|샘플|척도|설문|도구|타당도|가설|문헌|메타\s*분석|골드\s*스탠더드|코딩|신뢰|의존|캘리브레이션|교정|보정/.test(normalized);
128
+ }
129
+ function looksLikeResearchCommitmentPrompt(prompt) {
130
+ return looksLikeResearchDomainPrompt(prompt) && looksLikeClosurePrompt(prompt);
131
+ }
132
+ function buildResponseOnlyAdvisoryQuestions(prompt) {
133
+ if (looksLikeLongTableProductOrToolingPrompt(prompt)) {
134
+ return [];
135
+ }
136
+ const opportunities = buildQuestionOpportunitySpecs(prompt, {
137
+ includeFallback: false,
138
+ autoOnly: true
139
+ });
140
+ if (opportunities.length === 0) {
141
+ return [];
142
+ }
143
+ if (!looksLikeResearchDomainPrompt(prompt) && !/\b(needed questions?|necessary questions?|clarifying questions?|question generation|assumptions?|uncertain|not sure|gap|tension|trade[- ]?off)\b/i.test(prompt) && !/필요한\s*질문|질문\s*생성|물어봐|질문해|전제|가정|불확실|모르겠|공백|긴장|상충|균형/.test(prompt)) {
144
+ return [];
145
+ }
146
+ return opportunities.slice(0, 3);
147
+ }
148
+ function shouldCreateRequiredQuestionsForPrompt(prompt) {
149
+ return !looksLikeLongTableProductOrToolingPrompt(prompt) && looksLikeResearchCommitmentPrompt(prompt);
123
150
  }
124
151
  function shouldApplyProtectedDecisionClosure(runtime, prompt) {
125
152
  return Boolean(runtime.context.session.protectedDecision) &&
126
- looksLikeClosurePrompt(prompt) &&
127
- !looksLikeLongTableEngineeringPrompt(prompt);
153
+ shouldCreateRequiredQuestionsForPrompt(prompt);
128
154
  }
129
155
  function protectedDecisionClosurePrompt(prompt) {
130
156
  return [
@@ -194,6 +220,16 @@ function buildGeneratedQuestionsContext(questions, created) {
194
220
  lines.push("Do not choose or record answers for these checkpoints unless the researcher explicitly provides the selections.");
195
221
  return lines.join("\n");
196
222
  }
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
+ }
197
233
  function buildPendingObligationContext(obligation) {
198
234
  return [
199
235
  `Pending LongTable research obligation: ${obligation.prompt}`,
@@ -245,13 +281,14 @@ async function userPromptSubmitContext(runtime, prompt) {
245
281
  }
246
282
  const generatedQuestions = [];
247
283
  let createdQuestions = false;
248
- if (shouldAutoCreateQuestionsForPrompt(prompt)) {
284
+ if (shouldCreateRequiredQuestionsForPrompt(prompt)) {
249
285
  const generated = await createWorkspaceFollowUpQuestions({
250
286
  context: runtime.context,
251
287
  prompt,
252
288
  provider: "codex",
253
289
  required: true,
254
- auto: true
290
+ auto: true,
291
+ requiredOnly: true
255
292
  });
256
293
  generatedQuestions.push(...generated.questions);
257
294
  createdQuestions = createdQuestions || generated.created;
@@ -262,7 +299,8 @@ async function userPromptSubmitContext(runtime, prompt) {
262
299
  prompt: protectedDecisionClosurePrompt(prompt),
263
300
  provider: "codex",
264
301
  required: true,
265
- auto: true
302
+ auto: true,
303
+ requiredOnly: true
266
304
  });
267
305
  generatedQuestions.push(...protectedGenerated.questions.filter((question) => !generatedQuestions.some((existing) => existing.id === question.id)));
268
306
  createdQuestions = createdQuestions || protectedGenerated.created;
@@ -270,11 +308,9 @@ async function userPromptSubmitContext(runtime, prompt) {
270
308
  if (generatedQuestions.length > 0) {
271
309
  return buildGeneratedQuestionsContext(generatedQuestions, createdQuestions);
272
310
  }
273
- if (shouldApplyProtectedDecisionClosure(runtime, prompt)) {
274
- return [
275
- `This workspace marks ${runtime.context.session.protectedDecision} as a protected decision.`,
276
- "Before you settle it through drafting, revision, or closure, surface one researcher-facing checkpoint grounded in the current blocker or open questions."
277
- ].join("\n");
311
+ const advisoryQuestions = buildResponseOnlyAdvisoryQuestions(prompt);
312
+ if (advisoryQuestions.length > 0) {
313
+ return buildAdvisoryQuestionsContext(advisoryQuestions);
278
314
  }
279
315
  return null;
280
316
  }
@@ -227,6 +227,7 @@ type FollowUpQuestionSpec = QuestionOpportunity;
227
227
  interface BuildFollowUpQuestionOptions {
228
228
  includeFallback?: boolean;
229
229
  autoOnly?: boolean;
230
+ requiredOnly?: boolean;
230
231
  }
231
232
  export declare function buildQuestionOpportunitySpecs(prompt: string, options?: BuildFollowUpQuestionOptions): FollowUpQuestionSpec[];
232
233
  export declare function generateQuestionOpportunities(prompt: string, options?: BuildFollowUpQuestionOptions): QuestionGenerationResult;
@@ -237,6 +238,7 @@ export declare function createWorkspaceFollowUpQuestions(options: {
237
238
  required?: boolean;
238
239
  force?: boolean;
239
240
  auto?: boolean;
241
+ requiredOnly?: boolean;
240
242
  }): Promise<{
241
243
  questions: QuestionRecord[];
242
244
  state: ResearchState;
@@ -990,7 +990,7 @@ export function buildQuestionOpportunitySpecs(prompt, options = {}) {
990
990
  function push(spec) {
991
991
  if (!specs.some((candidate) => candidate.key === spec.key)) {
992
992
  specs.push({
993
- required: true,
993
+ required: false,
994
994
  confidence: "medium",
995
995
  autoEligible: false,
996
996
  cues: [],
@@ -1076,6 +1076,7 @@ export function buildQuestionOpportunitySpecs(prompt, options = {}) {
1076
1076
  options: followUpQuestionOptions({ value: "keep_open", label: "Keep it open", description: "Do not treat the decision as settled; preserve it as an explicit blocker.", recommended: true }, { value: "ask_researcher", label: "Ask the researcher now", description: "Pause execution until the researcher chooses the decision boundary." }, { value: "proceed_with_record", label: "Proceed with record", description: "Continue only after recording the assumption and residual risk." }),
1077
1077
  confidence: "high",
1078
1078
  autoEligible: true,
1079
+ required: true,
1079
1080
  cues: ["protected_decision", "closure_pressure"]
1080
1081
  });
1081
1082
  }
@@ -1226,7 +1227,11 @@ export function buildQuestionOpportunitySpecs(prompt, options = {}) {
1226
1227
  options: followUpQuestionOptions({ value: "scope", label: "Clarify scope first", description: "Ask what is included and excluded before acting.", recommended: true }, { value: "criteria", label: "Clarify success criteria", description: "Ask what would count as a good result." }, { value: "proceed", label: "Proceed with visible assumptions", description: "Continue, but make assumptions explicit." })
1227
1228
  });
1228
1229
  }
1229
- return options.autoOnly === true ? specs.filter((spec) => spec.autoEligible) : specs;
1230
+ let selected = options.autoOnly === true ? specs.filter((spec) => spec.autoEligible) : specs;
1231
+ if (options.requiredOnly === true) {
1232
+ selected = selected.filter((spec) => spec.kind === "research_commitment");
1233
+ }
1234
+ return selected;
1230
1235
  }
1231
1236
  function buildFollowUpQuestionSpecs(prompt) {
1232
1237
  return buildQuestionOpportunitySpecs(prompt);
@@ -1261,7 +1266,8 @@ export async function createWorkspaceFollowUpQuestions(options) {
1261
1266
  : ["mcp_elicitation", "terminal_selector", "numbered"];
1262
1267
  const specs = buildQuestionOpportunitySpecs(options.prompt, {
1263
1268
  includeFallback: options.force === true ? true : options.auto !== true,
1264
- autoOnly: options.auto === true
1269
+ autoOnly: options.auto === true,
1270
+ requiredOnly: options.requiredOnly === true
1265
1271
  });
1266
1272
  if (specs.length === 0) {
1267
1273
  return { questions: [], state, created: false, alreadyAnswered: false };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@longtable/cli",
3
- "version": "0.1.39",
3
+ "version": "0.1.41",
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.39",
33
- "@longtable/core": "0.1.39",
34
- "@longtable/memory": "0.1.39",
35
- "@longtable/provider-claude": "0.1.39",
36
- "@longtable/provider-codex": "0.1.39",
37
- "@longtable/setup": "0.1.39"
32
+ "@longtable/checkpoints": "0.1.41",
33
+ "@longtable/core": "0.1.41",
34
+ "@longtable/memory": "0.1.41",
35
+ "@longtable/provider-claude": "0.1.41",
36
+ "@longtable/provider-codex": "0.1.41",
37
+ "@longtable/setup": "0.1.41"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/node": "^22.10.1",