@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.
- package/dist/budget/agent-budget.d.ts +29 -0
- package/dist/cli/index.js +14 -14
- package/dist/cli-node/index.js +14 -14
- package/dist/features/matrix-inventory/features.js +1 -1
- package/dist/features/upstream-sync/check.d.ts +1 -1
- package/dist/index.js +172 -8
- package/dist/observability/progress.d.ts +34 -0
- package/dist/recovery/checkpoint.d.ts +42 -0
- package/dist/resilience/retry.d.ts +18 -0
- package/dist/security/injection-guard.d.ts +32 -0
- package/dist/security/validation-guard.d.ts +25 -0
- package/dist/skills/skill-registry.d.ts +33 -0
- package/dist/skills/skill-test-runner.d.ts +41 -0
- package/package.json +1 -1
|
@@ -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.
|
|
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: `
|
|
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: "
|
|
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}
|
|
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.
|
|
83380
|
-
v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on Steroids.
|
|
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
|
|
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(`
|
|
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("
|
|
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 ? "
|
|
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("
|
|
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("
|
|
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
|
|
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
|
|
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 + `
|
package/dist/cli-node/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.
|
|
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: `
|
|
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: "
|
|
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}
|
|
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.
|
|
83435
|
-
v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on Steroids.
|
|
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
|
|
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(`
|
|
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("
|
|
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 ? "
|
|
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("
|
|
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("
|
|
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
|
|
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
|
|
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
|
|
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.",
|
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 = `//
|
|
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.
|
|
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: `
|
|
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: "
|
|
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}
|
|
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.
|
|
369156
|
-
v${latestVersion} available. Restart OpenCode to apply.` : "OpenCode is now on Steroids.
|
|
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 -
|
|
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