@kl-c/matrixos 0.1.6 → 0.1.7
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/cli/index.js +2 -1
- package/dist/cli-node/index.js +2 -1
- package/dist/config/schema/oh-my-opencode-config.d.ts +1 -0
- package/dist/config/schema/watchdog.d.ts +1 -0
- package/dist/features/anti-loop/logger.d.ts +15 -0
- package/dist/hooks/agent-anti-loop/hook.d.ts +5 -26
- package/dist/index.js +174 -102
- package/dist/oh-my-opencode.schema.json +7 -0
- package/dist/plugin/agent-anti-loop.d.ts +2 -5
- package/dist/tui.js +1 -0
- package/package.json +1 -1
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.7",
|
|
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",
|
|
@@ -122361,6 +122361,7 @@ init_zod();
|
|
|
122361
122361
|
var WatchdogConfigSchema = object({
|
|
122362
122362
|
enabled: boolean2().default(true),
|
|
122363
122363
|
doomLoopThreshold: number2().int().positive().max(20).default(3),
|
|
122364
|
+
softDoomLoopThreshold: number2().int().positive().max(20).default(5),
|
|
122364
122365
|
stuckTimeoutSec: number2().int().positive().max(600).default(90),
|
|
122365
122366
|
auditLogPath: string2().optional(),
|
|
122366
122367
|
recoveryStrategy: _enum2(["nudge", "fallback", "restart", "notify", "safe"]).default("nudge"),
|
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.7",
|
|
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",
|
|
@@ -122416,6 +122416,7 @@ init_zod();
|
|
|
122416
122416
|
var WatchdogConfigSchema = object({
|
|
122417
122417
|
enabled: boolean2().default(true),
|
|
122418
122418
|
doomLoopThreshold: number2().int().positive().max(20).default(3),
|
|
122419
|
+
softDoomLoopThreshold: number2().int().positive().max(20).default(5),
|
|
122419
122420
|
stuckTimeoutSec: number2().int().positive().max(600).default(90),
|
|
122420
122421
|
auditLogPath: string2().optional(),
|
|
122421
122422
|
recoveryStrategy: _enum2(["nudge", "fallback", "restart", "notify", "safe"]).default("nudge"),
|
|
@@ -2449,6 +2449,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
|
|
|
2449
2449
|
watchdog: z.ZodOptional<z.ZodObject<{
|
|
2450
2450
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
2451
2451
|
doomLoopThreshold: z.ZodDefault<z.ZodNumber>;
|
|
2452
|
+
softDoomLoopThreshold: z.ZodDefault<z.ZodNumber>;
|
|
2452
2453
|
stuckTimeoutSec: z.ZodDefault<z.ZodNumber>;
|
|
2453
2454
|
auditLogPath: z.ZodOptional<z.ZodString>;
|
|
2454
2455
|
recoveryStrategy: z.ZodDefault<z.ZodEnum<{
|
|
@@ -6,6 +6,7 @@ import * as z from "zod";
|
|
|
6
6
|
export declare const WatchdogConfigSchema: z.ZodObject<{
|
|
7
7
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
8
8
|
doomLoopThreshold: z.ZodDefault<z.ZodNumber>;
|
|
9
|
+
softDoomLoopThreshold: z.ZodDefault<z.ZodNumber>;
|
|
9
10
|
stuckTimeoutSec: z.ZodDefault<z.ZodNumber>;
|
|
10
11
|
auditLogPath: z.ZodOptional<z.ZodString>;
|
|
11
12
|
recoveryStrategy: z.ZodDefault<z.ZodEnum<{
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type AntiLoopPattern = "doom_loop" | "soft_doom_loop" | "stuck" | "zombie_session" | "hook_recursion" | "agent_avoidance" | "context_bloat" | "runaway_task";
|
|
2
|
+
export interface AntiLoopEvent {
|
|
3
|
+
timestamp: string;
|
|
4
|
+
sessionId?: string;
|
|
5
|
+
pattern: AntiLoopPattern;
|
|
6
|
+
agent?: string;
|
|
7
|
+
toolName?: string;
|
|
8
|
+
detail: string;
|
|
9
|
+
actionTaken: string;
|
|
10
|
+
outcome?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AntiLoopLogger {
|
|
13
|
+
log(event: Omit<AntiLoopEvent, "timestamp">): void;
|
|
14
|
+
}
|
|
15
|
+
export declare function createAntiLoopLogger(logsDir: string): AntiLoopLogger;
|
|
@@ -1,49 +1,28 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent-level anti-loop watchdog (§4.12).
|
|
3
|
-
*
|
|
4
|
-
* Attaches to `tool.execute.after` to track tool call signatures and detect
|
|
5
|
-
* doom loops (same tool ≥3x identical). Also monitors a stuck timer (90s
|
|
6
|
-
* default) since the last meaningful tool call.
|
|
7
|
-
*
|
|
8
|
-
* Recovery escalation (CDC §4.12.3):
|
|
9
|
-
* Level 1 — Nudge: inject a message telling the agent it appears stuck
|
|
10
|
-
* Level 2 — Fallback: switch model (delegates to runtime-fallback)
|
|
11
|
-
* Level 3 — Restart: kill + restart session (future phase)
|
|
12
|
-
*
|
|
13
|
-
* The watchdog is opt-in via `watchdog.enabled` in the config.
|
|
14
|
-
*/
|
|
15
1
|
import type { WatchdogConfig } from "../../config/schema/watchdog";
|
|
16
2
|
export interface ToolCallRecord {
|
|
17
|
-
/** Tool name, e.g. "bash", "edit", "read". */
|
|
18
3
|
tool: string;
|
|
19
|
-
/** Stable signature: toolName + sorted JSON args. */
|
|
20
4
|
signature: string;
|
|
21
|
-
/** Timestamp of the call. */
|
|
22
5
|
timestamp: number;
|
|
23
|
-
/** Whether the tool produced meaningful output (text > 0). */
|
|
24
6
|
meaningful: boolean;
|
|
25
7
|
}
|
|
8
|
+
export declare function signaturesSimilar(a: string, b: string): boolean;
|
|
26
9
|
export interface AgentAntiLoopState {
|
|
27
|
-
/** Per-signature consecutive count. */
|
|
28
10
|
consecutiveBySignature: Map<string, number>;
|
|
29
|
-
|
|
11
|
+
recentSignatures: string[];
|
|
30
12
|
lastMeaningfulToolAt: number;
|
|
31
|
-
/** Whether a nudge has already been sent (cooldown). */
|
|
32
13
|
nudged: boolean;
|
|
33
|
-
/** Whether fallback has been triggered. */
|
|
34
14
|
fallbackTriggered: boolean;
|
|
15
|
+
avoidanceCount: number;
|
|
16
|
+
avoidanceEscalated: boolean;
|
|
35
17
|
}
|
|
36
18
|
export interface AgentAntiLoopHooks {
|
|
37
|
-
/** Call on every tool.execute.after. */
|
|
38
19
|
onToolAfter(tool: string, args: unknown, output: unknown): void;
|
|
39
|
-
|
|
20
|
+
onAgentMessage(content: string): void;
|
|
40
21
|
checkStuck(): {
|
|
41
22
|
stuck: boolean;
|
|
42
23
|
secondsSinceLastMeaningful: number;
|
|
43
24
|
};
|
|
44
|
-
/** Reset the state (e.g. on session start). */
|
|
45
25
|
reset(): void;
|
|
46
|
-
/** Get the current state (for audit). */
|
|
47
26
|
getState(): AgentAntiLoopState;
|
|
48
27
|
}
|
|
49
28
|
export declare function createAgentAntiLoopHooks(config: WatchdogConfig): AgentAntiLoopHooks;
|
package/dist/index.js
CHANGED
|
@@ -57285,7 +57285,7 @@ var require_dist10 = __commonJS((exports, module) => {
|
|
|
57285
57285
|
var import_node_worker_threads2 = __require("worker_threads");
|
|
57286
57286
|
var import_collection2 = require_dist3();
|
|
57287
57287
|
var import_node_events = __require("events");
|
|
57288
|
-
var
|
|
57288
|
+
var import_node_path128 = __require("path");
|
|
57289
57289
|
var import_node_worker_threads = __require("worker_threads");
|
|
57290
57290
|
var import_collection = require_dist3();
|
|
57291
57291
|
var WorkerSendPayloadOp = /* @__PURE__ */ ((WorkerSendPayloadOp2) => {
|
|
@@ -57420,18 +57420,18 @@ var require_dist10 = __commonJS((exports, module) => {
|
|
|
57420
57420
|
resolveWorkerPath() {
|
|
57421
57421
|
const path28 = this.options.workerPath;
|
|
57422
57422
|
if (!path28) {
|
|
57423
|
-
return (0,
|
|
57423
|
+
return (0, import_node_path128.join)(__dirname, "defaultWorker.js");
|
|
57424
57424
|
}
|
|
57425
|
-
if ((0,
|
|
57425
|
+
if ((0, import_node_path128.isAbsolute)(path28)) {
|
|
57426
57426
|
return path28;
|
|
57427
57427
|
}
|
|
57428
57428
|
if (/^\.\.?[/\\]/.test(path28)) {
|
|
57429
|
-
return (0,
|
|
57429
|
+
return (0, import_node_path128.resolve)(path28);
|
|
57430
57430
|
}
|
|
57431
57431
|
try {
|
|
57432
57432
|
return __require.resolve(path28);
|
|
57433
57433
|
} catch {
|
|
57434
|
-
return (0,
|
|
57434
|
+
return (0, import_node_path128.resolve)(path28);
|
|
57435
57435
|
}
|
|
57436
57436
|
}
|
|
57437
57437
|
async waitForWorkerReady(worker) {
|
|
@@ -233073,7 +233073,7 @@ import * as Crypto from "crypto";
|
|
|
233073
233073
|
import { once } from "events";
|
|
233074
233074
|
import { createReadStream, createWriteStream, promises as fs26, WriteStream } from "fs";
|
|
233075
233075
|
import { tmpdir as tmpdir8 } from "os";
|
|
233076
|
-
import { join as
|
|
233076
|
+
import { join as join136 } from "path";
|
|
233077
233077
|
import { Readable as Readable2, Transform } from "stream";
|
|
233078
233078
|
import { URL as URL2 } from "url";
|
|
233079
233079
|
async function getMediaKeys(buffer2, mediaType) {
|
|
@@ -233151,7 +233151,7 @@ async function generateThumbnail(file2, mediaType, options) {
|
|
|
233151
233151
|
};
|
|
233152
233152
|
}
|
|
233153
233153
|
} else if (mediaType === "video") {
|
|
233154
|
-
const imgFilename =
|
|
233154
|
+
const imgFilename = join136(getTmpFilesDirectory(), generateMessageIDV2() + ".jpg");
|
|
233155
233155
|
try {
|
|
233156
233156
|
await extractVideoThumb(file2, imgFilename, "00:00:00", { width: 32, height: 32 });
|
|
233157
233157
|
const buff = await fs26.readFile(imgFilename);
|
|
@@ -233194,7 +233194,7 @@ var import_boom5, getTmpFilesDirectory = () => tmpdir8(), getImageProcessingLibr
|
|
|
233194
233194
|
const { stream: stream3 } = await getStream(media);
|
|
233195
233195
|
logger7?.debug("got stream for raw upload");
|
|
233196
233196
|
const hasher = Crypto.createHash("sha256");
|
|
233197
|
-
const filePath =
|
|
233197
|
+
const filePath = join136(tmpdir8(), mediaType + generateMessageIDV2());
|
|
233198
233198
|
const fileWriteStream = createWriteStream(filePath);
|
|
233199
233199
|
let fileLength = 0;
|
|
233200
233200
|
try {
|
|
@@ -233334,12 +233334,12 @@ var import_boom5, getTmpFilesDirectory = () => tmpdir8(), getImageProcessingLibr
|
|
|
233334
233334
|
logger7?.debug("fetched media stream");
|
|
233335
233335
|
const mediaKey = Crypto.randomBytes(32);
|
|
233336
233336
|
const { cipherKey, iv, macKey } = await getMediaKeys(mediaKey, mediaType);
|
|
233337
|
-
const encFilePath =
|
|
233337
|
+
const encFilePath = join136(getTmpFilesDirectory(), mediaType + generateMessageIDV2() + "-enc");
|
|
233338
233338
|
const encFileWriteStream = createWriteStream(encFilePath);
|
|
233339
233339
|
let originalFileStream;
|
|
233340
233340
|
let originalFilePath;
|
|
233341
233341
|
if (saveOriginalFileIfRequired) {
|
|
233342
|
-
originalFilePath =
|
|
233342
|
+
originalFilePath = join136(getTmpFilesDirectory(), mediaType + generateMessageIDV2() + "-original");
|
|
233343
233343
|
originalFileStream = createWriteStream(originalFilePath);
|
|
233344
233344
|
}
|
|
233345
233345
|
let fileLength = 0;
|
|
@@ -242744,7 +242744,7 @@ var init_auth_utils = __esm(() => {
|
|
|
242744
242744
|
|
|
242745
242745
|
// node_modules/.bun/@whiskeysockets+baileys@7.0.0-rc13+13d21a63c79191a3/node_modules/@whiskeysockets/baileys/lib/Utils/use-multi-file-auth-state.js
|
|
242746
242746
|
import { mkdir as mkdir11, readFile as readFile14, stat as stat8, unlink as unlink3, writeFile as writeFile4 } from "fs/promises";
|
|
242747
|
-
import { join as
|
|
242747
|
+
import { join as join137 } from "path";
|
|
242748
242748
|
var fileLocks, getFileLock = (path28) => {
|
|
242749
242749
|
let mutex = fileLocks.get(path28);
|
|
242750
242750
|
if (!mutex) {
|
|
@@ -242754,7 +242754,7 @@ var fileLocks, getFileLock = (path28) => {
|
|
|
242754
242754
|
return mutex;
|
|
242755
242755
|
}, useMultiFileAuthState = async (folder) => {
|
|
242756
242756
|
const writeData = async (data3, file2) => {
|
|
242757
|
-
const filePath =
|
|
242757
|
+
const filePath = join137(folder, fixFileName(file2));
|
|
242758
242758
|
const mutex = getFileLock(filePath);
|
|
242759
242759
|
return mutex.acquire().then(async (release2) => {
|
|
242760
242760
|
try {
|
|
@@ -242766,7 +242766,7 @@ var fileLocks, getFileLock = (path28) => {
|
|
|
242766
242766
|
};
|
|
242767
242767
|
const readData = async (file2) => {
|
|
242768
242768
|
try {
|
|
242769
|
-
const filePath =
|
|
242769
|
+
const filePath = join137(folder, fixFileName(file2));
|
|
242770
242770
|
const mutex = getFileLock(filePath);
|
|
242771
242771
|
return await mutex.acquire().then(async (release2) => {
|
|
242772
242772
|
try {
|
|
@@ -242782,7 +242782,7 @@ var fileLocks, getFileLock = (path28) => {
|
|
|
242782
242782
|
};
|
|
242783
242783
|
const removeData = async (file2) => {
|
|
242784
242784
|
try {
|
|
242785
|
-
const filePath =
|
|
242785
|
+
const filePath = join137(folder, fixFileName(file2));
|
|
242786
242786
|
const mutex = getFileLock(filePath);
|
|
242787
242787
|
return mutex.acquire().then(async (release2) => {
|
|
242788
242788
|
try {
|
|
@@ -263753,7 +263753,7 @@ var require_thread_stream = __commonJS((exports, module) => {
|
|
|
263753
263753
|
var { version: version2 } = require_package3();
|
|
263754
263754
|
var { EventEmitter: EventEmitter4 } = __require("events");
|
|
263755
263755
|
var { Worker } = __require("worker_threads");
|
|
263756
|
-
var { join:
|
|
263756
|
+
var { join: join138 } = __require("path");
|
|
263757
263757
|
var { pathToFileURL: pathToFileURL2 } = __require("url");
|
|
263758
263758
|
var { wait: wait2 } = require_wait2();
|
|
263759
263759
|
var {
|
|
@@ -263796,7 +263796,7 @@ var require_thread_stream = __commonJS((exports, module) => {
|
|
|
263796
263796
|
function createWorker(stream3, opts) {
|
|
263797
263797
|
const { filename, workerData } = opts;
|
|
263798
263798
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
263799
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
263799
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join138(__dirname, "lib", "worker.js");
|
|
263800
263800
|
const worker = new Worker(toExecute, {
|
|
263801
263801
|
...opts.workerOpts,
|
|
263802
263802
|
trackUnmanagedFds: false,
|
|
@@ -264197,7 +264197,7 @@ var require_transport = __commonJS((exports, module) => {
|
|
|
264197
264197
|
var __dirname = "/home/shiro/MaTrixOS/node_modules/.bun/pino@9.14.0/node_modules/pino/lib";
|
|
264198
264198
|
var { createRequire: createRequire4 } = __require("module");
|
|
264199
264199
|
var getCallers = require_caller();
|
|
264200
|
-
var { join:
|
|
264200
|
+
var { join: join138, isAbsolute: isAbsolute21, sep: sep3 } = __require("path");
|
|
264201
264201
|
var sleep3 = require_atomic_sleep();
|
|
264202
264202
|
var onExit = require_on_exit_leak_free();
|
|
264203
264203
|
var ThreadStream = require_thread_stream();
|
|
@@ -264260,7 +264260,7 @@ var require_transport = __commonJS((exports, module) => {
|
|
|
264260
264260
|
throw new Error("only one of target or targets can be specified");
|
|
264261
264261
|
}
|
|
264262
264262
|
if (targets) {
|
|
264263
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
264263
|
+
target = bundlerOverrides["pino-worker"] || join138(__dirname, "worker.js");
|
|
264264
264264
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
264265
264265
|
return {
|
|
264266
264266
|
...dest,
|
|
@@ -264277,7 +264277,7 @@ var require_transport = __commonJS((exports, module) => {
|
|
|
264277
264277
|
});
|
|
264278
264278
|
});
|
|
264279
264279
|
} else if (pipeline3) {
|
|
264280
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
264280
|
+
target = bundlerOverrides["pino-worker"] || join138(__dirname, "worker.js");
|
|
264281
264281
|
options.pipelines = [pipeline3.map((dest) => {
|
|
264282
264282
|
return {
|
|
264283
264283
|
...dest,
|
|
@@ -264299,7 +264299,7 @@ var require_transport = __commonJS((exports, module) => {
|
|
|
264299
264299
|
return origin;
|
|
264300
264300
|
}
|
|
264301
264301
|
if (origin === "pino/file") {
|
|
264302
|
-
return
|
|
264302
|
+
return join138(__dirname, "..", "file.js");
|
|
264303
264303
|
}
|
|
264304
264304
|
let fixTarget2;
|
|
264305
264305
|
for (const filePath of callers) {
|
|
@@ -265237,7 +265237,7 @@ var require_safe_stable_stringify = __commonJS((exports, module) => {
|
|
|
265237
265237
|
return circularValue;
|
|
265238
265238
|
}
|
|
265239
265239
|
let res = "";
|
|
265240
|
-
let
|
|
265240
|
+
let join138 = ",";
|
|
265241
265241
|
const originalIndentation = indentation;
|
|
265242
265242
|
if (Array.isArray(value)) {
|
|
265243
265243
|
if (value.length === 0) {
|
|
@@ -265251,7 +265251,7 @@ var require_safe_stable_stringify = __commonJS((exports, module) => {
|
|
|
265251
265251
|
indentation += spacer;
|
|
265252
265252
|
res += `
|
|
265253
265253
|
${indentation}`;
|
|
265254
|
-
|
|
265254
|
+
join138 = `,
|
|
265255
265255
|
${indentation}`;
|
|
265256
265256
|
}
|
|
265257
265257
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -265259,13 +265259,13 @@ ${indentation}`;
|
|
|
265259
265259
|
for (;i < maximumValuesToStringify - 1; i++) {
|
|
265260
265260
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
265261
265261
|
res += tmp2 !== undefined ? tmp2 : "null";
|
|
265262
|
-
res +=
|
|
265262
|
+
res += join138;
|
|
265263
265263
|
}
|
|
265264
265264
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
265265
265265
|
res += tmp !== undefined ? tmp : "null";
|
|
265266
265266
|
if (value.length - 1 > maximumBreadth) {
|
|
265267
265267
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
265268
|
-
res += `${
|
|
265268
|
+
res += `${join138}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
265269
265269
|
}
|
|
265270
265270
|
if (spacer !== "") {
|
|
265271
265271
|
res += `
|
|
@@ -265286,7 +265286,7 @@ ${originalIndentation}`;
|
|
|
265286
265286
|
let separator = "";
|
|
265287
265287
|
if (spacer !== "") {
|
|
265288
265288
|
indentation += spacer;
|
|
265289
|
-
|
|
265289
|
+
join138 = `,
|
|
265290
265290
|
${indentation}`;
|
|
265291
265291
|
whitespace = " ";
|
|
265292
265292
|
}
|
|
@@ -265300,13 +265300,13 @@ ${indentation}`;
|
|
|
265300
265300
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
265301
265301
|
if (tmp !== undefined) {
|
|
265302
265302
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
265303
|
-
separator =
|
|
265303
|
+
separator = join138;
|
|
265304
265304
|
}
|
|
265305
265305
|
}
|
|
265306
265306
|
if (keyLength > maximumBreadth) {
|
|
265307
265307
|
const removedKeys = keyLength - maximumBreadth;
|
|
265308
265308
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
265309
|
-
separator =
|
|
265309
|
+
separator = join138;
|
|
265310
265310
|
}
|
|
265311
265311
|
if (spacer !== "" && separator.length > 1) {
|
|
265312
265312
|
res = `
|
|
@@ -265346,7 +265346,7 @@ ${originalIndentation}`;
|
|
|
265346
265346
|
}
|
|
265347
265347
|
const originalIndentation = indentation;
|
|
265348
265348
|
let res = "";
|
|
265349
|
-
let
|
|
265349
|
+
let join138 = ",";
|
|
265350
265350
|
if (Array.isArray(value)) {
|
|
265351
265351
|
if (value.length === 0) {
|
|
265352
265352
|
return "[]";
|
|
@@ -265359,7 +265359,7 @@ ${originalIndentation}`;
|
|
|
265359
265359
|
indentation += spacer;
|
|
265360
265360
|
res += `
|
|
265361
265361
|
${indentation}`;
|
|
265362
|
-
|
|
265362
|
+
join138 = `,
|
|
265363
265363
|
${indentation}`;
|
|
265364
265364
|
}
|
|
265365
265365
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -265367,13 +265367,13 @@ ${indentation}`;
|
|
|
265367
265367
|
for (;i < maximumValuesToStringify - 1; i++) {
|
|
265368
265368
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
265369
265369
|
res += tmp2 !== undefined ? tmp2 : "null";
|
|
265370
|
-
res +=
|
|
265370
|
+
res += join138;
|
|
265371
265371
|
}
|
|
265372
265372
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
265373
265373
|
res += tmp !== undefined ? tmp : "null";
|
|
265374
265374
|
if (value.length - 1 > maximumBreadth) {
|
|
265375
265375
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
265376
|
-
res += `${
|
|
265376
|
+
res += `${join138}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
265377
265377
|
}
|
|
265378
265378
|
if (spacer !== "") {
|
|
265379
265379
|
res += `
|
|
@@ -265386,7 +265386,7 @@ ${originalIndentation}`;
|
|
|
265386
265386
|
let whitespace = "";
|
|
265387
265387
|
if (spacer !== "") {
|
|
265388
265388
|
indentation += spacer;
|
|
265389
|
-
|
|
265389
|
+
join138 = `,
|
|
265390
265390
|
${indentation}`;
|
|
265391
265391
|
whitespace = " ";
|
|
265392
265392
|
}
|
|
@@ -265395,7 +265395,7 @@ ${indentation}`;
|
|
|
265395
265395
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
265396
265396
|
if (tmp !== undefined) {
|
|
265397
265397
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
265398
|
-
separator =
|
|
265398
|
+
separator = join138;
|
|
265399
265399
|
}
|
|
265400
265400
|
}
|
|
265401
265401
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -265452,20 +265452,20 @@ ${originalIndentation}`;
|
|
|
265452
265452
|
indentation += spacer;
|
|
265453
265453
|
let res2 = `
|
|
265454
265454
|
${indentation}`;
|
|
265455
|
-
const
|
|
265455
|
+
const join139 = `,
|
|
265456
265456
|
${indentation}`;
|
|
265457
265457
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
265458
265458
|
let i = 0;
|
|
265459
265459
|
for (;i < maximumValuesToStringify - 1; i++) {
|
|
265460
265460
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
265461
265461
|
res2 += tmp2 !== undefined ? tmp2 : "null";
|
|
265462
|
-
res2 +=
|
|
265462
|
+
res2 += join139;
|
|
265463
265463
|
}
|
|
265464
265464
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
265465
265465
|
res2 += tmp !== undefined ? tmp : "null";
|
|
265466
265466
|
if (value.length - 1 > maximumBreadth) {
|
|
265467
265467
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
265468
|
-
res2 += `${
|
|
265468
|
+
res2 += `${join139}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
265469
265469
|
}
|
|
265470
265470
|
res2 += `
|
|
265471
265471
|
${originalIndentation}`;
|
|
@@ -265481,16 +265481,16 @@ ${originalIndentation}`;
|
|
|
265481
265481
|
return '"[Object]"';
|
|
265482
265482
|
}
|
|
265483
265483
|
indentation += spacer;
|
|
265484
|
-
const
|
|
265484
|
+
const join138 = `,
|
|
265485
265485
|
${indentation}`;
|
|
265486
265486
|
let res = "";
|
|
265487
265487
|
let separator = "";
|
|
265488
265488
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
265489
265489
|
if (isTypedArrayWithEntries(value)) {
|
|
265490
|
-
res += stringifyTypedArray(value,
|
|
265490
|
+
res += stringifyTypedArray(value, join138, maximumBreadth);
|
|
265491
265491
|
keys = keys.slice(value.length);
|
|
265492
265492
|
maximumPropertiesToStringify -= value.length;
|
|
265493
|
-
separator =
|
|
265493
|
+
separator = join138;
|
|
265494
265494
|
}
|
|
265495
265495
|
if (deterministic) {
|
|
265496
265496
|
keys = sort(keys, comparator);
|
|
@@ -265501,13 +265501,13 @@ ${indentation}`;
|
|
|
265501
265501
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
265502
265502
|
if (tmp !== undefined) {
|
|
265503
265503
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
265504
|
-
separator =
|
|
265504
|
+
separator = join138;
|
|
265505
265505
|
}
|
|
265506
265506
|
}
|
|
265507
265507
|
if (keyLength > maximumBreadth) {
|
|
265508
265508
|
const removedKeys = keyLength - maximumBreadth;
|
|
265509
265509
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
265510
|
-
separator =
|
|
265510
|
+
separator = join138;
|
|
265511
265511
|
}
|
|
265512
265512
|
if (separator !== "") {
|
|
265513
265513
|
res = `
|
|
@@ -266157,7 +266157,7 @@ var init_Defaults = __esm(() => {
|
|
|
266157
266157
|
import { createHash as createHash13 } from "crypto";
|
|
266158
266158
|
import { createWriteStream as createWriteStream2, promises as fs28 } from "fs";
|
|
266159
266159
|
import { tmpdir as tmpdir9 } from "os";
|
|
266160
|
-
import { join as
|
|
266160
|
+
import { join as join138 } from "path";
|
|
266161
266161
|
async function uploadingNecessaryImagesOfProduct(product, waUploadToServer, timeoutMs = 30000) {
|
|
266162
266162
|
product = {
|
|
266163
266163
|
...product,
|
|
@@ -266335,7 +266335,7 @@ var import_boom12, parseCatalogNode = (node) => {
|
|
|
266335
266335
|
}
|
|
266336
266336
|
const { stream: stream3 } = await getStream(img);
|
|
266337
266337
|
const hasher = createHash13("sha256");
|
|
266338
|
-
const filePath =
|
|
266338
|
+
const filePath = join138(tmpdir9(), "img" + generateMessageIDV2());
|
|
266339
266339
|
const encFileWriteStream = createWriteStream2(filePath);
|
|
266340
266340
|
for await (const block2 of stream3) {
|
|
266341
266341
|
hasher.update(block2);
|
|
@@ -297183,18 +297183,18 @@ var init_merge = __esm(() => {
|
|
|
297183
297183
|
});
|
|
297184
297184
|
|
|
297185
297185
|
// packages/omo-config-core/src/loader/types.ts
|
|
297186
|
-
import { existsSync as
|
|
297186
|
+
import { existsSync as existsSync114, lstatSync as lstatSync5, readFileSync as readFileSync77 } from "fs";
|
|
297187
297187
|
var DEFAULT_READ_FILE_SYSTEM;
|
|
297188
297188
|
var init_types7 = __esm(() => {
|
|
297189
297189
|
DEFAULT_READ_FILE_SYSTEM = {
|
|
297190
|
-
existsSync:
|
|
297190
|
+
existsSync: existsSync114,
|
|
297191
297191
|
lstatSync: lstatSync5,
|
|
297192
297192
|
readFileSync: readFileSync77
|
|
297193
297193
|
};
|
|
297194
297194
|
});
|
|
297195
297195
|
|
|
297196
297196
|
// packages/omo-config-core/src/loader/paths.ts
|
|
297197
|
-
import { dirname as dirname45, isAbsolute as isAbsolute21, join as
|
|
297197
|
+
import { dirname as dirname45, isAbsolute as isAbsolute21, join as join139, relative as relative15, resolve as resolve42 } from "path";
|
|
297198
297198
|
function containsPath2(parent, child) {
|
|
297199
297199
|
const pathToChild = relative15(parent, child);
|
|
297200
297200
|
return pathToChild === "" || !pathToChild.startsWith("..") && !isAbsolute21(pathToChild);
|
|
@@ -297203,23 +297203,23 @@ function resolveHomeDir(env2 = process.env) {
|
|
|
297203
297203
|
return resolve42(env2.HOME ?? env2.USERPROFILE ?? process.cwd());
|
|
297204
297204
|
}
|
|
297205
297205
|
function resolveUserMatrixosConfigPath(env2 = process.env, platform4 = process.platform) {
|
|
297206
|
-
return
|
|
297206
|
+
return join139(resolveUserMatrixosConfigDirectory(env2, platform4), "omo.jsonc");
|
|
297207
297207
|
}
|
|
297208
297208
|
function resolveUserMatrixosConfigDirectory(env2 = process.env, platform4 = process.platform) {
|
|
297209
297209
|
if (platform4 === "win32" && env2.APPDATA !== undefined && env2.APPDATA.length > 0) {
|
|
297210
|
-
return
|
|
297210
|
+
return join139(env2.APPDATA, "omo");
|
|
297211
297211
|
}
|
|
297212
297212
|
if (env2.XDG_CONFIG_HOME !== undefined && env2.XDG_CONFIG_HOME.length > 0) {
|
|
297213
|
-
return
|
|
297213
|
+
return join139(env2.XDG_CONFIG_HOME, "omo");
|
|
297214
297214
|
}
|
|
297215
|
-
return
|
|
297215
|
+
return join139(resolveHomeDir(env2), ".config", "omo");
|
|
297216
297216
|
}
|
|
297217
297217
|
function detectUserOmoJsonPath(env2, platform4, fileSystem) {
|
|
297218
297218
|
const configDir = resolveUserMatrixosConfigDirectory(env2, platform4);
|
|
297219
|
-
const jsoncPath =
|
|
297219
|
+
const jsoncPath = join139(configDir, "omo.jsonc");
|
|
297220
297220
|
if (fileSystem.existsSync(jsoncPath))
|
|
297221
297221
|
return jsoncPath;
|
|
297222
|
-
const jsonPath =
|
|
297222
|
+
const jsonPath = join139(configDir, "omo.json");
|
|
297223
297223
|
return fileSystem.existsSync(jsonPath) ? jsonPath : jsoncPath;
|
|
297224
297224
|
}
|
|
297225
297225
|
function isSymlinkedProjectPath(path28, fileSystem) {
|
|
@@ -297237,13 +297237,13 @@ function isLoadableProjectConfigFile(path28, fileSystem) {
|
|
|
297237
297237
|
return fileSystem.existsSync(path28) && !isSymlinkedProjectPath(path28, fileSystem);
|
|
297238
297238
|
}
|
|
297239
297239
|
function detectOmoJsonPath(dir2, fileSystem) {
|
|
297240
|
-
const omoDir =
|
|
297240
|
+
const omoDir = join139(dir2, ".omo");
|
|
297241
297241
|
if (isSymlinkedProjectPath(omoDir, fileSystem))
|
|
297242
297242
|
return null;
|
|
297243
|
-
const jsoncPath =
|
|
297243
|
+
const jsoncPath = join139(omoDir, "omo.jsonc");
|
|
297244
297244
|
if (isLoadableProjectConfigFile(jsoncPath, fileSystem))
|
|
297245
297245
|
return jsoncPath;
|
|
297246
|
-
const jsonPath =
|
|
297246
|
+
const jsonPath = join139(omoDir, "omo.json");
|
|
297247
297247
|
return isLoadableProjectConfigFile(jsonPath, fileSystem) ? jsonPath : null;
|
|
297248
297248
|
}
|
|
297249
297249
|
function findProjectConfigPathsFarthestFirst(cwd, homeDir, fileSystem) {
|
|
@@ -297504,9 +297504,9 @@ var init_loader3 = __esm(() => {
|
|
|
297504
297504
|
// packages/omo-config-core/src/writer/types.ts
|
|
297505
297505
|
import {
|
|
297506
297506
|
copyFileSync as copyFileSync3,
|
|
297507
|
-
existsSync as
|
|
297507
|
+
existsSync as existsSync115,
|
|
297508
297508
|
lstatSync as lstatSync6,
|
|
297509
|
-
mkdirSync as
|
|
297509
|
+
mkdirSync as mkdirSync25,
|
|
297510
297510
|
readFileSync as readFileSync78,
|
|
297511
297511
|
readdirSync as readdirSync29,
|
|
297512
297512
|
renameSync as renameSync10,
|
|
@@ -297517,9 +297517,9 @@ var DEFAULT_WRITE_FILE_SYSTEM, MatrixosConfigWriteError;
|
|
|
297517
297517
|
var init_types8 = __esm(() => {
|
|
297518
297518
|
DEFAULT_WRITE_FILE_SYSTEM = {
|
|
297519
297519
|
copyFileSync: copyFileSync3,
|
|
297520
|
-
existsSync:
|
|
297520
|
+
existsSync: existsSync115,
|
|
297521
297521
|
lstatSync: lstatSync6,
|
|
297522
|
-
mkdirSync:
|
|
297522
|
+
mkdirSync: mkdirSync25,
|
|
297523
297523
|
readFileSync: readFileSync78,
|
|
297524
297524
|
readdirSync: readdirSync29,
|
|
297525
297525
|
renameSync: renameSync10,
|
|
@@ -297544,7 +297544,7 @@ var init_types8 = __esm(() => {
|
|
|
297544
297544
|
|
|
297545
297545
|
// packages/omo-config-core/src/writer/writer.ts
|
|
297546
297546
|
import { randomUUID as randomUUID13 } from "crypto";
|
|
297547
|
-
import { dirname as dirname46, join as
|
|
297547
|
+
import { dirname as dirname46, join as join140 } from "path";
|
|
297548
297548
|
function backupSuffix() {
|
|
297549
297549
|
return new Date().toISOString().replace(/[:.]/g, "-");
|
|
297550
297550
|
}
|
|
@@ -297575,13 +297575,13 @@ function resolveWritePath(options) {
|
|
|
297575
297575
|
const jsoncPath2 = resolveUserMatrixosConfigPath(options.env, options.platform ?? process.platform);
|
|
297576
297576
|
if (fileSystem.existsSync(jsoncPath2))
|
|
297577
297577
|
return jsoncPath2;
|
|
297578
|
-
const jsonPath2 =
|
|
297578
|
+
const jsonPath2 = join140(dirname46(jsoncPath2), "omo.json");
|
|
297579
297579
|
return fileSystem.existsSync(jsonPath2) ? jsonPath2 : jsoncPath2;
|
|
297580
297580
|
}
|
|
297581
|
-
const jsoncPath =
|
|
297581
|
+
const jsoncPath = join140(options.projectDir ?? process.cwd(), ".omo", "omo.jsonc");
|
|
297582
297582
|
if (fileSystem.existsSync(jsoncPath))
|
|
297583
297583
|
return jsoncPath;
|
|
297584
|
-
const jsonPath =
|
|
297584
|
+
const jsonPath = join140(dirname46(jsoncPath), "omo.json");
|
|
297585
297585
|
return fileSystem.existsSync(jsonPath) ? jsonPath : jsoncPath;
|
|
297586
297586
|
}
|
|
297587
297587
|
function writeAtomically(path28, content, fileSystem) {
|
|
@@ -297693,8 +297693,8 @@ var init_writer2 = __esm(() => {
|
|
|
297693
297693
|
});
|
|
297694
297694
|
|
|
297695
297695
|
// packages/omo-config-core/src/generator/mini-os-generator.ts
|
|
297696
|
-
import { existsSync as
|
|
297697
|
-
import { dirname as dirname47, join as
|
|
297696
|
+
import { existsSync as existsSync116, mkdirSync as mkdirSync26, writeFileSync as writeFileSync26 } from "fs";
|
|
297697
|
+
import { dirname as dirname47, join as join141 } from "path";
|
|
297698
297698
|
function generateMiniOS(options) {
|
|
297699
297699
|
const fs29 = options.fs ?? defaultFS;
|
|
297700
297700
|
const profile3 = options.profile;
|
|
@@ -297705,29 +297705,29 @@ function generateMiniOS(options) {
|
|
|
297705
297705
|
if (!fs29.existsSync(targetDir)) {
|
|
297706
297706
|
fs29.mkdirSync(targetDir, { recursive: true });
|
|
297707
297707
|
}
|
|
297708
|
-
const pkgPath =
|
|
297708
|
+
const pkgPath = join141(targetDir, "package.json");
|
|
297709
297709
|
writeIfMissing(fs29, pkgPath, TPL_PACKAGE_JSON(packageName, displayName, profile3.version, profile3.description, profile3.extends, profile3.baseAgent));
|
|
297710
297710
|
filesWritten.push(pkgPath);
|
|
297711
|
-
const srcDir =
|
|
297711
|
+
const srcDir = join141(targetDir, "src");
|
|
297712
297712
|
fs29.mkdirSync(srcDir, { recursive: true });
|
|
297713
|
-
const indexPath =
|
|
297713
|
+
const indexPath = join141(srcDir, "index.ts");
|
|
297714
297714
|
writeIfMissing(fs29, indexPath, TPL_INDEX_TS(profile3.name, displayName, profile3.description));
|
|
297715
297715
|
filesWritten.push(indexPath);
|
|
297716
|
-
const binDir =
|
|
297716
|
+
const binDir = join141(targetDir, "bin");
|
|
297717
297717
|
fs29.mkdirSync(binDir, { recursive: true });
|
|
297718
|
-
const binPath =
|
|
297718
|
+
const binPath = join141(binDir, "matrixos-mini.js");
|
|
297719
297719
|
writeIfMissing(fs29, binPath, TPL_BIN);
|
|
297720
297720
|
filesWritten.push(binPath);
|
|
297721
|
-
const scriptDir =
|
|
297721
|
+
const scriptDir = join141(targetDir, "script");
|
|
297722
297722
|
fs29.mkdirSync(scriptDir, { recursive: true });
|
|
297723
|
-
const buildPath =
|
|
297723
|
+
const buildPath = join141(scriptDir, "build.ts");
|
|
297724
297724
|
writeIfMissing(fs29, buildPath, TPL_BUILD_TS);
|
|
297725
297725
|
filesWritten.push(buildPath);
|
|
297726
297726
|
if (Object.keys(profile3.agents).length > 0) {
|
|
297727
|
-
const agentsDir =
|
|
297727
|
+
const agentsDir = join141(targetDir, "agents");
|
|
297728
297728
|
fs29.mkdirSync(agentsDir, { recursive: true });
|
|
297729
297729
|
for (const [agentName, agentDef] of Object.entries(profile3.agents)) {
|
|
297730
|
-
const agentFile =
|
|
297730
|
+
const agentFile = join141(agentsDir, `${agentName}.ts`);
|
|
297731
297731
|
const description2 = agentDef.description ?? `Custom ${displayName} agent: ${agentName}`;
|
|
297732
297732
|
writeIfMissing(fs29, agentFile, `// ${description2}
|
|
297733
297733
|
// Generated by MaTrixOS Mini-OS Profile Generator.
|
|
@@ -297738,10 +297738,10 @@ export const description = ${JSON.stringify(description2)}
|
|
|
297738
297738
|
}
|
|
297739
297739
|
}
|
|
297740
297740
|
if (profile3.skills.length > 0) {
|
|
297741
|
-
const skillsDir =
|
|
297741
|
+
const skillsDir = join141(targetDir, "skills");
|
|
297742
297742
|
fs29.mkdirSync(skillsDir, { recursive: true });
|
|
297743
297743
|
for (const skill2 of profile3.skills) {
|
|
297744
|
-
const skillFile =
|
|
297744
|
+
const skillFile = join141(skillsDir, `${skill2}.md`);
|
|
297745
297745
|
writeIfMissing(fs29, skillFile, `# ${skill2}
|
|
297746
297746
|
|
|
297747
297747
|
_Skill required by the ${displayName} profile. Implementation goes here._
|
|
@@ -297749,12 +297749,12 @@ _Skill required by the ${displayName} profile. Implementation goes here._
|
|
|
297749
297749
|
filesWritten.push(skillFile);
|
|
297750
297750
|
}
|
|
297751
297751
|
}
|
|
297752
|
-
const readmePath =
|
|
297752
|
+
const readmePath = join141(targetDir, "README.md");
|
|
297753
297753
|
const agentsList = Object.keys(profile3.agents);
|
|
297754
297754
|
const skillsList = profile3.skills;
|
|
297755
297755
|
writeIfMissing(fs29, readmePath, TPL_README(packageName, displayName, profile3.description, profile3.version, profile3.baseAgent, profile3.extends, agentsList, skillsList));
|
|
297756
297756
|
filesWritten.push(readmePath);
|
|
297757
|
-
const agentsMdPath =
|
|
297757
|
+
const agentsMdPath = join141(targetDir, "AGENTS.md");
|
|
297758
297758
|
writeIfMissing(fs29, agentsMdPath, TPL_AGENT_MD(displayName, profile3.description));
|
|
297759
297759
|
filesWritten.push(agentsMdPath);
|
|
297760
297760
|
return { packageName, packageDir: targetDir, filesWritten };
|
|
@@ -297906,7 +297906,7 @@ This profile is activated when the user mentions the profile name in their reque
|
|
|
297906
297906
|
- Profiles can be composed: multiple profiles in \`profiles: [...]\` are merged in order.
|
|
297907
297907
|
`;
|
|
297908
297908
|
var init_mini_os_generator = __esm(() => {
|
|
297909
|
-
defaultFS = { existsSync:
|
|
297909
|
+
defaultFS = { existsSync: existsSync116, mkdirSync: mkdirSync26, writeFileSync: writeFileSync26 };
|
|
297910
297910
|
});
|
|
297911
297911
|
|
|
297912
297912
|
// packages/omo-config-core/src/generator/index.ts
|
|
@@ -367932,7 +367932,7 @@ function getCachedVersion(options = {}) {
|
|
|
367932
367932
|
// package.json
|
|
367933
367933
|
var package_default = {
|
|
367934
367934
|
name: "@kl-c/matrixos",
|
|
367935
|
-
version: "0.1.
|
|
367935
|
+
version: "0.1.7",
|
|
367936
367936
|
description: "MaTrixOS \u2014 Agentic OS for OpenCode. Personalizable, communicating, self-improving, resilient.",
|
|
367937
367937
|
main: "./dist/index.js",
|
|
367938
367938
|
types: "dist/index.d.ts",
|
|
@@ -441310,12 +441310,30 @@ function createPluginInterface(args) {
|
|
|
441310
441310
|
}
|
|
441311
441311
|
|
|
441312
441312
|
// packages/omo-opencode/src/hooks/agent-anti-loop/hook.ts
|
|
441313
|
+
function signaturesSimilar(a, b) {
|
|
441314
|
+
if (a === b)
|
|
441315
|
+
return true;
|
|
441316
|
+
const aTool = a.split(":")[0] ?? "";
|
|
441317
|
+
const bTool = b.split(":")[0] ?? "";
|
|
441318
|
+
if (aTool !== bTool)
|
|
441319
|
+
return false;
|
|
441320
|
+
return true;
|
|
441321
|
+
}
|
|
441322
|
+
var AVOIDANCE_PATTERNS = [
|
|
441323
|
+
/\btry\s+(again|a different|another)\b/i,
|
|
441324
|
+
/\bI'?ll\s+(try|attempt|give\s+it\s+another)\b/i,
|
|
441325
|
+
/\blet\s+me\s+try\s+again\b/i,
|
|
441326
|
+
/\bI\s+apologize\b.*\btry\b/i
|
|
441327
|
+
];
|
|
441313
441328
|
function createAgentAntiLoopHooks(config) {
|
|
441314
441329
|
const state3 = {
|
|
441315
441330
|
consecutiveBySignature: new Map,
|
|
441331
|
+
recentSignatures: [],
|
|
441316
441332
|
lastMeaningfulToolAt: Date.now(),
|
|
441317
441333
|
nudged: false,
|
|
441318
|
-
fallbackTriggered: false
|
|
441334
|
+
fallbackTriggered: false,
|
|
441335
|
+
avoidanceCount: 0,
|
|
441336
|
+
avoidanceEscalated: false
|
|
441319
441337
|
};
|
|
441320
441338
|
function makeSignature(tool3, args) {
|
|
441321
441339
|
try {
|
|
@@ -441341,6 +441359,7 @@ function createAgentAntiLoopHooks(config) {
|
|
|
441341
441359
|
const prev = state3.consecutiveBySignature.get(sig) ?? 0;
|
|
441342
441360
|
const count = prev + 1;
|
|
441343
441361
|
state3.consecutiveBySignature.set(sig, count);
|
|
441362
|
+
state3.recentSignatures.push(sig);
|
|
441344
441363
|
if (isMeaningfulOutput(output)) {
|
|
441345
441364
|
state3.lastMeaningfulToolAt = now;
|
|
441346
441365
|
state3.nudged = false;
|
|
@@ -441349,29 +441368,68 @@ function createAgentAntiLoopHooks(config) {
|
|
|
441349
441368
|
if (count >= config.doomLoopThreshold) {
|
|
441350
441369
|
state3.consecutiveBySignature.set(sig, 0);
|
|
441351
441370
|
}
|
|
441371
|
+
const similarCount = state3.recentSignatures.filter((s) => signaturesSimilar(s, sig)).length;
|
|
441372
|
+
if (similarCount >= config.softDoomLoopThreshold) {
|
|
441373
|
+
state3.consecutiveBySignature.set(sig, 0);
|
|
441374
|
+
}
|
|
441375
|
+
},
|
|
441376
|
+
onAgentMessage(content) {
|
|
441377
|
+
const isAvoidance = AVOIDANCE_PATTERNS.some((p) => p.test(content));
|
|
441378
|
+
if (isAvoidance) {
|
|
441379
|
+
state3.avoidanceCount += 1;
|
|
441380
|
+
} else {
|
|
441381
|
+
state3.avoidanceCount = 0;
|
|
441382
|
+
}
|
|
441352
441383
|
},
|
|
441353
441384
|
checkStuck() {
|
|
441354
441385
|
const now = Date.now();
|
|
441355
441386
|
const elapsed = now - state3.lastMeaningfulToolAt;
|
|
441356
|
-
|
|
441357
|
-
const stuck = secondsSinceLastMeaningful >= config.stuckTimeoutSec;
|
|
441358
|
-
return { stuck, secondsSinceLastMeaningful };
|
|
441387
|
+
return { stuck: elapsed >= config.stuckTimeoutSec * 1000, secondsSinceLastMeaningful: Math.floor(elapsed / 1000) };
|
|
441359
441388
|
},
|
|
441360
441389
|
reset() {
|
|
441361
441390
|
state3.consecutiveBySignature.clear();
|
|
441391
|
+
state3.recentSignatures = [];
|
|
441362
441392
|
state3.lastMeaningfulToolAt = Date.now();
|
|
441363
441393
|
state3.nudged = false;
|
|
441364
441394
|
state3.fallbackTriggered = false;
|
|
441395
|
+
state3.avoidanceCount = 0;
|
|
441396
|
+
state3.avoidanceEscalated = false;
|
|
441365
441397
|
},
|
|
441366
441398
|
getState() {
|
|
441367
|
-
return { ...state3, consecutiveBySignature: new Map(state3.consecutiveBySignature) };
|
|
441399
|
+
return { ...state3, consecutiveBySignature: new Map(state3.consecutiveBySignature), recentSignatures: [...state3.recentSignatures] };
|
|
441400
|
+
}
|
|
441401
|
+
};
|
|
441402
|
+
}
|
|
441403
|
+
|
|
441404
|
+
// packages/omo-opencode/src/features/anti-loop/logger.ts
|
|
441405
|
+
import { existsSync as existsSync112, mkdirSync as mkdirSync24, appendFileSync as appendFileSync8 } from "fs";
|
|
441406
|
+
import { join as join134 } from "path";
|
|
441407
|
+
function createAntiLoopLogger(logsDir) {
|
|
441408
|
+
const logFile = join134(logsDir, "anti-loop.jsonl");
|
|
441409
|
+
const parentDir = join134(logsDir, "..");
|
|
441410
|
+
if (!existsSync112(logsDir)) {
|
|
441411
|
+
mkdirSync24(logsDir, { recursive: true });
|
|
441412
|
+
}
|
|
441413
|
+
return {
|
|
441414
|
+
log(event) {
|
|
441415
|
+
const entry = {
|
|
441416
|
+
...event,
|
|
441417
|
+
timestamp: new Date().toISOString()
|
|
441418
|
+
};
|
|
441419
|
+
try {
|
|
441420
|
+
appendFileSync8(logFile, JSON.stringify(entry) + `
|
|
441421
|
+
`, "utf-8");
|
|
441422
|
+
} catch {}
|
|
441368
441423
|
}
|
|
441369
441424
|
};
|
|
441370
441425
|
}
|
|
441371
441426
|
|
|
441372
441427
|
// packages/omo-opencode/src/plugin/agent-anti-loop.ts
|
|
441428
|
+
import { join as join135 } from "path";
|
|
441373
441429
|
function createAgentAntiLoopWiring(config, deps) {
|
|
441374
441430
|
const hooks = createAgentAntiLoopHooks(config);
|
|
441431
|
+
const logDir = deps.projectDir ? join135(deps.projectDir, ".matrixos", "logs") : process.cwd();
|
|
441432
|
+
const antiLoopLog = createAntiLoopLogger(logDir);
|
|
441375
441433
|
return {
|
|
441376
441434
|
toolExecuteAfter(input) {
|
|
441377
441435
|
hooks.onToolAfter(input.tool, input.args, input.output);
|
|
@@ -441379,25 +441437,38 @@ function createAgentAntiLoopWiring(config, deps) {
|
|
|
441379
441437
|
const sig = `${input.tool}:${JSON.stringify(input.args)}`;
|
|
441380
441438
|
const count = state3.consecutiveBySignature.get(sig) ?? 0;
|
|
441381
441439
|
if (count === 0 && state3.consecutiveBySignature.has(sig)) {
|
|
441382
|
-
deps.log("[agent-anti-loop] doom loop detected", {
|
|
441383
|
-
|
|
441384
|
-
threshold: config.doomLoopThreshold
|
|
441385
|
-
});
|
|
441440
|
+
deps.log("[agent-anti-loop] doom loop detected", { tool: input.tool, threshold: config.doomLoopThreshold });
|
|
441441
|
+
antiLoopLog.log({ sessionId: process.env.OMO_SESSION_ID, pattern: "doom_loop", toolName: input.tool, detail: `${input.tool} called >=${config.doomLoopThreshold}x identical`, actionTaken: "counter_reset" });
|
|
441386
441442
|
if (deps.injectNudge) {
|
|
441387
|
-
deps.injectNudge(
|
|
441443
|
+
deps.injectNudge(`Watchdog: tool ${input.tool} repeated without progress. Try a different approach.`);
|
|
441388
441444
|
}
|
|
441389
441445
|
}
|
|
441446
|
+
const similarCount = state3.recentSignatures.filter((s) => s.startsWith(input.tool + ":")).length;
|
|
441447
|
+
if (similarCount >= config.softDoomLoopThreshold) {
|
|
441448
|
+
deps.log("[agent-anti-loop] soft doom loop warning", { tool: input.tool, similarCalls: similarCount });
|
|
441449
|
+
antiLoopLog.log({ sessionId: process.env.OMO_SESSION_ID, pattern: "soft_doom_loop", toolName: input.tool, detail: `${input.tool} called ${similarCount}x with similar args`, actionTaken: "warning" });
|
|
441450
|
+
}
|
|
441451
|
+
},
|
|
441452
|
+
onAgentMessage(content) {
|
|
441453
|
+
hooks.onAgentMessage(content);
|
|
441454
|
+
const state3 = hooks.getState();
|
|
441455
|
+
if (state3.avoidanceCount >= 3 && !state3.avoidanceEscalated) {
|
|
441456
|
+
deps.log("[agent-anti-loop] agent avoidance detected", { avoidanceCount: state3.avoidanceCount });
|
|
441457
|
+
antiLoopLog.log({ sessionId: process.env.OMO_SESSION_ID, pattern: "agent_avoidance", detail: `"I'll try again" pattern ${state3.avoidanceCount}x`, actionTaken: "nudge" });
|
|
441458
|
+
if (deps.injectNudge) {
|
|
441459
|
+
deps.injectNudge("You appear stuck in a loop. Stop and analyze what went wrong before trying again.");
|
|
441460
|
+
}
|
|
441461
|
+
state3.avoidanceEscalated = true;
|
|
441462
|
+
}
|
|
441390
441463
|
},
|
|
441391
441464
|
async sessionIdle() {
|
|
441392
441465
|
const { stuck, secondsSinceLastMeaningful } = hooks.checkStuck();
|
|
441393
441466
|
if (!stuck)
|
|
441394
441467
|
return;
|
|
441395
|
-
deps.log("[agent-anti-loop] stuck detected", {
|
|
441396
|
-
|
|
441397
|
-
recoveryStrategy: config.recoveryStrategy
|
|
441398
|
-
});
|
|
441468
|
+
deps.log("[agent-anti-loop] stuck detected", { secondsSinceLastMeaningful, recoveryStrategy: config.recoveryStrategy });
|
|
441469
|
+
antiLoopLog.log({ sessionId: process.env.OMO_SESSION_ID, pattern: "stuck", detail: `No progress for ${secondsSinceLastMeaningful}s`, actionTaken: config.recoveryStrategy });
|
|
441399
441470
|
if (config.recoveryStrategy === "nudge" && deps.injectNudge) {
|
|
441400
|
-
deps.injectNudge(
|
|
441471
|
+
deps.injectNudge(`Watchdog: no progress for ${secondsSinceLastMeaningful}s. Try a different approach.`);
|
|
441401
441472
|
}
|
|
441402
441473
|
},
|
|
441403
441474
|
sessionCreated() {
|
|
@@ -443391,6 +443462,7 @@ import * as z54 from "zod";
|
|
|
443391
443462
|
var WatchdogConfigSchema = z54.object({
|
|
443392
443463
|
enabled: z54.boolean().default(true),
|
|
443393
443464
|
doomLoopThreshold: z54.number().int().positive().max(20).default(3),
|
|
443465
|
+
softDoomLoopThreshold: z54.number().int().positive().max(20).default(5),
|
|
443394
443466
|
stuckTimeoutSec: z54.number().int().positive().max(600).default(90),
|
|
443395
443467
|
auditLogPath: z54.string().optional(),
|
|
443396
443468
|
recoveryStrategy: z54.enum(["nudge", "fallback", "restart", "notify", "safe"]).default("nudge"),
|
|
@@ -444168,22 +444240,22 @@ init_plugin_identity();
|
|
|
444168
444240
|
// packages/telemetry-core/src/activity-state.ts
|
|
444169
444241
|
init_atomic_write();
|
|
444170
444242
|
init_xdg_data_dir();
|
|
444171
|
-
import { existsSync as
|
|
444172
|
-
import { basename as basename26, join as
|
|
444243
|
+
import { existsSync as existsSync119, mkdirSync as mkdirSync27, readFileSync as readFileSync80 } from "fs";
|
|
444244
|
+
import { basename as basename26, join as join143 } from "path";
|
|
444173
444245
|
var POSTHOG_ACTIVITY_STATE_FILE = "posthog-activity.json";
|
|
444174
444246
|
function resolveTelemetryStateDir(product, options = {}) {
|
|
444175
444247
|
const dataDir = resolveXdgDataDir(product.cacheDirName, {
|
|
444176
444248
|
env: options.env,
|
|
444177
444249
|
osProvider: options.osProvider
|
|
444178
444250
|
});
|
|
444179
|
-
const xdgStateDir = options.env?.XDG_DATA_HOME === undefined ? undefined :
|
|
444251
|
+
const xdgStateDir = options.env?.XDG_DATA_HOME === undefined ? undefined : join143(options.env.XDG_DATA_HOME, product.cacheDirName);
|
|
444180
444252
|
if (dataDir === xdgStateDir || xdgStateDir === undefined && basename26(dataDir) === product.cacheDirName) {
|
|
444181
444253
|
return dataDir;
|
|
444182
444254
|
}
|
|
444183
|
-
return
|
|
444255
|
+
return join143(dataDir, product.cacheDirName);
|
|
444184
444256
|
}
|
|
444185
444257
|
function getTelemetryActivityStateFilePath(stateDir) {
|
|
444186
|
-
return
|
|
444258
|
+
return join143(stateDir, POSTHOG_ACTIVITY_STATE_FILE);
|
|
444187
444259
|
}
|
|
444188
444260
|
function getDailyActiveCaptureState(input2) {
|
|
444189
444261
|
const state3 = readPostHogActivityState(input2.stateDir, input2.diagnostics);
|
|
@@ -444208,7 +444280,7 @@ function isPostHogActivityState(value) {
|
|
|
444208
444280
|
}
|
|
444209
444281
|
function readPostHogActivityState(stateDir, diagnostics) {
|
|
444210
444282
|
const stateFilePath = getTelemetryActivityStateFilePath(stateDir);
|
|
444211
|
-
if (!
|
|
444283
|
+
if (!existsSync119(stateFilePath)) {
|
|
444212
444284
|
return {};
|
|
444213
444285
|
}
|
|
444214
444286
|
try {
|
|
@@ -444231,7 +444303,7 @@ function readPostHogActivityState(stateDir, diagnostics) {
|
|
|
444231
444303
|
function writePostHogActivityState(stateDir, nextState, diagnostics) {
|
|
444232
444304
|
const stateFilePath = getTelemetryActivityStateFilePath(stateDir);
|
|
444233
444305
|
try {
|
|
444234
|
-
|
|
444306
|
+
mkdirSync27(stateDir, { recursive: true });
|
|
444235
444307
|
writeFileAtomically(stateFilePath, `${JSON.stringify(nextState, null, 2)}
|
|
444236
444308
|
`);
|
|
444237
444309
|
} catch (error) {
|
|
@@ -7091,6 +7091,12 @@
|
|
|
7091
7091
|
"exclusiveMinimum": 0,
|
|
7092
7092
|
"maximum": 20
|
|
7093
7093
|
},
|
|
7094
|
+
"softDoomLoopThreshold": {
|
|
7095
|
+
"default": 5,
|
|
7096
|
+
"type": "integer",
|
|
7097
|
+
"exclusiveMinimum": 0,
|
|
7098
|
+
"maximum": 20
|
|
7099
|
+
},
|
|
7094
7100
|
"stuckTimeoutSec": {
|
|
7095
7101
|
"default": 90,
|
|
7096
7102
|
"type": "integer",
|
|
@@ -7177,6 +7183,7 @@
|
|
|
7177
7183
|
"required": [
|
|
7178
7184
|
"enabled",
|
|
7179
7185
|
"doomLoopThreshold",
|
|
7186
|
+
"softDoomLoopThreshold",
|
|
7180
7187
|
"stuckTimeoutSec",
|
|
7181
7188
|
"recoveryStrategy",
|
|
7182
7189
|
"heartbeatIntervalSec",
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import type { WatchdogConfig } from "../config/schema/watchdog";
|
|
2
2
|
export interface AgentAntiLoopDeps {
|
|
3
|
-
/** Injected logger. */
|
|
4
3
|
log: (msg: string, meta?: Record<string, unknown>) => void;
|
|
5
|
-
/** Injected function to inject a nudge message into the current session. */
|
|
6
4
|
injectNudge?: (text: string) => Promise<void>;
|
|
5
|
+
projectDir?: string;
|
|
7
6
|
}
|
|
8
7
|
export interface AgentAntiLoopWiring {
|
|
9
|
-
/** Handler for `tool.execute.after` — tracks tool signatures. */
|
|
10
8
|
toolExecuteAfter: (input: {
|
|
11
9
|
tool: string;
|
|
12
10
|
args: unknown;
|
|
13
11
|
output: unknown;
|
|
14
12
|
}) => void;
|
|
15
|
-
/** Handler for `session.idle` — checks stuck timer and escalates. */
|
|
16
13
|
sessionIdle: () => Promise<void>;
|
|
17
|
-
/** Reset on session start. */
|
|
18
14
|
sessionCreated: () => void;
|
|
15
|
+
onAgentMessage: (content: string) => void;
|
|
19
16
|
}
|
|
20
17
|
export declare function createAgentAntiLoopWiring(config: WatchdogConfig, deps: AgentAntiLoopDeps): AgentAntiLoopWiring;
|
package/dist/tui.js
CHANGED
|
@@ -64557,6 +64557,7 @@ var init_watchdog = __esm(() => {
|
|
|
64557
64557
|
WatchdogConfigSchema = object({
|
|
64558
64558
|
enabled: boolean2().default(true),
|
|
64559
64559
|
doomLoopThreshold: number2().int().positive().max(20).default(3),
|
|
64560
|
+
softDoomLoopThreshold: number2().int().positive().max(20).default(5),
|
|
64560
64561
|
stuckTimeoutSec: number2().int().positive().max(600).default(90),
|
|
64561
64562
|
auditLogPath: string2().optional(),
|
|
64562
64563
|
recoveryStrategy: _enum2(["nudge", "fallback", "restart", "notify", "safe"]).default("nudge"),
|
package/package.json
CHANGED