@indigoai-us/hq-cli 5.345.56 → 5.345.58
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/CHANGELOG.md +9 -0
- package/dist/command-catalog.generated.d.ts +88 -0
- package/dist/command-catalog.generated.js +109 -0
- package/dist/commands/access.d.ts +14 -0
- package/dist/commands/access.js +69 -1
- package/dist/commands/lanes-loop.d.ts +12 -0
- package/dist/commands/lanes-loop.js +214 -0
- package/dist/commands/lanes-questions.js +37 -11
- package/dist/commands/lanes-resume.js +19 -1
- package/dist/commands/lanes-shared.d.ts +12 -1
- package/dist/commands/lanes.js +262 -22
- package/dist/lib/lanes/delivery.d.ts +3 -0
- package/dist/lib/lanes/delivery.js +5 -0
- package/dist/lib/lanes/dropbox.d.ts +3 -0
- package/dist/lib/lanes/dropbox.js +103 -1
- package/dist/lib/lanes/flag-keys.d.ts +4 -0
- package/dist/lib/lanes/flag-keys.js +4 -0
- package/dist/lib/lanes/loop.d.ts +158 -0
- package/dist/lib/lanes/loop.js +743 -0
- package/dist/lib/lanes/outpost-dispatch.d.ts +9 -1
- package/dist/lib/lanes/outpost-dispatch.js +21 -7
- package/dist/lib/lanes/reconcile.d.ts +19 -0
- package/dist/lib/lanes/reconcile.js +173 -6
- package/dist/lib/lanes/spawn.d.ts +2 -0
- package/dist/lib/lanes/spawn.js +10 -8
- package/dist/lib/lanes/store.js +49 -2
- package/dist/lib/lanes/types.d.ts +18 -0
- package/dist/lib/lanes/types.js +2 -2
- package/dist/lib/lanes/watcher.js +3 -0
- package/package.json +1 -1
|
@@ -291,7 +291,7 @@ export function createLaneQuestionsHandlers(deps) {
|
|
|
291
291
|
const body = parseOutpostQuestionBody(response.body, outpostId, question.question_id);
|
|
292
292
|
return { question, audience, body };
|
|
293
293
|
}
|
|
294
|
-
async function loadPrimaryOwnedOutpostQuestions(ctx, hqRoot, companyFilter) {
|
|
294
|
+
async function loadPrimaryOwnedOutpostQuestions(ctx, hqRoot, companyFilter, questionId, visibilityFilter) {
|
|
295
295
|
const hostedLanes = loadAllLanes(hqRoot).filter((lane) => lane.host.kind === "outpost" &&
|
|
296
296
|
!laneIsHostedHere(ctx, lane) &&
|
|
297
297
|
(!companyFilter ||
|
|
@@ -356,7 +356,7 @@ export function createLaneQuestionsHandlers(deps) {
|
|
|
356
356
|
};
|
|
357
357
|
}
|
|
358
358
|
try {
|
|
359
|
-
const remoteQuestions = await readOutpostQuestionRecords(ctx, outpostId, group.company);
|
|
359
|
+
const remoteQuestions = await readOutpostQuestionRecords(ctx, outpostId, group.company, questionId, visibilityFilter);
|
|
360
360
|
const localLanesById = new Map(group.lanes.map((lane) => [lane.lane_id, lane]));
|
|
361
361
|
const groupQuestions = [];
|
|
362
362
|
const seenQuestionIds = new Set();
|
|
@@ -595,8 +595,32 @@ export function createLaneQuestionsHandlers(deps) {
|
|
|
595
595
|
}
|
|
596
596
|
return true;
|
|
597
597
|
});
|
|
598
|
+
const deliveredLocalQuestions = new Map();
|
|
599
|
+
const currentSessionId = sessionIdFromEnv(ctx.env);
|
|
600
|
+
if (currentSessionId) {
|
|
601
|
+
const deliveredAt = ctx.now().toISOString();
|
|
602
|
+
for (const question of localQuestions) {
|
|
603
|
+
if (question.status !== "pending")
|
|
604
|
+
continue;
|
|
605
|
+
const audience = resolveAudience(hqRoot, question, ctx);
|
|
606
|
+
if (audience.kind !== "session" || audience.id !== currentSessionId)
|
|
607
|
+
continue;
|
|
608
|
+
const delivered = casUpdateQuestion(hqRoot, question.question_id, (current) => current.status !== "pending" ||
|
|
609
|
+
(current.seen_at && current.seen_session_id === currentSessionId)
|
|
610
|
+
? current
|
|
611
|
+
: { ...current, seen_at: deliveredAt, seen_session_id: currentSessionId });
|
|
612
|
+
deliveredLocalQuestions.set(question.question_id, delivered);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
598
615
|
const outpostLoad = opts.allHosts
|
|
599
|
-
? await loadPrimaryOwnedOutpostQuestions(ctx, hqRoot, company
|
|
616
|
+
? await loadPrimaryOwnedOutpostQuestions(ctx, hqRoot, company, undefined, {
|
|
617
|
+
sessionId: currentSessionId ?? undefined,
|
|
618
|
+
for: opts.for,
|
|
619
|
+
from: opts.from,
|
|
620
|
+
project: opts.project,
|
|
621
|
+
story: opts.story,
|
|
622
|
+
status: opts.status,
|
|
623
|
+
})
|
|
600
624
|
: { questions: [], errors: [] };
|
|
601
625
|
for (const owner of outpostLoad.questions) {
|
|
602
626
|
assertQuestionCompanyAccess(owner.question, owner.lane, company, hqRoot);
|
|
@@ -607,12 +631,13 @@ export function createLaneQuestionsHandlers(deps) {
|
|
|
607
631
|
...localQuestions
|
|
608
632
|
.filter((q) => !remoteQuestionIds.has(q.question_id))
|
|
609
633
|
.map((q) => {
|
|
634
|
+
const visibleQuestion = deliveredLocalQuestions.get(q.question_id) ?? q;
|
|
610
635
|
const row = {
|
|
611
|
-
...
|
|
612
|
-
priority:
|
|
613
|
-
priority_display:
|
|
614
|
-
audience: resolveAudience(hqRoot,
|
|
615
|
-
...(
|
|
636
|
+
...visibleQuestion,
|
|
637
|
+
priority: visibleQuestion.priority ?? null,
|
|
638
|
+
priority_display: visibleQuestion.priority ?? "-",
|
|
639
|
+
audience: resolveAudience(hqRoot, visibleQuestion, ctx),
|
|
640
|
+
...(visibleQuestion.question_kind === "continue" ? { flag: "continue-loop" } : {}),
|
|
616
641
|
};
|
|
617
642
|
if (!opts.allHosts)
|
|
618
643
|
return row;
|
|
@@ -662,7 +687,7 @@ export function createLaneQuestionsHandlers(deps) {
|
|
|
662
687
|
catch (err) {
|
|
663
688
|
if (!isLanesError(err) || err.error !== "question_not_found")
|
|
664
689
|
throw err;
|
|
665
|
-
const lookup = await loadPrimaryOwnedOutpostQuestions(ctx, hqRoot);
|
|
690
|
+
const lookup = await loadPrimaryOwnedOutpostQuestions(ctx, hqRoot, undefined, questionId);
|
|
666
691
|
if (lookup.errors.length > 0) {
|
|
667
692
|
throw new LanesError("outpost_question_lookup_unavailable", `Could not verify whether Outposts own question ${questionId}`, {
|
|
668
693
|
question_id: questionId,
|
|
@@ -717,7 +742,7 @@ export function createLaneQuestionsHandlers(deps) {
|
|
|
717
742
|
if (!isLanesError(err) || err.error !== "question_not_found")
|
|
718
743
|
throw err;
|
|
719
744
|
const company = explicitCompany ?? await resolveActiveQuestionCompany(ctx, "Cannot look up this lane question because the active HQ company could not be resolved; re-run with --company <slug>");
|
|
720
|
-
const lookup = await loadPrimaryOwnedOutpostQuestions(ctx, hqRoot, company);
|
|
745
|
+
const lookup = await loadPrimaryOwnedOutpostQuestions(ctx, hqRoot, company, questionId);
|
|
721
746
|
const matches = lookup.questions.filter((entry) => entry.question.question_id === questionId);
|
|
722
747
|
if (matches.length === 0 && lookup.errors.length > 0) {
|
|
723
748
|
throw new LanesError("outpost_question_lookup_unavailable", `Could not verify whether Outposts own question ${questionId}`, {
|
|
@@ -726,7 +751,7 @@ export function createLaneQuestionsHandlers(deps) {
|
|
|
726
751
|
});
|
|
727
752
|
}
|
|
728
753
|
if (matches.length === 0) {
|
|
729
|
-
const allCompanyLookup = await loadPrimaryOwnedOutpostQuestions(ctx, hqRoot);
|
|
754
|
+
const allCompanyLookup = await loadPrimaryOwnedOutpostQuestions(ctx, hqRoot, undefined, questionId);
|
|
730
755
|
const otherCompanyMatch = allCompanyLookup.questions.find((entry) => entry.question.question_id === questionId);
|
|
731
756
|
if (otherCompanyMatch) {
|
|
732
757
|
assertQuestionCompanyAccess(otherCompanyMatch.question, otherCompanyMatch.lane, company, hqRoot);
|
|
@@ -818,6 +843,7 @@ export function createLaneQuestionsHandlers(deps) {
|
|
|
818
843
|
company: recordedCompany,
|
|
819
844
|
body: nextBody,
|
|
820
845
|
status: "answered",
|
|
846
|
+
delivered_at: null,
|
|
821
847
|
answer: {
|
|
822
848
|
choice,
|
|
823
849
|
answer_kind: freeform ? "freeform" : "option",
|
|
@@ -91,6 +91,9 @@ export function createLaneResumeHandlers(deps) {
|
|
|
91
91
|
const hqRoot = ctx.hqRoot();
|
|
92
92
|
const resolution = await deps.resolveCommandLane(ctx, laneId);
|
|
93
93
|
let lane = resolution.lane;
|
|
94
|
+
if (opts.freshThread === true && lane.loop_mode !== true) {
|
|
95
|
+
throw new LanesError("fresh_thread_loop_only", "--fresh-thread is reserved for loop-lane phases", { lane_id: laneId });
|
|
96
|
+
}
|
|
94
97
|
const failedResumeReason = opts.reason?.trim();
|
|
95
98
|
if (opts.reason !== undefined && opts.fromFailed !== true) {
|
|
96
99
|
throw new LanesError("failed_resume_reason_requires_flag", "--reason on hq lanes resume requires --from-failed", { lane_id: laneId });
|
|
@@ -153,6 +156,9 @@ export function createLaneResumeHandlers(deps) {
|
|
|
153
156
|
throw new LanesError("effort_resume_unsupported", `Provider ${lane.provider} cannot change effort on a resumed session`, { lane_id: laneId, provider: lane.provider });
|
|
154
157
|
}
|
|
155
158
|
lane = laneWithRecoveredProviderSession(hqRoot, lane);
|
|
159
|
+
if (opts.loopSessionId !== undefined && opts.loopSessionId !== lane.provider_session_id) {
|
|
160
|
+
lane = casUpdateLane(hqRoot, laneId, (current) => ({ ...current, provider_session_id: opts.loopSessionId }));
|
|
161
|
+
}
|
|
156
162
|
if (opts.model !== undefined && opts.account === undefined) {
|
|
157
163
|
throw new LanesError("model_requires_account", "--model on hq lanes resume is only accepted together with --account", {});
|
|
158
164
|
}
|
|
@@ -233,7 +239,7 @@ export function createLaneResumeHandlers(deps) {
|
|
|
233
239
|
}
|
|
234
240
|
const refusal = queuedProfileRecovery || lane.state === "awaiting_input"
|
|
235
241
|
? null
|
|
236
|
-
: resumeCommandRefusal(lane, { allowFailed: opts.fromFailed === true || isFailedQuotaKeepAliveLane(lane) });
|
|
242
|
+
: resumeCommandRefusal(lane, { allowFailed: opts.fromFailed === true || isFailedQuotaKeepAliveLane(lane), allowFresh: opts.freshThread === true });
|
|
237
243
|
if (refusal !== null) {
|
|
238
244
|
throw new LanesError(refusal.error, refusal.message, {
|
|
239
245
|
lane_id: laneId,
|
|
@@ -435,6 +441,8 @@ export function createLaneResumeHandlers(deps) {
|
|
|
435
441
|
...(deliveryText !== undefined ? { text: deliveryText } : {}),
|
|
436
442
|
...(messageId !== undefined ? { message_id: messageId } : {}),
|
|
437
443
|
compact: opts.compact !== false,
|
|
444
|
+
...(opts.freshThread === true ? { fresh_thread: true } : {}),
|
|
445
|
+
...(opts.workingDirectory ? { working_directory: opts.workingDirectory } : {}),
|
|
438
446
|
},
|
|
439
447
|
});
|
|
440
448
|
lane = move.lane;
|
|
@@ -469,6 +477,8 @@ export function createLaneResumeHandlers(deps) {
|
|
|
469
477
|
...(deliveryText !== undefined ? { text: deliveryText } : {}),
|
|
470
478
|
...(messageId !== undefined ? { message_id: messageId } : {}),
|
|
471
479
|
compact: opts.compact !== false,
|
|
480
|
+
...(opts.freshThread === true ? { fresh_thread: true } : {}),
|
|
481
|
+
...(opts.workingDirectory ? { working_directory: opts.workingDirectory } : {}),
|
|
472
482
|
},
|
|
473
483
|
accountSelection: selection,
|
|
474
484
|
});
|
|
@@ -496,6 +506,8 @@ export function createLaneResumeHandlers(deps) {
|
|
|
496
506
|
...(deliveryText !== undefined ? { text: deliveryText } : {}),
|
|
497
507
|
...(messageId !== undefined ? { message_id: messageId } : {}),
|
|
498
508
|
compact: opts.compact !== false,
|
|
509
|
+
...(opts.freshThread === true ? { fresh_thread: true } : {}),
|
|
510
|
+
...(opts.workingDirectory ? { working_directory: opts.workingDirectory } : {}),
|
|
499
511
|
},
|
|
500
512
|
});
|
|
501
513
|
lane = move.lane;
|
|
@@ -535,6 +547,8 @@ export function createLaneResumeHandlers(deps) {
|
|
|
535
547
|
...(deliveryText !== undefined ? { text: deliveryText } : {}),
|
|
536
548
|
...(messageId !== undefined ? { message_id: messageId } : {}),
|
|
537
549
|
compact: opts.compact !== false,
|
|
550
|
+
...(opts.freshThread === true ? { fresh_thread: true } : {}),
|
|
551
|
+
...(opts.workingDirectory ? { working_directory: opts.workingDirectory } : {}),
|
|
538
552
|
at: quotaHoldAt,
|
|
539
553
|
};
|
|
540
554
|
resumed = markSpawnFailure(hqRoot, laneId, "account_quota_exhausted", {
|
|
@@ -590,6 +604,8 @@ export function createLaneResumeHandlers(deps) {
|
|
|
590
604
|
...(deliveryText !== undefined ? { text: deliveryText } : {}),
|
|
591
605
|
...(messageId !== undefined ? { message_id: messageId } : {}),
|
|
592
606
|
compact: opts.compact !== false,
|
|
607
|
+
...(opts.freshThread === true ? { fresh_thread: true } : {}),
|
|
608
|
+
...(opts.workingDirectory ? { working_directory: opts.workingDirectory } : {}),
|
|
593
609
|
at,
|
|
594
610
|
},
|
|
595
611
|
};
|
|
@@ -610,10 +626,12 @@ export function createLaneResumeHandlers(deps) {
|
|
|
610
626
|
resolveMachineIdentity: ctx.resolveMachineIdentity,
|
|
611
627
|
runCompaction: ctx.runCompaction,
|
|
612
628
|
locateTranscript: ctx.locateTranscript,
|
|
629
|
+
...(opts.workingDirectory ? { workingDirectory: opts.workingDirectory } : {}),
|
|
613
630
|
}, {
|
|
614
631
|
trigger: {
|
|
615
632
|
kind: "resume",
|
|
616
633
|
from: resumedFrom,
|
|
634
|
+
...(opts.freshThread === true ? { fresh: true } : {}),
|
|
617
635
|
...(resumedFrom === "awaiting_input" && pendingQuestions.length === 0 ? { allowAwaitingInput: true } : {}),
|
|
618
636
|
...(opts.fromFailed === true ? { fromFailed: true } : {}),
|
|
619
637
|
...(failedResumeExpectedSenior !== undefined
|
|
@@ -77,6 +77,10 @@ export interface LaneResumeOptions {
|
|
|
77
77
|
effort?: string;
|
|
78
78
|
worker?: string;
|
|
79
79
|
keepAlive?: boolean;
|
|
80
|
+
freshThread?: boolean;
|
|
81
|
+
workingDirectory?: string;
|
|
82
|
+
/** Internal loop runner session; selects this story's saved provider session. */
|
|
83
|
+
loopSessionId?: string;
|
|
80
84
|
meshCompany?: string;
|
|
81
85
|
profileRepinContext?: string;
|
|
82
86
|
grantContext?: string;
|
|
@@ -458,7 +462,14 @@ export interface LaneQuestionsHandlerDeps {
|
|
|
458
462
|
questionCompanyForLane(question: QuestionRecord, lane: Pick<LaneRecord, "company" | "mesh_company" | "project_id" | "lane_id">, hqRoot?: string): LaneCompanyRef | null;
|
|
459
463
|
questionCompanyRefMatches(recordCompany: LaneCompanyRef | null | undefined, filter: LaneCompanyRef): boolean;
|
|
460
464
|
questionListCompanyArg(company: LaneCompanyRef | null): string | undefined;
|
|
461
|
-
readOutpostQuestionRecords(ctx: Ctx, outpostId: string, company: LaneCompanyRef | null
|
|
465
|
+
readOutpostQuestionRecords(ctx: Ctx, outpostId: string, company: LaneCompanyRef | null, questionId?: string, visibilityFilter?: {
|
|
466
|
+
sessionId?: string;
|
|
467
|
+
for?: string;
|
|
468
|
+
from?: string;
|
|
469
|
+
project?: string;
|
|
470
|
+
story?: string;
|
|
471
|
+
status?: string;
|
|
472
|
+
}): Promise<OutpostQuestionRow[]>;
|
|
462
473
|
readQuestionBody(hqRoot: string, question: QuestionRecord): QuestionBody | null;
|
|
463
474
|
printJson(value: unknown): void;
|
|
464
475
|
readSessionMeta(hqRoot: string, sessionId: string, ctx: Ctx): Record<string, unknown> | null;
|