@indigoai-us/hq-cli 5.345.197 → 5.345.199
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 +111 -0
- package/dist/command-catalog.generated.d.ts +393 -12
- package/dist/command-catalog.generated.js +482 -12
- package/dist/commands/bot-events.d.ts +19 -0
- package/dist/commands/bot-events.js +46 -0
- package/dist/commands/bot-jobs.d.ts +2 -0
- package/dist/commands/bot-jobs.js +43 -2
- package/dist/commands/bot.d.ts +5 -0
- package/dist/commands/bot.js +33 -1
- package/dist/commands/core-resolve-company-native.d.ts +2 -1
- package/dist/commands/core-resolve-company-native.js +2 -24
- package/dist/commands/deploy-domains.d.ts +14 -2
- package/dist/commands/deploy-domains.js +726 -42
- package/dist/commands/integrations-connect.js +41 -3
- package/dist/commands/lanes-report.d.ts +2 -1
- package/dist/commands/lanes-report.js +44 -1
- package/dist/commands/lanes.d.ts +9 -0
- package/dist/commands/lanes.js +95 -9
- package/dist/commands/meetings.js +1 -21
- package/dist/commands/secrets.js +27 -6
- package/dist/commands/signals-run.d.ts +2 -0
- package/dist/commands/signals-run.js +6 -1
- package/dist/lanes-drain-hook.js +9 -0
- package/dist/lib/bot/api.d.ts +5 -0
- package/dist/lib/bot/claude-login.d.ts +31 -0
- package/dist/lib/bot/claude-login.js +160 -0
- package/dist/lib/bot/company-bind.d.ts +34 -0
- package/dist/lib/bot/company-bind.js +112 -0
- package/dist/lib/bot/config.js +3 -1
- package/dist/lib/bot/events.d.ts +18 -0
- package/dist/lib/bot/events.js +160 -0
- package/dist/lib/bot/executive-settings.d.ts +10 -0
- package/dist/lib/bot/executive-settings.js +43 -0
- package/dist/lib/bot/fleet-cron.js +4 -0
- package/dist/lib/bot/fleet-local.d.ts +12 -0
- package/dist/lib/bot/fleet-local.js +50 -20
- package/dist/lib/bot/job-run.js +1 -1
- package/dist/lib/bot/jobs/hot-signal-sync.d.ts +8 -0
- package/dist/lib/bot/jobs/hot-signal-sync.js +2 -0
- package/dist/lib/bot/jobs/meeting-detect.d.ts +28 -0
- package/dist/lib/bot/jobs/meeting-detect.js +176 -0
- package/dist/lib/bot/jobs/meeting-rider.d.ts +53 -0
- package/dist/lib/bot/jobs/meeting-rider.js +284 -0
- package/dist/lib/bot/jobs/signal-to-lane.d.ts +32 -0
- package/dist/lib/bot/jobs/signal-to-lane.js +169 -0
- package/dist/lib/bot/local-jobs.d.ts +15 -2
- package/dist/lib/bot/local-jobs.js +24 -7
- package/dist/lib/bot/run.d.ts +7 -49
- package/dist/lib/bot/run.js +135 -12
- package/dist/lib/bot/session.d.ts +19 -1
- package/dist/lib/bot/session.js +75 -28
- package/dist/lib/bot/status.d.ts +21 -0
- package/dist/lib/core-utils/manifest-slugs.d.ts +2 -0
- package/dist/lib/core-utils/manifest-slugs.js +26 -0
- package/dist/lib/doctor/checks/bots.d.ts +6 -0
- package/dist/lib/doctor/checks/bots.js +47 -1
- package/dist/lib/hot-channels/adapters/meetings.d.ts +1 -0
- package/dist/lib/hot-channels/adapters/meetings.js +3 -1
- package/dist/lib/hot-channels/meeting-source-ref.d.ts +3 -0
- package/dist/lib/hot-channels/meeting-source-ref.js +7 -0
- package/dist/lib/hot-channels/schedule.js +2 -2
- package/dist/lib/hot-channels/signals-pass.d.ts +9 -32
- package/dist/lib/hot-channels/signals-pass.js +51 -17
- package/dist/lib/lanes/admission.d.ts +2 -0
- package/dist/lib/lanes/admission.js +4 -0
- package/dist/lib/lanes/approval-gate.js +4 -1
- package/dist/lib/lanes/links.d.ts +8 -1
- package/dist/lib/lanes/links.js +84 -3
- package/dist/lib/lanes/outcome.d.ts +154 -0
- package/dist/lib/lanes/outcome.js +151 -0
- package/dist/lib/lanes/reconcile.js +1 -0
- package/dist/lib/lanes/signal-brief-template.d.ts +7 -0
- package/dist/lib/lanes/signal-brief-template.js +40 -0
- package/dist/lib/lanes/signal-lane.d.ts +24 -0
- package/dist/lib/lanes/signal-lane.js +99 -0
- package/dist/lib/lanes/source-report.d.ts +37 -0
- package/dist/lib/lanes/source-report.js +66 -0
- package/dist/lib/lanes/spawn.d.ts +6 -0
- package/dist/lib/lanes/spawn.js +21 -0
- package/dist/lib/lanes/store.d.ts +3 -0
- package/dist/lib/lanes/store.js +64 -0
- package/dist/lib/lanes/story-ledger.d.ts +3 -0
- package/dist/lib/lanes/story-ledger.js +1 -0
- package/dist/lib/lanes/types.d.ts +137 -0
- package/dist/lib/lanes/types.js +17 -2
- package/dist/lib/lanes/watcher.js +4 -0
- package/dist/lib/live-meetings.d.ts +19 -0
- package/dist/lib/live-meetings.js +23 -0
- package/dist/lib/mesh/live/daemon/doctor.js +6 -7
- package/dist/lib/mesh/live/spool.d.ts +8 -0
- package/dist/lib/mesh/live/spool.js +59 -40
- package/dist/lib/plan-limit-nag.d.ts +30 -4
- package/dist/lib/plan-limit-nag.js +68 -17
- package/dist/lib/signals/engine.d.ts +4 -0
- package/dist/lib/signals/engine.js +25 -5
- package/dist/lib/signals/incremental.d.ts +42 -0
- package/dist/lib/signals/incremental.js +191 -0
- package/dist/lib/signals/prior-signals.d.ts +11 -0
- package/dist/lib/signals/prior-signals.js +44 -0
- package/dist/lib/signals/reply.js +6 -1
- package/dist/lib/signals/settings.d.ts +5 -0
- package/dist/lib/signals/settings.js +17 -0
- package/dist/lib/signals/steps/extract.d.ts +30 -2
- package/dist/lib/signals/steps/extract.js +153 -11
- package/dist/lib/signals/steps/types.d.ts +1 -0
- package/dist/lib/signals/write-guard.js +7 -0
- package/dist/secrets-env-action.d.ts +70 -0
- package/dist/secrets-env-action.js +220 -2
- package/dist/utils/cognito-callback-port.d.ts +15 -0
- package/dist/utils/cognito-callback-port.js +51 -0
- package/dist/utils/cognito-config.js +2 -3
- package/dist/utils/cognito-session.d.ts +7 -6
- package/dist/utils/cognito-session.js +14 -14
- package/dist/utils/interactive-caller.d.ts +15 -0
- package/dist/utils/interactive-caller.js +70 -0
- package/dist/utils/login-browser.js +3 -1
- package/dist/utils/resident-package-preload.js +4 -0
- package/package.json +9 -7
|
@@ -365,6 +365,39 @@ function withDocumentedRemoteMcp(target, domainHint) {
|
|
|
365
365
|
},
|
|
366
366
|
};
|
|
367
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* Google Workspace is a built-in OAuth connector (provider `google-workspace`,
|
|
370
|
+
* its own `/v1/integrations/google-workspace/connect` flow), not a remote MCP
|
|
371
|
+
* catalog entry. The CLI has no way to start that flow, so a bare `google` fell
|
|
372
|
+
* through to an install by free-text query, which hq-pro answers with
|
|
373
|
+
* "mcpUrl is required" because no catalog entry or domain resolves. The console
|
|
374
|
+
* is the surface that runs the built-in sign-in, so route there.
|
|
375
|
+
*/
|
|
376
|
+
const BUILT_IN_CONSOLE_APPS = {
|
|
377
|
+
google: "Google Workspace",
|
|
378
|
+
"google-workspace": "Google Workspace",
|
|
379
|
+
"google workspace": "Google Workspace",
|
|
380
|
+
google_workspace: "Google Workspace",
|
|
381
|
+
};
|
|
382
|
+
function builtInConsoleApp(app) {
|
|
383
|
+
return BUILT_IN_CONSOLE_APPS[app?.trim().toLowerCase() ?? ""];
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* hq-pro rejects an install/sign-in that names neither an endpoint nor a
|
|
387
|
+
* resolvable catalog entry or domain with a bare "mcpUrl is required". That is
|
|
388
|
+
* the caller's name not matching anything, so say so and name the way forward.
|
|
389
|
+
*/
|
|
390
|
+
function explainUnresolvableApp(target, err) {
|
|
391
|
+
if (!(err instanceof IntegrationsCliError) ||
|
|
392
|
+
err.code !== "DIRECT_MCP_INVALID_INPUT" ||
|
|
393
|
+
target.ref.mcpUrl ||
|
|
394
|
+
target.ref.discoveryReceiptId ||
|
|
395
|
+
target.ref.catalogEntryId) {
|
|
396
|
+
return err;
|
|
397
|
+
}
|
|
398
|
+
return new IntegrationsCliError(`${target.label} was not found in the app catalog, so HQ has no MCP server address for it. ` +
|
|
399
|
+
"Search with `hq integrations catalog <name>`, or re-run with --mcp-url <endpoint>.", { expected: true, status: err.status, code: err.code });
|
|
400
|
+
}
|
|
368
401
|
function unsupportedCatalogSurfaceError(label, cause) {
|
|
369
402
|
return new IntegrationsCliError(`${label} cannot be connected because the app catalog has no MCP server URL. ` +
|
|
370
403
|
"Re-run with --mcp-url <endpoint> (find it with `hq integrations inspect`).", { expected: true, status: cause.status, code: cause.code });
|
|
@@ -1100,6 +1133,11 @@ function reportInstall(result, opts, expectedRevivedConnectionId) {
|
|
|
1100
1133
|
* URL: hq-pro recognizes the domain and revives the revoked row in place.
|
|
1101
1134
|
*/
|
|
1102
1135
|
async function connectApp(token, companyUid, app, opts, expectedRevivedConnectionId) {
|
|
1136
|
+
const builtIn = opts.mcpUrl || opts.docsUrl || opts.entryId ? undefined : builtInConsoleApp(app);
|
|
1137
|
+
if (builtIn) {
|
|
1138
|
+
await consoleHandoff({ ref: {}, label: builtIn }, opts);
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1103
1141
|
const resolved = await resolveTarget(token, companyUid, app, opts, expectedRevivedConnectionId !== undefined);
|
|
1104
1142
|
const scope = connectScopeFromOptions(opts);
|
|
1105
1143
|
const target = scope ? { ...resolved, ref: { ...resolved.ref, scope } } : resolved;
|
|
@@ -1130,7 +1168,7 @@ async function connectApp(token, companyUid, app, opts, expectedRevivedConnectio
|
|
|
1130
1168
|
await finishWithAccessKey();
|
|
1131
1169
|
return;
|
|
1132
1170
|
}
|
|
1133
|
-
throw err;
|
|
1171
|
+
throw explainUnresolvableApp(target, err);
|
|
1134
1172
|
}
|
|
1135
1173
|
return;
|
|
1136
1174
|
}
|
|
@@ -1174,7 +1212,7 @@ async function connectApp(token, companyUid, app, opts, expectedRevivedConnectio
|
|
|
1174
1212
|
await finishWithAccessKey(bearerToken);
|
|
1175
1213
|
return;
|
|
1176
1214
|
}
|
|
1177
|
-
throw oauthErr;
|
|
1215
|
+
throw explainUnresolvableApp(target, oauthErr);
|
|
1178
1216
|
}
|
|
1179
1217
|
return;
|
|
1180
1218
|
}
|
|
@@ -1182,7 +1220,7 @@ async function connectApp(token, companyUid, app, opts, expectedRevivedConnectio
|
|
|
1182
1220
|
err.code === "INTEGRATION_FACTORY_UNSUPPORTED_SURFACE") {
|
|
1183
1221
|
throw unsupportedCatalogSurfaceError(target.label, err);
|
|
1184
1222
|
}
|
|
1185
|
-
throw err;
|
|
1223
|
+
throw explainUnresolvableApp(target, err);
|
|
1186
1224
|
}
|
|
1187
1225
|
}
|
|
1188
1226
|
/**
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
import { type QuestionBody } from "../lib/lanes/questions.js";
|
|
3
|
-
import type { LaneCompanyRef, QuestionRecord } from "../lib/lanes/types.js";
|
|
3
|
+
import type { LaneCompanyRef, LaneRecord, QuestionRecord } from "../lib/lanes/types.js";
|
|
4
4
|
import { type LaneChecksDeps } from "./lanes-checks.js";
|
|
5
5
|
type WrapHandler = <Args extends unknown[]>(action: (...args: Args) => Promise<void>) => (...args: Args) => Promise<void>;
|
|
6
6
|
export interface LaneReportsDeps extends LaneChecksDeps {
|
|
7
|
+
laneRunsHere: (lane: LaneRecord) => boolean;
|
|
7
8
|
readQuestionBody: (root: string, question: QuestionRecord) => QuestionBody;
|
|
8
9
|
focusDashboardEnabled: (company: LaneCompanyRef) => Promise<boolean>;
|
|
9
10
|
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
1
2
|
import * as path from "node:path";
|
|
2
3
|
import { LanesError } from "../lib/lanes/errors.js";
|
|
3
4
|
import { assertQuestionBodySecretSafe } from "../lib/lanes/questions.js";
|
|
4
|
-
import { questionRecordPath } from "../lib/lanes/store.js";
|
|
5
|
+
import { listLanesBySource, questionRecordPath } from "../lib/lanes/store.js";
|
|
5
6
|
import { normalizeIsoTimestamp } from "../lib/lanes/timestamp.js";
|
|
6
7
|
import { mapSourceStoryStatus } from "../lib/mesh/story-status.js";
|
|
7
8
|
import { buildTrackerOwnerReport, buildTrackerTeamPage, renderTrackerOwnerReportText, renderTrackerTeamPageText, } from "../lib/lanes/tracker-report.js";
|
|
8
9
|
import { FIRST_TRACKER_REPORT_SINCE, readTrackerReportState, writeTrackerReportState, } from "../lib/lanes/tracker-report-state.js";
|
|
9
10
|
import { listTrackerRecordsTolerant, loadCompanyQuestionRecords, loadProjectMappings, mappingIncludesStory, pathForTrackerRecord, readProject, resolveTrackerCompany, } from "./lanes-checks.js";
|
|
11
|
+
import { buildSourceReport, renderSourceReportText } from "../lib/lanes/source-report.js";
|
|
12
|
+
import { readLaneStatusRowFields } from "../lib/lanes/status-fields.js";
|
|
10
13
|
function fail(error, message, details = {}) {
|
|
11
14
|
throw new LanesError(error, message, details);
|
|
12
15
|
}
|
|
@@ -331,10 +334,50 @@ export function registerLaneReportCommands(parent, deps, wrap) {
|
|
|
331
334
|
parent.command("report")
|
|
332
335
|
.description("Generate the owner report for tracker teams")
|
|
333
336
|
.option("--company <slug>", "Select the company by slug")
|
|
337
|
+
.option("--source <ref>", "Report lanes for a source (requires --company; excludes --since)")
|
|
334
338
|
.option("--since <iso>", "Report activity from this ISO timestamp")
|
|
335
339
|
.option("--json", "Emit JSON instead of the owner report text")
|
|
336
340
|
.action(wrap(async (options) => {
|
|
341
|
+
if (options.source !== undefined && (!options.company?.trim() || options.since !== undefined || !options.source.trim())) {
|
|
342
|
+
fail("source_report_options_invalid", "--source requires --company and a non-empty ref, and cannot be combined with --since");
|
|
343
|
+
}
|
|
337
344
|
const company = await resolveTrackerCompany(deps, options.company);
|
|
345
|
+
if (options.source !== undefined) {
|
|
346
|
+
const root = deps.hqRoot();
|
|
347
|
+
const lanes = listLanesBySource(company.slug, options.source, root)
|
|
348
|
+
.filter(lane => lane.company?.uid === company.uid);
|
|
349
|
+
const ids = new Set(lanes.map(lane => lane.lane_id));
|
|
350
|
+
const questions = new Map();
|
|
351
|
+
if (lanes.length) {
|
|
352
|
+
const pending = loadCompanyQuestionRecords(root, company)
|
|
353
|
+
.filter(question => ids.has(question.lane_id) && question.status === "pending")
|
|
354
|
+
.sort((a, b) => a.asked_at.localeCompare(b.asked_at) || a.question_id.localeCompare(b.question_id));
|
|
355
|
+
for (const question of pending) {
|
|
356
|
+
if (questions.has(question.lane_id))
|
|
357
|
+
continue;
|
|
358
|
+
const body = deps.readQuestionBody(root, question);
|
|
359
|
+
assertQuestionBodySecretSafe(body);
|
|
360
|
+
questions.set(question.lane_id, { question_id: question.question_id, question: body.question });
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
const progress = new Map(lanes.filter(lane => lane.state === "running" || lane.state === "queued")
|
|
364
|
+
.map(lane => [lane.lane_id, readLaneStatusRowFields(root, lane, deps.now().getTime(), deps.laneRunsHere(lane)).last_line ?? "No progress recorded yet."]));
|
|
365
|
+
const report = buildSourceReport(company.slug, options.source, lanes, { questions, progress });
|
|
366
|
+
if (options.json)
|
|
367
|
+
console.log(JSON.stringify(report, null, 2));
|
|
368
|
+
else {
|
|
369
|
+
let template;
|
|
370
|
+
try {
|
|
371
|
+
template = fs.readFileSync(path.join(root, "personal/settings/executive/report.md"), "utf8");
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
if (error.code !== "ENOENT")
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
377
|
+
console.log(renderSourceReportText(report, template));
|
|
378
|
+
}
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
338
381
|
const root = deps.hqRoot();
|
|
339
382
|
const generatedAt = deps.now().toISOString();
|
|
340
383
|
const focusDashboardEnabled = await deps.focusDashboardEnabled(company);
|
package/dist/commands/lanes.d.ts
CHANGED
|
@@ -165,6 +165,15 @@ export declare function pickupFailureUpdater(reasonRaw: string, details: Record<
|
|
|
165
165
|
*/
|
|
166
166
|
export declare function applyOutpostAccountPickup(hqRoot: string, laneId: string, modelDeps?: KnownModelsDeps): LaneRecord;
|
|
167
167
|
export declare function cancelPendingQuestionsForLane(hqRoot: string, laneId: string, nowIso: string, operatorReason?: string): QuestionRecord[];
|
|
168
|
+
/** In-process signal entry point sharing CLI admission, dedupe and conductor rules. */
|
|
169
|
+
export declare function createLaneFromSignal(input: {
|
|
170
|
+
hqRoot: string;
|
|
171
|
+
company: string;
|
|
172
|
+
signal_id: string;
|
|
173
|
+
}, deps?: LanesCommandDeps): Promise<{
|
|
174
|
+
lane_id: string;
|
|
175
|
+
existing: boolean;
|
|
176
|
+
}>;
|
|
168
177
|
/** @internal Exported for regression tests of the profile-refresh company check. */
|
|
169
178
|
export declare function applyResumeProfileAndEffort(hqRoot: string, current: LaneRecord, next: LaneRecord, input: {
|
|
170
179
|
profile?: ResolvedResumeProfile;
|
package/dist/commands/lanes.js
CHANGED
|
@@ -75,6 +75,7 @@ import { resolveActiveMembershipCompany } from "../lib/mesh/api.js";
|
|
|
75
75
|
import { openMeshTransport, requireToken } from "../lib/mesh/client.js";
|
|
76
76
|
import { CompanySelectionError } from "../utils/company-selection-error.js";
|
|
77
77
|
import { assertNoSecretText } from "../lib/lanes/text-scan.js";
|
|
78
|
+
import { createSignalLane } from "../lib/lanes/signal-lane.js";
|
|
78
79
|
import { createLaneMesh, emitLaneDecisionEvents, emitLaneTerminalStateEvent, laneMeshEventIdentity, } from "../lib/lanes/mesh-events.js";
|
|
79
80
|
import { sessionIdFromEnv } from "../lib/mesh/live/session-identity.js";
|
|
80
81
|
import { applyLoopDisposition, loopDispositionSnapshot } from "../lib/lanes/loop-disposition.js";
|
|
@@ -285,7 +286,7 @@ function failJson(err) {
|
|
|
285
286
|
process.stderr.write(`hq lanes: ${commandError.message}\n`);
|
|
286
287
|
}
|
|
287
288
|
printJson({ ...commandError.toJSON(), message: commandError.message });
|
|
288
|
-
process.exit(1);
|
|
289
|
+
process.exit(["signal_not_found", "no_conductor_link"].includes(commandError.error) ? 2 : 1);
|
|
289
290
|
}
|
|
290
291
|
const message = commandError instanceof Error ? commandError.message : String(commandError);
|
|
291
292
|
process.stderr.write(`hq lanes: ${message}${commandError instanceof Error && commandError.stack ? `\n${commandError.stack}` : ""}\n`);
|
|
@@ -1935,6 +1936,7 @@ async function refreshRemoteLaneMirrors(ctx, hqRoot, records, parentLaneIds, opt
|
|
|
1935
1936
|
before.envelope_summary !== envelopeSummary ||
|
|
1936
1937
|
(mirroredReportAt !== undefined && before.last_host_report_at !== mirroredReportAt) ||
|
|
1937
1938
|
(isTerminalLaneState(owner.state) && (JSON.stringify(before.last_envelope) !== JSON.stringify(owner.last_envelope) ||
|
|
1939
|
+
JSON.stringify(before.outcome) !== JSON.stringify(owner.outcome) ||
|
|
1938
1940
|
before.story_complete !== owner.story_complete ||
|
|
1939
1941
|
before.story_complete_reason !== owner.story_complete_reason ||
|
|
1940
1942
|
before.story_status !== owner.story_status ||
|
|
@@ -1964,6 +1966,7 @@ async function refreshRemoteLaneMirrors(ctx, hqRoot, records, parentLaneIds, opt
|
|
|
1964
1966
|
...(mirroredReportAt !== undefined ? { last_host_report_at: mirroredReportAt } : {}),
|
|
1965
1967
|
...(isTerminalLaneState(owner.state) ? {
|
|
1966
1968
|
last_envelope: owner.last_envelope,
|
|
1969
|
+
outcome: owner.outcome,
|
|
1967
1970
|
story_complete: owner.story_complete,
|
|
1968
1971
|
story_complete_reason: owner.story_complete_reason,
|
|
1969
1972
|
story_status: owner.story_status,
|
|
@@ -3465,7 +3468,34 @@ export function cancelPendingQuestionsForLane(hqRoot, laneId, nowIso, operatorRe
|
|
|
3465
3468
|
function mintMessageId() {
|
|
3466
3469
|
return `msg_${Date.now().toString(36)}_${randomBytes(3).toString("hex")}`;
|
|
3467
3470
|
}
|
|
3471
|
+
/** In-process signal entry point sharing CLI admission, dedupe and conductor rules. */
|
|
3472
|
+
export async function createLaneFromSignal(input, deps = {}) {
|
|
3473
|
+
const ctx = resolveDeps({ ...deps, hqRoot: () => input.hqRoot });
|
|
3474
|
+
const company = await ctx.resolveCompany(input.company);
|
|
3475
|
+
const result = await createSignalLane(input.hqRoot, {
|
|
3476
|
+
company: company.slug, signal: input.signal_id, env: ctx.env,
|
|
3477
|
+
}, options => runCreate(ctx, { ...options, company: company.slug, project: "executive-bot",
|
|
3478
|
+
noStory: `signal:${input.signal_id}`, freshThread: true, quiet: true }));
|
|
3479
|
+
return { lane_id: result.lane.lane_id, existing: result.existing };
|
|
3480
|
+
}
|
|
3468
3481
|
async function runCreate(ctx, opts) {
|
|
3482
|
+
if (opts.signal !== undefined) {
|
|
3483
|
+
if (!opts.company?.trim())
|
|
3484
|
+
throw new LanesError("missing_company", "--signal requires --company");
|
|
3485
|
+
if (opts.story || opts.additionalStory?.length || opts.briefFile || (opts.project && opts.project !== "executive-bot")) {
|
|
3486
|
+
throw new LanesError("signal_option_conflict", "Signal lanes use project executive-bot and a generated brief without a story");
|
|
3487
|
+
}
|
|
3488
|
+
const company = await ctx.resolveCompany(opts.company);
|
|
3489
|
+
const result = await createSignalLane(ctx.hqRoot(), {
|
|
3490
|
+
company: company.slug, signal: opts.signal, rulesFile: opts.rulesFile ? resolveCallerPath(ctx.callerCwd(), opts.rulesFile) : undefined,
|
|
3491
|
+
anyType: opts.anyType, senior: opts.senior, link: opts.link, env: ctx.env,
|
|
3492
|
+
}, input => runCreate(ctx, { ...opts, ...input, company: company.slug, signal: undefined, project: "executive-bot", noStory: `signal:${opts.signal}`, freshThread: opts.runner === "subagent" ? undefined : true, quiet: true }));
|
|
3493
|
+
if (!opts.quiet)
|
|
3494
|
+
printJson({ lane_id: result.lane.lane_id, signal_id: result.lane.signal.signal_id,
|
|
3495
|
+
source_ref: result.lane.signal.source_ref, senior: result.lane.senior, link: result.lane.signal_link ?? null,
|
|
3496
|
+
existing: result.existing, brief_path: result.brief_path });
|
|
3497
|
+
return result.lane;
|
|
3498
|
+
}
|
|
3469
3499
|
if (opts.runner !== undefined && parseLaneRunner(opts.runner) === "subagent") {
|
|
3470
3500
|
return runCreateSubagent(ctx, opts);
|
|
3471
3501
|
}
|
|
@@ -4304,6 +4334,7 @@ async function runCreate(ctx, opts) {
|
|
|
4304
4334
|
const admissionReservedAt = admission.action === "start" ? ctx.now().toISOString() : undefined;
|
|
4305
4335
|
const laneInit = {
|
|
4306
4336
|
company,
|
|
4337
|
+
...(opts.signalMetadata ? { signal: opts.signalMetadata, signal_link: opts.signalLink } : {}),
|
|
4307
4338
|
...(company === null && meshCompany
|
|
4308
4339
|
? { mesh_company: meshCompany }
|
|
4309
4340
|
: {}),
|
|
@@ -6182,7 +6213,54 @@ function formatLaneListHuman(lanes) {
|
|
|
6182
6213
|
rows.push("No lanes.");
|
|
6183
6214
|
return rows.join("\n");
|
|
6184
6215
|
}
|
|
6185
|
-
async function
|
|
6216
|
+
async function runLaneStatus(ctx, laneId, opts) {
|
|
6217
|
+
const lane = (await resolveMessageLaneTarget(ctx, laneId)).lane;
|
|
6218
|
+
const status = {
|
|
6219
|
+
schema_version: "hq-lanes-lane-status.v1",
|
|
6220
|
+
lane_id: lane.lane_id,
|
|
6221
|
+
company: lane.company?.slug ?? null,
|
|
6222
|
+
state: lane.state,
|
|
6223
|
+
decision: lane.last_envelope?.decision ?? null,
|
|
6224
|
+
envelope_ref: lane.last_envelope?.ref ?? null,
|
|
6225
|
+
story_status: lane.story_status ?? null,
|
|
6226
|
+
story_complete: lane.story_complete ?? null,
|
|
6227
|
+
outcome: lane.outcome ?? null,
|
|
6228
|
+
};
|
|
6229
|
+
if (opts.json) {
|
|
6230
|
+
printJson(status);
|
|
6231
|
+
return;
|
|
6232
|
+
}
|
|
6233
|
+
const lines = [
|
|
6234
|
+
`lane ${status.lane_id}: ${status.state}` +
|
|
6235
|
+
(status.decision ? ` (decision ${status.decision})` : ""),
|
|
6236
|
+
];
|
|
6237
|
+
if (status.outcome) {
|
|
6238
|
+
lines.push(`outcome ${status.outcome.state}: ${status.outcome.outcome}`);
|
|
6239
|
+
for (const item of status.outcome.gathered) {
|
|
6240
|
+
lines.push(` gathered ${item.label}: ${item.text}${item.ref ? ` (${item.ref})` : ""}`);
|
|
6241
|
+
}
|
|
6242
|
+
for (const step of status.outcome.next_steps)
|
|
6243
|
+
lines.push(` next: ${step}`);
|
|
6244
|
+
if (status.outcome.decision_id)
|
|
6245
|
+
lines.push(` decision_id: ${status.outcome.decision_id}`);
|
|
6246
|
+
}
|
|
6247
|
+
else {
|
|
6248
|
+
lines.push("outcome: none");
|
|
6249
|
+
}
|
|
6250
|
+
console.log(lines.join("\n"));
|
|
6251
|
+
}
|
|
6252
|
+
async function runStatus(ctx, opts, laneId) {
|
|
6253
|
+
if (laneId !== undefined) {
|
|
6254
|
+
if (opts.project !== undefined || opts.company !== undefined) {
|
|
6255
|
+
throw new LanesError("invalid_args", "hq lanes status <lane-id> reports one lane; drop --project and --company", { lane_id: laneId });
|
|
6256
|
+
}
|
|
6257
|
+
await runLaneStatus(ctx, laneId, opts);
|
|
6258
|
+
return;
|
|
6259
|
+
}
|
|
6260
|
+
if (opts.project === undefined) {
|
|
6261
|
+
throw new LanesError("invalid_args", "hq lanes status requires --project <slug>, or a lane id for one lane", {});
|
|
6262
|
+
}
|
|
6263
|
+
const projectId = opts.project;
|
|
6186
6264
|
if (!ctx.storyLedgerEnabled()) {
|
|
6187
6265
|
throw new LanesError("story_ledger_disabled", "hq lanes status requires the lanes.story-ledger flag", {
|
|
6188
6266
|
flag: "lanes.story-ledger",
|
|
@@ -6216,7 +6294,7 @@ async function runStatus(ctx, opts) {
|
|
|
6216
6294
|
}
|
|
6217
6295
|
const snapshot = buildLaneStatusSnapshot({
|
|
6218
6296
|
hqRoot,
|
|
6219
|
-
projectId
|
|
6297
|
+
projectId,
|
|
6220
6298
|
...(company ? { companySlug: company.slug } : {}),
|
|
6221
6299
|
...(company ? { companyUid: company.uid } : {}),
|
|
6222
6300
|
lanes,
|
|
@@ -6500,6 +6578,7 @@ async function runShow(ctx, laneId, hasPendingQuestionForLane, resolveLaneTarget
|
|
|
6500
6578
|
fingerprint: lane.fingerprint ?? null,
|
|
6501
6579
|
envelope_repair_mode: lane.envelope_repair?.mode ?? null,
|
|
6502
6580
|
envelope_validation_errors: lane.envelope_validation_errors ?? [],
|
|
6581
|
+
outcome: lane.outcome ?? null,
|
|
6503
6582
|
last_resume: lane.last_resume ?? null,
|
|
6504
6583
|
// Public JSON key for the bounded start audit; `last_resume` remains unchanged.
|
|
6505
6584
|
resume_history: lane.resume_history ?? [],
|
|
@@ -9162,6 +9241,7 @@ async function runCreateSubagent(ctx, opts) {
|
|
|
9162
9241
|
const createdAt = ctx.now().toISOString();
|
|
9163
9242
|
const lane = createLane(hqRoot, {
|
|
9164
9243
|
company,
|
|
9244
|
+
...(opts.signalMetadata ? { signal: opts.signalMetadata, signal_link: opts.signalLink } : {}),
|
|
9165
9245
|
...(company === null && meshCompany ? { mesh_company: meshCompany } : {}),
|
|
9166
9246
|
project_id: project,
|
|
9167
9247
|
story_id: story ?? "",
|
|
@@ -10402,6 +10482,7 @@ export function registerLanesCommand(parent, deps = {}) {
|
|
|
10402
10482
|
});
|
|
10403
10483
|
registerLaneReportCommands(lanes, {
|
|
10404
10484
|
hqRoot: ctx.hqRoot,
|
|
10485
|
+
laneRunsHere: (lane) => laneRunsHere(lane, reconcileHostFromCtx(ctx)),
|
|
10405
10486
|
resolveCompany: ctx.resolveCompany,
|
|
10406
10487
|
now: ctx.now,
|
|
10407
10488
|
focusDashboardEnabled: (company) => readLanesRegistryFlagFailOff(LANE_FOCUS_DASHBOARD_FLAG, {
|
|
@@ -10446,12 +10527,16 @@ export function registerLanesCommand(parent, deps = {}) {
|
|
|
10446
10527
|
.description("Register a lane, run admission, and return immediately")
|
|
10447
10528
|
.option("--company <slug|uid>", "Company slug or cloud uid; omit for a core/personal lane")
|
|
10448
10529
|
.option("--mesh-company <slug|uid>", "Explicit Work Mesh company for a personal lane; membership is verified")
|
|
10449
|
-
.
|
|
10530
|
+
.option("--project <slug>", "HQ project slug (executive-bot for --signal)")
|
|
10531
|
+
.option("--signal <id>", "Create one lane for a company signal")
|
|
10532
|
+
.option("--rules-file <path>", "Standing rules for a signal lane")
|
|
10533
|
+
.option("--any-type", "Allow signal types other than action_item")
|
|
10534
|
+
.option("--link <id>", "Conductor link for a signal lane")
|
|
10450
10535
|
.option("--story <id>", "Story id from the project's prd.json")
|
|
10451
10536
|
.option("--focus-override <reason>", "Human-approved reason to override the lane focus guard")
|
|
10452
10537
|
.addOption(noStoryOption)
|
|
10453
10538
|
.option("--additional-story <id>", "Additional story carried by this lane; repeatable and discouraged when active", collectRepeatable)
|
|
10454
|
-
.
|
|
10539
|
+
.option("--brief-file <path>", "Path to the lane brief (generated for --signal)")
|
|
10455
10540
|
.option("--worker <name>", "HQ worker or reusable profile id")
|
|
10456
10541
|
.option("--fresh-thread", "Skip worker continuity and start a cold provider session")
|
|
10457
10542
|
.option("--loop", "Keep one worker lane registered to process queued phase envelopes")
|
|
@@ -10697,12 +10782,13 @@ export function registerLanesCommand(parent, deps = {}) {
|
|
|
10697
10782
|
}));
|
|
10698
10783
|
lanes
|
|
10699
10784
|
.command("status")
|
|
10700
|
-
.description("Summarize project stories, lanes, PRs, blockers, and pending questions")
|
|
10701
|
-
.
|
|
10785
|
+
.description("Summarize project stories, lanes, PRs, blockers, and pending questions; with a lane id, report that lane's outcome")
|
|
10786
|
+
.argument("[lane-id]", "Report one lane's state and outcome block instead of a project")
|
|
10787
|
+
.option("--project <slug>", "HQ project slug (required without a lane id)")
|
|
10702
10788
|
.option("--company <slug|uid>", "Company project scope; omit for a personal project")
|
|
10703
10789
|
.option("--json", "Emit JSON on stdout")
|
|
10704
|
-
.action(wrap(async (opts) => {
|
|
10705
|
-
await runStatus(ctx, opts);
|
|
10790
|
+
.action(wrap(async (laneId, opts) => {
|
|
10791
|
+
await runStatus(ctx, opts, laneId);
|
|
10706
10792
|
}));
|
|
10707
10793
|
lanes
|
|
10708
10794
|
.command("capacity")
|
|
@@ -6,6 +6,7 @@ import { sessionIdFromEnv } from "../lib/core-utils/session-id.js";
|
|
|
6
6
|
import { vaultApiFetch, getCompanyUid, resolveCallerPersonUid, } from "../utils/vault-api.js";
|
|
7
7
|
import { isPlanGateError, planGateErrorFromPayload, } from "../utils/plan-gate-error.js";
|
|
8
8
|
import { mapWithConcurrency } from "./sync-manifest.js";
|
|
9
|
+
import { fetchAttendedLiveBots } from "../lib/live-meetings.js";
|
|
9
10
|
import { isUsageOnly, pricingPlanFromBody, resolveCompanyPricingPlan, usageOnlyCardRequiredLines, usagePauseFromBody, } from "../lib/billing/usage-only.js";
|
|
10
11
|
const LIVE_SNAPSHOT_STATUSES = new Set([
|
|
11
12
|
"joining",
|
|
@@ -110,27 +111,6 @@ function liveBotTime(bot) {
|
|
|
110
111
|
.filter(Number.isFinite);
|
|
111
112
|
return times.length > 0 ? Math.max(...times) : Number.NEGATIVE_INFINITY;
|
|
112
113
|
}
|
|
113
|
-
/**
|
|
114
|
-
* Live meetings in this company the caller may read but did not record.
|
|
115
|
-
*
|
|
116
|
-
* `/v1/bot/list` returns only the caller's own notetakers, so a meeting a
|
|
117
|
-
* coworker recorded never appears there. The meetings API lists the live
|
|
118
|
-
* meetings the caller is an attendee of. An older server ignores `view=live`
|
|
119
|
-
* and answers with the ordinary meeting list, which has no `bots`, and any
|
|
120
|
-
* failure here leaves the caller's own list unchanged.
|
|
121
|
-
*/
|
|
122
|
-
async function fetchAttendedLiveBots(token, companyId) {
|
|
123
|
-
try {
|
|
124
|
-
const res = await vaultApiFetch({ token, path: "/v1/meetings", query: { companyId, view: "live" } });
|
|
125
|
-
if (!res.ok)
|
|
126
|
-
return [];
|
|
127
|
-
const data = (await res.json());
|
|
128
|
-
return Array.isArray(data.bots) ? data.bots : [];
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
return [];
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
114
|
/** The caller's own bots first; attended meetings they did not record added after. */
|
|
135
115
|
function mergeLiveMeetingBots(own, attended) {
|
|
136
116
|
const seen = new Set(own.map(liveBotId).filter((id) => Boolean(id)));
|
package/dist/commands/secrets.js
CHANGED
|
@@ -2,7 +2,7 @@ import { assertScriptUnchanged, planScriptBinding, selectChildLaunch } from "../
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import * as yaml from "js-yaml";
|
|
5
|
-
import { assertApiKeyCompany, buildSecretUsage, extractApiMessage, highSecuritySandboxOnlyMessage, loadRevealedSecrets, normalizeScriptLockMode, normalizeSecretTier, parseSecretNameList, requestedApiKeyCompany, runSecretsEnvCommand, scopeOpts, secretsCredentialOptions, } from "../secrets-env-action.js";
|
|
5
|
+
import { assertApiKeyCompany, assertDelegatedMachineSessionUsable, buildSecretUsage, callerIsCompanyOutpost, companyOutpostIdentityFromToken, companyOutpostReadDenialMessage, extractApiMessage, highSecuritySandboxOnlyMessage, loadRevealedSecrets, normalizeScriptLockMode, normalizeSecretTier, parseSecretNameList, requestedApiKeyCompany, resolveSecretsReadCompanyUid, runSecretsEnvCommand, scopeOpts, secretsCredentialOptions, } from "../secrets-env-action.js";
|
|
6
6
|
import { readSessionCompanyLock } from "../lib/session-company-lock.js";
|
|
7
7
|
import { sessionIdFromEnv } from "../lib/core-utils/session-id.js";
|
|
8
8
|
import { appendPersonalSecretsAudit, isEntityScopeRef, PERSONAL_SCOPE_READ_ONLY_MESSAGE, } from "../lib/personal-secrets-audit.js";
|
|
@@ -797,6 +797,7 @@ export function registerSecretsCommand(program) {
|
|
|
797
797
|
.option("--reveal", "Include the decrypted secret value")
|
|
798
798
|
.action(async (name, opts) => {
|
|
799
799
|
try {
|
|
800
|
+
assertDelegatedMachineSessionUsable();
|
|
800
801
|
const cred = await resolveVaultCredentialForCapability("secrets:read", "secrets get", secretsCredentialOptions());
|
|
801
802
|
if (cred.kind === "api-key") {
|
|
802
803
|
if (!opts.reveal) {
|
|
@@ -848,7 +849,7 @@ export function registerSecretsCommand(program) {
|
|
|
848
849
|
return;
|
|
849
850
|
}
|
|
850
851
|
const token = cred.token;
|
|
851
|
-
const companyUid = await
|
|
852
|
+
const companyUid = await resolveSecretsReadCompanyUid(token, scopeOpts(secrets.opts()));
|
|
852
853
|
const res = await vaultApiFetch({
|
|
853
854
|
token,
|
|
854
855
|
path: buildSecretNamePath(companyUid, name),
|
|
@@ -862,6 +863,16 @@ export function registerSecretsCommand(program) {
|
|
|
862
863
|
console.error(chalk.red(highSecuritySandboxOnlyMessage(name)));
|
|
863
864
|
process.exit(1);
|
|
864
865
|
}
|
|
866
|
+
// A company Outpost gets a code-less 403 both for an unshared secret
|
|
867
|
+
// and for an inactive binding; say both, as the reveal path does.
|
|
868
|
+
const outpost = companyOutpostIdentityFromToken(token);
|
|
869
|
+
const outpostDenial = outpost
|
|
870
|
+
? companyOutpostReadDenialMessage(name, res.status, body, companyUid, outpost)
|
|
871
|
+
: null;
|
|
872
|
+
if (outpostDenial) {
|
|
873
|
+
console.error(chalk.red(outpostDenial));
|
|
874
|
+
process.exit(1);
|
|
875
|
+
}
|
|
865
876
|
console.error(chalk.red(`Failed to get secret: ${extractApiMessage(body, res.statusText)}`));
|
|
866
877
|
process.exit(1);
|
|
867
878
|
}
|
|
@@ -1384,9 +1395,17 @@ export function registerSecretsCommand(program) {
|
|
|
1384
1395
|
// interactive session last ran a hook, and the job would read that
|
|
1385
1396
|
// session's company's same-named secret. Without a session id the caller
|
|
1386
1397
|
// must name its scope. HQ_API_KEY is exempt: the key is bound to one
|
|
1387
|
-
// company and never reads the session lock below.
|
|
1398
|
+
// company and never reads the session lock below. A company Outpost job
|
|
1399
|
+
// is exempt too: its machine identity names its one bound company.
|
|
1400
|
+
// An unusable HQ_MACHINE_SESSION_FILE fails here, naming the file,
|
|
1401
|
+
// before the scope check below can report a generic error.
|
|
1402
|
+
assertDelegatedMachineSessionUsable();
|
|
1388
1403
|
const hasCallerSession = Boolean(sessionIdFromEnv(process.env));
|
|
1389
|
-
if (!hasCallerSession &&
|
|
1404
|
+
if (!hasCallerSession &&
|
|
1405
|
+
!requestedCompany &&
|
|
1406
|
+
!parentScope.personal &&
|
|
1407
|
+
peekHqApiKey() === undefined &&
|
|
1408
|
+
!callerIsCompanyOutpost()) {
|
|
1390
1409
|
console.error(chalk.red("Error:"), SECRETS_EXEC_UNATTENDED_NO_COMPANY_MESSAGE);
|
|
1391
1410
|
process.exit(SECRETS_EXEC_UNATTENDED_NO_COMPANY_EXIT);
|
|
1392
1411
|
}
|
|
@@ -1454,7 +1473,7 @@ export function registerSecretsCommand(program) {
|
|
|
1454
1473
|
?? (unlockedApiKeyCompanyRef
|
|
1455
1474
|
? await assertApiKeyCompany(cred.token, unlockedApiKeyCompanyRef, "secrets exec")
|
|
1456
1475
|
: "__api_key__"))
|
|
1457
|
-
: await
|
|
1476
|
+
: await resolveSecretsReadCompanyUid(cred.token, secretScope, { allowOfflineScopeFallback: true });
|
|
1458
1477
|
if (entityScopeRef && companyUid !== entityScopeRef) {
|
|
1459
1478
|
throw new Error("Another person's personal vault is outside this session's scope; refusing.");
|
|
1460
1479
|
}
|
|
@@ -1482,8 +1501,10 @@ export function registerSecretsCommand(program) {
|
|
|
1482
1501
|
const readSecrets = async () => loadRevealedSecrets(cred.token, companyUid, keys, execUsage, { allowOfflineFallback: true, lockModes });
|
|
1483
1502
|
// API-key auth has no signed-in person identity for the CLI telemetry
|
|
1484
1503
|
// endpoint. Do not attribute that read to an unrelated cached session.
|
|
1504
|
+
// hq-pro refuses every route but the secret read to a company Outpost,
|
|
1505
|
+
// telemetry included, so an Outpost read sends no telemetry event.
|
|
1485
1506
|
let revealed;
|
|
1486
|
-
if (cred.kind === "cognito") {
|
|
1507
|
+
if (cred.kind === "cognito" && !companyOutpostIdentityFromToken(cred.token)) {
|
|
1487
1508
|
const { withCliFeatureUsed } = await import("../utils/cli-telemetry.js");
|
|
1488
1509
|
revealed = await withCliFeatureUsed("secret_read", readSecrets, companyUid);
|
|
1489
1510
|
}
|
|
@@ -11,6 +11,8 @@ import { Command } from "commander";
|
|
|
11
11
|
import { type RunSignalsResult, type SignalsStepChoice, type SignalsTrigger } from "../lib/signals/engine.js";
|
|
12
12
|
import type { SignalsRunAlertSenders } from "../lib/signals/failure-alert.js";
|
|
13
13
|
interface RunCliOptions {
|
|
14
|
+
source?: string;
|
|
15
|
+
incremental?: boolean;
|
|
14
16
|
company?: string;
|
|
15
17
|
dryRun?: boolean;
|
|
16
18
|
step: SignalsStepChoice;
|
|
@@ -109,6 +109,8 @@ export async function runSignalsCli(options, overrides = {}) {
|
|
|
109
109
|
const result = await runSignals({
|
|
110
110
|
hqRoot: options.hqRoot,
|
|
111
111
|
company: options.company,
|
|
112
|
+
source: options.source,
|
|
113
|
+
incremental: options.incremental,
|
|
112
114
|
dryRun: options.dryRun === true,
|
|
113
115
|
step: options.step,
|
|
114
116
|
trigger: options.trigger,
|
|
@@ -134,7 +136,8 @@ export async function runSignalsCli(options, overrides = {}) {
|
|
|
134
136
|
process.stdout.write(`${JSON.stringify({ status, startedAt, trigger })}\n`);
|
|
135
137
|
}
|
|
136
138
|
else if (options.json) {
|
|
137
|
-
const
|
|
139
|
+
const record = result.records[0];
|
|
140
|
+
const payload = options.incremental && record ? { ...record, ...record.steps.find((s) => s.name === "extract")?.detail } : options.company && result.records.length === 1 ? record : result;
|
|
138
141
|
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
139
142
|
}
|
|
140
143
|
else {
|
|
@@ -150,6 +153,8 @@ export function registerSignalsRunSubcommand(signals) {
|
|
|
150
153
|
run
|
|
151
154
|
.description("Run the local signals engine (garden, adapters, extract, garden, upload) for companies with capture on")
|
|
152
155
|
.option("--company <slug>", "Run one company (default: every company listed in the companies manifest)")
|
|
156
|
+
.option("--source <ref>", "Read a growing source: meeting:<id> or <channel>:<file> (needs --incremental and --company)")
|
|
157
|
+
.option("--incremental", "Extract only new signals from --source, retaining a cursor and prior signal ids")
|
|
153
158
|
.option("--dry-run", "Print what would run; run no mutating step and write nothing")
|
|
154
159
|
.addOption(new Option("--step <step>", "Run one step").choices([...SIGNALS_STEP_CHOICES]).default("all"))
|
|
155
160
|
.addOption(new Option("--trigger <trigger>", "What started the run").choices([...SIGNALS_TRIGGERS]).default("manual"))
|
package/dist/lanes-drain-hook.js
CHANGED
|
@@ -187,6 +187,15 @@ async function main() {
|
|
|
187
187
|
for await (const chunk of process.stdin)
|
|
188
188
|
chunks.push(Buffer.from(chunk));
|
|
189
189
|
const text = Buffer.concat(chunks).toString("utf8");
|
|
190
|
+
if (process.env.HQ_LANE_SIGNAL_LINK && process.env.HQ_ROOT) {
|
|
191
|
+
try {
|
|
192
|
+
const { bindSignalLaneHook } = await import("./lib/lanes/links.js");
|
|
193
|
+
bindSignalLaneHook(process.env.HQ_ROOT, text, process.env);
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
process.stderr.write("hq-lanes-drain: signal_link_binding_failed; conductor link remains unavailable\n");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
190
199
|
let input = {};
|
|
191
200
|
let inputError = "";
|
|
192
201
|
try {
|
package/dist/lib/bot/api.d.ts
CHANGED
|
@@ -62,6 +62,11 @@ export interface JobRunCompletion {
|
|
|
62
62
|
}
|
|
63
63
|
/** A job record as the cloud returns it (hq-pro-agents jobs/schema.ts `JobRecord`). */
|
|
64
64
|
export interface BotJobRecord {
|
|
65
|
+
trigger?: {
|
|
66
|
+
kind: "event";
|
|
67
|
+
event: string;
|
|
68
|
+
filter?: Record<string, string>;
|
|
69
|
+
};
|
|
65
70
|
jobId: string;
|
|
66
71
|
prompt: string;
|
|
67
72
|
status?: string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const CLAUDE_KEYCHAIN_SERVICE = "Claude Code-credentials";
|
|
2
|
+
export declare const CLAUDE_LOGIN_ENV_VARS: readonly ["ANTHROPIC_TOKEN", "CLAUDE_CODE_OAUTH_TOKEN", "ANTHROPIC_API_KEY"];
|
|
3
|
+
export type ClaudeLoginStatus = "ok" | "missing" | "expired" | "skipped";
|
|
4
|
+
export interface ClaudeLoginSource {
|
|
5
|
+
source: string;
|
|
6
|
+
status: ClaudeLoginStatus;
|
|
7
|
+
reason: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ClaudeLoginCheck {
|
|
10
|
+
signedIn: boolean;
|
|
11
|
+
/** The first source the runtime would use, when signed in. */
|
|
12
|
+
via: string | null;
|
|
13
|
+
sources: ClaudeLoginSource[];
|
|
14
|
+
}
|
|
15
|
+
export interface KeychainRead {
|
|
16
|
+
code: number;
|
|
17
|
+
stdout: string;
|
|
18
|
+
stderr: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ClaudeLoginDeps {
|
|
21
|
+
env?: NodeJS.ProcessEnv;
|
|
22
|
+
home?: string;
|
|
23
|
+
platform?: NodeJS.Platform;
|
|
24
|
+
readKeychain?: () => KeychainRead;
|
|
25
|
+
now?: () => number;
|
|
26
|
+
}
|
|
27
|
+
export declare function checkClaudeCodeLogin(deps?: ClaudeLoginDeps): ClaudeLoginCheck;
|
|
28
|
+
/** One sentence listing every source that did not yield a login. */
|
|
29
|
+
export declare function describeClaudeLoginSources(check: ClaudeLoginCheck): string;
|
|
30
|
+
export declare function claudeLoginFix(botName?: string): string;
|
|
31
|
+
//# sourceMappingURL=claude-login.d.ts.map
|