@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.
Files changed (36) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/assets/scaffold/core/scripts/checkpoint-stop-gate.sh +77 -2
  3. package/dist/command-catalog.generated.d.ts +7 -1
  4. package/dist/command-catalog.generated.js +9 -1
  5. package/dist/commands/agents.d.ts +1 -0
  6. package/dist/commands/agents.js +4 -8
  7. package/dist/commands/dm.js +1 -5
  8. package/dist/commands/lanes.js +125 -26
  9. package/dist/commands/mesh.js +25 -2
  10. package/dist/commands/report.d.ts +3 -1
  11. package/dist/commands/report.js +69 -15
  12. package/dist/lib/agent-kit/mcp/tools.js +2 -1
  13. package/dist/lib/bot/api.d.ts +4 -0
  14. package/dist/lib/bot/api.js +13 -1
  15. package/dist/lib/lanes/effort.d.ts +3 -2
  16. package/dist/lib/lanes/effort.js +5 -1
  17. package/dist/lib/lanes/errors.d.ts +1 -1
  18. package/dist/lib/lanes/index.d.ts +2 -0
  19. package/dist/lib/lanes/index.js +1 -0
  20. package/dist/lib/lanes/mesh-events.d.ts +4 -5
  21. package/dist/lib/lanes/mesh-events.js +14 -4
  22. package/dist/lib/lanes/profile.d.ts +48 -0
  23. package/dist/lib/lanes/profile.js +405 -0
  24. package/dist/lib/lanes/reconcile.js +25 -3
  25. package/dist/lib/lanes/registry.d.ts +3 -0
  26. package/dist/lib/lanes/registry.js +45 -1
  27. package/dist/lib/lanes/spawn.d.ts +14 -2
  28. package/dist/lib/lanes/spawn.js +238 -14
  29. package/dist/lib/lanes/store.js +10 -0
  30. package/dist/lib/lanes/types.d.ts +11 -1
  31. package/dist/lib/lanes/types.js +3 -3
  32. package/dist/lib/notify-recipient.d.ts +7 -0
  33. package/dist/lib/notify-recipient.js +11 -0
  34. package/dist/lib/report-publish.d.ts +2 -2
  35. package/dist/lib/report-publish.js +9 -8
  36. package/package.json +1 -1
@@ -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"],
@@ -0,0 +1,7 @@
1
+ /** Canonical recipients accepted by the notify DM wire contract. */
2
+ export declare const RECIPIENT_UID_PATTERN: RegExp;
3
+ export declare const AGENT_UID_PATTERN: RegExp;
4
+ export declare const EMAIL_PATTERN: RegExp;
5
+ export declare function isRecipientUid(value: string): boolean;
6
+ export declare function isAgentUid(value: string): boolean;
7
+ //# sourceMappingURL=notify-recipient.d.ts.map
@@ -0,0 +1,11 @@
1
+ /** Canonical recipients accepted by the notify DM wire contract. */
2
+ export const RECIPIENT_UID_PATTERN = /^(prs|agt)_[A-Za-z0-9_-]+$/;
3
+ export const AGENT_UID_PATTERN = /^agt_[A-Za-z0-9_-]+$/;
4
+ export const EMAIL_PATTERN = /^[^\s]+@[^\s]+$/;
5
+ export function isRecipientUid(value) {
6
+ return RECIPIENT_UID_PATTERN.test(value.trim());
7
+ }
8
+ export function isAgentUid(value) {
9
+ return AGENT_UID_PATTERN.test(value.trim());
10
+ }
11
+ //# sourceMappingURL=notify-recipient.js.map
@@ -124,8 +124,8 @@ export interface ReportAdoptDependencies {
124
124
  patch(report: ChannelReport, patch: ReportPatch): Promise<ChannelReport>;
125
125
  }
126
126
  export declare class ReportPublishError extends Error {
127
- readonly code: "already-running" | "source-invalid" | "deploy-failed" | "job-failed";
128
- constructor(message: string, code?: "already-running" | "source-invalid" | "deploy-failed" | "job-failed");
127
+ readonly code: "already-running" | "source-invalid" | "deploy-failed" | "job-failed" | "revision-conflict";
128
+ constructor(message: string, code?: "already-running" | "source-invalid" | "deploy-failed" | "job-failed" | "revision-conflict");
129
129
  }
130
130
  /** A deliberately boring, token-safe failure reason stored on the report. */
131
131
  export declare function plainFailureReason(error: unknown): string;
@@ -41,7 +41,7 @@ export class ReportPublishError extends Error {
41
41
  /** A deliberately boring, token-safe failure reason stored on the report. */
42
42
  export function plainFailureReason(error) {
43
43
  if (error instanceof ReportPublishError) {
44
- if (error.code === "source-invalid" || error.code === "job-failed")
44
+ if (error.code === "source-invalid" || error.code === "job-failed" || error.code === "revision-conflict")
45
45
  return error.message.slice(0, 240);
46
46
  if (error.code === "already-running")
47
47
  return "already running";
@@ -264,9 +264,10 @@ export async function adoptReport(report, deps) {
264
264
  export async function publishReport(report, directory, draft, deps) {
265
265
  const startedAt = deps.now();
266
266
  let locked = false;
267
+ let current = report;
267
268
  try {
268
269
  try {
269
- await deps.patch(report, { lastRun: { at: startedAt, status: "running" } });
270
+ current = await deps.patch(current, { lastRun: { at: startedAt, status: "running" } });
270
271
  locked = true;
271
272
  }
272
273
  catch (error) {
@@ -276,9 +277,9 @@ export async function publishReport(report, directory, draft, deps) {
276
277
  }
277
278
  const source = loadReportSource(directory);
278
279
  const deployment = await deps.deploy({
279
- slug: reportDeploySlug(report, draft),
280
+ slug: reportDeploySlug(current, draft),
280
281
  files: source.files,
281
- access: defaultAccessPolicy(report),
282
+ access: defaultAccessPolicy(current),
282
283
  });
283
284
  const completedAt = deps.now();
284
285
  const patch = {
@@ -295,13 +296,13 @@ export async function publishReport(report, directory, draft, deps) {
295
296
  patch.url = deployment.url;
296
297
  patch.deployAppId = deployment.appId;
297
298
  }
298
- return await deps.patch(report, patch);
299
+ return await deps.patch(current, patch);
299
300
  }
300
301
  catch (error) {
301
302
  if (locked) {
302
303
  const reason = plainFailureReason(error);
303
304
  try {
304
- await deps.patch(report, {
305
+ await deps.patch(current, {
305
306
  lastRun: { at: deps.now(), status: "failed", reason },
306
307
  });
307
308
  }
@@ -312,8 +313,8 @@ export async function publishReport(report, directory, draft, deps) {
312
313
  const notice = ownerFailureNotice({
313
314
  code: error instanceof ReportPublishError ? error.code : undefined,
314
315
  reason,
315
- reportUrl: report.url,
316
- ownerPersonUid: report.createdBy,
316
+ reportUrl: current.url,
317
+ ownerPersonUid: current.createdBy,
317
318
  });
318
319
  if (notice && deps.notifyOwner) {
319
320
  try {
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.143.0",
4
4
  "description": "HQ by Indigo management CLI \u2014 modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {