@pleri/olam-cli 0.1.167 → 0.1.168

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 (38) hide show
  1. package/dist/commands/plans.d.ts +3 -0
  2. package/dist/commands/plans.d.ts.map +1 -0
  3. package/dist/commands/plans.js +211 -0
  4. package/dist/commands/plans.js.map +1 -0
  5. package/dist/commands/setup.d.ts +16 -0
  6. package/dist/commands/setup.d.ts.map +1 -1
  7. package/dist/commands/setup.js +70 -13
  8. package/dist/commands/setup.js.map +1 -1
  9. package/dist/commands/skills-source.d.ts +24 -0
  10. package/dist/commands/skills-source.d.ts.map +1 -1
  11. package/dist/commands/skills-source.js +169 -15
  12. package/dist/commands/skills-source.js.map +1 -1
  13. package/dist/commands/skills.d.ts +21 -0
  14. package/dist/commands/skills.d.ts.map +1 -1
  15. package/dist/commands/skills.js +44 -0
  16. package/dist/commands/skills.js.map +1 -1
  17. package/dist/image-digests.json +8 -8
  18. package/dist/index.js +1877 -1166
  19. package/dist/index.js.map +1 -1
  20. package/dist/lib/bootstrap-kubernetes.d.ts.map +1 -1
  21. package/dist/lib/bootstrap-kubernetes.js +16 -2
  22. package/dist/lib/bootstrap-kubernetes.js.map +1 -1
  23. package/dist/lib/plans-client.d.ts +69 -0
  24. package/dist/lib/plans-client.d.ts.map +1 -0
  25. package/dist/lib/plans-client.js +137 -0
  26. package/dist/lib/plans-client.js.map +1 -0
  27. package/dist/mcp-server.js +269 -32
  28. package/hermes-bundle/version.json +1 -1
  29. package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
  30. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  31. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  32. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  33. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  34. package/host-cp/src/halt-detect.mjs +43 -0
  35. package/host-cp/src/panic-counter.mjs +94 -0
  36. package/host-cp/src/plan-chat-service.mjs +12 -1
  37. package/host-cp/src/server.mjs +75 -0
  38. package/package.json +1 -1
@@ -11894,16 +11894,42 @@ var init_loader = __esm({
11894
11894
  }
11895
11895
  });
11896
11896
 
11897
+ // ../core/dist/skill-sources/source-config-schema.js
11898
+ var PREFIX_PATTERN, SourceConfigSchema, SourceConfigSnapshotSchema;
11899
+ var init_source_config_schema = __esm({
11900
+ "../core/dist/skill-sources/source-config-schema.js"() {
11901
+ "use strict";
11902
+ init_v3();
11903
+ PREFIX_PATTERN = /^[a-z0-9][a-z0-9_-]{0,38}$/;
11904
+ SourceConfigSchema = external_exports.object({
11905
+ /**
11906
+ * Source's RECOMMENDED rename prefix. Operators inherit this when their
11907
+ * `~/.olam/config.json` has no explicit `prefix` override. Same regex
11908
+ * shape as operator-side `SkillSourceSchema.prefix`.
11909
+ */
11910
+ prefix: external_exports.string().regex(PREFIX_PATTERN, "source-config prefix must be ASCII lowercase + digits + dash/underscore (1-39 chars, no leading/trailing dash)").optional(),
11911
+ /**
11912
+ * Source's RECOMMENDED prefix scope. Same enum as operator-side
11913
+ * `SkillSourceSchema.prefixScope`. Operators inherit this when their
11914
+ * `~/.olam/config.json` has no explicit `prefixScope` override.
11915
+ */
11916
+ prefixScope: external_exports.array(external_exports.enum(["skill", "agent"])).optional()
11917
+ }).strict();
11918
+ SourceConfigSnapshotSchema = SourceConfigSchema;
11919
+ }
11920
+ });
11921
+
11897
11922
  // ../core/dist/skill-sources/schema.js
11898
- var SKILL_SOURCE_ID_LENGTH, NAME_PATTERN, URL_PATTERN, PREFIX_PATTERN, SkillSourceSchema;
11923
+ var SKILL_SOURCE_ID_LENGTH, NAME_PATTERN, URL_PATTERN, PREFIX_PATTERN2, SkillSourceSchema;
11899
11924
  var init_schema3 = __esm({
11900
11925
  "../core/dist/skill-sources/schema.js"() {
11901
11926
  "use strict";
11902
11927
  init_v3();
11928
+ init_source_config_schema();
11903
11929
  SKILL_SOURCE_ID_LENGTH = 12;
11904
11930
  NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
11905
11931
  URL_PATTERN = /^(?:https?:\/\/|git@|ssh:\/\/|file:\/\/|\/).+/;
11906
- PREFIX_PATTERN = /^[a-z0-9][a-z0-9_-]{0,38}$/;
11932
+ PREFIX_PATTERN2 = /^[a-z0-9][a-z0-9_-]{0,38}$/;
11907
11933
  SkillSourceSchema = external_exports.object({
11908
11934
  id: external_exports.string().length(SKILL_SOURCE_ID_LENGTH, `skill-source id must be exactly ${SKILL_SOURCE_ID_LENGTH} chars (sha256-of-url prefix)`).regex(/^[a-f0-9]+$/, "skill-source id must be lowercase hex"),
11909
11935
  name: external_exports.string().regex(NAME_PATTERN, "skill-source name must be ASCII lowercase + digits + dash (1-64 chars, no leading/trailing dash)"),
@@ -11920,7 +11946,7 @@ var init_schema3 = __esm({
11920
11946
  * use canonical names; `olam flywheel migrate-overlays --push` enforces
11921
11947
  * this via the reverse validator.
11922
11948
  */
11923
- prefix: external_exports.string().regex(PREFIX_PATTERN, "skill-source prefix must be ASCII lowercase + digits + dash/underscore (1-39 chars, no leading/trailing dash)").optional(),
11949
+ prefix: external_exports.string().regex(PREFIX_PATTERN2, "skill-source prefix must be ASCII lowercase + digits + dash/underscore (1-39 chars, no leading/trailing dash)").optional(),
11924
11950
  /**
11925
11951
  * Which artifact kinds get renamed when `prefix` is set. Optional; defaults
11926
11952
  * to `['skill', 'agent']` for back-compat with the original Phase A semantic
@@ -11932,7 +11958,17 @@ var init_schema3 = __esm({
11932
11958
  *
11933
11959
  * NOT applicable when `prefix` is undefined.
11934
11960
  */
11935
- prefixScope: external_exports.array(external_exports.enum(["skill", "agent"])).optional()
11961
+ prefixScope: external_exports.array(external_exports.enum(["skill", "agent"])).optional(),
11962
+ /**
11963
+ * Snapshot of the LAST source-config.yaml content this operator saw +
11964
+ * consented to (ADR-021). Trust-gate state: when the live source-config
11965
+ * differs from this snapshot, sync halts with a consent prompt instead
11966
+ * of silently rebranding. Snapshot is updated on accept; persists across
11967
+ * syncs. When undefined: operator has never seen a source-config from this
11968
+ * source (first-sync flow applies). Field shape mirrors SourceConfigSchema
11969
+ * for round-trip simplicity.
11970
+ */
11971
+ lastSeenSourcePrefix: SourceConfigSnapshotSchema.optional()
11936
11972
  });
11937
11973
  }
11938
11974
  });
@@ -12461,7 +12497,9 @@ var init_trust_audit_log = __esm({
12461
12497
  "meta-hook-stripped",
12462
12498
  "setup-skill-source-picked",
12463
12499
  "setup-project-sweep-completed",
12464
- "prefix-collision"
12500
+ "prefix-collision",
12501
+ "source-prefix-adopted",
12502
+ "source-prefix-changed"
12465
12503
  ]);
12466
12504
  TrustMethodSchema = external_exports.enum(["flag", "interactive", "auto-reject-tty", "none"]);
12467
12505
  TrustAuditEntrySchema = external_exports.object({
@@ -12575,7 +12613,7 @@ function updateSkillSource(id, patch) {
12575
12613
  }
12576
12614
  }
12577
12615
  if (patch.prefix !== void 0 && patch.prefix !== null) {
12578
- if (!PREFIX_PATTERN2.test(patch.prefix)) {
12616
+ if (!PREFIX_PATTERN3.test(patch.prefix)) {
12579
12617
  throw new Error(`prefix must match /^[a-z0-9][a-z0-9_-]{0,38}$/ \u2014 got "${patch.prefix}"`);
12580
12618
  }
12581
12619
  }
@@ -12595,6 +12633,14 @@ function updateSkillSource(id, patch) {
12595
12633
  } else if (patch.prefixScope !== void 0) {
12596
12634
  working = { ...working, prefixScope: [...patch.prefixScope] };
12597
12635
  }
12636
+ if (patch.lastSeenSourcePrefix === null) {
12637
+ const { lastSeenSourcePrefix: _l, ...rest } = working;
12638
+ void _l;
12639
+ working = rest;
12640
+ } else if (patch.lastSeenSourcePrefix !== void 0) {
12641
+ const validated = SourceConfigSnapshotSchema.parse(patch.lastSeenSourcePrefix);
12642
+ working = { ...working, lastSeenSourcePrefix: validated };
12643
+ }
12598
12644
  const updated = {
12599
12645
  ...working,
12600
12646
  ...patch.name !== void 0 ? { name: patch.name } : {},
@@ -12606,14 +12652,15 @@ function updateSkillSource(id, patch) {
12606
12652
  writeGlobalConfig({ ...config2, skillSources: next });
12607
12653
  return updated;
12608
12654
  }
12609
- var PREFIX_PATTERN2;
12655
+ var PREFIX_PATTERN3;
12610
12656
  var init_store2 = __esm({
12611
12657
  "../core/dist/skill-sources/store.js"() {
12612
12658
  "use strict";
12613
12659
  init_store();
12614
12660
  init_schema3();
12615
12661
  init_trust_audit_log();
12616
- PREFIX_PATTERN2 = /^[a-z0-9][a-z0-9_-]{0,38}$/;
12662
+ init_source_config_schema();
12663
+ PREFIX_PATTERN3 = /^[a-z0-9][a-z0-9_-]{0,38}$/;
12617
12664
  }
12618
12665
  });
12619
12666
 
@@ -15060,6 +15107,97 @@ var init_prefix_deploy = __esm({
15060
15107
  }
15061
15108
  });
15062
15109
 
15110
+ // ../core/dist/skill-sync/resolve-source-config.js
15111
+ import { readFileSync as readFileSync29, existsSync as existsSync31 } from "node:fs";
15112
+ import { join as join31 } from "node:path";
15113
+ import { parse as parseYaml4 } from "yaml";
15114
+ function sourceConfigPath(clonePath) {
15115
+ return join31(clonePath, "shared", "source-config.yaml");
15116
+ }
15117
+ function readSourceConfig(clonePath, sourceId) {
15118
+ const path52 = sourceConfigPath(clonePath);
15119
+ if (!existsSync31(path52))
15120
+ return void 0;
15121
+ let raw;
15122
+ try {
15123
+ raw = readFileSync29(path52, "utf-8");
15124
+ } catch (err) {
15125
+ emitMalformedWarning(sourceId, `read failed: ${errToMsg(err)}`);
15126
+ return void 0;
15127
+ }
15128
+ let parsed;
15129
+ try {
15130
+ parsed = parseYaml4(raw);
15131
+ } catch (err) {
15132
+ emitMalformedWarning(sourceId, `YAML parse failed: ${errToMsg(err)}`);
15133
+ return void 0;
15134
+ }
15135
+ const candidate = parsed === null || parsed === void 0 ? {} : parsed;
15136
+ const result = SourceConfigSchema.safeParse(candidate);
15137
+ if (!result.success) {
15138
+ emitMalformedWarning(sourceId, `schema validation failed: ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`);
15139
+ return void 0;
15140
+ }
15141
+ return result.data;
15142
+ }
15143
+ function emitMalformedWarning(sourceId, reason) {
15144
+ const id = sourceId ?? "<unknown source>";
15145
+ process.stderr.write(`[source-config:malformed] ${id}: ${reason}
15146
+ `);
15147
+ }
15148
+ function errToMsg(err) {
15149
+ return err instanceof Error ? err.message : String(err);
15150
+ }
15151
+ function resolveEffectivePrefix(operatorSource, sourceConfig) {
15152
+ const opPrefix = operatorSource.prefix;
15153
+ const opScope = operatorSource.prefixScope;
15154
+ const srcPrefix = sourceConfig?.prefix;
15155
+ const srcScope = sourceConfig?.prefixScope;
15156
+ const effectivePrefix = opPrefix ?? srcPrefix;
15157
+ const effectiveScope = opScope ?? srcScope;
15158
+ const operatorHasAny = opPrefix !== void 0 || opScope !== void 0 && opScope.length > 0;
15159
+ const sourceHasAny = srcPrefix !== void 0 || srcScope !== void 0 && srcScope.length > 0;
15160
+ const origin = operatorHasAny ? "operator" : sourceHasAny ? "source" : "none";
15161
+ const result = { origin };
15162
+ if (effectivePrefix !== void 0)
15163
+ result.prefix = effectivePrefix;
15164
+ if (effectiveScope !== void 0)
15165
+ result.prefixScope = effectiveScope;
15166
+ return result;
15167
+ }
15168
+ function sourceConfigsEqual(a, b) {
15169
+ const normalize = (c) => {
15170
+ if (c === void 0)
15171
+ return {};
15172
+ const out = {};
15173
+ if (c.prefix !== void 0)
15174
+ out.prefix = c.prefix;
15175
+ if (c.prefixScope !== void 0 && c.prefixScope.length > 0) {
15176
+ out.prefixScope = [...c.prefixScope];
15177
+ }
15178
+ return out;
15179
+ };
15180
+ const na = normalize(a);
15181
+ const nb = normalize(b);
15182
+ if (na.prefix !== nb.prefix)
15183
+ return false;
15184
+ const sa = na.prefixScope ?? [];
15185
+ const sb = nb.prefixScope ?? [];
15186
+ if (sa.length !== sb.length)
15187
+ return false;
15188
+ for (let i = 0; i < sa.length; i++) {
15189
+ if (sa[i] !== sb[i])
15190
+ return false;
15191
+ }
15192
+ return true;
15193
+ }
15194
+ var init_resolve_source_config = __esm({
15195
+ "../core/dist/skill-sync/resolve-source-config.js"() {
15196
+ "use strict";
15197
+ init_source_config_schema();
15198
+ }
15199
+ });
15200
+
15063
15201
  // ../core/dist/skill-sync/engine.js
15064
15202
  import * as fs31 from "node:fs";
15065
15203
  import * as os18 from "node:os";
@@ -15120,8 +15258,95 @@ async function syncSkills(opts = {}) {
15120
15258
  const memberOverlaysEnabled = process.env["OLAM_MEMBER_OVERLAYS"] === "1";
15121
15259
  const baseArtifacts = projectFilteredArtifacts.filter((a) => a.kind !== "overlay");
15122
15260
  const overlayArtifacts = memberOverlaysEnabled ? projectFilteredArtifacts.filter((a) => a.kind === "overlay") : [];
15123
- const sourcePrefixMap = buildSourcePrefixMap(sources);
15124
- const hasPrefixRewrites = sources.some((s) => s.prefix !== void 0 && s.prefix.length > 0);
15261
+ const effectiveSources = sources.map((s) => {
15262
+ const clonePath = skillSourceClonePath(s.id);
15263
+ const sourceConfig = fs31.existsSync(clonePath) ? readSourceConfig(clonePath, s.id) : void 0;
15264
+ const eff = resolveEffectivePrefix(s, sourceConfig);
15265
+ const entry = {
15266
+ id: s.id,
15267
+ origin: eff.origin,
15268
+ sourceConfig
15269
+ };
15270
+ if (eff.prefix !== void 0)
15271
+ entry.prefix = eff.prefix;
15272
+ if (eff.prefixScope !== void 0)
15273
+ entry.prefixScope = eff.prefixScope;
15274
+ return entry;
15275
+ });
15276
+ const sourcePrefixGateOutcomes = [];
15277
+ for (const eff of effectiveSources) {
15278
+ if (eff.sourceConfig === void 0) {
15279
+ sourcePrefixGateOutcomes.push({ sourceId: eff.id, outcome: "no-source-config" });
15280
+ continue;
15281
+ }
15282
+ if (eff.origin === "operator") {
15283
+ sourcePrefixGateOutcomes.push({ sourceId: eff.id, outcome: "no-change" });
15284
+ continue;
15285
+ }
15286
+ const operatorSource = sources.find((s) => s.id === eff.id);
15287
+ const lastSeen = operatorSource?.lastSeenSourcePrefix;
15288
+ const sameAsLastSeen = sourceConfigsEqual(lastSeen, eff.sourceConfig);
15289
+ if (sameAsLastSeen) {
15290
+ sourcePrefixGateOutcomes.push({ sourceId: eff.id, outcome: "no-change" });
15291
+ continue;
15292
+ }
15293
+ const kind = lastSeen === void 0 ? "first-time" : "changed";
15294
+ const flagGrant = kind === "first-time" && opts.autoAcceptSourcePrefix === true || kind === "changed" && opts.acceptSourcePrefixChanges === true;
15295
+ let consented = flagGrant;
15296
+ if (!consented && opts.sourcePrefixPrompt !== void 0) {
15297
+ try {
15298
+ const promptInput = {
15299
+ sourceName: operatorSource?.name ?? eff.id,
15300
+ sourceId: eff.id,
15301
+ newConfig: eff.sourceConfig,
15302
+ kind
15303
+ };
15304
+ if (lastSeen !== void 0)
15305
+ promptInput.priorConfig = lastSeen;
15306
+ consented = await opts.sourcePrefixPrompt(promptInput);
15307
+ } catch {
15308
+ consented = false;
15309
+ }
15310
+ }
15311
+ if (consented) {
15312
+ if (!opts.dryRun) {
15313
+ try {
15314
+ updateSkillSource(eff.id, { lastSeenSourcePrefix: eff.sourceConfig });
15315
+ appendTrustAudit({
15316
+ gitUrl: `internal:source-prefix-${kind === "first-time" ? "adopted" : "changed"}`,
15317
+ action: kind === "first-time" ? "source-prefix-adopted" : "source-prefix-changed",
15318
+ trustMethod: flagGrant ? "flag" : "interactive",
15319
+ sourceId: eff.id,
15320
+ note: kind === "first-time" ? `snapshot=${JSON.stringify(eff.sourceConfig)}` : `prior=${JSON.stringify(lastSeen ?? {})}; new=${JSON.stringify(eff.sourceConfig)}`
15321
+ });
15322
+ } catch {
15323
+ }
15324
+ }
15325
+ sourcePrefixGateOutcomes.push({
15326
+ sourceId: eff.id,
15327
+ outcome: kind === "first-time" ? "adopted" : "changed"
15328
+ });
15329
+ } else {
15330
+ delete eff.prefix;
15331
+ delete eff.prefixScope;
15332
+ eff.origin = "none";
15333
+ const isNonTty = opts.sourcePrefixPrompt === void 0;
15334
+ sourcePrefixGateOutcomes.push({
15335
+ sourceId: eff.id,
15336
+ outcome: isNonTty ? "skipped-non-tty" : "rejected"
15337
+ });
15338
+ if (isNonTty) {
15339
+ process.stderr.write(`[source-prefix:skipped] ${operatorSource?.name ?? eff.id}: source-config has prefix-suggestion '${eff.sourceConfig.prefix ?? "<empty>"}' but no consent (non-TTY without --auto-accept-source-prefix). Skipping for this sync; canonical names deployed.
15340
+ `);
15341
+ }
15342
+ }
15343
+ }
15344
+ const sourcePrefixMap = buildSourcePrefixMap(effectiveSources);
15345
+ const hasPrefixRewrites = effectiveSources.some((s) => s.prefix !== void 0 && s.prefix.length > 0);
15346
+ const effectivePrefixOrigins = {};
15347
+ for (const s of effectiveSources) {
15348
+ effectivePrefixOrigins[s.id] = s.origin;
15349
+ }
15125
15350
  const willMutateManagedDir = !opts.dryRun && (memberOverlaysEnabled && overlayArtifacts.length > 0 || hasPrefixRewrites);
15126
15351
  if (willMutateManagedDir) {
15127
15352
  const claude = claudeDir();
@@ -15170,7 +15395,7 @@ async function syncSkills(opts = {}) {
15170
15395
  const permissionFiles = projectFilteredArtifacts.filter((a) => a.kind === "permission").map((a) => a.sourcePath);
15171
15396
  const claudeDirForRewrites = claudeDir();
15172
15397
  const prefixRewriteResult = applyPrefixRewrites(baseArtifacts, sourcePrefixMap, claudeDirForRewrites, opts.dryRun === true);
15173
- const prefixCollisions = detectPrefixCollisions(sources);
15398
+ const prefixCollisions = detectPrefixCollisions(effectiveSources);
15174
15399
  if (!opts.dryRun) {
15175
15400
  for (const collision of prefixCollisions) {
15176
15401
  try {
@@ -15197,7 +15422,9 @@ async function syncSkills(opts = {}) {
15197
15422
  metaHooks: void 0,
15198
15423
  perSource,
15199
15424
  prefixRewrites: prefixRewriteResult.entries,
15200
- prefixCollisions
15425
+ prefixCollisions,
15426
+ effectivePrefixOrigins,
15427
+ sourcePrefixGateOutcomes
15201
15428
  };
15202
15429
  if (opts.dryRun) {
15203
15430
  summary.collisions = detectCollisions(baseArtifacts).collisions;
@@ -15329,6 +15556,8 @@ var init_engine = __esm({
15329
15556
  init_markdown_merger();
15330
15557
  init_managed_merge();
15331
15558
  init_prefix_deploy();
15559
+ init_resolve_source_config();
15560
+ init_store2();
15332
15561
  }
15333
15562
  });
15334
15563
 
@@ -15841,6 +16070,8 @@ __export(skill_sources_exports, {
15841
16070
  SkillOverrideSchema: () => SkillOverrideSchema,
15842
16071
  SkillSourceGitError: () => SkillSourceGitError,
15843
16072
  SkillSourceSchema: () => SkillSourceSchema,
16073
+ SourceConfigSchema: () => SourceConfigSchema,
16074
+ SourceConfigSnapshotSchema: () => SourceConfigSnapshotSchema,
15844
16075
  TrustActionSchema: () => TrustActionSchema,
15845
16076
  TrustAuditEntrySchema: () => TrustAuditEntrySchema,
15846
16077
  TrustMethodSchema: () => TrustMethodSchema,
@@ -15880,12 +16111,14 @@ __export(skill_sources_exports, {
15880
16111
  pullSkillSource: () => pullSkillSource,
15881
16112
  readLatestMigrationSnapshot: () => readLatestMigrationSnapshot,
15882
16113
  readMigrationSnapshotFromPath: () => readMigrationSnapshotFromPath,
16114
+ readSourceConfig: () => readSourceConfig,
15883
16115
  readTrustAuditLog: () => readTrustAuditLog,
15884
16116
  redactUrl: () => redactUrl2,
15885
16117
  removeSkillSource: () => removeSkillSource,
15886
16118
  removeSkillSourceClone: () => removeSkillSourceClone,
15887
16119
  reorderSkillSource: () => reorderSkillSource,
15888
16120
  resolveAtlasUser: () => resolveAtlasUser,
16121
+ resolveEffectivePrefix: () => resolveEffectivePrefix,
15889
16122
  resolveSourceArtifacts: () => resolveSourceArtifacts,
15890
16123
  resolveSubscriptions: () => resolveSubscriptions,
15891
16124
  restoreCloneToBranchHead: () => restoreCloneToBranchHead,
@@ -15896,6 +16129,8 @@ __export(skill_sources_exports, {
15896
16129
  skillSourcesAuditLogPath: () => skillSourcesAuditLogPath,
15897
16130
  skillSourcesRootDir: () => skillSourcesRootDir,
15898
16131
  skillsHookSettingsPathFor: () => settingsPathFor,
16132
+ sourceConfigPath: () => sourceConfigPath,
16133
+ sourceConfigsEqual: () => sourceConfigsEqual,
15899
16134
  syncSkills: () => syncSkills,
15900
16135
  uninstallSkillsHookFromFile: () => uninstallSkillsHookFromFile,
15901
16136
  updateSkillSource: () => updateSkillSource,
@@ -15912,6 +16147,8 @@ var init_skill_sources = __esm({
15912
16147
  init_hook_install();
15913
16148
  init_migration_snapshot();
15914
16149
  init_engine();
16150
+ init_resolve_source_config();
16151
+ init_source_config_schema();
15915
16152
  init_file_lock();
15916
16153
  init_schema5();
15917
16154
  init_per_project_override();
@@ -36489,7 +36726,7 @@ import * as path41 from "node:path";
36489
36726
 
36490
36727
  // ../core/dist/kg/storage-paths.js
36491
36728
  import { homedir as homedir24 } from "node:os";
36492
- import { join as join40, resolve as resolve9 } from "node:path";
36729
+ import { join as join41, resolve as resolve9 } from "node:path";
36493
36730
 
36494
36731
  // ../core/dist/world/workspace-name.js
36495
36732
  var InvalidWorkspaceNameError = class extends Error {
@@ -36510,13 +36747,13 @@ function validateWorkspaceName(name) {
36510
36747
 
36511
36748
  // ../core/dist/kg/storage-paths.js
36512
36749
  function olamHome() {
36513
- return process.env.OLAM_HOME ?? join40(homedir24(), ".olam");
36750
+ return process.env.OLAM_HOME ?? join41(homedir24(), ".olam");
36514
36751
  }
36515
36752
  function kgRoot() {
36516
- return join40(olamHome(), "kg");
36753
+ return join41(olamHome(), "kg");
36517
36754
  }
36518
36755
  function worldsRoot() {
36519
- return join40(olamHome(), "worlds");
36756
+ return join41(olamHome(), "worlds");
36520
36757
  }
36521
36758
  function assertWithinPrefix(path52, prefix, label) {
36522
36759
  if (!path52.startsWith(prefix + "/")) {
@@ -36526,7 +36763,7 @@ function assertWithinPrefix(path52, prefix, label) {
36526
36763
  function kgPristinePath(workspace) {
36527
36764
  validateWorkspaceName(workspace);
36528
36765
  const root = kgRoot();
36529
- const path52 = resolve9(join40(root, workspace));
36766
+ const path52 = resolve9(join41(root, workspace));
36530
36767
  assertWithinPrefix(path52, root, "kgPristinePath");
36531
36768
  return path52;
36532
36769
  }
@@ -36804,7 +37041,7 @@ function extractStderr(err) {
36804
37041
  function carryUncommittedEdits(repos, workspacePath, deps = {}) {
36805
37042
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync6(cmd, args, opts));
36806
37043
  const homedir30 = deps.homedir ?? (() => os26.homedir());
36807
- const existsSync47 = deps.existsSync ?? ((p) => fs42.existsSync(p));
37044
+ const existsSync48 = deps.existsSync ?? ((p) => fs42.existsSync(p));
36808
37045
  const copyFileSync9 = deps.copyFileSync ?? ((src, dest) => fs42.copyFileSync(src, dest));
36809
37046
  const mkdirSync30 = deps.mkdirSync ?? ((dirPath, opts) => {
36810
37047
  fs42.mkdirSync(dirPath, opts);
@@ -36815,9 +37052,9 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
36815
37052
  continue;
36816
37053
  const repoPath = expandHome2(repo.path, homedir30);
36817
37054
  const worktreePath = path42.join(workspacePath, repo.name);
36818
- if (!existsSync47(repoPath))
37055
+ if (!existsSync48(repoPath))
36819
37056
  continue;
36820
- if (!existsSync47(worktreePath)) {
37057
+ if (!existsSync48(worktreePath)) {
36821
37058
  console.warn(`[carry] ${repo.name}: world worktree ${worktreePath} missing; skipping carry for this repo`);
36822
37059
  continue;
36823
37060
  }
@@ -36877,7 +37114,7 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
36877
37114
  for (const rel of plan.diff.untracked) {
36878
37115
  const src = path42.join(plan.repoPath, rel);
36879
37116
  const dest = path42.join(plan.worktreePath, rel);
36880
- if (!existsSync47(src))
37117
+ if (!existsSync48(src))
36881
37118
  continue;
36882
37119
  try {
36883
37120
  mkdirSync30(path42.dirname(dest), { recursive: true });
@@ -38139,14 +38376,14 @@ function enrichReposWithManifests(repos, workspacePath) {
38139
38376
  // ../core/dist/policies/loader.js
38140
38377
  import * as fs45 from "node:fs";
38141
38378
  import * as path46 from "node:path";
38142
- import { parse as parseYaml4 } from "yaml";
38379
+ import { parse as parseYaml5 } from "yaml";
38143
38380
  function parseFrontmatter2(content) {
38144
38381
  const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/m.exec(content);
38145
38382
  if (!match)
38146
38383
  return null;
38147
38384
  const [, yamlText = "", body = ""] = match;
38148
38385
  try {
38149
- const frontmatter = parseYaml4(yamlText);
38386
+ const frontmatter = parseYaml5(yamlText);
38150
38387
  return { frontmatter, body };
38151
38388
  } catch {
38152
38389
  return null;
@@ -41447,8 +41684,8 @@ var PleriClient = class {
41447
41684
  };
41448
41685
 
41449
41686
  // ../mcp-server/src/env-loader.ts
41450
- import { readFileSync as readFileSync38, existsSync as existsSync46, statSync as statSync14 } from "node:fs";
41451
- import { join as join51, dirname as dirname29, resolve as resolve13 } from "node:path";
41687
+ import { readFileSync as readFileSync39, existsSync as existsSync47, statSync as statSync14 } from "node:fs";
41688
+ import { join as join52, dirname as dirname29, resolve as resolve13 } from "node:path";
41452
41689
  var PROJECT_MARKERS = [
41453
41690
  ".olam/config.yaml",
41454
41691
  ".olam/config.yml",
@@ -41460,12 +41697,12 @@ function findProjectRoot2(startDir) {
41460
41697
  const root = resolve13("/");
41461
41698
  while (true) {
41462
41699
  for (const marker of PROJECT_MARKERS) {
41463
- if (existsSync46(join51(dir, marker))) return dir;
41700
+ if (existsSync47(join52(dir, marker))) return dir;
41464
41701
  }
41465
- const pkg = join51(dir, "package.json");
41466
- if (existsSync46(pkg)) {
41702
+ const pkg = join52(dir, "package.json");
41703
+ if (existsSync47(pkg)) {
41467
41704
  try {
41468
- const json = JSON.parse(readFileSync38(pkg, "utf8"));
41705
+ const json = JSON.parse(readFileSync39(pkg, "utf8"));
41469
41706
  const isOlamWorkspace = typeof json.name === "string" && json.name.startsWith("@olam/");
41470
41707
  const hasOlamDep = json.dependencies && Object.keys(json.dependencies).some((k) => k.startsWith("@olam/")) || json.devDependencies && Object.keys(json.devDependencies).some((k) => k.startsWith("@olam/"));
41471
41708
  if (isOlamWorkspace || hasOlamDep) return dir;
@@ -41479,7 +41716,7 @@ function findProjectRoot2(startDir) {
41479
41716
  }
41480
41717
  function parseEnvFile(path52) {
41481
41718
  const out = {};
41482
- const raw = readFileSync38(path52, "utf8");
41719
+ const raw = readFileSync39(path52, "utf8");
41483
41720
  for (const line of raw.split(/\r?\n/)) {
41484
41721
  const trimmed = line.trim();
41485
41722
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -41502,8 +41739,8 @@ function loadProjectEnv(startDir = process.cwd()) {
41502
41739
  const filesRead = [];
41503
41740
  const merged = {};
41504
41741
  for (const name of [".env", ".env.local"]) {
41505
- const p = join51(root, name);
41506
- if (existsSync46(p) && statSync14(p).isFile()) {
41742
+ const p = join52(root, name);
41743
+ if (existsSync47(p) && statSync14(p).isFile()) {
41507
41744
  Object.assign(merged, parseEnvFile(p));
41508
41745
  filesRead.push(p);
41509
41746
  }
@@ -1,4 +1,4 @@
1
1
  {
2
- "bundledAt": "2026-05-23T04:15:22.463Z",
2
+ "bundledAt": "2026-05-23T09:39:55.721Z",
3
3
  "kgFirstSha": "29a9ccce1b115d049e375c4a90eb5cf7c123e610e2d0590270a4db2cdbc64a28"
4
4
  }
@@ -111,7 +111,7 @@ spec:
111
111
  # k3d), started by `olam upgrade` Step 0.7 — not inside this Pod.
112
112
  containers:
113
113
  - name: olam-host-cp
114
- image: ghcr.io/pleri/olam-host-cp@sha256:b89b6e518d852c1a4f2bcd4cf08f9a46c62d71de18ceabc993b6f8cac080fb72
114
+ image: ghcr.io/pleri/olam-host-cp@sha256:766e07263fcf7e765c3689a7b8d40c47754b4ab90c697710843265a7fc84969a
115
115
  imagePullPolicy: IfNotPresent
116
116
  securityContext:
117
117
  runAsNonRoot: true
@@ -70,7 +70,7 @@ spec:
70
70
  mountPath: /data
71
71
  containers:
72
72
  - name: olam-auth-service
73
- image: ghcr.io/pleri/olam-auth@sha256:86a8921ba22de43122592904e3f853e33e29ee3e30213d550ae9315a47e2ad2c
73
+ image: ghcr.io/pleri/olam-auth@sha256:c6d163f7ac5fe1ca4652ed34afb1d8555c6f61d06398db767db65fee0944b209
74
74
  imagePullPolicy: IfNotPresent
75
75
  securityContext:
76
76
  runAsNonRoot: true
@@ -61,7 +61,7 @@ spec:
61
61
  mountPath: /data
62
62
  containers:
63
63
  - name: olam-kg-service
64
- image: ghcr.io/pleri/olam-kg-service@sha256:f5e10089a5f87bf772f52fd62693639ab8db244a17586b654da9db022a7ff266
64
+ image: ghcr.io/pleri/olam-kg-service@sha256:77fd9b19d87c6f4cba4d33d76ff476dd7677f78725f3bf75a9076009e17355cc
65
65
  imagePullPolicy: IfNotPresent
66
66
  securityContext:
67
67
  runAsNonRoot: true
@@ -68,7 +68,7 @@ spec:
68
68
  mountPath: /data
69
69
  containers:
70
70
  - name: olam-mcp-auth-service
71
- image: ghcr.io/pleri/olam-mcp-auth@sha256:01d663eda72772be77123c121b3d4cb7b8364b134fca7edcf21cb185ad0273ba
71
+ image: ghcr.io/pleri/olam-mcp-auth@sha256:cb5b1d7caece5bca4a4723eb20522a748cd48001aa94a7e7ec106d29bd2142b0
72
72
  imagePullPolicy: IfNotPresent
73
73
  securityContext:
74
74
  runAsNonRoot: true
@@ -70,7 +70,7 @@ spec:
70
70
  # bootstrap-placeholder comment + run `npm run refresh:manifest-digests`
71
71
  # once ghcr.io/pleri/olam-memory-service has a real published digest.
72
72
  # bootstrap-placeholder: pre-publish; refresh after first release
73
- image: ghcr.io/pleri/olam-memory-service@sha256:6a895bfc815daadfeb1b62ae5b603659317f617300c3cccbe7b2e4adc638b56d
73
+ image: ghcr.io/pleri/olam-memory-service@sha256:38b2c1f36e49183f5d36999c6519533a8402f3e784109ede8ad7f6e1a205c195
74
74
  imagePullPolicy: IfNotPresent
75
75
  securityContext:
76
76
  runAsNonRoot: true
@@ -0,0 +1,43 @@
1
+ // W4 — Halt-shape detection for the host-cp chunk-write proxy.
2
+ //
3
+ // When plan-DO's dispatchPlanningAgent (W1) trips a guardrail, it
4
+ // emits a chunk with chunk_type='goal_mode_assumption' and content
5
+ // matching: `[assumption: <cap>-tripped — spent $X.XXXX of $Y]` (or
6
+ // similar shape per GuardrailState.haltChunkText()).
7
+ //
8
+ // host-cp's /api/plan-chat proxy passes the chunk through to the
9
+ // chunks substrate AND, if it detects a halt-shaped chunk, broadcasts
10
+ // a typed `plan.halted` event on host-stream so the SPA's
11
+ // PlanHaltBanner subscriber fires.
12
+ //
13
+ // Extracted as a pure fn so it can be unit-tested without booting
14
+ // the host-cp server.
15
+
16
+ const HALT_RE =
17
+ /^\[assumption:\s*(usd|turns|tool_calls|wall_clock)-tripped(?:\s*—\s*spent\s*\$([0-9.]+))?/;
18
+
19
+ /**
20
+ * Detect a halt-shaped chunk + extract its components.
21
+ *
22
+ * Returns null when:
23
+ * - chunk is null/undefined
24
+ * - chunk_type isn't 'goal_mode_assumption'
25
+ * - content doesn't match the halt regex
26
+ *
27
+ * Returns the parsed payload otherwise. Caller broadcasts this as
28
+ * the `plan.halted` event payload.
29
+ */
30
+ export function detectHaltChunk(chunk) {
31
+ if (!chunk || typeof chunk !== 'object') return null;
32
+ if (chunk.chunk_type !== 'goal_mode_assumption') return null;
33
+ if (typeof chunk.chunk !== 'string') return null;
34
+ const m = chunk.chunk.match(HALT_RE);
35
+ if (!m) return null;
36
+ return {
37
+ plan_id: chunk.session_id ?? 'unknown',
38
+ operator_id: chunk.operator_id ?? 'unknown',
39
+ halt_reason: m[1],
40
+ usd_spent_so_far: m[2] ? Number.parseFloat(m[2]) : undefined,
41
+ halted_at: Date.now(),
42
+ };
43
+ }