@kl-c/matrixos 0.1.39 → 0.1.49

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.
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Per-agent token budget (cost guardrails).
3
+ *
4
+ * Tracks cumulative tokens consumed per agent and triggers an action when
5
+ * the configured budget is exceeded. Inspired by Sprint B9 (cost-alerter)
6
+ * but per-agent instead of global.
7
+ *
8
+ * Defaults: tank=50k, morpheus=200k, general=100k, unlimited for others.
9
+ * Action on overrun: warn (log) by default; can be set to "throttle" (block
10
+ * the call) or "throw" (reject the call) via the action field.
11
+ */
12
+ export type BudgetAction = "warn" | "throttle" | "throw";
13
+ export type BudgetConfig = {
14
+ tokens: number;
15
+ action: BudgetAction;
16
+ };
17
+ export declare function setBudget(agent: string, config: BudgetConfig): void;
18
+ export declare function recordTokens(agent: string, tokens: number): BudgetStatus;
19
+ export declare function getUsed(agent: string): number;
20
+ export declare function resetBudget(agent?: string): void;
21
+ export type BudgetStatus = {
22
+ used: number;
23
+ limit: number;
24
+ percent: number;
25
+ action: BudgetAction | null;
26
+ over: boolean;
27
+ };
28
+ /** Convenience: throw if action=throw and budget is over. Returns the status either way. */
29
+ export declare function enforceBudget(agent: string, tokens: number): BudgetStatus;
package/dist/cli/index.js CHANGED
@@ -2145,7 +2145,7 @@ var package_default;
2145
2145
  var init_package = __esm(() => {
2146
2146
  package_default = {
2147
2147
  name: "@kl-c/matrixos",
2148
- version: "0.1.39",
2148
+ version: "0.1.49",
2149
2149
  description: "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
2150
2150
  main: "./dist/index.js",
2151
2151
  types: "dist/index.d.ts",
@@ -82991,7 +82991,7 @@ function ignoreToastError(error51) {
82991
82991
  async function showUpdateAvailableToast(ctx, latestVersion, getToastMessage) {
82992
82992
  await ctx.client.tui.showToast({
82993
82993
  body: {
82994
- title: `OhMyOpenCode ${latestVersion}`,
82994
+ title: `MaTrixOS ${latestVersion}`,
82995
82995
  message: getToastMessage(true, latestVersion),
82996
82996
  variant: "info",
82997
82997
  duration: 8000
@@ -83002,7 +83002,7 @@ async function showUpdateAvailableToast(ctx, latestVersion, getToastMessage) {
83002
83002
  async function showAutoUpdatedToast(ctx, oldVersion, newVersion) {
83003
83003
  await ctx.client.tui.showToast({
83004
83004
  body: {
83005
- title: "OhMyOpenCode Updated!",
83005
+ title: "MaTrixOS Updated!",
83006
83006
  message: `v${oldVersion} \u2192 v${newVersion}
83007
83007
  Restart OpenCode to apply.`,
83008
83008
  variant: "success",
@@ -83328,7 +83328,7 @@ async function showSpinnerToast(ctx, version3, message) {
83328
83328
  const spinner2 = MORPHEUS_SPINNER[i3 % MORPHEUS_SPINNER.length];
83329
83329
  await ctx.client.tui.showToast({
83330
83330
  body: {
83331
- title: `${spinner2} OhMyOpenCode ${version3}`,
83331
+ title: `${spinner2} MaTrixOS ${version3}`,
83332
83332
  message,
83333
83333
  variant: "info",
83334
83334
  duration: frameInterval + 50
@@ -83376,8 +83376,8 @@ Morpheus pilote OpenCode.
83376
83376
  v${latestVersion} disponible. Red\xE9marre pour appliquer.` : `${brand}
83377
83377
  Morpheus pilote OpenCode.`;
83378
83378
  }
83379
- return isUpdate ? `OpenCode is now on Steroids. oMoMoMoMo...
83380
- v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on Steroids. oMoMoMoMo...";
83379
+ return isUpdate ? `OpenCode is now on Steroids. MaTrixOS...
83380
+ v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on Steroids. MaTrixOS...";
83381
83381
  };
83382
83382
  let hasChecked = false;
83383
83383
  let hasScheduled = false;
@@ -117796,7 +117796,7 @@ function executeMigrateCommand(opts, targetPath = "matrixos.jsonc") {
117796
117796
  `;
117797
117797
  fsys.writeFileSync(targetPath, serialized);
117798
117798
  return {
117799
- stdout: `Migrated OMO config '${opts.sourcePath}' \u2192 '${targetPath}'
117799
+ stdout: `Migrated MaTrixOS config '${opts.sourcePath}' \u2192 '${targetPath}'
117800
117800
  ` + `Carried: ${KNOWN_KEYS.filter((k) => (k in target)).join(", ") || "(none)"}
117801
117801
  ` + (ignored.length ? `Ignored (review manually): ${ignored.join(", ")}
117802
117802
  ` : `No ignored keys.
@@ -118581,7 +118581,7 @@ function formatConfigSummary(config) {
118581
118581
  function printHeader(isUpdate) {
118582
118582
  const mode = isUpdate ? "Update" : "Install";
118583
118583
  console.log();
118584
- console.log(import_picocolors.default.bgMagenta(import_picocolors.default.white(` oMoMoMoMo... ${mode} `)));
118584
+ console.log(import_picocolors.default.bgMagenta(import_picocolors.default.white(` MaTrixOS... ${mode} `)));
118585
118585
  console.log();
118586
118586
  }
118587
118587
  function printStep(step, total, message) {
@@ -119315,7 +119315,7 @@ async function runCliInstaller(args, version) {
119315
119315
  if (args.tui) {
119316
119316
  await maybePromptForGitHubStars(config.platform);
119317
119317
  }
119318
- console.log(import_picocolors3.default.dim("oMoMoMoMo... Enjoy!"));
119318
+ console.log(import_picocolors3.default.dim("MaTrixOS... Enjoy!"));
119319
119319
  console.log();
119320
119320
  if (hasOpenCode && (config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
119321
119321
  printBox(`Run ${import_picocolors3.default.cyan("opencode auth login")} and select your provider:
@@ -121239,7 +121239,7 @@ async function runTuiInstaller(args, version) {
121239
121239
  gatewayTelegramToken: null
121240
121240
  };
121241
121241
  const isUpdate = hasOpenCode && detected.isInstalled;
121242
- intro(import_picocolors4.default.bgMagenta(import_picocolors4.default.white(isUpdate ? " oMoMoMoMo... Update " : " oMoMoMoMo... ")));
121242
+ intro(import_picocolors4.default.bgMagenta(import_picocolors4.default.white(isUpdate ? " MaTrixOS... Update " : " MaTrixOS... ")));
121243
121243
  if (isUpdate) {
121244
121244
  const initial = detectedToInitialValues(detected);
121245
121245
  log4.info(`Existing configuration detected: Claude=${initial.claude}, Gemini=${initial.gemini}`);
@@ -121335,7 +121335,7 @@ async function runTuiInstaller(args, version) {
121335
121335
  log4.warn("Make sure GitHub CLI is installed and authenticated.");
121336
121336
  }
121337
121337
  }
121338
- outro(import_picocolors4.default.green("oMoMoMoMo... Enjoy!"));
121338
+ outro(import_picocolors4.default.green("MaTrixOS... Enjoy!"));
121339
121339
  if (config.hasOpenCode && (config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
121340
121340
  const providers = [];
121341
121341
  if (config.hasClaude)
@@ -133980,7 +133980,7 @@ function formatStatusMark(available) {
133980
133980
  }
133981
133981
  function formatHeader() {
133982
133982
  return `
133983
- ${import_picocolors18.default.bgMagenta(import_picocolors18.default.white(" oMoMoMoMo Doctor "))}
133983
+ ${import_picocolors18.default.bgMagenta(import_picocolors18.default.white(" MaTrixOS Doctor "))}
133984
133984
  `;
133985
133985
  }
133986
133986
  function formatIssue(issue2, index) {
@@ -142227,7 +142227,7 @@ function configureRuntimeCommands(program2) {
142227
142227
  });
142228
142228
  process.exit(exitCode);
142229
142229
  });
142230
- program2.command("upstream").description("Upstream sync commands (read-only, NEVER auto-merge)").command("check").description("Fetch recent OMO releases and classify commits (merge | cherry-pick | manual | skip). Human decides.").option("--repo <owner/name>", "Override upstream repo (default: shirofx/MaTrixOS)").option("--token <token>", "GitHub token (default: $GITHUB_TOKEN)").option("--recent <n>", "Limit to N most recent releases", (v) => Number.parseInt(v, 10), 3).option("--json", "Output as JSON").action(async (options) => {
142230
+ program2.command("upstream").description("Upstream sync commands (read-only, NEVER auto-merge)").command("check").description("Fetch recent MaTrixOS releases and classify commits (merge | cherry-pick | manual | skip). Human decides.").option("--repo <owner/name>", "Override upstream repo (default: shirofx/MaTrixOS)").option("--token <token>", "GitHub token (default: $GITHUB_TOKEN)").option("--recent <n>", "Limit to N most recent releases", (v) => Number.parseInt(v, 10), 3).option("--json", "Output as JSON").action(async (options) => {
142231
142231
  const exitCode = await upstreamCheckCli({
142232
142232
  repo: options.repo,
142233
142233
  token: options.token,
@@ -142538,7 +142538,7 @@ program2.command("profile-create <name>").description("Create a new business pro
142538
142538
  process.stdout.write(result.stdout + `
142539
142539
  `);
142540
142540
  });
142541
- program2.command("migrate").description("Import an OMO config into MaTrixOS (scope minimal: known keys)").requiredOption("--from-omo <path>", "Path to the source omo.jsonc").option("--out <path>", "Target config path", "matrixos.jsonc").action(async (options) => {
142541
+ program2.command("migrate").description("Import a MaTrixOS config into MaTrixOS (scope minimal: known keys)").requiredOption("--from-omo <path>", "Path to the source omo.jsonc").option("--out <path>", "Target config path", "matrixos.jsonc").action(async (options) => {
142542
142542
  const { executeMigrateCommand: executeMigrateCommand2 } = await Promise.resolve().then(() => (init_migrate(), exports_migrate));
142543
142543
  const result = executeMigrateCommand2({ sourcePath: options.fromOmo }, options.out ?? "matrixos.jsonc");
142544
142544
  process.stdout.write(result.stdout + `
@@ -2145,7 +2145,7 @@ var package_default;
2145
2145
  var init_package = __esm(() => {
2146
2146
  package_default = {
2147
2147
  name: "@kl-c/matrixos",
2148
- version: "0.1.39",
2148
+ version: "0.1.49",
2149
2149
  description: "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
2150
2150
  main: "./dist/index.js",
2151
2151
  types: "dist/index.d.ts",
@@ -83046,7 +83046,7 @@ function ignoreToastError(error51) {
83046
83046
  async function showUpdateAvailableToast(ctx, latestVersion, getToastMessage) {
83047
83047
  await ctx.client.tui.showToast({
83048
83048
  body: {
83049
- title: `OhMyOpenCode ${latestVersion}`,
83049
+ title: `MaTrixOS ${latestVersion}`,
83050
83050
  message: getToastMessage(true, latestVersion),
83051
83051
  variant: "info",
83052
83052
  duration: 8000
@@ -83057,7 +83057,7 @@ async function showUpdateAvailableToast(ctx, latestVersion, getToastMessage) {
83057
83057
  async function showAutoUpdatedToast(ctx, oldVersion, newVersion) {
83058
83058
  await ctx.client.tui.showToast({
83059
83059
  body: {
83060
- title: "OhMyOpenCode Updated!",
83060
+ title: "MaTrixOS Updated!",
83061
83061
  message: `v${oldVersion} \u2192 v${newVersion}
83062
83062
  Restart OpenCode to apply.`,
83063
83063
  variant: "success",
@@ -83383,7 +83383,7 @@ async function showSpinnerToast(ctx, version3, message) {
83383
83383
  const spinner2 = MORPHEUS_SPINNER[i3 % MORPHEUS_SPINNER.length];
83384
83384
  await ctx.client.tui.showToast({
83385
83385
  body: {
83386
- title: `${spinner2} OhMyOpenCode ${version3}`,
83386
+ title: `${spinner2} MaTrixOS ${version3}`,
83387
83387
  message,
83388
83388
  variant: "info",
83389
83389
  duration: frameInterval + 50
@@ -83431,8 +83431,8 @@ Morpheus pilote OpenCode.
83431
83431
  v${latestVersion} disponible. Red\xE9marre pour appliquer.` : `${brand}
83432
83432
  Morpheus pilote OpenCode.`;
83433
83433
  }
83434
- return isUpdate ? `OpenCode is now on Steroids. oMoMoMoMo...
83435
- v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on Steroids. oMoMoMoMo...";
83434
+ return isUpdate ? `OpenCode is now on Steroids. MaTrixOS...
83435
+ v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on Steroids. MaTrixOS...";
83436
83436
  };
83437
83437
  let hasChecked = false;
83438
83438
  let hasScheduled = false;
@@ -117851,7 +117851,7 @@ function executeMigrateCommand(opts, targetPath = "matrixos.jsonc") {
117851
117851
  `;
117852
117852
  fsys.writeFileSync(targetPath, serialized);
117853
117853
  return {
117854
- stdout: `Migrated OMO config '${opts.sourcePath}' \u2192 '${targetPath}'
117854
+ stdout: `Migrated MaTrixOS config '${opts.sourcePath}' \u2192 '${targetPath}'
117855
117855
  ` + `Carried: ${KNOWN_KEYS.filter((k) => (k in target)).join(", ") || "(none)"}
117856
117856
  ` + (ignored.length ? `Ignored (review manually): ${ignored.join(", ")}
117857
117857
  ` : `No ignored keys.
@@ -118636,7 +118636,7 @@ function formatConfigSummary(config) {
118636
118636
  function printHeader(isUpdate) {
118637
118637
  const mode = isUpdate ? "Update" : "Install";
118638
118638
  console.log();
118639
- console.log(import_picocolors.default.bgMagenta(import_picocolors.default.white(` oMoMoMoMo... ${mode} `)));
118639
+ console.log(import_picocolors.default.bgMagenta(import_picocolors.default.white(` MaTrixOS... ${mode} `)));
118640
118640
  console.log();
118641
118641
  }
118642
118642
  function printStep(step, total, message) {
@@ -119370,7 +119370,7 @@ async function runCliInstaller(args, version) {
119370
119370
  if (args.tui) {
119371
119371
  await maybePromptForGitHubStars(config.platform);
119372
119372
  }
119373
- console.log(import_picocolors3.default.dim("oMoMoMoMo... Enjoy!"));
119373
+ console.log(import_picocolors3.default.dim("MaTrixOS... Enjoy!"));
119374
119374
  console.log();
119375
119375
  if (hasOpenCode && (config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
119376
119376
  printBox(`Run ${import_picocolors3.default.cyan("opencode auth login")} and select your provider:
@@ -121294,7 +121294,7 @@ async function runTuiInstaller(args, version) {
121294
121294
  gatewayTelegramToken: null
121295
121295
  };
121296
121296
  const isUpdate = hasOpenCode && detected.isInstalled;
121297
- intro(import_picocolors4.default.bgMagenta(import_picocolors4.default.white(isUpdate ? " oMoMoMoMo... Update " : " oMoMoMoMo... ")));
121297
+ intro(import_picocolors4.default.bgMagenta(import_picocolors4.default.white(isUpdate ? " MaTrixOS... Update " : " MaTrixOS... ")));
121298
121298
  if (isUpdate) {
121299
121299
  const initial = detectedToInitialValues(detected);
121300
121300
  log4.info(`Existing configuration detected: Claude=${initial.claude}, Gemini=${initial.gemini}`);
@@ -121390,7 +121390,7 @@ async function runTuiInstaller(args, version) {
121390
121390
  log4.warn("Make sure GitHub CLI is installed and authenticated.");
121391
121391
  }
121392
121392
  }
121393
- outro(import_picocolors4.default.green("oMoMoMoMo... Enjoy!"));
121393
+ outro(import_picocolors4.default.green("MaTrixOS... Enjoy!"));
121394
121394
  if (config.hasOpenCode && (config.hasClaude || config.hasGemini || config.hasCopilot) && !args.skipAuth) {
121395
121395
  const providers = [];
121396
121396
  if (config.hasClaude)
@@ -134035,7 +134035,7 @@ function formatStatusMark(available) {
134035
134035
  }
134036
134036
  function formatHeader() {
134037
134037
  return `
134038
- ${import_picocolors18.default.bgMagenta(import_picocolors18.default.white(" oMoMoMoMo Doctor "))}
134038
+ ${import_picocolors18.default.bgMagenta(import_picocolors18.default.white(" MaTrixOS Doctor "))}
134039
134039
  `;
134040
134040
  }
134041
134041
  function formatIssue(issue2, index) {
@@ -142282,7 +142282,7 @@ function configureRuntimeCommands(program2) {
142282
142282
  });
142283
142283
  process.exit(exitCode);
142284
142284
  });
142285
- program2.command("upstream").description("Upstream sync commands (read-only, NEVER auto-merge)").command("check").description("Fetch recent OMO releases and classify commits (merge | cherry-pick | manual | skip). Human decides.").option("--repo <owner/name>", "Override upstream repo (default: shirofx/MaTrixOS)").option("--token <token>", "GitHub token (default: $GITHUB_TOKEN)").option("--recent <n>", "Limit to N most recent releases", (v) => Number.parseInt(v, 10), 3).option("--json", "Output as JSON").action(async (options) => {
142285
+ program2.command("upstream").description("Upstream sync commands (read-only, NEVER auto-merge)").command("check").description("Fetch recent MaTrixOS releases and classify commits (merge | cherry-pick | manual | skip). Human decides.").option("--repo <owner/name>", "Override upstream repo (default: shirofx/MaTrixOS)").option("--token <token>", "GitHub token (default: $GITHUB_TOKEN)").option("--recent <n>", "Limit to N most recent releases", (v) => Number.parseInt(v, 10), 3).option("--json", "Output as JSON").action(async (options) => {
142286
142286
  const exitCode = await upstreamCheckCli({
142287
142287
  repo: options.repo,
142288
142288
  token: options.token,
@@ -142593,7 +142593,7 @@ program2.command("profile-create <name>").description("Create a new business pro
142593
142593
  process.stdout.write(result.stdout + `
142594
142594
  `);
142595
142595
  });
142596
- program2.command("migrate").description("Import an OMO config into MaTrixOS (scope minimal: known keys)").requiredOption("--from-omo <path>", "Path to the source omo.jsonc").option("--out <path>", "Target config path", "matrixos.jsonc").action(async (options) => {
142596
+ program2.command("migrate").description("Import a MaTrixOS config into MaTrixOS (scope minimal: known keys)").requiredOption("--from-omo <path>", "Path to the source omo.jsonc").option("--out <path>", "Target config path", "matrixos.jsonc").action(async (options) => {
142597
142597
  const { executeMigrateCommand: executeMigrateCommand2 } = await Promise.resolve().then(() => (init_migrate(), exports_migrate));
142598
142598
  const result = executeMigrateCommand2({ sourcePath: options.fromOmo }, options.out ?? "matrixos.jsonc");
142599
142599
  process.stdout.write(result.stdout + `
@@ -93,7 +93,7 @@ var MATRIX_FEATURES = [
93
93
  {
94
94
  id: "upstream-sync",
95
95
  name: "Upstream Sync",
96
- description: "Periodic comparison with upstream OMO releases, classified into merge/cherry-pick/skip recommendations.",
96
+ description: "Periodic comparison with upstream MaTrixOS releases, classified into merge/cherry-pick/skip recommendations.",
97
97
  enabledByDefault: false,
98
98
  status: "opt-in",
99
99
  userBenefit: "Stay current with upstream fixes without blindly auto-merging.",
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Upstream Sync (§4.10) — fetch OMO releases and classify commits.
2
+ * Upstream Sync (§4.10) — fetch MaTrixOS releases and classify commits.
3
3
  *
4
4
  * Per CDC §4.10: never auto-merge. This module is read-only:
5
5
  * - Fetches recent releases from the upstream repo
package/dist/index.js CHANGED
@@ -297678,7 +297678,7 @@ function updateMatrixosConfig(options) {
297678
297678
  writeAtomically(path28, nextContent, fileSystem);
297679
297679
  return backupPath === undefined ? { path: path28 } : { backupPath, path: path28 };
297680
297680
  }
297681
- var EMPTY_OMO_CONFIG = `// OMO configuration
297681
+ var EMPTY_OMO_CONFIG = `// MaTrixOS configuration
297682
297682
  {
297683
297683
  }
297684
297684
  `, FORMATTING_OPTIONS;
@@ -368023,7 +368023,7 @@ function getCachedVersion(options = {}) {
368023
368023
  // package.json
368024
368024
  var package_default = {
368025
368025
  name: "@kl-c/matrixos",
368026
- version: "0.1.39",
368026
+ version: "0.1.49",
368027
368027
  description: "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
368028
368028
  main: "./dist/index.js",
368029
368029
  types: "dist/index.d.ts",
@@ -368779,7 +368779,7 @@ function ignoreToastError(error) {
368779
368779
  async function showUpdateAvailableToast(ctx, latestVersion, getToastMessage) {
368780
368780
  await ctx.client.tui.showToast({
368781
368781
  body: {
368782
- title: `OhMyOpenCode ${latestVersion}`,
368782
+ title: `MaTrixOS ${latestVersion}`,
368783
368783
  message: getToastMessage(true, latestVersion),
368784
368784
  variant: "info",
368785
368785
  duration: 8000
@@ -368790,7 +368790,7 @@ async function showUpdateAvailableToast(ctx, latestVersion, getToastMessage) {
368790
368790
  async function showAutoUpdatedToast(ctx, oldVersion, newVersion) {
368791
368791
  await ctx.client.tui.showToast({
368792
368792
  body: {
368793
- title: "OhMyOpenCode Updated!",
368793
+ title: "MaTrixOS Updated!",
368794
368794
  message: `v${oldVersion} \u2192 v${newVersion}
368795
368795
  Restart OpenCode to apply.`,
368796
368796
  variant: "success",
@@ -369090,7 +369090,7 @@ async function showSpinnerToast(ctx, version, message) {
369090
369090
  const spinner = MORPHEUS_SPINNER[i % MORPHEUS_SPINNER.length];
369091
369091
  await ctx.client.tui.showToast({
369092
369092
  body: {
369093
- title: `${spinner} OhMyOpenCode ${version}`,
369093
+ title: `${spinner} MaTrixOS ${version}`,
369094
369094
  message,
369095
369095
  variant: "info",
369096
369096
  duration: frameInterval + 50
@@ -369152,8 +369152,8 @@ Morpheus pilote OpenCode.
369152
369152
  v${latestVersion} disponible. Red\xE9marre pour appliquer.` : `${brand}
369153
369153
  Morpheus pilote OpenCode.`;
369154
369154
  }
369155
- return isUpdate ? `OpenCode is now on Steroids. oMoMoMoMo...
369156
- v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on Steroids. oMoMoMoMo...";
369155
+ return isUpdate ? `OpenCode is now on Steroids. MaTrixOS...
369156
+ v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on Steroids. MaTrixOS...";
369157
369157
  };
369158
369158
  let hasChecked = false;
369159
369159
  let hasScheduled = false;
@@ -431108,7 +431108,7 @@ async function buildTheOracleAgentConfig(params) {
431108
431108
  mode: "primary",
431109
431109
  prompt: getTheOraclePrompt(resolvedModel, params.disabledTools),
431110
431110
  permission: THE_ORACLE_PERMISSION,
431111
- description: `${params.configAgentPlan?.description ?? "Plan agent"} (TheOracle - OhMyOpenCode)`,
431111
+ description: `${params.configAgentPlan?.description ?? "Plan agent"} (TheOracle - MaTrixOS)`,
431112
431112
  color: params.configAgentPlan?.color ?? "#FF5722",
431113
431113
  ...temperatureToUse !== undefined ? { temperature: temperatureToUse } : {},
431114
431114
  ...topPToUse !== undefined ? { top_p: topPToUse } : {},
@@ -441224,6 +441224,149 @@ async function resolveSessionAgent(client5, sessionId) {
441224
441224
  // packages/omo-opencode/src/plugin/tool-execute-before.ts
441225
441225
  init_constants3();
441226
441226
  init_storage();
441227
+
441228
+ // packages/omo-opencode/src/security/validation-guard.ts
441229
+ var PATTERNS = [
441230
+ {
441231
+ id: "bash.rm-recursive",
441232
+ description: "Recursively deletes files (rm -rf). Confirm before running.",
441233
+ match: (c) => c.tool.toLowerCase() === "bash" && typeof c.args.command === "string" && /\brm\s+(-[a-zA-Z]*r[a-zA-Z]*f|-[a-zA-Z]*f[a-zA-Z]*r)\b/.test(c.args.command)
441234
+ },
441235
+ {
441236
+ id: "bash.git-force-push",
441237
+ description: "Force-pushes git history. Can destroy remote work.",
441238
+ match: (c) => c.tool.toLowerCase() === "bash" && typeof c.args.command === "string" && /\bgit\s+push\s+(-[a-zA-Z]*f|--force(?!-with-lease))/.test(c.args.command)
441239
+ },
441240
+ {
441241
+ id: "bash.git-reset-hard",
441242
+ description: "git reset --hard destroys uncommitted changes.",
441243
+ match: (c) => c.tool.toLowerCase() === "bash" && typeof c.args.command === "string" && /\bgit\s+reset\s+--hard\b/.test(c.args.command)
441244
+ },
441245
+ {
441246
+ id: "bash.npm-publish",
441247
+ description: "Publishes a package to a public registry. Confirm version + scope.",
441248
+ match: (c) => c.tool.toLowerCase() === "bash" && typeof c.args.command === "string" && /\bnpm\s+publish\b/.test(c.args.command)
441249
+ },
441250
+ {
441251
+ id: "bash.chmod-777",
441252
+ description: "chmod 777 opens the file to everyone. Confirm intent.",
441253
+ match: (c) => c.tool.toLowerCase() === "bash" && typeof c.args.command === "string" && /\bchmod\s+(-[a-zA-Z]*R\s+)?777\b/.test(c.args.command)
441254
+ },
441255
+ {
441256
+ id: "bash.curl-pipe-bash",
441257
+ description: "Pipes a remote script into bash (remote code execution).",
441258
+ match: (c) => c.tool.toLowerCase() === "bash" && typeof c.args.command === "string" && /curl[^|]*\|\s*(sudo\s+)?bash/.test(c.args.command)
441259
+ },
441260
+ {
441261
+ id: "write.env-or-secrets",
441262
+ description: "Writes to a .env / credentials / secrets file.",
441263
+ match: (c) => {
441264
+ if (c.tool.toLowerCase() !== "write" && c.tool.toLowerCase() !== "edit")
441265
+ return false;
441266
+ const path27 = typeof c.args.filePath === "string" ? c.args.filePath : typeof c.args.path === "string" ? c.args.path : "";
441267
+ return /\.env(\.|$)|\/\.klc-secrets\/|\/\.aws\/credentials|id_rsa|id_ed25519/.test(path27);
441268
+ }
441269
+ },
441270
+ {
441271
+ id: "write.system-path",
441272
+ description: "Writes to a system path (/etc/, /usr/, /var/). Confirm intent.",
441273
+ match: (c) => {
441274
+ if (c.tool.toLowerCase() !== "write" && c.tool.toLowerCase() !== "edit")
441275
+ return false;
441276
+ const path27 = typeof c.args.filePath === "string" ? c.args.filePath : typeof c.args.path === "string" ? c.args.path : "";
441277
+ return /^\s*(\/etc\/|\/usr\/|\/var\/)/.test(path27);
441278
+ }
441279
+ }
441280
+ ];
441281
+ function checkValidation(tool3, args) {
441282
+ const call = { tool: tool3, args };
441283
+ for (const p of PATTERNS) {
441284
+ if (p.match(call)) {
441285
+ return {
441286
+ verdict: "deny",
441287
+ reason: `[P-001 Prepare-Never-Submit] Blocked: ${p.description} (pattern: ${p.id}). Ask the user to confirm before running this command.`,
441288
+ pattern: p.id
441289
+ };
441290
+ }
441291
+ }
441292
+ return { verdict: "allow" };
441293
+ }
441294
+
441295
+ // packages/omo-opencode/src/security/injection-guard.ts
441296
+ var INJECTION_PATTERNS = [
441297
+ { id: "ignore-previous", re: /\bignore\s+(all\s+)?(previous|prior|above)\s+(instructions?|directives?|prompts?)/i, description: "ignore previous instructions" },
441298
+ { id: "you-are-now", re: /\byou\s+are\s+now\s+(a|an)\s+/i, description: "you are now a \u2026" },
441299
+ { id: "system-prompt-tag", re: /<\|im_start\|>\s*system|<\|im_end\|>/i, description: "ChatML system tag (model-tag injection)" },
441300
+ { id: "assistant-tag-injection", re: /<\|im_start\|>\s*assistant\b/i, description: "ChatML assistant tag in user content" },
441301
+ { id: "developer-mode", re: /\b(developer|dan|jailbreak|do\s+anything\s+now)\s+mode\b/i, description: "jailbreak mode trigger" },
441302
+ { id: "disregard-safety", re: /\b(disregard|bypass|ignore)\s+(safety|guardrails?|restrictions?|policies)/i, description: "disregard safety guardrails" },
441303
+ { id: "execute-following", re: /\bexecute\s+the\s+following\s+(command|code|instructions?)/i, description: "execute the following \u2026" },
441304
+ { id: "new-instructions", re: /\bnew\s+instructions?:/i, description: "new instructions: header" },
441305
+ { id: "repeat-after-me", re: /\brepeat\s+after\s+me\b/i, description: "repeat after me" },
441306
+ { id: "system-colon-override", re: /^\s*system\s*:\s*[\w]/im, description: "system: override (line-start)" }
441307
+ ];
441308
+ function containsInjection(text) {
441309
+ for (const p of INJECTION_PATTERNS) {
441310
+ const m = p.re.exec(text);
441311
+ if (m) {
441312
+ const start = Math.max(0, m.index - 20);
441313
+ const end = Math.min(text.length, m.index + m[0].length + 20);
441314
+ return { id: p.id, description: p.description, snippet: text.slice(start, end) };
441315
+ }
441316
+ }
441317
+ return null;
441318
+ }
441319
+ var STRICT_FIELDS = {
441320
+ bash: {
441321
+ command: "string-narrow",
441322
+ timeout: "number"
441323
+ },
441324
+ write: {
441325
+ filePath: "string-strict",
441326
+ content: "string-narrow"
441327
+ },
441328
+ edit: {
441329
+ filePath: "string-strict",
441330
+ oldString: "string-strict",
441331
+ newString: "string-narrow"
441332
+ },
441333
+ read: {
441334
+ filePath: "string-strict"
441335
+ },
441336
+ glob: {
441337
+ pattern: "string-strict"
441338
+ },
441339
+ grep: {
441340
+ pattern: "string-strict",
441341
+ path: "string-strict"
441342
+ }
441343
+ };
441344
+ var PATH_RE = /^[^\x00-\x1f]*$/;
441345
+ var MAX_NARROW = 1e5;
441346
+ function sanitizeToolArgs(tool3, args) {
441347
+ const schema2 = STRICT_FIELDS[tool3.toLowerCase()];
441348
+ if (!schema2)
441349
+ return { ok: true };
441350
+ for (const [field, kind] of Object.entries(schema2)) {
441351
+ const v = args[field];
441352
+ if (v === undefined || v === null)
441353
+ continue;
441354
+ if (typeof v !== "string" && typeof v !== "number" && typeof v !== "boolean") {
441355
+ return { ok: false, reason: `field ${field} has wrong type ${typeof v}`, field };
441356
+ }
441357
+ if (typeof v === "string") {
441358
+ if (kind === "string-strict" && !PATH_RE.test(v)) {
441359
+ return { ok: false, reason: `field ${field} contains control characters or is empty`, field };
441360
+ }
441361
+ if (kind === "string-narrow" && v.length > MAX_NARROW) {
441362
+ return { ok: false, reason: `field ${field} too long (${v.length} > ${MAX_NARROW})`, field };
441363
+ }
441364
+ }
441365
+ }
441366
+ return { ok: true };
441367
+ }
441368
+
441369
+ // packages/omo-opencode/src/plugin/tool-execute-before.ts
441227
441370
  var BACKGROUND_WAIT_BLOCK_MESSAGE = [
441228
441371
  "Background task wait is already managed by the plugin.",
441229
441372
  "End this response now and wait for the <system-reminder> completion notification.",
@@ -441300,6 +441443,27 @@ function createToolExecuteBeforeHandler3(args) {
441300
441443
  if (egressDecision?.verdict === "deny") {
441301
441444
  throw new Error(`Egress blocked: ${egressDecision.reason}`);
441302
441445
  }
441446
+ const validation = checkValidation(input.tool, output.args);
441447
+ if (validation.verdict === "deny") {
441448
+ throw new Error(validation.reason);
441449
+ }
441450
+ const sanitize = sanitizeToolArgs(input.tool, output.args);
441451
+ if (!sanitize.ok) {
441452
+ throw new Error(`[A12 injection-guard] Tool arg rejected: ${sanitize.reason} (field: ${sanitize.field})`);
441453
+ }
441454
+ if (input.tool.toLowerCase() === "bash" && typeof output.args.command === "string") {
441455
+ const inj = containsInjection(output.args.command);
441456
+ if (inj) {
441457
+ log2("[A12 injection-guard] Possible prompt injection in bash command", {
441458
+ sessionID: input.sessionID,
441459
+ callID: input.callID,
441460
+ match: inj
441461
+ });
441462
+ if (output.args.command.includes("MTRX-CANARY-")) {
441463
+ throw new Error(`[A12 injection-guard] Bash command contains canary token \u2014 possible exfiltration attempt. Aborting.`);
441464
+ }
441465
+ }
441466
+ }
441303
441467
  await hooks.writeExistingFileGuard?.["tool.execute.before"]?.(input, output);
441304
441468
  await hooks.notepadWriteGuard?.["tool.execute.before"]?.(input, output);
441305
441469
  await hooks.questionLabelTruncator?.["tool.execute.before"]?.(input, output);
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Task Progress Streaming (ANNEXE A17).
3
+ *
4
+ * Emits structured progress events for long-running tool calls so the
5
+ * gateway (or CLI) can display real-time status instead of a silent wait.
6
+ *
7
+ * NOTE: today the consumer is the structured log. The Telegram gateway
8
+ * (CDC §7) is not implemented yet — when it is, it can subscribe to
9
+ * these events to edit messages in real time. The schema is stable.
10
+ */
11
+ export type ProgressEvent = {
12
+ type: "task.progress";
13
+ taskId: string;
14
+ tool: string;
15
+ sessionID: string;
16
+ callID: string;
17
+ step: number;
18
+ totalSteps: number;
19
+ message: string;
20
+ startedAt: number;
21
+ elapsedMs: number;
22
+ };
23
+ type Listener = (e: ProgressEvent) => void;
24
+ /** Subscribe to progress events. Returns an unsubscribe function. */
25
+ export declare function onProgress(listener: Listener): () => void;
26
+ /** Start a task. Returns the taskId. */
27
+ export declare function startTask(tool: string, sessionID: string, callID: string, totalSteps?: number): string;
28
+ /** Advance the current task. */
29
+ export declare function advance(message: string): void;
30
+ /** End the current task. */
31
+ export declare function endTask(message?: string): void;
32
+ /** Run an async operation with task progress tracking. */
33
+ export declare function withProgress<T>(tool: string, sessionID: string, callID: string, op: (advance: (msg: string) => void) => Promise<T>): Promise<T>;
34
+ export {};
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Mid-Task Checkpoint (ANNEXE A9).
3
+ *
4
+ * Saves the in-flight task state every 30s so a crash (network, OOM, SIGKILL)
5
+ * can resume mid-task instead of restarting from scratch.
6
+ *
7
+ * Difference from snapshot (CDC §18.7): checkpoint is automatic + granular
8
+ * (one file, the in-flight task state), snapshot is manual + coarse
9
+ * (full DB + files).
10
+ *
11
+ * Storage: .matrixos/checkpoints/<taskId>.json (last write wins).
12
+ */
13
+ export type CheckpointState = {
14
+ taskId: string;
15
+ tool: string;
16
+ sessionID: string;
17
+ startedAt: number;
18
+ updatedAt: number;
19
+ step: number;
20
+ totalSteps: number;
21
+ history: {
22
+ tool: string;
23
+ args: Record<string, unknown>;
24
+ at: number;
25
+ ok: boolean;
26
+ }[];
27
+ context: Record<string, unknown>;
28
+ };
29
+ /** Start checkpointing a new task. Replaces any prior current task. */
30
+ export declare function startCheckpoint(taskId: string, tool: string, sessionID: string, totalSteps?: number, context?: Record<string, unknown>): void;
31
+ /** Record that a tool call happened. */
32
+ export declare function recordStep(tool: string, args: Record<string, unknown>, ok: boolean): void;
33
+ /** Update free-form context (e.g. current goal, partial results). */
34
+ export declare function updateContext(patch: Record<string, unknown>): void;
35
+ /** Force a flush to disk (in addition to the 30s timer). */
36
+ export declare function flush(): Promise<void>;
37
+ /** Stop the current checkpoint (call when the task completes). */
38
+ export declare function stopCheckpoint(): void;
39
+ /** Read a saved checkpoint by taskId, if it exists. */
40
+ export declare function loadCheckpoint(taskId: string, dir?: string): Promise<CheckpointState | null>;
41
+ /** List all checkpoints (for crash-recovery on session start). */
42
+ export declare function listCheckpoints(dir?: string): Promise<string[]>;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Graceful Degradation / Retry with Backoff (ANNEXE A14).
3
+ *
4
+ * Generic retry wrapper with exponential backoff + jitter.
5
+ * Used by the model resolver to retry on transient failures
6
+ * (rate-limit, network blip, 5xx) before falling back to the
7
+ * next provider in the chain.
8
+ */
9
+ export type RetryOptions = {
10
+ maxAttempts: number;
11
+ baseDelayMs: number;
12
+ maxDelayMs: number;
13
+ jitterRatio: number;
14
+ shouldRetry: (err: unknown) => boolean;
15
+ };
16
+ export declare function withRetry<T>(fn: () => Promise<T>, opts?: Partial<RetryOptions>): Promise<T>;
17
+ /** Default shouldRetry: retry on transient errors, NOT on validation/programmer errors. */
18
+ export declare function isTransientError(err: unknown): boolean;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Prompt Injection Defense (ANNEXE A12).
3
+ *
4
+ * Three defense layers applied at the tool boundary:
5
+ * 1. containsInjection() — detect known prompt-injection patterns in content
6
+ * the agent is about to consume (file contents, command output, etc.).
7
+ * 2. extractCanary() — pull a canary token from the system prompt and let
8
+ * checkCanaryInOutput() flag any tool output that contains it (a sign
9
+ * that the system prompt was exfiltrated into a tool result).
10
+ * 3. sanitizeToolArgs() — reject free-form text in tool arg fields that
11
+ * should be strictly typed (paths, IDs, enums).
12
+ */
13
+ export type InjectionMatch = {
14
+ id: string;
15
+ description: string;
16
+ snippet: string;
17
+ };
18
+ /** Returns the first injection match found, or null if clean. */
19
+ export declare function containsInjection(text: string): InjectionMatch | null;
20
+ /** Returns the canary token to embed in the system prompt. */
21
+ export declare function generateCanary(): string;
22
+ /** Returns true if the canary appears in the output (sign of exfiltration). */
23
+ export declare function checkCanaryInOutput(output: string, canary: string): boolean;
24
+ export type SanitizeResult = {
25
+ ok: true;
26
+ } | {
27
+ ok: false;
28
+ reason: string;
29
+ field: string;
30
+ };
31
+ /** Reject tool args that don't match the strict schema (no control chars in paths, etc.). */
32
+ export declare function sanitizeToolArgs(tool: string, args: Record<string, unknown>): SanitizeResult;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Prepare-Never-Submit (P-001) — tool-level validation guard.
3
+ *
4
+ * Inspired by ANNEXE_A A3. Detects high-risk tool calls BEFORE execution and
5
+ * throws so the agent sees the error and asks the human to confirm.
6
+ *
7
+ * NOTE: The annex proposes a skill-level frontmatter (requires_validation).
8
+ * The current OpenCode hook system does not expose skill context at the
9
+ * tool.execute.before layer, so this guard is PATTERN-based on tool + args.
10
+ * This is less fine-grained but more robust (catches both skill-driven and
11
+ * ad-hoc risky calls) and applicable today without a hook refactor.
12
+ */
13
+ export type ToolCall = {
14
+ tool: string;
15
+ args: Record<string, unknown>;
16
+ };
17
+ export type ValidationDecision = {
18
+ verdict: "deny";
19
+ reason: string;
20
+ pattern: string;
21
+ } | {
22
+ verdict: "allow";
23
+ };
24
+ /** Decide whether the tool call needs human validation. Throws nothing — pure decision. */
25
+ export declare function checkValidation(tool: string, args: Record<string, unknown>): ValidationDecision;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Skill versioning.
3
+ *
4
+ * Convention: <root>/<skill-name>/<semver>/SKILL.md
5
+ * The active version is recorded in <root>/<skill-name>/active (a file
6
+ * whose content is the version string, e.g. "1.0.0").
7
+ *
8
+ * Why: when modifying a skill, the old version is preserved. The active
9
+ * pointer lets the runtime pick the current version without breaking
10
+ * the in-flight calls. Rollback = rewrite the active file.
11
+ */
12
+ export type SkillVersion = {
13
+ name: string;
14
+ version: string;
15
+ path: string;
16
+ };
17
+ export declare class SkillRegistry {
18
+ private root;
19
+ constructor(root: string);
20
+ /** All versions of a skill, newest first. */
21
+ list(name: string): Promise<SkillVersion[]>;
22
+ /** List all skills that have at least one versioned SKILL.md. */
23
+ listAll(): Promise<{
24
+ name: string;
25
+ versions: SkillVersion[];
26
+ }[]>;
27
+ /** Read the active version (or the latest if no active file). */
28
+ getActive(name: string): Promise<SkillVersion | null>;
29
+ /** Set the active version. */
30
+ setActive(name: string, version: string): Promise<void>;
31
+ /** Add a new version (mkdir + write SKILL.md content). */
32
+ addVersion(name: string, version: string, content: string): Promise<SkillVersion>;
33
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Skill test runner.
3
+ *
4
+ * Convention: a skill may have a co-located <name>.test.ts (or
5
+ * __tests__/<name>.test.ts) that exercises the skill instructions. The
6
+ * runner discovers these files, parses the skill frontmatter, and exposes
7
+ * the metadata to the test as a fixture.
8
+ *
9
+ * Usage (CLI):
10
+ * matrixos skill test <name> # run a skill's tests
11
+ * matrixos skill test --all # run all skills' tests
12
+ *
13
+ * Usage (programmatic):
14
+ * import { runSkillTest, parseSkillFrontmatter } from "./skill-test-runner"
15
+ */
16
+ export type SkillFrontmatter = {
17
+ name: string;
18
+ description: string;
19
+ triggers: string[];
20
+ requiresValidation: boolean;
21
+ raw: Record<string, unknown>;
22
+ };
23
+ export declare function parseSkillFrontmatter(content: string): {
24
+ frontmatter: SkillFrontmatter;
25
+ body: string;
26
+ } | null;
27
+ /** Find the test file for a skill. */
28
+ export declare function findSkillTestFile(skillRoot: string, skillName: string): Promise<string | null>;
29
+ /** Run a single skill test (programmatic). Returns a result object. */
30
+ export declare function runSkillTest(skillRoot: string, skillName: string, testFn: (ctx: {
31
+ skill: SkillFrontmatter;
32
+ body: string;
33
+ }) => void | Promise<void>): Promise<{
34
+ ok: boolean;
35
+ error?: string;
36
+ }>;
37
+ /** Discover all skills with test files. */
38
+ export declare function discoverSkillTests(skillRoot: string): Promise<{
39
+ name: string;
40
+ testFile: string;
41
+ }[]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kl-c/matrixos",
3
- "version": "0.1.39",
3
+ "version": "0.1.49",
4
4
  "description": "MaTrixOS — Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "dist/index.d.ts",