@longtable/cli 0.1.57 → 0.1.59
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 +365 -73
- package/dist/debate.js +19 -31
- package/dist/longtable-codex-native-hook.js +36 -8
- package/dist/panel-runtime.d.ts +1 -0
- package/dist/panel-runtime.js +447 -88
- package/dist/panel.d.ts +13 -1
- package/dist/panel.js +343 -31
- package/dist/project-session.d.ts +0 -1
- package/dist/project-session.js +75 -116
- package/package.json +7 -7
package/dist/project-session.js
CHANGED
|
@@ -499,96 +499,12 @@ function formatQuestionMetadata(record) {
|
|
|
499
499
|
}
|
|
500
500
|
const QUESTION_SURFACES = new Set([
|
|
501
501
|
"native_structured",
|
|
502
|
+
"tmux_popup",
|
|
502
503
|
"mcp_elicitation",
|
|
503
504
|
"numbered",
|
|
504
505
|
"terminal_selector",
|
|
505
506
|
"web_form"
|
|
506
507
|
]);
|
|
507
|
-
function asStringArray(value) {
|
|
508
|
-
if (Array.isArray(value)) {
|
|
509
|
-
return value.filter((entry) => typeof entry === "string");
|
|
510
|
-
}
|
|
511
|
-
return typeof value === "string" ? [value] : [];
|
|
512
|
-
}
|
|
513
|
-
function legacyQuestionAnswerRecord(record) {
|
|
514
|
-
return asRecord(record.answer);
|
|
515
|
-
}
|
|
516
|
-
function labelForQuestionAnswerValue(record, value) {
|
|
517
|
-
const option = record.prompt.options.find((candidate) => candidate.value === value || candidate.label === value);
|
|
518
|
-
if (option) {
|
|
519
|
-
return option.label;
|
|
520
|
-
}
|
|
521
|
-
if (value === "other") {
|
|
522
|
-
return record.prompt.otherLabel ?? "Other";
|
|
523
|
-
}
|
|
524
|
-
return value;
|
|
525
|
-
}
|
|
526
|
-
function selectedValuesForQuestion(record) {
|
|
527
|
-
const answer = legacyQuestionAnswerRecord(record);
|
|
528
|
-
if (!answer) {
|
|
529
|
-
return [];
|
|
530
|
-
}
|
|
531
|
-
const directValues = asStringArray(answer.selectedValues);
|
|
532
|
-
if (directValues.length > 0) {
|
|
533
|
-
return directValues;
|
|
534
|
-
}
|
|
535
|
-
const legacyValues = [
|
|
536
|
-
...asStringArray(answer.selectedValue),
|
|
537
|
-
...asStringArray(answer.selected),
|
|
538
|
-
...asStringArray(answer.selectedOption),
|
|
539
|
-
...asStringArray(answer.answer),
|
|
540
|
-
...asStringArray(answer.value)
|
|
541
|
-
];
|
|
542
|
-
return uniqueStrings(legacyValues);
|
|
543
|
-
}
|
|
544
|
-
function selectedLabelsForQuestion(record, selectedValues) {
|
|
545
|
-
const answer = legacyQuestionAnswerRecord(record);
|
|
546
|
-
const directLabels = asStringArray(answer?.selectedLabels);
|
|
547
|
-
if (directLabels.length > 0) {
|
|
548
|
-
return directLabels;
|
|
549
|
-
}
|
|
550
|
-
return selectedValues.map((value) => labelForQuestionAnswerValue(record, value));
|
|
551
|
-
}
|
|
552
|
-
function legacyAnswerShapeWarnings(questions) {
|
|
553
|
-
return questions.flatMap((record) => {
|
|
554
|
-
if (record.status !== "answered" || !legacyQuestionAnswerRecord(record)) {
|
|
555
|
-
return [];
|
|
556
|
-
}
|
|
557
|
-
const selectedValues = asStringArray(legacyQuestionAnswerRecord(record)?.selectedValues);
|
|
558
|
-
const selectedLabels = asStringArray(legacyQuestionAnswerRecord(record)?.selectedLabels);
|
|
559
|
-
if (selectedValues.length > 0 && selectedLabels.length > 0) {
|
|
560
|
-
return [];
|
|
561
|
-
}
|
|
562
|
-
return [{
|
|
563
|
-
questionId: record.id,
|
|
564
|
-
...(record.decisionRecordId ? { decisionRecordId: record.decisionRecordId } : {}),
|
|
565
|
-
issue: "Answered question uses a legacy answer shape that is missing selectedValues or selectedLabels.",
|
|
566
|
-
suggestion: "Run `longtable repair-state --cwd <project-path>` to normalize the answer without changing the recorded selection."
|
|
567
|
-
}];
|
|
568
|
-
});
|
|
569
|
-
}
|
|
570
|
-
function numericOtherAnswerWarnings(questions) {
|
|
571
|
-
return questions.flatMap((record) => {
|
|
572
|
-
if (record.status !== "answered" || !selectedValuesForQuestion(record).includes("other")) {
|
|
573
|
-
return [];
|
|
574
|
-
}
|
|
575
|
-
const answer = legacyQuestionAnswerRecord(record);
|
|
576
|
-
const raw = typeof answer?.otherText === "string"
|
|
577
|
-
? answer.otherText
|
|
578
|
-
: selectedLabelsForQuestion(record, selectedValuesForQuestion(record))[0] ?? "";
|
|
579
|
-
if (!/^\d+$/.test(raw.trim())) {
|
|
580
|
-
return [];
|
|
581
|
-
}
|
|
582
|
-
const index = Number(raw.trim()) - 1;
|
|
583
|
-
const option = record.prompt.options[index];
|
|
584
|
-
return [{
|
|
585
|
-
questionId: record.id,
|
|
586
|
-
...(record.decisionRecordId ? { decisionRecordId: record.decisionRecordId } : {}),
|
|
587
|
-
issue: `Numeric answer "${raw.trim()}" was stored as other text.`,
|
|
588
|
-
...(option ? { suggestion: `Use "${option.value}" (${option.label}) for this checkpoint option.` } : {})
|
|
589
|
-
}];
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
508
|
function compactLine(value, limit = 160) {
|
|
593
509
|
const compacted = value.replace(/\s+/g, " ").trim();
|
|
594
510
|
return compacted.length > limit ? `${compacted.slice(0, limit - 1)}…` : compacted;
|
|
@@ -598,6 +514,15 @@ function asRecord(value) {
|
|
|
598
514
|
? value
|
|
599
515
|
: null;
|
|
600
516
|
}
|
|
517
|
+
function asStringArray(value) {
|
|
518
|
+
if (Array.isArray(value)) {
|
|
519
|
+
return value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
|
|
520
|
+
}
|
|
521
|
+
return typeof value === "string" && value.trim().length > 0 ? [value] : [];
|
|
522
|
+
}
|
|
523
|
+
function isQuestionSurfaceValue(value) {
|
|
524
|
+
return typeof value === "string" && QUESTION_SURFACES.has(value);
|
|
525
|
+
}
|
|
601
526
|
const SPEC_DIFF_IGNORED_PATHS = new Set([
|
|
602
527
|
"createdAt",
|
|
603
528
|
"updatedAt",
|
|
@@ -694,10 +619,10 @@ function buildResearchSpecificationGapQuestion(gaps, timestamp, sourceEvidenceId
|
|
|
694
619
|
"Research Specification is the required durable interview artifact.",
|
|
695
620
|
"Missing required sections can make later resume, screening, coding, or evidence decisions stale."
|
|
696
621
|
],
|
|
697
|
-
preferredSurfaces: ["mcp_elicitation", "numbered"]
|
|
622
|
+
preferredSurfaces: ["tmux_popup", "mcp_elicitation", "numbered"]
|
|
698
623
|
},
|
|
699
624
|
transportStatus: {
|
|
700
|
-
surface: "
|
|
625
|
+
surface: "tmux_popup",
|
|
701
626
|
status: "not_attempted",
|
|
702
627
|
updatedAt: timestamp,
|
|
703
628
|
...(sourceEvidenceIds.length > 0 ? { message: `Source evidence: ${sourceEvidenceIds.join(", ")}` } : {})
|
|
@@ -946,10 +871,22 @@ function summarizeWorkspaceInspection(context, state) {
|
|
|
946
871
|
...(record.selectedOption ? { selectedOption: record.selectedOption } : {}),
|
|
947
872
|
timestamp: record.timestamp
|
|
948
873
|
})),
|
|
949
|
-
answerWarnings:
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
874
|
+
answerWarnings: questions
|
|
875
|
+
.filter((record) => record.status === "answered" && record.answer?.selectedValues.includes("other"))
|
|
876
|
+
.flatMap((record) => {
|
|
877
|
+
const raw = record.answer?.otherText ?? record.answer?.selectedLabels[0] ?? "";
|
|
878
|
+
if (!/^\d+$/.test(raw.trim())) {
|
|
879
|
+
return [];
|
|
880
|
+
}
|
|
881
|
+
const index = Number(raw.trim()) - 1;
|
|
882
|
+
const option = record.prompt.options[index];
|
|
883
|
+
return [{
|
|
884
|
+
questionId: record.id,
|
|
885
|
+
...(record.decisionRecordId ? { decisionRecordId: record.decisionRecordId } : {}),
|
|
886
|
+
issue: `Numeric answer "${raw.trim()}" was stored as other text.`,
|
|
887
|
+
...(option ? { suggestion: `Use "${option.value}" (${option.label}) for this checkpoint option.` } : {})
|
|
888
|
+
}];
|
|
889
|
+
})
|
|
953
890
|
};
|
|
954
891
|
}
|
|
955
892
|
function buildProjectAgentsMd(project, session) {
|
|
@@ -2762,7 +2699,7 @@ export async function createWorkspaceFollowUpQuestions(options) {
|
|
|
2762
2699
|
const createdAt = nowIso();
|
|
2763
2700
|
const preferredSurfaces = options.provider === "claude"
|
|
2764
2701
|
? ["native_structured", "terminal_selector", "numbered"]
|
|
2765
|
-
: ["mcp_elicitation", "terminal_selector", "numbered"];
|
|
2702
|
+
: ["tmux_popup", "mcp_elicitation", "terminal_selector", "numbered"];
|
|
2766
2703
|
const specs = buildQuestionOpportunitySpecs(options.prompt, {
|
|
2767
2704
|
includeFallback: options.force === true ? true : options.auto !== true,
|
|
2768
2705
|
autoOnly: options.auto === true,
|
|
@@ -2875,7 +2812,7 @@ export async function createWorkspaceQuestion(options) {
|
|
|
2875
2812
|
rationale,
|
|
2876
2813
|
preferredSurfaces: options.provider === "claude"
|
|
2877
2814
|
? ["native_structured", "numbered"]
|
|
2878
|
-
: ["mcp_elicitation", "numbered"]
|
|
2815
|
+
: ["tmux_popup", "mcp_elicitation", "numbered"]
|
|
2879
2816
|
}
|
|
2880
2817
|
};
|
|
2881
2818
|
const updated = appendQuestionRecords(state, [question]);
|
|
@@ -3078,6 +3015,15 @@ function normalizeQuestionAnswerSelection(question, rawAnswer) {
|
|
|
3078
3015
|
...(inlineRationale ? { inlineRationale } : {})
|
|
3079
3016
|
};
|
|
3080
3017
|
}
|
|
3018
|
+
function selectedLabelsForValues(question, selectedValues) {
|
|
3019
|
+
return selectedValues.map((value) => {
|
|
3020
|
+
if (value === "other") {
|
|
3021
|
+
return question.prompt.otherLabel ?? "Other";
|
|
3022
|
+
}
|
|
3023
|
+
const option = question.prompt.options.find((candidate) => candidate.value === value);
|
|
3024
|
+
return option?.label ?? value;
|
|
3025
|
+
});
|
|
3026
|
+
}
|
|
3081
3027
|
export async function answerWorkspaceQuestion(options) {
|
|
3082
3028
|
const state = await loadResearchState(options.context.stateFilePath);
|
|
3083
3029
|
const question = findQuestionForDecision(state, options.questionId);
|
|
@@ -3116,7 +3062,12 @@ export async function answerWorkspaceQuestion(options) {
|
|
|
3116
3062
|
updatedAt: timestamp,
|
|
3117
3063
|
status: "answered",
|
|
3118
3064
|
answer,
|
|
3119
|
-
decisionRecordId: decision.id
|
|
3065
|
+
decisionRecordId: decision.id,
|
|
3066
|
+
transportStatus: {
|
|
3067
|
+
surface: answer.surface,
|
|
3068
|
+
status: "accepted",
|
|
3069
|
+
updatedAt: timestamp
|
|
3070
|
+
}
|
|
3120
3071
|
};
|
|
3121
3072
|
const withQuestion = {
|
|
3122
3073
|
...state,
|
|
@@ -3322,41 +3273,49 @@ export async function repairWorkspaceStateConsistency(options) {
|
|
|
3322
3273
|
})
|
|
3323
3274
|
};
|
|
3324
3275
|
}
|
|
3325
|
-
const
|
|
3276
|
+
const repairTimestamp = nowIso();
|
|
3326
3277
|
const repairedQuestionLog = (updated.questionLog ?? []).map((record) => {
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
}
|
|
3330
|
-
const answer = legacyQuestionAnswerRecord(record);
|
|
3331
|
-
if (!answer) {
|
|
3278
|
+
const answerRecord = asRecord(record.answer);
|
|
3279
|
+
if (!answerRecord) {
|
|
3332
3280
|
return record;
|
|
3333
3281
|
}
|
|
3334
|
-
const selectedValues =
|
|
3282
|
+
const selectedValues = [
|
|
3283
|
+
...asStringArray(answerRecord.selectedValues),
|
|
3284
|
+
...asStringArray(answerRecord.selectedValue),
|
|
3285
|
+
...asStringArray(answerRecord.selectedOptions),
|
|
3286
|
+
...asStringArray(answerRecord.value)
|
|
3287
|
+
];
|
|
3335
3288
|
if (selectedValues.length === 0) {
|
|
3336
3289
|
return record;
|
|
3337
3290
|
}
|
|
3338
|
-
const selectedLabels =
|
|
3339
|
-
const needsRepair =
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
!QUESTION_SURFACES.has(answer.surface);
|
|
3291
|
+
const selectedLabels = asStringArray(answerRecord.selectedLabels);
|
|
3292
|
+
const needsRepair = typeof answerRecord.promptId !== "string" ||
|
|
3293
|
+
selectedLabels.length === 0 ||
|
|
3294
|
+
!isQuestionSurfaceValue(answerRecord.surface);
|
|
3343
3295
|
if (!needsRepair) {
|
|
3344
3296
|
return record;
|
|
3345
3297
|
}
|
|
3346
3298
|
repaired.push(`normalized legacy answer shape for question ${record.id}`);
|
|
3347
3299
|
const normalizedAnswer = {
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
...(typeof
|
|
3354
|
-
|
|
3355
|
-
|
|
3300
|
+
promptId: typeof answerRecord.promptId === "string" ? answerRecord.promptId : record.prompt.id,
|
|
3301
|
+
selectedValues: uniqueStrings(selectedValues),
|
|
3302
|
+
selectedLabels: selectedLabels.length > 0
|
|
3303
|
+
? selectedLabels
|
|
3304
|
+
: selectedLabelsForValues(record, uniqueStrings(selectedValues)),
|
|
3305
|
+
...(typeof answerRecord.otherText === "string" && answerRecord.otherText.trim()
|
|
3306
|
+
? { otherText: answerRecord.otherText }
|
|
3307
|
+
: {}),
|
|
3308
|
+
...(typeof answerRecord.rationale === "string" && answerRecord.rationale.trim()
|
|
3309
|
+
? { rationale: answerRecord.rationale }
|
|
3310
|
+
: {}),
|
|
3311
|
+
...(answerRecord.provider === "codex" || answerRecord.provider === "claude"
|
|
3312
|
+
? { provider: answerRecord.provider }
|
|
3313
|
+
: {}),
|
|
3314
|
+
surface: isQuestionSurfaceValue(answerRecord.surface) ? answerRecord.surface : "numbered"
|
|
3356
3315
|
};
|
|
3357
3316
|
return {
|
|
3358
3317
|
...record,
|
|
3359
|
-
updatedAt:
|
|
3318
|
+
updatedAt: repairTimestamp,
|
|
3360
3319
|
answer: normalizedAnswer
|
|
3361
3320
|
};
|
|
3362
3321
|
});
|
|
@@ -3366,7 +3325,7 @@ export async function repairWorkspaceStateConsistency(options) {
|
|
|
3366
3325
|
questionLog: repairedQuestionLog
|
|
3367
3326
|
};
|
|
3368
3327
|
}
|
|
3369
|
-
if (repaired.length > 0
|
|
3328
|
+
if (repaired.length > 0) {
|
|
3370
3329
|
await writeFile(options.context.stateFilePath, JSON.stringify(updated, null, 2), "utf8");
|
|
3371
3330
|
await syncCurrentWorkspaceView(options.context);
|
|
3372
3331
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longtable/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.59",
|
|
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.59",
|
|
33
|
+
"@longtable/core": "0.1.59",
|
|
34
|
+
"@longtable/memory": "0.1.59",
|
|
35
|
+
"@longtable/provider-claude": "0.1.59",
|
|
36
|
+
"@longtable/provider-codex": "0.1.59",
|
|
37
|
+
"@longtable/setup": "0.1.59"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^22.10.1",
|