@longtable/setup 0.1.49 → 0.1.51

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 CHANGED
@@ -32,9 +32,9 @@ Global setup should answer:
32
32
  - where LongTable may install runtime support
33
33
  - which provider surfaces are approved
34
34
  - how strongly LongTable may interrupt research decisions
35
- - whether setup should show the provider-native `$longtable-interview` launch steps
35
+ - whether setup should show the provider-native `$longtable-start` launch steps
36
36
 
37
- Project and session intake belongs to `$longtable-interview` inside Codex or
37
+ Project and session intake belongs to `$longtable-start` inside Codex or
38
38
  Claude Code, not library-level setup helpers. `longtable start` is a fallback
39
39
  for scripts and automation, not the primary research-start experience.
40
40
 
@@ -3,11 +3,24 @@ export function buildNumberedCheckpointPrompt(spec) {
3
3
  if (spec.instructions) {
4
4
  lines.push(spec.instructions, "");
5
5
  }
6
- spec.options.forEach((option, index) => {
7
- lines.push(`${index + 1}. ${option.label}`);
8
- });
9
- lines.push("");
10
- if (spec.allowRationale) {
6
+ if (spec.selectionMode !== "free_text") {
7
+ spec.options.forEach((option, index) => {
8
+ lines.push(`${index + 1}. ${option.label}`);
9
+ });
10
+ lines.push("");
11
+ }
12
+ if (spec.selectionMode === "free_text") {
13
+ lines.push("Reply with a concise free-text answer.");
14
+ }
15
+ else if (spec.selectionMode === "multi") {
16
+ if (spec.allowRationale) {
17
+ lines.push("Reply with one or more numbers separated by commas, or the numbers followed by a short rationale on the next line.");
18
+ }
19
+ else {
20
+ lines.push(`Reply with one or more numbers separated by commas: ${spec.options.map((_, index) => index + 1).join(", ")}.`);
21
+ }
22
+ }
23
+ else if (spec.allowRationale) {
11
24
  lines.push("Reply with one number only, or one number followed by a short rationale on the next line.");
12
25
  }
13
26
  else {
@@ -21,6 +34,44 @@ export function parseNumberedCheckpointResponse(spec, input) {
21
34
  return null;
22
35
  }
23
36
  const [firstLine, ...restLines] = trimmed.split(/\r?\n/);
37
+ const rationale = restLines.join("\n").trim();
38
+ if (spec.selectionMode === "free_text") {
39
+ return {
40
+ index: -1,
41
+ value: trimmed,
42
+ label: trimmed,
43
+ values: [trimmed],
44
+ labels: [trimmed],
45
+ rationale: undefined
46
+ };
47
+ }
48
+ if (spec.selectionMode === "multi") {
49
+ const tokens = firstLine.split(/[;,]/).map((token) => token.trim()).filter(Boolean);
50
+ if (tokens.length === 0 || !tokens.every((token) => /^\d+$/.test(token))) {
51
+ return null;
52
+ }
53
+ const indices = [...new Set(tokens.map((token) => Number(token) - 1))];
54
+ const selected = indices.map((index) => ({ index, option: spec.options[index] }));
55
+ if (selected.some((entry) => !entry.option)) {
56
+ return null;
57
+ }
58
+ if (!spec.allowRationale && rationale.length > 0) {
59
+ return null;
60
+ }
61
+ const first = selected[0];
62
+ if (!first?.option) {
63
+ return null;
64
+ }
65
+ return {
66
+ index: first.index,
67
+ value: first.option.value,
68
+ label: first.option.label,
69
+ indices,
70
+ values: selected.map((entry) => entry.option.value),
71
+ labels: selected.map((entry) => entry.option.label),
72
+ rationale: rationale.length > 0 ? rationale : undefined
73
+ };
74
+ }
24
75
  if (!/^\d+$/.test(firstLine.trim())) {
25
76
  return null;
26
77
  }
@@ -29,7 +80,6 @@ export function parseNumberedCheckpointResponse(spec, input) {
29
80
  if (!option) {
30
81
  return null;
31
82
  }
32
- const rationale = restLines.join("\n").trim();
33
83
  if (!spec.allowRationale && rationale.length > 0) {
34
84
  return null;
35
85
  }
@@ -37,6 +87,9 @@ export function parseNumberedCheckpointResponse(spec, input) {
37
87
  index,
38
88
  value: option.value,
39
89
  label: option.label,
90
+ indices: [index],
91
+ values: [option.value],
92
+ labels: [option.label],
40
93
  rationale: rationale.length > 0 ? rationale : undefined
41
94
  };
42
95
  }
package/dist/types.d.ts CHANGED
@@ -65,11 +65,15 @@ export interface NumberedCheckpointSpec {
65
65
  instructions?: string;
66
66
  options: NumberedCheckpointOption[];
67
67
  allowRationale?: boolean;
68
+ selectionMode?: "single" | "multi" | "free_text";
68
69
  }
69
70
  export interface ParsedCheckpointSelection {
70
71
  index: number;
71
72
  value: string;
72
73
  label: string;
74
+ indices?: number[];
75
+ values?: string[];
76
+ labels?: string[];
73
77
  rationale?: string;
74
78
  }
75
79
  export type { CheckpointIntensity, ExperienceLevel, ProviderKind, ResearchState } from "@longtable/core";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@longtable/setup",
3
- "version": "0.1.49",
3
+ "version": "0.1.51",
4
4
  "private": false,
5
5
  "description": "Researcher onboarding and setup flows for LongTable",
6
6
  "type": "module",
@@ -23,8 +23,8 @@
23
23
  "typecheck": "tsc -p tsconfig.json --noEmit"
24
24
  },
25
25
  "dependencies": {
26
- "@longtable/core": "0.1.49",
27
- "@longtable/memory": "0.1.49"
26
+ "@longtable/core": "0.1.51",
27
+ "@longtable/memory": "0.1.51"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/node": "^22.0.0",