@indigoai-us/hq-cli 5.141.0 → 5.143.0
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 +31 -0
- package/assets/scaffold/core/scripts/checkpoint-stop-gate.sh +77 -2
- package/dist/command-catalog.generated.d.ts +7 -1
- package/dist/command-catalog.generated.js +9 -1
- package/dist/commands/agents.d.ts +1 -0
- package/dist/commands/agents.js +4 -8
- package/dist/commands/dm.js +1 -5
- package/dist/commands/lanes.js +125 -26
- package/dist/commands/mesh.js +25 -2
- package/dist/commands/report.d.ts +3 -1
- package/dist/commands/report.js +69 -15
- package/dist/lib/agent-kit/mcp/tools.js +2 -1
- package/dist/lib/bot/api.d.ts +4 -0
- package/dist/lib/bot/api.js +13 -1
- package/dist/lib/lanes/effort.d.ts +3 -2
- package/dist/lib/lanes/effort.js +5 -1
- package/dist/lib/lanes/errors.d.ts +1 -1
- package/dist/lib/lanes/index.d.ts +2 -0
- package/dist/lib/lanes/index.js +1 -0
- package/dist/lib/lanes/mesh-events.d.ts +4 -5
- package/dist/lib/lanes/mesh-events.js +14 -4
- package/dist/lib/lanes/profile.d.ts +48 -0
- package/dist/lib/lanes/profile.js +405 -0
- package/dist/lib/lanes/reconcile.js +25 -3
- package/dist/lib/lanes/registry.d.ts +3 -0
- package/dist/lib/lanes/registry.js +45 -1
- package/dist/lib/lanes/spawn.d.ts +14 -2
- package/dist/lib/lanes/spawn.js +238 -14
- package/dist/lib/lanes/store.js +10 -0
- package/dist/lib/lanes/types.d.ts +11 -1
- package/dist/lib/lanes/types.js +3 -3
- package/dist/lib/notify-recipient.d.ts +7 -0
- package/dist/lib/notify-recipient.js +11 -0
- package/dist/lib/report-publish.d.ts +2 -2
- package/dist/lib/report-publish.js +9 -8
- package/package.json +1 -1
package/dist/commands/mesh.js
CHANGED
|
@@ -400,7 +400,30 @@ async function runProjectRegister(projectId, opts) {
|
|
|
400
400
|
}
|
|
401
401
|
const { token, company } = await withCompany(opts);
|
|
402
402
|
const principalUid = await resolveMeshPrincipalUid(token, loadCachedTokens());
|
|
403
|
-
const
|
|
403
|
+
const companyRef = company.companySlug || company.companyUid;
|
|
404
|
+
try {
|
|
405
|
+
const board = await getProjectView(token, company.companyUid, projectId);
|
|
406
|
+
if (board.companyUid !== company.companyUid || board.projectId !== projectId) {
|
|
407
|
+
fail(`Work mesh project ${projectId} has no Board view in company ${companyRef}. Create the Board before registering it.`);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
catch (err) {
|
|
411
|
+
if (httpStatus(err) === 404) {
|
|
412
|
+
fail(`Work mesh project ${projectId} has no Board view in company ${companyRef}. Create the Board before registering it.`);
|
|
413
|
+
}
|
|
414
|
+
throw err;
|
|
415
|
+
}
|
|
416
|
+
let registration;
|
|
417
|
+
try {
|
|
418
|
+
registration = await registerMeshProject(token, company.companyUid, projectId);
|
|
419
|
+
}
|
|
420
|
+
catch (err) {
|
|
421
|
+
const failure = err;
|
|
422
|
+
if (failure.status === 403 && failure.code === "PROJECT_NOT_IN_COMPANY") {
|
|
423
|
+
fail(`Work mesh project ${projectId} could not be registered in company ${companyRef}: the Board or its genesis thread is missing. Run "hq mesh project ensure ${projectId} --company ${companyRef} --stories-file <prd.json>" to create or restore them.`);
|
|
424
|
+
}
|
|
425
|
+
throw err;
|
|
426
|
+
}
|
|
404
427
|
const boardState = "registered";
|
|
405
428
|
if (opts.json) {
|
|
406
429
|
console.log(JSON.stringify({ ok: true, action: "project.register", principalUid, boardState, ...registration }, null, 2));
|
|
@@ -1601,7 +1624,7 @@ export function registerMeshCommand(program) {
|
|
|
1601
1624
|
.action((projectId, opts) => wrap(() => runProjectEnsure(projectId, opts))());
|
|
1602
1625
|
project
|
|
1603
1626
|
.command("register <projectId>")
|
|
1604
|
-
.description("
|
|
1627
|
+
.description("Register an existing Board and bind its project channel; use project ensure to create or repair a Board")
|
|
1605
1628
|
.requiredOption("--company <slug|uid>", "Company slug or cloud uid")
|
|
1606
1629
|
.option("--channel <channelId>", "Reserved: the current server chooses the project channel")
|
|
1607
1630
|
.option("--json", "Print machine-readable JSON")
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { buildReportTarball, deployOrgContext, type ChannelReport, type DeployAccessPolicy, type ReportDeployment, type ReportPatch } from "../lib/report-publish.js";
|
|
3
|
+
type ReportPatchInput = ReportPatch | ((current: ChannelReport) => ReportPatch);
|
|
3
4
|
/** Explicit context has priority; discovery is the authenticated fallback for normal CLI use. */
|
|
4
5
|
export declare function resolveReport(token: string, reportId: string, requestedChannelId?: string): Promise<ChannelReport>;
|
|
5
|
-
export declare function patchReport(token: string, report: ChannelReport, patch:
|
|
6
|
+
export declare function patchReport(token: string, report: ChannelReport, patch: ReportPatchInput): Promise<ChannelReport>;
|
|
6
7
|
export declare function resolveCompanySlug(token: string, companyUid: string): Promise<string>;
|
|
7
8
|
export declare function deployReportStatic(token: string, input: {
|
|
8
9
|
slug: string;
|
|
@@ -12,4 +13,5 @@ export declare function deployReportStatic(token: string, input: {
|
|
|
12
13
|
}): Promise<ReportDeployment>;
|
|
13
14
|
export declare function registerReportCommand(program: Command): void;
|
|
14
15
|
export declare function runReportCommand(action: () => Promise<void>): Promise<void>;
|
|
16
|
+
export {};
|
|
15
17
|
//# sourceMappingURL=report.d.ts.map
|
package/dist/commands/report.js
CHANGED
|
@@ -86,10 +86,39 @@ function print(value, json) {
|
|
|
86
86
|
else
|
|
87
87
|
console.log(typeof value === "string" ? value : JSON.stringify(value, null, 2));
|
|
88
88
|
}
|
|
89
|
+
async function listReportChannels(token) {
|
|
90
|
+
const channels = await vaultApiFetch({ token, path: "/v1/notify/channels" });
|
|
91
|
+
if (!channels.ok)
|
|
92
|
+
throw new ReportPublishError("Could not resolve the report channel.");
|
|
93
|
+
const listed = await channels.json();
|
|
94
|
+
return Array.isArray(listed.channels) ? listed.channels : [];
|
|
95
|
+
}
|
|
96
|
+
function isCompanyReportChannel(channel) {
|
|
97
|
+
return channel.scope === "company"
|
|
98
|
+
|| (typeof channel.scope !== "string" && Boolean(channel.companyUid));
|
|
99
|
+
}
|
|
100
|
+
function requireCompanyReportChannel(channels, channelId) {
|
|
101
|
+
const channel = channels.find((row) => row.channelId === channelId);
|
|
102
|
+
if (!channel)
|
|
103
|
+
throw new ReportPublishError("Report channel was not found in your channels.");
|
|
104
|
+
if (!isCompanyReportChannel(channel))
|
|
105
|
+
throw new ReportPublishError("Channel reports require a company channel.");
|
|
106
|
+
}
|
|
107
|
+
async function readReportInChannel(token, channelId, reportId) {
|
|
108
|
+
const res = await vaultApiFetch({ token, path: reportPath(channelId, reportId) });
|
|
109
|
+
if (!res.ok)
|
|
110
|
+
return undefined;
|
|
111
|
+
const body = await res.json();
|
|
112
|
+
if (!body.report)
|
|
113
|
+
throw new ReportPublishError("Report response was incomplete.");
|
|
114
|
+
return body.report;
|
|
115
|
+
}
|
|
89
116
|
/** Explicit context has priority; discovery is the authenticated fallback for normal CLI use. */
|
|
90
117
|
export async function resolveReport(token, reportId, requestedChannelId) {
|
|
91
118
|
const explicit = requestedChannelId ?? process.env.HQ_REPORT_CHANNEL_ID;
|
|
119
|
+
const channels = await listReportChannels(token);
|
|
92
120
|
if (explicit) {
|
|
121
|
+
requireCompanyReportChannel(channels, explicit);
|
|
93
122
|
const res = await vaultApiFetch({ token, path: reportPath(explicit, reportId) });
|
|
94
123
|
if (!res.ok)
|
|
95
124
|
throw new ReportPublishError("Report was not found in the supplied channel context.");
|
|
@@ -100,24 +129,20 @@ export async function resolveReport(token, reportId, requestedChannelId) {
|
|
|
100
129
|
}
|
|
101
130
|
const recordedChannel = locallyRecordedChannel(reportId);
|
|
102
131
|
if (recordedChannel) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return body.report;
|
|
108
|
-
}
|
|
132
|
+
requireCompanyReportChannel(channels, recordedChannel);
|
|
133
|
+
const recorded = await readReportInChannel(token, recordedChannel, reportId);
|
|
134
|
+
if (recorded)
|
|
135
|
+
return recorded;
|
|
109
136
|
}
|
|
110
137
|
// The report API is intentionally channel-scoped. Discover only among the
|
|
111
138
|
// caller's existing channels, using list endpoints so missing reports never
|
|
112
139
|
// become one server-side 404 per channel.
|
|
113
|
-
const channels = await vaultApiFetch({ token, path: "/v1/notify/channels" });
|
|
114
|
-
if (!channels.ok)
|
|
115
|
-
throw new ReportPublishError("Could not resolve the report channel.");
|
|
116
|
-
const listed = await channels.json();
|
|
117
140
|
let scannedChannels = 0;
|
|
118
|
-
for (const row of
|
|
141
|
+
for (const row of channels) {
|
|
119
142
|
if (!row.channelId)
|
|
120
143
|
continue;
|
|
144
|
+
if (!isCompanyReportChannel(row))
|
|
145
|
+
continue;
|
|
121
146
|
if (scannedChannels >= MAX_REPORT_DISCOVERY_CHANNELS)
|
|
122
147
|
break;
|
|
123
148
|
scannedChannels += 1;
|
|
@@ -125,19 +150,45 @@ export async function resolveReport(token, reportId, requestedChannelId) {
|
|
|
125
150
|
if (!res.ok)
|
|
126
151
|
continue;
|
|
127
152
|
const body = await res.json();
|
|
128
|
-
const
|
|
153
|
+
const reports = Array.isArray(body.reports) ? body.reports : [];
|
|
154
|
+
const match = reports.find((report) => report.reportId === reportId);
|
|
129
155
|
if (match)
|
|
130
156
|
return match;
|
|
131
157
|
}
|
|
132
158
|
throw new ReportPublishError(notFoundMessage(scannedChannels));
|
|
133
159
|
}
|
|
134
160
|
export async function patchReport(token, report, patch) {
|
|
135
|
-
|
|
161
|
+
if (!report.companyUid)
|
|
162
|
+
throw new ReportPublishError("Channel reports require a company channel.");
|
|
163
|
+
const patchOnce = (current) => vaultApiFetch({
|
|
164
|
+
token,
|
|
165
|
+
path: reportPath(current.channelId, current.reportId),
|
|
166
|
+
method: "PATCH",
|
|
167
|
+
body: {
|
|
168
|
+
...(typeof patch === "function" ? patch(current) : patch),
|
|
169
|
+
revision: current.revision,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
let res = await patchOnce(report);
|
|
136
173
|
if (res.status === 409) {
|
|
137
174
|
const body = await res.json().catch(() => ({}));
|
|
138
175
|
if (body.error === "already-running")
|
|
139
176
|
throw new ReportPublishError("already running", "already-running");
|
|
140
|
-
|
|
177
|
+
if (body.error !== "revision-mismatch")
|
|
178
|
+
throw new ReportPublishError("Report changed while it was being updated.", "revision-conflict");
|
|
179
|
+
const latest = await readReportInChannel(token, report.channelId, report.reportId);
|
|
180
|
+
if (!latest)
|
|
181
|
+
throw new ReportPublishError("Could not reread the report after it changed.", "revision-conflict");
|
|
182
|
+
if (typeof patch !== "function") {
|
|
183
|
+
throw new ReportPublishError("Report changed while it was being updated; refresh and retry.", "revision-conflict");
|
|
184
|
+
}
|
|
185
|
+
res = await patchOnce(latest);
|
|
186
|
+
if (res.status === 409) {
|
|
187
|
+
const retryBody = await res.json().catch(() => ({}));
|
|
188
|
+
if (retryBody.error === "already-running")
|
|
189
|
+
throw new ReportPublishError("already running", "already-running");
|
|
190
|
+
throw new ReportPublishError("Report changed while it was being updated; refresh and retry.", "revision-conflict");
|
|
191
|
+
}
|
|
141
192
|
}
|
|
142
193
|
if (!res.ok)
|
|
143
194
|
throw new ReportPublishError("Could not update the report record.");
|
|
@@ -267,7 +318,10 @@ async function discardDraftAction(reportId, options) {
|
|
|
267
318
|
if (!res.ok && res.status !== 404)
|
|
268
319
|
throw new ReportPublishError("Could not remove the draft deployment.");
|
|
269
320
|
}
|
|
270
|
-
const updated = await patchReport(token, report,
|
|
321
|
+
const updated = await patchReport(token, report, (current) => ({
|
|
322
|
+
draft: null,
|
|
323
|
+
state: current.url ? "live" : "draft-pending",
|
|
324
|
+
}));
|
|
271
325
|
print(updated, options.json === true);
|
|
272
326
|
}
|
|
273
327
|
async function accessAction(reportId, options) {
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { CLI_VERSION } from "../../../cli-version.js";
|
|
19
19
|
import { peekIdToken } from "../../../utils/id-token.js";
|
|
20
|
+
import { isRecipientUid } from "../../../lib/notify-recipient.js";
|
|
20
21
|
import { markInboxDone, mergeAgentInbox, readDoneIds, summarizeInboxEntry } from "../inbox-state.js";
|
|
21
22
|
import { errorResult, McpToolInputError, textResult } from "./jsonrpc.js";
|
|
22
23
|
export const MAX_TOOL_OUTPUT_CHARS = 40_000;
|
|
@@ -222,7 +223,7 @@ export function buildAgentMcpTools(clients) {
|
|
|
222
223
|
const message = str(args, "message", { required: true, max: 20_000 }).trim();
|
|
223
224
|
const body = /^[^\s]+@[^\s]+$/.test(to)
|
|
224
225
|
? { toEmail: to.toLowerCase(), body: message }
|
|
225
|
-
:
|
|
226
|
+
: isRecipientUid(to)
|
|
226
227
|
? { toPersonUid: to, body: message }
|
|
227
228
|
: (() => {
|
|
228
229
|
throw new McpToolInputError('"to" must be an email, prs_… or agt_… uid');
|
package/dist/lib/bot/api.d.ts
CHANGED
|
@@ -143,6 +143,10 @@ export declare class BotApiError extends Error {
|
|
|
143
143
|
readonly tokenAgentUid?: string | undefined;
|
|
144
144
|
constructor(status: number, path: string, code?: string | undefined, detail?: string | undefined, retryAfterMs?: number | undefined, tokenAgentUid?: string | undefined);
|
|
145
145
|
}
|
|
146
|
+
export declare class InvalidDmRecipientError extends Error {
|
|
147
|
+
readonly recipient: string;
|
|
148
|
+
constructor(recipient: string);
|
|
149
|
+
}
|
|
146
150
|
/** Parse a Retry-After header (delta-seconds or HTTP-date) to milliseconds. */
|
|
147
151
|
export declare function retryAfterHeaderMs(value: string | null | undefined, nowMs?: number): number | undefined;
|
|
148
152
|
export interface BotApiOptions {
|
package/dist/lib/bot/api.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { vaultApiFetch } from "../../utils/vault-api.js";
|
|
9
9
|
import { tokenAgentUid } from "../heartbeat-identity.js";
|
|
10
10
|
import { assertNoSecretKeys } from "./local-config.js";
|
|
11
|
+
import { isRecipientUid } from "../notify-recipient.js";
|
|
11
12
|
export class BotApiError extends Error {
|
|
12
13
|
status;
|
|
13
14
|
path;
|
|
@@ -26,6 +27,14 @@ export class BotApiError extends Error {
|
|
|
26
27
|
this.name = "BotApiError";
|
|
27
28
|
}
|
|
28
29
|
}
|
|
30
|
+
export class InvalidDmRecipientError extends Error {
|
|
31
|
+
recipient;
|
|
32
|
+
constructor(recipient) {
|
|
33
|
+
super(`Invalid DM recipient '${recipient}': expected a prs_ or agt_ uid.`);
|
|
34
|
+
this.recipient = recipient;
|
|
35
|
+
this.name = "InvalidDmRecipientError";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
29
38
|
/** Parse a Retry-After header (delta-seconds or HTTP-date) to milliseconds. */
|
|
30
39
|
export function retryAfterHeaderMs(value, nowMs = Date.now()) {
|
|
31
40
|
if (!value)
|
|
@@ -141,7 +150,10 @@ export class BotApi {
|
|
|
141
150
|
}
|
|
142
151
|
/** POST /v1/notify/dm — send as the bot (agent identity). */
|
|
143
152
|
async sendDm(input) {
|
|
144
|
-
const
|
|
153
|
+
const recipient = input.toPersonUid.trim();
|
|
154
|
+
if (!isRecipientUid(recipient))
|
|
155
|
+
throw new InvalidDmRecipientError(input.toPersonUid);
|
|
156
|
+
const payload = { toPersonUid: recipient, body: input.body };
|
|
145
157
|
if (input.rootEventId)
|
|
146
158
|
payload.rootEventId = input.rootEventId;
|
|
147
159
|
const { body } = await this.call("/v1/notify/dm", { method: "POST", body: payload });
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import type { LaneProvider } from "./types.js";
|
|
21
21
|
export declare const PROVIDER_EFFORT_LEVELS: Record<LaneProvider, readonly string[]>;
|
|
22
|
-
export declare const EFFORT_SOURCES: readonly ["cli", "account", "provider", "default_rule", "none"];
|
|
22
|
+
export declare const EFFORT_SOURCES: readonly ["cli", "profile", "account", "provider", "default_rule", "none"];
|
|
23
23
|
export type EffortSource = (typeof EFFORT_SOURCES)[number];
|
|
24
24
|
export interface ResolvedEffort {
|
|
25
25
|
effort?: string;
|
|
@@ -35,9 +35,10 @@ export declare function parseConfigEffort(provider: LaneProvider, raw: unknown,
|
|
|
35
35
|
* Keyed on the model already chosen for the lane; it does not pick a model.
|
|
36
36
|
*/
|
|
37
37
|
export declare function defaultEffortForModel(model: string | undefined): string | undefined;
|
|
38
|
-
/** Precedence: `--effort`,
|
|
38
|
+
/** Precedence: `--effort`, profile, account, provider, then the default rule. */
|
|
39
39
|
export declare function resolveLaneEffort(input: {
|
|
40
40
|
cliEffort?: string;
|
|
41
|
+
profileEffort?: string;
|
|
41
42
|
accountEffort?: string;
|
|
42
43
|
providerEffort?: string;
|
|
43
44
|
model?: string;
|
package/dist/lib/lanes/effort.js
CHANGED
|
@@ -25,6 +25,7 @@ export const PROVIDER_EFFORT_LEVELS = {
|
|
|
25
25
|
};
|
|
26
26
|
export const EFFORT_SOURCES = [
|
|
27
27
|
"cli",
|
|
28
|
+
"profile",
|
|
28
29
|
"account",
|
|
29
30
|
"provider",
|
|
30
31
|
"default_rule",
|
|
@@ -65,10 +66,13 @@ export function defaultEffortForModel(model) {
|
|
|
65
66
|
}
|
|
66
67
|
return undefined;
|
|
67
68
|
}
|
|
68
|
-
/** Precedence: `--effort`,
|
|
69
|
+
/** Precedence: `--effort`, profile, account, provider, then the default rule. */
|
|
69
70
|
export function resolveLaneEffort(input) {
|
|
70
71
|
if (input.cliEffort !== undefined)
|
|
71
72
|
return { effort: input.cliEffort, source: "cli" };
|
|
73
|
+
if (input.profileEffort !== undefined) {
|
|
74
|
+
return { effort: input.profileEffort, source: "profile" };
|
|
75
|
+
}
|
|
72
76
|
if (input.accountEffort !== undefined) {
|
|
73
77
|
return { effort: input.accountEffort, source: "account" };
|
|
74
78
|
}
|
|
@@ -34,6 +34,6 @@ export declare class AccountResolutionError extends LanesError {
|
|
|
34
34
|
constructor(error: "unknown_account" | "account_disabled" | "no_enabled_account" | "account_model_unavailable" | "account_quota_exhausted", message: string, details?: Record<string, unknown>);
|
|
35
35
|
}
|
|
36
36
|
export declare class WorkerResolutionError extends LanesError {
|
|
37
|
-
constructor(error: "worker_not_found" | "worker_tenancy_unresolved" | "worker_not_available" | "worker_not_active" | "worker_id_conflict" | "package_workers_unmounted" | "worker_registry_unreadable", message: string, details?: Record<string, unknown>);
|
|
37
|
+
constructor(error: "worker_not_found" | "worker_tenancy_unresolved" | "worker_not_available" | "worker_not_active" | "worker_id_conflict" | "worker_profile_invalid" | "worker_profile_ambiguous" | "package_workers_unmounted" | "worker_registry_unreadable", message: string, details?: Record<string, unknown>);
|
|
38
38
|
}
|
|
39
39
|
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -45,6 +45,8 @@ export type { KnownModels, KnownModelsDeps, ProbeCommand, ProbeResult } from "./
|
|
|
45
45
|
export { SESSION_MOVE_REASON, copySessionFiles, encodeClaudeProjectDir, findCodexRollout, planClaudeSessionCopy, planCodexSessionCopy, planSessionCopy, } from "./move-account.js";
|
|
46
46
|
export type { SessionCopyPlan, SessionCopyResult } from "./move-account.js";
|
|
47
47
|
export { WORKER_REGISTRY_REL, personalWorkerDir, personalWorkerExists, readWorkerRegistryFile, registryPath, resolveContextBasePaths, resolveLaneWorker, resolveSkillFiles, tenancyFromRegistryPath, } from "./registry.js";
|
|
48
|
+
export { ignoredWorkerProfileFields, loadWorkerProfile, materializeWorkerProfile, personalWorkerProfileDir, workerProfileMarker, workerProfilePrompt, } from "./profile.js";
|
|
49
|
+
export type { WorkerProfile, WorkerProfileMeta, WorkerProfileRuntime, } from "./profile.js";
|
|
48
50
|
export type { RegistryWorkerEntry, ResolvedLaneWorker, WorkerTenancy, WorkerYaml, } from "./registry.js";
|
|
49
51
|
export { bodyStoreForLane, envelopeQuestionId, parseQuestionBodyStore, questionBodyAbsPath, questionBodyRef, raiseEnvelopeQuestions, raiseLaneQuestion, sha256Text, writeQuestionBody, } from "./questions.js";
|
|
50
52
|
export type { QuestionBody, RaiseLaneQuestionInput } from "./questions.js";
|
package/dist/lib/lanes/index.js
CHANGED
|
@@ -25,6 +25,7 @@ export { PROVIDER_REJECTED_REASON, PROVIDER_REJECTION_MESSAGE_CAP, parseClaudeRe
|
|
|
25
25
|
export { CODEX_MODELS_CACHE_NAME, MODEL_PROBE_TIMEOUT_MS, claudeKnownModels, codexKnownModels, defaultProbe, grokKnownModels, knownModels, modelIsKnown, parseClaudeHelpModels, parseGrokModelsOutput, validateLaneModel, } from "./models.js";
|
|
26
26
|
export { SESSION_MOVE_REASON, copySessionFiles, encodeClaudeProjectDir, findCodexRollout, planClaudeSessionCopy, planCodexSessionCopy, planSessionCopy, } from "./move-account.js";
|
|
27
27
|
export { WORKER_REGISTRY_REL, personalWorkerDir, personalWorkerExists, readWorkerRegistryFile, registryPath, resolveContextBasePaths, resolveLaneWorker, resolveSkillFiles, tenancyFromRegistryPath, } from "./registry.js";
|
|
28
|
+
export { ignoredWorkerProfileFields, loadWorkerProfile, materializeWorkerProfile, personalWorkerProfileDir, workerProfileMarker, workerProfilePrompt, } from "./profile.js";
|
|
28
29
|
export { bodyStoreForLane, envelopeQuestionId, parseQuestionBodyStore, questionBodyAbsPath, questionBodyRef, raiseEnvelopeQuestions, raiseLaneQuestion, sha256Text, writeQuestionBody, } from "./questions.js";
|
|
29
30
|
export { LANE_DELIVERY_MECHANISMS, LAUNCH_TRIGGERS, PROVIDER_SESSION_RESUME, RESUMABLE_LANE_STATES, RESUME_COMMAND_STATES, SESSION_ID_ABSENT_REASONS, claimableStatesFor, deliveryRefusalReason, hasRecordedSessionId, isResumableLaneState, isResumeCommandState, laneDeliveryMechanism, parseClaudeResultOutput, parseCodexEventOutput, parseWorkerRunOutput, planLaneLaunch, providerSupportsSessionResume, readWorkerRunResult, resumeCommandRefusal, } from "./delivery.js";
|
|
30
31
|
export { DROPBOX_DIR, INBOX_NAME, appendDropboxMessage, answerDropboxMessage, drainDropbox, dropboxDir, dropboxInboxPath, formatOperatorInstruction, hookAdditionalContextJson, laneAcceptsDropboxDelivery, laneAcceptsOperatorMessage, laneIdForAnswerDelivery, operatorMessageRefusalReason, readToolActivity, recordToolActivity, runDrainHook, toolActivityPath, TOOL_ACTIVITY_NAME, } from "./dropbox.js";
|
|
@@ -80,11 +80,10 @@ export interface CreateLaneMeshOptions {
|
|
|
80
80
|
token?: () => Promise<string>;
|
|
81
81
|
}
|
|
82
82
|
export declare function createLaneMesh(opts?: CreateLaneMeshOptions): LaneMesh;
|
|
83
|
-
/**
|
|
84
|
-
export declare function
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
};
|
|
83
|
+
/** Resolve the explicit mesh attribution before falling back to the lane tenant. */
|
|
84
|
+
export declare function laneMeshCompany(lane: Pick<LaneRecord, "company" | "mesh_company">): LaneCompanyRef | undefined;
|
|
85
|
+
/** Company attribution + thread present. Unscoped personal lanes emit nothing. */
|
|
86
|
+
export declare function laneCanEmit(lane: Pick<LaneRecord, "company" | "mesh_company" | "thread_id">): boolean;
|
|
88
87
|
/**
|
|
89
88
|
* Spec §8 terminal-envelope events. `done` → lane_done and story → review;
|
|
90
89
|
* `blocked` → lane_blocked; `ask` → lane_ask with the queue ids. The story is
|
|
@@ -186,9 +186,13 @@ export function createLaneMesh(opts = {}) {
|
|
|
186
186
|
},
|
|
187
187
|
};
|
|
188
188
|
}
|
|
189
|
-
/**
|
|
189
|
+
/** Resolve the explicit mesh attribution before falling back to the lane tenant. */
|
|
190
|
+
export function laneMeshCompany(lane) {
|
|
191
|
+
return lane.mesh_company ?? lane.company ?? undefined;
|
|
192
|
+
}
|
|
193
|
+
/** Company attribution + thread present. Unscoped personal lanes emit nothing. */
|
|
190
194
|
export function laneCanEmit(lane) {
|
|
191
|
-
return lane
|
|
195
|
+
return laneMeshCompany(lane) !== undefined && !!lane.thread_id;
|
|
192
196
|
}
|
|
193
197
|
function baseIdentity(lane) {
|
|
194
198
|
const lastMove = lane.account_history?.[lane.account_history.length - 1];
|
|
@@ -209,8 +213,10 @@ function baseIdentity(lane) {
|
|
|
209
213
|
export async function emitLaneDecisionEvents(mesh, lane, envelope, opts = {}) {
|
|
210
214
|
if (!laneCanEmit(lane))
|
|
211
215
|
return;
|
|
212
|
-
const company = lane
|
|
216
|
+
const company = laneMeshCompany(lane);
|
|
213
217
|
const threadId = lane.thread_id;
|
|
218
|
+
if (!company || !threadId)
|
|
219
|
+
return;
|
|
214
220
|
switch (envelope.decision) {
|
|
215
221
|
case "done": {
|
|
216
222
|
const outcomes = await Promise.allSettled([
|
|
@@ -260,7 +266,11 @@ export async function emitLaneDecisionEvents(mesh, lane, envelope, opts = {}) {
|
|
|
260
266
|
export async function emitLaneProgressEvent(mesh, lane, detail, signal) {
|
|
261
267
|
if (!laneCanEmit(lane))
|
|
262
268
|
return;
|
|
263
|
-
|
|
269
|
+
const company = laneMeshCompany(lane);
|
|
270
|
+
const threadId = lane.thread_id;
|
|
271
|
+
if (!company || !threadId)
|
|
272
|
+
return;
|
|
273
|
+
await mesh.appendThreadEvent(company, threadId, "lane_progress", {
|
|
264
274
|
...baseIdentity(lane),
|
|
265
275
|
detail,
|
|
266
276
|
}, signal);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reusable lane worker profiles stored under personal/workers/<id>.
|
|
3
|
+
*
|
|
4
|
+
* A profile is deliberately independent from the worker registry. The
|
|
5
|
+
* registry describes a worker persona that can be resolved from the company
|
|
6
|
+
* and package trees; this module describes the provider launch contract that
|
|
7
|
+
* must be re-read for every spawn.
|
|
8
|
+
*/
|
|
9
|
+
import { type LaneProvider } from "./types.js";
|
|
10
|
+
export interface WorkerProfileMeta {
|
|
11
|
+
version?: string;
|
|
12
|
+
provider: LaneProvider;
|
|
13
|
+
model: string;
|
|
14
|
+
account: string;
|
|
15
|
+
effort: string;
|
|
16
|
+
fast_mode: boolean;
|
|
17
|
+
max_concurrent?: number;
|
|
18
|
+
source?: string;
|
|
19
|
+
accounts?: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface WorkerProfile {
|
|
22
|
+
id: string;
|
|
23
|
+
dir: string;
|
|
24
|
+
meta: WorkerProfileMeta;
|
|
25
|
+
systemPrompt: string;
|
|
26
|
+
settings?: Record<string, unknown>;
|
|
27
|
+
policyFiles: string[];
|
|
28
|
+
hookFiles: string[];
|
|
29
|
+
contentHash: string;
|
|
30
|
+
}
|
|
31
|
+
export interface WorkerProfileRuntime {
|
|
32
|
+
settingsPath?: string;
|
|
33
|
+
hooksDir?: string;
|
|
34
|
+
}
|
|
35
|
+
export declare function personalWorkerProfileDir(hqRoot: string, id: string): string;
|
|
36
|
+
/** A meta.yaml file is the explicit marker for a personal worker profile. */
|
|
37
|
+
export declare function workerProfileMarker(hqRoot: string, id: string): "absent" | "present";
|
|
38
|
+
export declare function loadWorkerProfile(hqRoot: string, id: string): WorkerProfile;
|
|
39
|
+
export declare function workerProfilePrompt(profile: WorkerProfile): string;
|
|
40
|
+
export declare function ignoredWorkerProfileFields(provider: LaneProvider): string[];
|
|
41
|
+
/**
|
|
42
|
+
* Materialize provider settings and hook files in the lane run directory.
|
|
43
|
+
* The path is intentionally run-local so every fresh, resumed, moved, and
|
|
44
|
+
* repair spawn gets the profile currently on disk without mutating an account
|
|
45
|
+
* home or a shared provider configuration.
|
|
46
|
+
*/
|
|
47
|
+
export declare function materializeWorkerProfile(profile: WorkerProfile, runDir: string): WorkerProfileRuntime;
|
|
48
|
+
//# sourceMappingURL=profile.d.ts.map
|