@indigoai-us/hq-cli 5.141.0 → 5.142.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.
@@ -11,7 +11,7 @@ import { PROVIDER_HOME_ENV } from "./accounts.js";
11
11
  import { type RunCompactionFn } from "./compaction.js";
12
12
  import { type LaunchTrigger } from "./delivery.js";
13
13
  import { type MachineIdentity } from "./machine-identity.js";
14
- import { type LaneProvider, type LaneRecord } from "./types.js";
14
+ import { type LaneCompanyRef, type LaneProvider, type LaneRecord } from "./types.js";
15
15
  export declare const LANES_RUNS_REL: string;
16
16
  /** Written by reconcile before a resume spawn; the worker prompt names this path. */
17
17
  export declare const ANSWERED_QUESTIONS_FILE = "answered-questions.json";
@@ -27,12 +27,18 @@ export declare const CODEX_FAST_MODE_FLAGS: readonly ["-c", "service_tier=\"fast
27
27
  export declare function parseCliModel(raw: string | undefined): string | undefined;
28
28
  export declare function resolveLaneModel(input: {
29
29
  cliModel?: string;
30
+ profileModel?: string;
30
31
  accountModel?: string;
31
32
  providerModel?: string;
32
33
  }): string | undefined;
33
34
  export declare function appendModelFlag(provider: LaneProvider, args: string[], model: string | undefined): string[];
34
35
  /** Add Codex fast-mode flags before the prompt/positional separator. */
35
36
  export declare function appendFastModeFlags(provider: LaneProvider, args: string[], enabled: boolean | undefined): string[];
37
+ export interface ProviderProfileLaunch {
38
+ systemPrompt: string;
39
+ settingsPath?: string;
40
+ ignoredFields?: readonly string[];
41
+ }
36
42
  export type DetachedStdio = ["ignore", number, number];
37
43
  export interface DetachedSpawnOptions {
38
44
  detached: true;
@@ -197,6 +203,8 @@ export declare function buildProviderCommand(provider: LaneProvider, input: {
197
203
  effort?: string;
198
204
  /** Enable Codex's fast service tier for this resolved model. */
199
205
  fastMode?: boolean;
206
+ /** Per-spawn worker profile instructions and materialized settings. */
207
+ profile?: ProviderProfileLaunch;
200
208
  /** Continue a recorded session. Only providers in PROVIDER_SESSION_RESUME accept this. */
201
209
  resume?: ProviderResumeInput;
202
210
  /**
@@ -209,7 +217,7 @@ export declare function buildProviderCommand(provider: LaneProvider, input: {
209
217
  export declare function workerEnv(base: NodeJS.ProcessEnv, resolved: {
210
218
  envVar: string;
211
219
  home: string;
212
- }, laneId: string, hqRoot: string, autoCompactTokens?: number): NodeJS.ProcessEnv;
220
+ }, laneId: string, hqRoot: string, autoCompactTokens?: number, meshCompany?: LaneCompanyRef): NodeJS.ProcessEnv;
213
221
  export declare function markSpawnFailure(hqRoot: string, laneId: string, reasonRaw: string, details: Record<string, unknown>): LaneRecord;
214
222
  /**
215
223
  * Spec §5.2 executing-side check. Compares this machine's identity to
@@ -227,6 +235,10 @@ export interface SpawnManifestFile {
227
235
  /** Byte length of logs/worker.out before this run started; its result is after this. */
228
236
  worker_out_offset?: number;
229
237
  fast_mode?: boolean;
238
+ worker_profile?: string;
239
+ worker_profile_hash?: string;
240
+ worker_profile_ignored?: string[];
241
+ worker_profile_settings?: string;
230
242
  }
231
243
  /** Read the per-run manifest. Missing file or field reads as absent. */
232
244
  export declare function readSpawnManifest(runDir: string): SpawnManifestFile;
@@ -18,6 +18,7 @@ import { loadLanesConfig, providerAutoCompactTokens, providerCompactAfterMs, } f
18
18
  import { appendEffortFlag, resolveLaneEffort } from "./effort.js";
19
19
  import { claimableStatesFor, planLaneLaunch, providerSupportsSessionResume, } from "./delivery.js";
20
20
  import { AccountResolutionError, LanesError } from "./errors.js";
21
+ import { ignoredWorkerProfileFields, loadWorkerProfile, materializeWorkerProfile, workerProfilePrompt, } from "./profile.js";
21
22
  import { resolveMachineIdentity, } from "./machine-identity.js";
22
23
  import { readLane, retryUpdateLane } from "./store.js";
23
24
  import { LANE_ENVELOPE_JSON_SCHEMA, parseLaneProvider, } from "./types.js";
@@ -86,6 +87,9 @@ export function parseCliModel(raw) {
86
87
  export function resolveLaneModel(input) {
87
88
  if (input.cliModel !== undefined)
88
89
  return input.cliModel;
90
+ if (input.profileModel !== undefined && input.profileModel.trim().length > 0) {
91
+ return input.profileModel.trim();
92
+ }
89
93
  if (input.accountModel !== undefined && input.accountModel.trim().length > 0) {
90
94
  return input.accountModel.trim();
91
95
  }
@@ -119,6 +123,40 @@ export function appendFastModeFlags(provider, args, enabled) {
119
123
  return [...args, ...flags];
120
124
  return [...args.slice(0, end), ...flags, ...args.slice(end)];
121
125
  }
126
+ function appendProviderProfileFlags(provider, args, profile) {
127
+ if (profile === undefined)
128
+ return args;
129
+ const ignored = new Set(profile.ignoredFields ?? []);
130
+ switch (provider) {
131
+ case "claude": {
132
+ const flags = [
133
+ "--append-system-prompt",
134
+ profile.systemPrompt,
135
+ // A profile is a per-spawn input. Do not let Claude's session resume
136
+ // snapshot hide a changed profile from the next launch.
137
+ "--system-prompt-snapshot",
138
+ "off",
139
+ ...(profile.settingsPath !== undefined && !ignored.has("settings")
140
+ ? ["--settings", profile.settingsPath]
141
+ : []),
142
+ ];
143
+ return [...args, ...flags];
144
+ }
145
+ case "codex": {
146
+ const flags = ["-c", `developer_instructions=${JSON.stringify(profile.systemPrompt)}`];
147
+ const end = args.indexOf("--");
148
+ if (end === -1)
149
+ return [...args, ...flags];
150
+ return [...args.slice(0, end), ...flags, ...args.slice(end)];
151
+ }
152
+ case "grok":
153
+ return [...args, "--rules", profile.systemPrompt];
154
+ default: {
155
+ const _exhaustive = provider;
156
+ return _exhaustive;
157
+ }
158
+ }
159
+ }
122
160
  export const PID_LIVENESS_DECISIONS = [
123
161
  "esrch",
124
162
  "starttime_mismatch",
@@ -713,10 +751,10 @@ export function buildProviderCommand(provider, input) {
713
751
  }
714
752
  return {
715
753
  command,
716
- args: appendFastModeFlags(parsed, appendEffortFlag(parsed, appendModelFlag(parsed, args, input.model), input.effort), input.fastMode),
754
+ args: appendFastModeFlags(parsed, appendEffortFlag(parsed, appendModelFlag(parsed, appendProviderProfileFlags(parsed, args, input.profile), input.model), input.effort), input.fastMode),
717
755
  };
718
756
  }
719
- export function workerEnv(base, resolved, laneId, hqRoot, autoCompactTokens) {
757
+ export function workerEnv(base, resolved, laneId, hqRoot, autoCompactTokens, meshCompany) {
720
758
  const accepted = Object.values(PROVIDER_HOME_ENV);
721
759
  if (!accepted.includes(resolved.envVar)) {
722
760
  throw new LanesError("unknown_provider_home_env", `Unknown provider home variable ${JSON.stringify(resolved.envVar)}. Accepted: ${accepted.join(", ")}`, { accepted, value: resolved.envVar });
@@ -731,6 +769,12 @@ export function workerEnv(base, resolved, laneId, hqRoot, autoCompactTokens) {
731
769
  }
732
770
  env.HQ_LANE_ID = laneId;
733
771
  env.HQ_ROOT = hqRoot;
772
+ if (meshCompany) {
773
+ env.HQ_SPAWN_COMPANY = meshCompany.slug || meshCompany.uid;
774
+ }
775
+ else {
776
+ delete env.HQ_SPAWN_COMPANY;
777
+ }
734
778
  return env;
735
779
  }
736
780
  function ensureDir(dir) {
@@ -752,6 +796,15 @@ function writeText(filePath, text) {
752
796
  ensureDir(path.dirname(filePath));
753
797
  fs.writeFileSync(filePath, text, "utf8");
754
798
  }
799
+ function appendWorkerProfileEvent(runDir, event) {
800
+ const eventsPath = path.join(runDir, "watcher", "profile-events.jsonl");
801
+ ensureDir(path.dirname(eventsPath));
802
+ fs.appendFileSync(eventsPath, `${JSON.stringify({
803
+ event: "profile_applied",
804
+ ...event,
805
+ at: new Date().toISOString(),
806
+ })}\n`);
807
+ }
755
808
  function openLog(filePath) {
756
809
  ensureDir(path.dirname(filePath));
757
810
  return fs.openSync(filePath, "a");
@@ -906,6 +959,16 @@ function writeSpawnManifest(runDir, input) {
906
959
  resume: input.resume,
907
960
  worker_out_offset: input.workerOutOffset,
908
961
  ...(input.fastMode ? { fast_mode: true } : {}),
962
+ ...(input.profile
963
+ ? {
964
+ worker_profile: input.profile.id,
965
+ worker_profile_hash: input.profile.hash,
966
+ worker_profile_ignored: [...input.profile.ignoredFields],
967
+ ...(input.profile.settingsPath
968
+ ? { worker_profile_settings: input.profile.settingsPath }
969
+ : {}),
970
+ }
971
+ : {}),
909
972
  }, null, 2)}\n`);
910
973
  }
911
974
  /** Arm (or re-arm) the detached per-lane watcher. */
@@ -969,6 +1032,15 @@ export function readSpawnManifest(runDir) {
969
1032
  }
970
1033
  if (typeof rec.fast_mode === "boolean")
971
1034
  out.fast_mode = rec.fast_mode;
1035
+ if (typeof rec.worker_profile === "string")
1036
+ out.worker_profile = rec.worker_profile;
1037
+ if (typeof rec.worker_profile_hash === "string")
1038
+ out.worker_profile_hash = rec.worker_profile_hash;
1039
+ if (Array.isArray(rec.worker_profile_ignored) && rec.worker_profile_ignored.every((item) => typeof item === "string")) {
1040
+ out.worker_profile_ignored = rec.worker_profile_ignored;
1041
+ }
1042
+ if (typeof rec.worker_profile_settings === "string")
1043
+ out.worker_profile_settings = rec.worker_profile_settings;
972
1044
  if (rec.resume &&
973
1045
  typeof rec.resume === "object" &&
974
1046
  typeof rec.resume.session_id === "string") {
@@ -1024,13 +1096,38 @@ export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
1024
1096
  const logsDir = path.join(runDir, "logs");
1025
1097
  ensureDir(logsDir);
1026
1098
  ensureDir(path.join(runDir, "envelopes"));
1099
+ const profile = existing.worker_profile
1100
+ ? loadWorkerProfile(hqRoot, existing.worker_profile)
1101
+ : undefined;
1102
+ const profileDefaultsApply = profile !== undefined && profile.meta.provider === existing.provider;
1103
+ const profileModel = profileDefaultsApply ? profile.meta.model : undefined;
1104
+ const profileEffort = profileDefaultsApply ? profile.meta.effort : undefined;
1105
+ const ignoredProfileFields = profile
1106
+ ? ignoredWorkerProfileFields(existing.provider)
1107
+ : [];
1108
+ const profileRuntime = profile
1109
+ ? materializeWorkerProfile(profile, runDir)
1110
+ : undefined;
1111
+ const profileLaunch = profile
1112
+ ? {
1113
+ systemPrompt: workerProfilePrompt(profile),
1114
+ ...(profileRuntime?.settingsPath !== undefined
1115
+ ? { settingsPath: profileRuntime.settingsPath }
1116
+ : {}),
1117
+ ignoredFields: ignoredProfileFields,
1118
+ }
1119
+ : undefined;
1120
+ const profileChanged = profile !== undefined && existing.worker_profile_hash !== profile.contentHash;
1027
1121
  const config = loadLanesConfig(hqRoot);
1122
+ const pinnedModel = existing.model_source === undefined || existing.model_source === "cli"
1123
+ ? existing.model
1124
+ : undefined;
1028
1125
  let resolved;
1029
1126
  try {
1030
1127
  resolved = resolveAccount(lane.provider, lane.account, config, {
1031
1128
  hqRoot,
1032
1129
  existsSync,
1033
- model: lane.model,
1130
+ model: pinnedModel ?? profileModel,
1034
1131
  });
1035
1132
  }
1036
1133
  catch (err) {
@@ -1078,21 +1175,26 @@ export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
1078
1175
  const autoCompactTokens = lane.provider === "claude"
1079
1176
  ? providerAutoCompactTokens(config.providers.claude)
1080
1177
  : undefined;
1081
- const childEnv = workerEnv(env, { envVar: resolved.envVar, home: resolved.home }, lane.lane_id, hqRoot, autoCompactTokens);
1178
+ const childEnv = workerEnv(env, { envVar: resolved.envVar, home: resolved.home }, lane.lane_id, hqRoot, autoCompactTokens, lane.mesh_company ?? lane.company ?? undefined);
1082
1179
  const model = resolveLaneModel({
1083
- cliModel: lane.model,
1180
+ cliModel: pinnedModel,
1181
+ profileModel,
1084
1182
  accountModel: accountCfg?.model,
1085
1183
  providerModel: config.providers[lane.provider].model,
1086
1184
  });
1087
1185
  const effort = resolveLaneEffort({
1088
1186
  cliEffort: existing.effort_source === "cli" ? existing.effort : undefined,
1187
+ profileEffort,
1089
1188
  accountEffort: accountCfg?.effort,
1090
1189
  providerEffort: config.providers[lane.provider].effort,
1091
1190
  model,
1092
1191
  });
1093
- const fastMode = lane.provider === "codex" &&
1094
- model !== undefined &&
1095
- (config.providers.codex.fast_mode_models ?? []).includes(model);
1192
+ const fastMode = lane.provider === "codex"
1193
+ ? profileDefaultsApply
1194
+ ? profile?.meta.fast_mode === true
1195
+ : model !== undefined &&
1196
+ (config.providers.codex.fast_mode_models ?? []).includes(model)
1197
+ : false;
1096
1198
  const resume = plan.mode === "resume"
1097
1199
  ? {
1098
1200
  session_id: plan.session_id,
@@ -1122,6 +1224,7 @@ export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
1122
1224
  model,
1123
1225
  effort: effort.effort,
1124
1226
  fastMode,
1227
+ profile: profileLaunch,
1125
1228
  resume,
1126
1229
  });
1127
1230
  // A systemd PATH mismatch is an environment defect, not a lane failure.
@@ -1170,6 +1273,7 @@ export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
1170
1273
  model,
1171
1274
  effort: effort.effort,
1172
1275
  fastMode,
1276
+ profile: profileLaunch,
1173
1277
  resume: { session_id: resume.session_id, prompt: COMPACTION_PROMPT },
1174
1278
  });
1175
1279
  compaction = compactLaneSession({
@@ -1213,13 +1317,36 @@ export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
1213
1317
  pending_resume: undefined,
1214
1318
  account: resolved.id,
1215
1319
  ...(model !== undefined ? { model } : {}),
1320
+ ...(model !== undefined
1321
+ ? {
1322
+ model_source: pinnedModel !== undefined
1323
+ ? "cli"
1324
+ : profileDefaultsApply
1325
+ ? "profile"
1326
+ : accountCfg?.model !== undefined
1327
+ ? "account"
1328
+ : config.providers[lane.provider].model !== undefined
1329
+ ? "provider"
1330
+ : "none",
1331
+ }
1332
+ : { model_source: "none" }),
1216
1333
  effort_source: effort.source,
1217
1334
  last_host_report_at: nowIso,
1335
+ ...(profile
1336
+ ? {
1337
+ worker_profile_hash: profile.contentHash,
1338
+ worker_profile_ignored: [...ignoredProfileFields],
1339
+ }
1340
+ : {}),
1218
1341
  };
1219
1342
  if (effort.effort !== undefined)
1220
1343
  next.effort = effort.effort;
1221
1344
  else
1222
1345
  delete next.effort;
1346
+ // `undefined` deliberately overlays the CAS merge's current record so a
1347
+ // dynamic default disappearing removes the stale persisted model.
1348
+ if (model === undefined)
1349
+ next.model = undefined;
1223
1350
  if (fastMode)
1224
1351
  next.fast_mode = true;
1225
1352
  else
@@ -1295,7 +1422,28 @@ export function spawnLaneWorker(hqRoot, lane, deps = {}, launch = {}) {
1295
1422
  resume: resume ? { session_id: resume.session_id } : null,
1296
1423
  workerOutOffset,
1297
1424
  fastMode,
1425
+ ...(profile
1426
+ ? {
1427
+ profile: {
1428
+ id: profile.id,
1429
+ hash: profile.contentHash,
1430
+ ignoredFields: ignoredProfileFields,
1431
+ ...(profileRuntime?.settingsPath !== undefined
1432
+ ? { settingsPath: profileRuntime.settingsPath }
1433
+ : {}),
1434
+ },
1435
+ }
1436
+ : {}),
1298
1437
  });
1438
+ if (profile !== undefined) {
1439
+ appendWorkerProfileEvent(runDir, {
1440
+ profile_id: profile.id,
1441
+ profile_hash: profile.contentHash,
1442
+ changed: profileChanged,
1443
+ provider: lane.provider,
1444
+ ignored_fields: ignoredProfileFields,
1445
+ });
1446
+ }
1299
1447
  }
1300
1448
  catch (err) {
1301
1449
  if (workerPid !== undefined)
@@ -1355,30 +1503,59 @@ export function spawnEnvelopeRepair(hqRoot, lane, input, deps = {}) {
1355
1503
  const logsDir = path.join(runDir, "logs");
1356
1504
  ensureDir(logsDir);
1357
1505
  const config = loadLanesConfig(hqRoot);
1506
+ const profile = lane.worker_profile
1507
+ ? loadWorkerProfile(hqRoot, lane.worker_profile)
1508
+ : undefined;
1509
+ const profileDefaultsApply = profile !== undefined && profile.meta.provider === lane.provider;
1510
+ const profileModel = profileDefaultsApply ? profile.meta.model : undefined;
1511
+ const profileEffort = profileDefaultsApply ? profile.meta.effort : undefined;
1512
+ const ignoredProfileFields = profile
1513
+ ? ignoredWorkerProfileFields(lane.provider)
1514
+ : [];
1515
+ const profileRuntime = profile
1516
+ ? materializeWorkerProfile(profile, runDir)
1517
+ : undefined;
1518
+ const profileLaunch = profile
1519
+ ? {
1520
+ systemPrompt: workerProfilePrompt(profile),
1521
+ ...(profileRuntime?.settingsPath !== undefined
1522
+ ? { settingsPath: profileRuntime.settingsPath }
1523
+ : {}),
1524
+ ignoredFields: ignoredProfileFields,
1525
+ }
1526
+ : undefined;
1527
+ const pinnedModel = lane.model_source === undefined || lane.model_source === "cli"
1528
+ ? lane.model
1529
+ : undefined;
1358
1530
  const resolved = resolveAccount(lane.provider, lane.account, config, {
1359
1531
  hqRoot,
1360
1532
  existsSync,
1361
- model: lane.model,
1533
+ model: pinnedModel ?? profileModel,
1362
1534
  });
1363
1535
  const autoCompactTokens = lane.provider === "claude"
1364
1536
  ? providerAutoCompactTokens(config.providers.claude)
1365
1537
  : undefined;
1366
- const childEnv = workerEnv(env, { envVar: resolved.envVar, home: resolved.home }, lane.lane_id, hqRoot, autoCompactTokens);
1538
+ const childEnv = workerEnv(env, { envVar: resolved.envVar, home: resolved.home }, lane.lane_id, hqRoot, autoCompactTokens, lane.mesh_company ?? lane.company ?? undefined);
1367
1539
  const accountCfg = config.providers[lane.provider].accounts[resolved.id];
1368
1540
  const model = resolveLaneModel({
1369
- cliModel: lane.model,
1541
+ cliModel: pinnedModel,
1542
+ profileModel,
1370
1543
  accountModel: accountCfg?.model,
1371
1544
  providerModel: config.providers[lane.provider].model,
1372
1545
  });
1373
1546
  const effort = resolveLaneEffort({
1374
1547
  cliEffort: lane.effort_source === "cli" ? lane.effort : undefined,
1548
+ profileEffort,
1375
1549
  accountEffort: accountCfg?.effort,
1376
1550
  providerEffort: config.providers[lane.provider].effort,
1377
1551
  model,
1378
1552
  });
1379
- const fastMode = lane.provider === "codex" &&
1380
- model !== undefined &&
1381
- (config.providers.codex.fast_mode_models ?? []).includes(model);
1553
+ const fastMode = lane.provider === "codex"
1554
+ ? profileDefaultsApply
1555
+ ? profile?.meta.fast_mode === true
1556
+ : model !== undefined &&
1557
+ (config.providers.codex.fast_mode_models ?? []).includes(model)
1558
+ : false;
1382
1559
  const repairPrompt = envelopeRepairPrompt({
1383
1560
  envelopePath: input.envelopePath,
1384
1561
  error: input.error,
@@ -1392,6 +1569,7 @@ export function spawnEnvelopeRepair(hqRoot, lane, input, deps = {}) {
1392
1569
  model,
1393
1570
  effort: effort.effort,
1394
1571
  fastMode,
1572
+ profile: profileLaunch,
1395
1573
  ...(mode === "resume" && sessionId !== null
1396
1574
  ? { resume: { session_id: sessionId, prompt: repairPrompt } }
1397
1575
  : { freshTurnPrompt: repairPrompt }),
@@ -1418,9 +1596,55 @@ export function spawnEnvelopeRepair(hqRoot, lane, input, deps = {}) {
1418
1596
  resume: mode === "resume" && sessionId !== null ? { session_id: sessionId } : null,
1419
1597
  workerOutOffset,
1420
1598
  fastMode,
1599
+ ...(profile
1600
+ ? {
1601
+ profile: {
1602
+ id: profile.id,
1603
+ hash: profile.contentHash,
1604
+ ignoredFields: ignoredProfileFields,
1605
+ ...(profileRuntime?.settingsPath !== undefined
1606
+ ? { settingsPath: profileRuntime.settingsPath }
1607
+ : {}),
1608
+ },
1609
+ }
1610
+ : {}),
1421
1611
  });
1612
+ if (profile !== undefined) {
1613
+ appendWorkerProfileEvent(runDir, {
1614
+ profile_id: profile.id,
1615
+ profile_hash: profile.contentHash,
1616
+ changed: lane.worker_profile_hash !== profile.contentHash,
1617
+ provider: lane.provider,
1618
+ ignored_fields: ignoredProfileFields,
1619
+ });
1620
+ }
1422
1621
  retryUpdateLane(hqRoot, lane.lane_id, "spawn", (current) => {
1423
1622
  const next = { ...current };
1623
+ if (profile !== undefined) {
1624
+ next.worker_profile_hash = profile.contentHash;
1625
+ next.worker_profile_ignored = [...ignoredProfileFields];
1626
+ if (model !== undefined) {
1627
+ next.model = model;
1628
+ next.model_source = pinnedModel !== undefined
1629
+ ? "cli"
1630
+ : profileDefaultsApply
1631
+ ? "profile"
1632
+ : accountCfg?.model !== undefined
1633
+ ? "account"
1634
+ : config.providers[lane.provider].model !== undefined
1635
+ ? "provider"
1636
+ : "none";
1637
+ }
1638
+ else {
1639
+ next.model = undefined;
1640
+ next.model_source = "none";
1641
+ }
1642
+ next.effort_source = effort.source;
1643
+ if (effort.effort !== undefined)
1644
+ next.effort = effort.effort;
1645
+ else
1646
+ delete next.effort;
1647
+ }
1424
1648
  if (fastMode)
1425
1649
  next.fast_mode = true;
1426
1650
  else
@@ -268,6 +268,15 @@ function parseOptionalCompanyField(raw, filePath) {
268
268
  requireString(raw.company.slug, "company.slug");
269
269
  requireString(raw.company.uid, "company.uid");
270
270
  }
271
+ function parseOptionalMeshCompanyField(raw, filePath) {
272
+ if (raw.mesh_company === undefined)
273
+ return;
274
+ if (!isPlainObject(raw.mesh_company)) {
275
+ throw new LaneSchemaError("mesh_company must be an object", { path: filePath });
276
+ }
277
+ requireString(raw.mesh_company.slug, "mesh_company.slug");
278
+ requireString(raw.mesh_company.uid, "mesh_company.uid");
279
+ }
271
280
  export function parseLaneRecord(raw, filePath) {
272
281
  if (!isPlainObject(raw)) {
273
282
  throw new LaneSchemaError("Lane record must be a JSON object", {
@@ -294,6 +303,7 @@ export function parseLaneRecord(raw, filePath) {
294
303
  throw new LaneSchemaError(`Unknown provider ${JSON.stringify(raw.provider)}`, { path: filePath, value: raw.provider });
295
304
  }
296
305
  parseOptionalCompanyField(raw, filePath);
306
+ parseOptionalMeshCompanyField(raw, filePath);
297
307
  if (!isPlainObject(raw.senior)) {
298
308
  throw new LaneSchemaError("senior must be an object", { path: filePath });
299
309
  }
@@ -242,6 +242,8 @@ export interface LaneRecord {
242
242
  lane_id: string;
243
243
  /** `null` is a core/personal lane (spec §6.2 / §10). Not an empty slug. */
244
244
  company: LaneCompanyRef | null;
245
+ /** Explicit Work Mesh attribution for a personal lane; never inferred from cwd. */
246
+ mesh_company?: LaneCompanyRef;
245
247
  project_id: string;
246
248
  story_id: string;
247
249
  thread_id?: string;
@@ -265,6 +267,12 @@ export interface LaneRecord {
265
267
  worker_path?: string;
266
268
  /** Package name when the worker's realpath is under core/packages. */
267
269
  worker_pack?: string;
270
+ /** Personal worker profile id applied to every spawn. */
271
+ worker_profile?: string;
272
+ /** Content hash of the profile last applied to this lane. */
273
+ worker_profile_hash?: string;
274
+ /** Profile fields intentionally unsupported by the selected provider. */
275
+ worker_profile_ignored?: string[];
268
276
  provider: LaneProvider;
269
277
  account?: string;
270
278
  /**
@@ -296,10 +304,12 @@ export interface LaneRecord {
296
304
  last_envelope?: LastEnvelopeRef;
297
305
  /** Effective model id recorded at create/spawn. Omitted when the provider chooses. */
298
306
  model?: string;
307
+ /** Where the effective model came from; profile values are re-read on spawn. */
308
+ model_source?: "cli" | "profile" | "account" | "provider" | "none";
299
309
  /** Effective effort level passed to the provider at the last spawn (effort.ts). */
300
310
  effort?: string;
301
311
  /** Where `effort` came from. `cli` pins it across later spawns. */
302
- effort_source?: "cli" | "account" | "provider" | "default_rule" | "none";
312
+ effort_source?: "cli" | "profile" | "account" | "provider" | "default_rule" | "none";
303
313
  /** Whether the last spawn used Codex fast mode, including false when disabled. */
304
314
  fast_mode?: boolean;
305
315
  /** Time of the last operator message accepted for this lane. Drives compaction. */
@@ -195,15 +195,15 @@ export const LANE_WRITERS = ["creator", "command", "watcher", "reconcile", "spaw
195
195
  /** Field ownership at the durable-record mutation boundary (spec §10.1). */
196
196
  export const LANE_FIELD_WRITERS = {
197
197
  schema_version: ["creator"], lane_id: ["creator"], company: ["creator"],
198
- project_id: ["command"], story_id: ["command"], thread_id: ["creator", "command"],
198
+ project_id: ["command"], story_id: ["command"], thread_id: ["creator", "command"], mesh_company: ["creator"],
199
199
  depth: ["command"], senior: ["command"], senior_history: ["command"],
200
200
  state: ["creator", "command", "watcher", "reconcile", "spawn"], queued_reason: ["creator", "command", "spawn", "reconcile"],
201
201
  pickup_validation_pending: ["creator", "command", "spawn", "reconcile"],
202
202
  pickup_validation_pending_since: ["creator", "command", "spawn", "reconcile"],
203
- priority: ["command"], worker: ["creator"], worker_path: ["creator"], worker_pack: ["creator"],
203
+ priority: ["command"], worker: ["creator"], worker_path: ["creator"], worker_pack: ["creator"], worker_profile: ["creator"], worker_profile_hash: ["creator", "spawn"], worker_profile_ignored: ["creator", "spawn"],
204
204
  provider: ["creator"], account: ["creator", "spawn", "command"], account_history: ["command"], pending_resume: ["command", "spawn"], host: ["creator"], origin_host: ["creator"], origin_host_source: ["creator"],
205
205
  version: ["creator"], created_at: ["creator"], updated_at: ["creator"], attribution_history: ["command"],
206
- last_envelope: ["watcher", "reconcile"], model: ["creator", "spawn", "command"], effort: ["creator", "spawn"], effort_source: ["creator", "spawn"], fast_mode: ["spawn"],
206
+ last_envelope: ["watcher", "reconcile"], model: ["creator", "spawn", "command"], model_source: ["creator", "spawn", "command"], effort: ["creator", "spawn"], effort_source: ["creator", "spawn"], fast_mode: ["spawn"],
207
207
  last_message_at: ["command"], last_compaction: ["spawn"], story_complete: ["watcher", "reconcile"], story_complete_reason: ["watcher", "reconcile"], story_status: ["watcher", "reconcile"],
208
208
  overdue: ["reconcile"], overdue_at: ["reconcile"], last_host_report_at: ["watcher", "spawn", "reconcile"], stalled: ["watcher"], stalled_at: ["watcher"], stalled_reason: ["watcher"],
209
209
  admitted_reason: ["reconcile"], terminal_reason: ["command", "watcher", "spawn", "reconcile"], terminal_details: ["command", "spawn", "watcher", "reconcile"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.141.0",
3
+ "version": "5.142.0",
4
4
  "description": "HQ by Indigo management CLI \u2014 modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {