@mono-agent/agent-app 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +108 -2
- package/dist/app.js.map +1 -1
- package/dist/background.d.ts +81 -0
- package/dist/background.d.ts.map +1 -0
- package/dist/background.js +326 -0
- package/dist/background.js.map +1 -0
- package/dist/channels.d.ts +4 -6
- package/dist/channels.d.ts.map +1 -1
- package/dist/channels.js +72 -28
- package/dist/channels.js.map +1 -1
- package/dist/cli.d.ts +10 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +124 -10
- package/dist/cli.js.map +1 -1
- package/dist/doctor.js +111 -5
- package/dist/doctor.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +1 -2
- package/dist/init.js.map +1 -1
- package/dist/launchd.d.ts +67 -0
- package/dist/launchd.d.ts.map +1 -0
- package/dist/launchd.js +164 -0
- package/dist/launchd.js.map +1 -0
- package/dist/memory-rituals.d.ts +51 -0
- package/dist/memory-rituals.d.ts.map +1 -0
- package/dist/memory-rituals.js +228 -0
- package/dist/memory-rituals.js.map +1 -0
- package/package.json +15 -15
- package/skills/mono-agent-composer/SKILL.md +2 -2
- package/skills/mono-agent-composer/references/config-blueprint.md +28 -11
- package/skills/mono-agent-composer/references/discovery-questions.md +100 -4
- package/skills/mono-agent-composer/references/feature-coverage.md +8 -8
- package/skills/mono-agent-composer/references/package-map.md +4 -6
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin, side-effect-light helpers around macOS launchd. The `launchctl` runner
|
|
3
|
+
* is injectable so orchestration can be unit tested without touching the real
|
|
4
|
+
* service domain. Everything here is pure except `makeLaunchctlRunner`.
|
|
5
|
+
*/
|
|
6
|
+
export interface LaunchctlResult {
|
|
7
|
+
readonly code: number;
|
|
8
|
+
readonly stdout: string;
|
|
9
|
+
readonly stderr: string;
|
|
10
|
+
}
|
|
11
|
+
export type LaunchctlRunner = (args: readonly string[]) => Promise<LaunchctlResult>;
|
|
12
|
+
export interface LaunchdPaths {
|
|
13
|
+
readonly plistPath: string;
|
|
14
|
+
readonly stdoutPath: string;
|
|
15
|
+
readonly stderrPath: string;
|
|
16
|
+
readonly logDir: string;
|
|
17
|
+
readonly launchAgentsDir: string;
|
|
18
|
+
}
|
|
19
|
+
export interface PlistInput {
|
|
20
|
+
readonly label: string;
|
|
21
|
+
readonly nodePath: string;
|
|
22
|
+
readonly cliPath: string;
|
|
23
|
+
readonly configPath: string;
|
|
24
|
+
readonly cwd: string;
|
|
25
|
+
readonly envFile?: string;
|
|
26
|
+
readonly port?: number;
|
|
27
|
+
readonly noConsole: boolean;
|
|
28
|
+
readonly stdoutPath: string;
|
|
29
|
+
readonly stderrPath: string;
|
|
30
|
+
readonly pathEnv: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A stable, launchd-legal label derived from the resolved config path. The
|
|
34
|
+
* folder name keeps it human-readable; an 8-char hash of the absolute config
|
|
35
|
+
* path disambiguates same-named folders and keeps the label deterministic so
|
|
36
|
+
* `start`/`stop`/`status` all address the same service.
|
|
37
|
+
*/
|
|
38
|
+
export declare function deriveLaunchdLabel(configPath: string): string;
|
|
39
|
+
export declare function launchdPathsFor(label: string, home?: string): LaunchdPaths;
|
|
40
|
+
export declare function escapeXml(value: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* The plist runs `node <cli.js> start --foreground …` (the existing blocking
|
|
43
|
+
* worker) in the config's directory. No secrets are written here — the worker
|
|
44
|
+
* loads `.env` from its working directory exactly like the foreground CLI.
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildPlistXml(input: PlistInput): string;
|
|
47
|
+
/**
|
|
48
|
+
* PATH for the background worker: the launching shell's PATH (so the user's
|
|
49
|
+
* toolchain is reachable) plus Homebrew/usr-local in case launchd started from
|
|
50
|
+
* a bare login. Never includes anything secret.
|
|
51
|
+
*/
|
|
52
|
+
export declare function defaultPathEnv(env?: Record<string, string | undefined>): string;
|
|
53
|
+
export declare function domainTarget(uid: number): string;
|
|
54
|
+
export declare function serviceTarget(label: string, uid: number): string;
|
|
55
|
+
export declare function makeLaunchctlRunner(): LaunchctlRunner;
|
|
56
|
+
/** True when the service is bootstrapped in the user's gui domain. */
|
|
57
|
+
export declare function isLoaded(runner: LaunchctlRunner, label: string, uid: number): Promise<boolean>;
|
|
58
|
+
/** Bootstrap (load + RunAtLoad-launch) the plist. Caller tolerates "already bootstrapped". */
|
|
59
|
+
export declare function bootstrap(runner: LaunchctlRunner, plistPath: string, uid: number): Promise<LaunchctlResult>;
|
|
60
|
+
/** Kill and restart an already-loaded service, picking up a rewritten plist. */
|
|
61
|
+
export declare function kickstartRestart(runner: LaunchctlRunner, label: string, uid: number): Promise<LaunchctlResult>;
|
|
62
|
+
/**
|
|
63
|
+
* Remove the service from the domain. Sends SIGTERM and — unlike a plain kill —
|
|
64
|
+
* prevents KeepAlive from relaunching it. Caller tolerates "not loaded".
|
|
65
|
+
*/
|
|
66
|
+
export declare function bootout(runner: LaunchctlRunner, label: string, uid: number): Promise<LaunchctlResult>;
|
|
67
|
+
//# sourceMappingURL=launchd.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launchd.d.ts","sourceRoot":"","sources":["../src/launchd.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;AAEpF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAOD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAW7D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAAkB,GAAG,YAAY,CAUrF;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAO/C;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAiDvD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,MAAM,CAY5F;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,mBAAmB,IAAI,eAAe,CAmBrD;AAED,sEAAsE;AACtE,wBAAsB,QAAQ,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGpG;AAED,8FAA8F;AAC9F,wBAAsB,SAAS,CAAC,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAEjH;AAED,gFAAgF;AAChF,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAEpH;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAE3G"}
|
package/dist/launchd.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { basename, dirname, resolve } from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
const LABEL_PREFIX = "com.mono-agent";
|
|
7
|
+
const MAX_FOLDER_SEGMENT = 40;
|
|
8
|
+
const FALLBACK_PATH = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin";
|
|
9
|
+
const PATH_EXTRAS = ["/opt/homebrew/bin", "/usr/local/bin"];
|
|
10
|
+
/**
|
|
11
|
+
* A stable, launchd-legal label derived from the resolved config path. The
|
|
12
|
+
* folder name keeps it human-readable; an 8-char hash of the absolute config
|
|
13
|
+
* path disambiguates same-named folders and keeps the label deterministic so
|
|
14
|
+
* `start`/`stop`/`status` all address the same service.
|
|
15
|
+
*/
|
|
16
|
+
export function deriveLaunchdLabel(configPath) {
|
|
17
|
+
const resolved = resolve(configPath);
|
|
18
|
+
const folder = basename(dirname(resolved))
|
|
19
|
+
.toLowerCase()
|
|
20
|
+
.replace(/[^a-z0-9-]+/gu, "-")
|
|
21
|
+
.replace(/-+/gu, "-")
|
|
22
|
+
.replace(/^-+|-+$/gu, "")
|
|
23
|
+
.slice(0, MAX_FOLDER_SEGMENT)
|
|
24
|
+
.replace(/-+$/gu, "");
|
|
25
|
+
const hash = createHash("sha256").update(resolved).digest("hex").slice(0, 8);
|
|
26
|
+
return `${LABEL_PREFIX}.${folder.length === 0 ? "agent" : folder}-${hash}`;
|
|
27
|
+
}
|
|
28
|
+
export function launchdPathsFor(label, home = homedir()) {
|
|
29
|
+
const launchAgentsDir = resolve(home, "Library", "LaunchAgents");
|
|
30
|
+
const logDir = resolve(home, ".mono-agent", "logs");
|
|
31
|
+
return {
|
|
32
|
+
launchAgentsDir,
|
|
33
|
+
logDir,
|
|
34
|
+
plistPath: resolve(launchAgentsDir, `${label}.plist`),
|
|
35
|
+
stdoutPath: resolve(logDir, `${label}.out.log`),
|
|
36
|
+
stderrPath: resolve(logDir, `${label}.err.log`),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function escapeXml(value) {
|
|
40
|
+
return value
|
|
41
|
+
.replace(/&/gu, "&")
|
|
42
|
+
.replace(/</gu, "<")
|
|
43
|
+
.replace(/>/gu, ">")
|
|
44
|
+
.replace(/"/gu, """)
|
|
45
|
+
.replace(/'/gu, "'");
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The plist runs `node <cli.js> start --foreground …` (the existing blocking
|
|
49
|
+
* worker) in the config's directory. No secrets are written here — the worker
|
|
50
|
+
* loads `.env` from its working directory exactly like the foreground CLI.
|
|
51
|
+
*/
|
|
52
|
+
export function buildPlistXml(input) {
|
|
53
|
+
const programArguments = [
|
|
54
|
+
input.nodePath,
|
|
55
|
+
input.cliPath,
|
|
56
|
+
"start",
|
|
57
|
+
"--foreground",
|
|
58
|
+
"--config",
|
|
59
|
+
input.configPath,
|
|
60
|
+
...(input.envFile === undefined ? [] : ["--env-file", input.envFile]),
|
|
61
|
+
...(input.port === undefined ? [] : ["--port", String(input.port)]),
|
|
62
|
+
...(input.noConsole ? ["--no-console"] : []),
|
|
63
|
+
];
|
|
64
|
+
const argsXml = programArguments.map((arg) => ` <string>${escapeXml(arg)}</string>`).join("\n");
|
|
65
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
66
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
67
|
+
<plist version="1.0">
|
|
68
|
+
<dict>
|
|
69
|
+
<key>Label</key>
|
|
70
|
+
<string>${escapeXml(input.label)}</string>
|
|
71
|
+
<key>ProgramArguments</key>
|
|
72
|
+
<array>
|
|
73
|
+
${argsXml}
|
|
74
|
+
</array>
|
|
75
|
+
<key>WorkingDirectory</key>
|
|
76
|
+
<string>${escapeXml(input.cwd)}</string>
|
|
77
|
+
<key>EnvironmentVariables</key>
|
|
78
|
+
<dict>
|
|
79
|
+
<key>PATH</key>
|
|
80
|
+
<string>${escapeXml(input.pathEnv)}</string>
|
|
81
|
+
</dict>
|
|
82
|
+
<key>RunAtLoad</key>
|
|
83
|
+
<true/>
|
|
84
|
+
<key>KeepAlive</key>
|
|
85
|
+
<dict>
|
|
86
|
+
<key>SuccessfulExit</key>
|
|
87
|
+
<false/>
|
|
88
|
+
</dict>
|
|
89
|
+
<key>StandardOutPath</key>
|
|
90
|
+
<string>${escapeXml(input.stdoutPath)}</string>
|
|
91
|
+
<key>StandardErrorPath</key>
|
|
92
|
+
<string>${escapeXml(input.stderrPath)}</string>
|
|
93
|
+
<key>ThrottleInterval</key>
|
|
94
|
+
<integer>10</integer>
|
|
95
|
+
<key>ProcessType</key>
|
|
96
|
+
<string>Interactive</string>
|
|
97
|
+
</dict>
|
|
98
|
+
</plist>
|
|
99
|
+
`;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* PATH for the background worker: the launching shell's PATH (so the user's
|
|
103
|
+
* toolchain is reachable) plus Homebrew/usr-local in case launchd started from
|
|
104
|
+
* a bare login. Never includes anything secret.
|
|
105
|
+
*/
|
|
106
|
+
export function defaultPathEnv(env = process.env) {
|
|
107
|
+
const current = env.PATH?.trim();
|
|
108
|
+
if (current === undefined || current.length === 0) {
|
|
109
|
+
return FALLBACK_PATH;
|
|
110
|
+
}
|
|
111
|
+
const parts = current.split(":").filter((part) => part.length > 0);
|
|
112
|
+
for (const extra of PATH_EXTRAS) {
|
|
113
|
+
if (!parts.includes(extra)) {
|
|
114
|
+
parts.push(extra);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return parts.join(":");
|
|
118
|
+
}
|
|
119
|
+
export function domainTarget(uid) {
|
|
120
|
+
return `gui/${uid}`;
|
|
121
|
+
}
|
|
122
|
+
export function serviceTarget(label, uid) {
|
|
123
|
+
return `gui/${uid}/${label}`;
|
|
124
|
+
}
|
|
125
|
+
export function makeLaunchctlRunner() {
|
|
126
|
+
return (args) => new Promise((resolvePromise) => {
|
|
127
|
+
const child = spawn("launchctl", [...args], { stdio: ["ignore", "pipe", "pipe"] });
|
|
128
|
+
let stdout = "";
|
|
129
|
+
let stderr = "";
|
|
130
|
+
child.stdout?.on("data", (chunk) => {
|
|
131
|
+
stdout += chunk.toString("utf8");
|
|
132
|
+
});
|
|
133
|
+
child.stderr?.on("data", (chunk) => {
|
|
134
|
+
stderr += chunk.toString("utf8");
|
|
135
|
+
});
|
|
136
|
+
child.on("error", (error) => {
|
|
137
|
+
resolvePromise({ code: 127, stdout, stderr: `${stderr}${error.message}` });
|
|
138
|
+
});
|
|
139
|
+
child.on("close", (code) => {
|
|
140
|
+
resolvePromise({ code: code ?? 0, stdout, stderr });
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/** True when the service is bootstrapped in the user's gui domain. */
|
|
145
|
+
export async function isLoaded(runner, label, uid) {
|
|
146
|
+
const result = await runner(["print", serviceTarget(label, uid)]);
|
|
147
|
+
return result.code === 0;
|
|
148
|
+
}
|
|
149
|
+
/** Bootstrap (load + RunAtLoad-launch) the plist. Caller tolerates "already bootstrapped". */
|
|
150
|
+
export async function bootstrap(runner, plistPath, uid) {
|
|
151
|
+
return await runner(["bootstrap", domainTarget(uid), plistPath]);
|
|
152
|
+
}
|
|
153
|
+
/** Kill and restart an already-loaded service, picking up a rewritten plist. */
|
|
154
|
+
export async function kickstartRestart(runner, label, uid) {
|
|
155
|
+
return await runner(["kickstart", "-k", serviceTarget(label, uid)]);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Remove the service from the domain. Sends SIGTERM and — unlike a plain kill —
|
|
159
|
+
* prevents KeepAlive from relaunching it. Caller tolerates "not loaded".
|
|
160
|
+
*/
|
|
161
|
+
export async function bootout(runner, label, uid) {
|
|
162
|
+
return await runner(["bootout", serviceTarget(label, uid)]);
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=launchd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launchd.js","sourceRoot":"","sources":["../src/launchd.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-app memory ritual scheduler for the `bujo` tier.
|
|
3
|
+
*
|
|
4
|
+
* Schedules `store.reflect()` and `store.migrate()` on their configured cron
|
|
5
|
+
* cadences (defaults: `0 3 * * *` / `0 4 1 * *`). Uses a hand-rolled minimal
|
|
6
|
+
* cron next-run calculator (5-field `m h dom mon dow`); avoids adding
|
|
7
|
+
* `cron-parser` as a direct dep of this package.
|
|
8
|
+
*
|
|
9
|
+
* Design guarantees:
|
|
10
|
+
* - Only schedules for `store.tier() === "bujo"` (needs the LLM tier).
|
|
11
|
+
* - Rituals default-enabled; set `enabled: false` to opt out.
|
|
12
|
+
* - Skip-overlap: never starts a run while the previous is in flight.
|
|
13
|
+
* - Never-throws: errors are caught and logged via `logger.warn`; the
|
|
14
|
+
* scheduler reschedules after every run (success or failure).
|
|
15
|
+
* - Injectable `now` / `setTimer` / `clearTimer` for deterministic testing.
|
|
16
|
+
*/
|
|
17
|
+
export interface MemoryRitualSchedule {
|
|
18
|
+
readonly enabled?: boolean;
|
|
19
|
+
readonly cron?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface StartMemoryRitualsInput {
|
|
22
|
+
readonly store: {
|
|
23
|
+
tier(): string;
|
|
24
|
+
reflect(): Promise<unknown>;
|
|
25
|
+
migrate(): Promise<unknown>;
|
|
26
|
+
};
|
|
27
|
+
/** From config.memory.reflection */
|
|
28
|
+
readonly reflection?: MemoryRitualSchedule;
|
|
29
|
+
/** From config.memory.migration */
|
|
30
|
+
readonly migration?: MemoryRitualSchedule;
|
|
31
|
+
readonly logger?: {
|
|
32
|
+
info(m: string): void;
|
|
33
|
+
warn(m: string): void;
|
|
34
|
+
};
|
|
35
|
+
/** Injectable clock for tests. Defaults to `() => new Date()`. */
|
|
36
|
+
readonly now?: () => Date;
|
|
37
|
+
/**
|
|
38
|
+
* Injectable timer factory for tests.
|
|
39
|
+
* Defaults to a `setTimeout` wrapper returning the timeout handle.
|
|
40
|
+
*/
|
|
41
|
+
readonly setTimer?: (cb: () => void, ms: number) => {
|
|
42
|
+
unref?: () => void;
|
|
43
|
+
};
|
|
44
|
+
/** Injectable timer canceller. Defaults to `clearTimeout`. */
|
|
45
|
+
readonly clearTimer?: (handle: unknown) => void;
|
|
46
|
+
}
|
|
47
|
+
export interface RunningRituals {
|
|
48
|
+
stop(): void;
|
|
49
|
+
}
|
|
50
|
+
export declare function startMemoryRituals(input: StartMemoryRitualsInput): RunningRituals;
|
|
51
|
+
//# sourceMappingURL=memory-rituals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-rituals.d.ts","sourceRoot":"","sources":["../src/memory-rituals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,KAAK,EAAE;QACd,IAAI,IAAI,MAAM,CAAC;QACf,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;QAC5B,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;KAC7B,CAAC;IACF,oCAAoC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAC3C,mCAAmC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,oBAAoB,CAAC;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE;QAChB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACvB,CAAC;IACF,kEAAkE;IAClE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK;QAAE,KAAK,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;IAC3E,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CACjD;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,IAAI,IAAI,CAAC;CACd;AAMD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,cAAc,CAqGjF"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-app memory ritual scheduler for the `bujo` tier.
|
|
3
|
+
*
|
|
4
|
+
* Schedules `store.reflect()` and `store.migrate()` on their configured cron
|
|
5
|
+
* cadences (defaults: `0 3 * * *` / `0 4 1 * *`). Uses a hand-rolled minimal
|
|
6
|
+
* cron next-run calculator (5-field `m h dom mon dow`); avoids adding
|
|
7
|
+
* `cron-parser` as a direct dep of this package.
|
|
8
|
+
*
|
|
9
|
+
* Design guarantees:
|
|
10
|
+
* - Only schedules for `store.tier() === "bujo"` (needs the LLM tier).
|
|
11
|
+
* - Rituals default-enabled; set `enabled: false` to opt out.
|
|
12
|
+
* - Skip-overlap: never starts a run while the previous is in flight.
|
|
13
|
+
* - Never-throws: errors are caught and logged via `logger.warn`; the
|
|
14
|
+
* scheduler reschedules after every run (success or failure).
|
|
15
|
+
* - Injectable `now` / `setTimer` / `clearTimer` for deterministic testing.
|
|
16
|
+
*/
|
|
17
|
+
const DEFAULT_REFLECTION_CRON = "0 3 * * *";
|
|
18
|
+
const DEFAULT_MIGRATION_CRON = "0 4 1 * *";
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Public entry point
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
export function startMemoryRituals(input) {
|
|
23
|
+
const { store, logger } = input;
|
|
24
|
+
// Only schedule for the bujo tier.
|
|
25
|
+
if (store.tier() !== "bujo") {
|
|
26
|
+
return noopRituals();
|
|
27
|
+
}
|
|
28
|
+
const now = input.now ?? (() => new Date());
|
|
29
|
+
const setTimer = input.setTimer ?? defaultSetTimer;
|
|
30
|
+
const clearTimer = input.clearTimer ?? ((h) => clearTimeout(h));
|
|
31
|
+
const handles = [];
|
|
32
|
+
let stopped = false;
|
|
33
|
+
function scheduleRitual(name, cronExpr, run) {
|
|
34
|
+
let inFlight = false;
|
|
35
|
+
let currentHandle;
|
|
36
|
+
function schedule() {
|
|
37
|
+
if (stopped) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const current = now();
|
|
41
|
+
let delayMs;
|
|
42
|
+
try {
|
|
43
|
+
delayMs = nextCronDelayMs(cronExpr, current);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
logger?.warn(`Memory ritual "${name}" has an invalid cron expression "${cronExpr}": ${err instanceof Error ? err.message : String(err)}. Ritual disabled.`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const handle = setTimer(() => {
|
|
50
|
+
// Remove from tracked handles (it has fired)
|
|
51
|
+
const idx = handles.indexOf(handle);
|
|
52
|
+
if (idx !== -1) {
|
|
53
|
+
handles.splice(idx, 1);
|
|
54
|
+
}
|
|
55
|
+
currentHandle = undefined;
|
|
56
|
+
if (stopped) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (inFlight) {
|
|
60
|
+
// Skip: the previous run is still in flight. Do NOT reschedule here — the in-flight run's
|
|
61
|
+
// .finally schedules the next tick, keeping exactly one pending timer per ritual (no double-schedule).
|
|
62
|
+
logger?.warn(`Memory ritual "${name}" skipped — previous run is still in flight.`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
inFlight = true;
|
|
66
|
+
run()
|
|
67
|
+
.catch((err) => {
|
|
68
|
+
logger?.warn(`Memory ritual "${name}" failed: ${err instanceof Error ? err.message : String(err)}.`);
|
|
69
|
+
})
|
|
70
|
+
.finally(() => {
|
|
71
|
+
inFlight = false;
|
|
72
|
+
schedule();
|
|
73
|
+
});
|
|
74
|
+
}, delayMs);
|
|
75
|
+
handle.unref?.();
|
|
76
|
+
currentHandle = handle;
|
|
77
|
+
handles.push(handle);
|
|
78
|
+
}
|
|
79
|
+
schedule();
|
|
80
|
+
void currentHandle; // suppress unused-variable lint; reference is in handles
|
|
81
|
+
}
|
|
82
|
+
// Schedule reflection ritual
|
|
83
|
+
if (input.reflection?.enabled !== false) {
|
|
84
|
+
const cronExpr = input.reflection?.cron ?? DEFAULT_REFLECTION_CRON;
|
|
85
|
+
scheduleRitual("reflect", cronExpr, () => store.reflect());
|
|
86
|
+
}
|
|
87
|
+
// Schedule migration ritual
|
|
88
|
+
if (input.migration?.enabled !== false) {
|
|
89
|
+
const cronExpr = input.migration?.cron ?? DEFAULT_MIGRATION_CRON;
|
|
90
|
+
scheduleRitual("migrate", cronExpr, () => store.migrate());
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
stop() {
|
|
94
|
+
stopped = true;
|
|
95
|
+
for (const h of handles.splice(0)) {
|
|
96
|
+
if (h !== undefined) {
|
|
97
|
+
clearTimer(h);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// Minimal 5-field cron next-run calculator
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
//
|
|
107
|
+
// Supports `m h dom mon dow` where each field is:
|
|
108
|
+
// * matches every value
|
|
109
|
+
// <number> exact match
|
|
110
|
+
// */n step (e.g. */5 = every 5)
|
|
111
|
+
// a-b range
|
|
112
|
+
// a,b,c list
|
|
113
|
+
// a-b/n range with step
|
|
114
|
+
//
|
|
115
|
+
// Sufficient for the two defaults + most simple expressions.
|
|
116
|
+
// Time complexity: O(minutes-until-next-run), bounded by 366*24*60 ≈ 530k.
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
function nextCronDelayMs(expression, from) {
|
|
119
|
+
const fields = expression.trim().split(/\s+/u);
|
|
120
|
+
if (fields.length !== 5) {
|
|
121
|
+
throw new Error(`Expected 5 fields; got ${fields.length}`);
|
|
122
|
+
}
|
|
123
|
+
const [mField, hField, domField, monField, dowField] = fields;
|
|
124
|
+
// Search forward minute by minute for up to ~2 years
|
|
125
|
+
// Start from the NEXT minute after `from` (cron fires at the start of the minute)
|
|
126
|
+
const candidate = new Date(from.getTime());
|
|
127
|
+
// Advance to the next whole minute
|
|
128
|
+
candidate.setUTCSeconds(0, 0);
|
|
129
|
+
candidate.setUTCMinutes(candidate.getUTCMinutes() + 1);
|
|
130
|
+
const MAX_ITERATIONS = 365 * 24 * 60 * 2; // 2 years in minutes
|
|
131
|
+
for (let i = 0; i < MAX_ITERATIONS; i++) {
|
|
132
|
+
const min = candidate.getUTCMinutes();
|
|
133
|
+
const hour = candidate.getUTCHours();
|
|
134
|
+
const dom = candidate.getUTCDate();
|
|
135
|
+
const mon = candidate.getUTCMonth() + 1; // 1-12
|
|
136
|
+
const dow = candidate.getUTCDay(); // 0 (Sun) – 6 (Sat)
|
|
137
|
+
if (matchField(mField, min, 0, 59) &&
|
|
138
|
+
matchField(hField, hour, 0, 23) &&
|
|
139
|
+
matchField(monField, mon, 1, 12) &&
|
|
140
|
+
matchDayField(domField, dowField, dom, dow)) {
|
|
141
|
+
return candidate.getTime() - from.getTime();
|
|
142
|
+
}
|
|
143
|
+
candidate.setUTCMinutes(candidate.getUTCMinutes() + 1);
|
|
144
|
+
}
|
|
145
|
+
throw new Error(`No match found in 2 years for cron expression "${expression}"`);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Standard cron DOM/DOW logic:
|
|
149
|
+
* - If BOTH dom and dow are restricted (not `*`), either matching satisfies.
|
|
150
|
+
* - If only one is restricted, only that one must match.
|
|
151
|
+
* - If both are `*`, always matches.
|
|
152
|
+
*/
|
|
153
|
+
function matchDayField(domField, dowField, dom, dow) {
|
|
154
|
+
const domRestricted = domField !== "*";
|
|
155
|
+
const dowRestricted = dowField !== "*";
|
|
156
|
+
if (domRestricted && dowRestricted) {
|
|
157
|
+
return matchField(domField, dom, 1, 31) || matchField(dowField, dow, 0, 6);
|
|
158
|
+
}
|
|
159
|
+
if (domRestricted) {
|
|
160
|
+
return matchField(domField, dom, 1, 31);
|
|
161
|
+
}
|
|
162
|
+
if (dowRestricted) {
|
|
163
|
+
return matchField(dowField, dow, 0, 6);
|
|
164
|
+
}
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
function matchField(field, value, _min, _max) {
|
|
168
|
+
// Comma-separated list
|
|
169
|
+
const parts = field.split(",");
|
|
170
|
+
return parts.some((part) => matchPart(part.trim(), value, _min, _max));
|
|
171
|
+
}
|
|
172
|
+
function matchPart(part, value, min, max) {
|
|
173
|
+
// Wildcard
|
|
174
|
+
if (part === "*") {
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
// Step: */n or a-b/n
|
|
178
|
+
const slashIdx = part.indexOf("/");
|
|
179
|
+
if (slashIdx !== -1) {
|
|
180
|
+
const stepStr = part.slice(slashIdx + 1);
|
|
181
|
+
const step = parseInt(stepStr, 10);
|
|
182
|
+
if (Number.isNaN(step) || step <= 0) {
|
|
183
|
+
throw new Error(`Invalid step in cron field part "${part}"`);
|
|
184
|
+
}
|
|
185
|
+
const rangePart = part.slice(0, slashIdx);
|
|
186
|
+
let rangeStart = min;
|
|
187
|
+
let rangeEnd = max;
|
|
188
|
+
if (rangePart !== "*") {
|
|
189
|
+
const dashIdx = rangePart.indexOf("-");
|
|
190
|
+
if (dashIdx !== -1) {
|
|
191
|
+
rangeStart = parseInt(rangePart.slice(0, dashIdx), 10);
|
|
192
|
+
rangeEnd = parseInt(rangePart.slice(dashIdx + 1), 10);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
rangeStart = parseInt(rangePart, 10);
|
|
196
|
+
rangeEnd = max;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (value < rangeStart || value > rangeEnd) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
return (value - rangeStart) % step === 0;
|
|
203
|
+
}
|
|
204
|
+
// Range: a-b
|
|
205
|
+
const dashIdx = part.indexOf("-");
|
|
206
|
+
if (dashIdx !== -1) {
|
|
207
|
+
const rangeStart = parseInt(part.slice(0, dashIdx), 10);
|
|
208
|
+
const rangeEnd = parseInt(part.slice(dashIdx + 1), 10);
|
|
209
|
+
return value >= rangeStart && value <= rangeEnd;
|
|
210
|
+
}
|
|
211
|
+
// Exact number
|
|
212
|
+
const num = parseInt(part, 10);
|
|
213
|
+
if (Number.isNaN(num)) {
|
|
214
|
+
throw new Error(`Invalid cron field part "${part}"`);
|
|
215
|
+
}
|
|
216
|
+
return value === num;
|
|
217
|
+
}
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
// Helpers
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
function noopRituals() {
|
|
222
|
+
return { stop() { } };
|
|
223
|
+
}
|
|
224
|
+
function defaultSetTimer(cb, ms) {
|
|
225
|
+
const handle = setTimeout(cb, ms);
|
|
226
|
+
return { unref: () => handle.unref() };
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=memory-rituals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-rituals.js","sourceRoot":"","sources":["../src/memory-rituals.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mono-agent/agent-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Config-first mono-agent host: builds a responder and starts every configured communication channel, operator console, and traceability from one mono-agent.config.json.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -22,20 +22,20 @@
|
|
|
22
22
|
"README.md"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@mono-agent/a2a-adapter": "0.
|
|
26
|
-
"@mono-agent/agent-contracts": "0.
|
|
27
|
-
"@mono-agent/agent-host": "0.
|
|
28
|
-
"@mono-agent/config": "0.
|
|
29
|
-
"@mono-agent/cron-adapter": "0.
|
|
30
|
-
"@mono-agent/observability": "0.
|
|
31
|
-
"@mono-agent/openai-api-adapter": "0.
|
|
32
|
-
"@mono-agent/operator-console": "0.
|
|
33
|
-
"@mono-agent/runtime-adapter": "0.
|
|
34
|
-
"@mono-agent/settings": "0.
|
|
35
|
-
"@mono-agent/slack-adapter": "0.
|
|
36
|
-
"@mono-agent/telegram-adapter": "0.
|
|
37
|
-
"@mono-agent/webhook-adapter": "0.
|
|
38
|
-
"@mono-agent/whatsapp-adapter": "0.
|
|
25
|
+
"@mono-agent/a2a-adapter": "0.3.0",
|
|
26
|
+
"@mono-agent/agent-contracts": "0.3.0",
|
|
27
|
+
"@mono-agent/agent-host": "0.3.0",
|
|
28
|
+
"@mono-agent/config": "0.3.0",
|
|
29
|
+
"@mono-agent/cron-adapter": "0.3.0",
|
|
30
|
+
"@mono-agent/observability": "0.3.0",
|
|
31
|
+
"@mono-agent/openai-api-adapter": "0.3.0",
|
|
32
|
+
"@mono-agent/operator-console": "0.3.0",
|
|
33
|
+
"@mono-agent/runtime-adapter": "0.3.0",
|
|
34
|
+
"@mono-agent/settings": "0.3.0",
|
|
35
|
+
"@mono-agent/slack-adapter": "0.3.0",
|
|
36
|
+
"@mono-agent/telegram-adapter": "0.3.0",
|
|
37
|
+
"@mono-agent/webhook-adapter": "0.3.0",
|
|
38
|
+
"@mono-agent/whatsapp-adapter": "0.3.0"
|
|
39
39
|
},
|
|
40
40
|
"publishConfig": {
|
|
41
41
|
"access": "public"
|
|
@@ -41,7 +41,7 @@ Everything below runs in the user's agent folder, not the workspace.
|
|
|
41
41
|
2. **Scaffold.** In the user's folder run:
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
|
-
mono-agent init --model <ref> [--fallback-models <csv>] [--memory
|
|
44
|
+
mono-agent init --model <ref> [--fallback-models <csv>] [--memory lite|journal|bujo]
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
This writes a minimal `mono-agent.config.json` (webhook enabled as the zero-credential smoke channel), an `IDENTITY.md` that references any knowledge files already present, and `.mono-agent/` working directories. It never overwrites existing files.
|
|
@@ -63,7 +63,7 @@ Everything below runs in the user's agent folder, not the workspace.
|
|
|
63
63
|
|
|
64
64
|
## When Config Is Not Enough
|
|
65
65
|
|
|
66
|
-
Config-first covers one responder served over any combination of the seven channels (webhook, OpenAI-compatible API, Telegram, Slack, WhatsApp, A2A, cron) plus the operator console, sandbox, memory (
|
|
66
|
+
Config-first covers one responder served over any combination of the seven channels (webhook, OpenAI-compatible API, Telegram, Slack, WhatsApp, A2A, cron) plus the operator console, sandbox, memory (lite with FTS-only recall, journal with hybrid BM25+vector recall + Ollama embeddings, or bujo with SQLite-indexed hybrid recall + LLM capture/reconcile + entity graph + auto-scheduled reflection/migration), and traceability. Drop to programmatic composition only for: custom runtimes (`MonoRuntimeLike`, incl. the OpenAI Agents SDK), request-scoped runtime extensions, tool approval gates, structured output schemas, multi-agent orchestration (`@mono-agent/agent-orchestrator`), custom channel message texts, or bespoke transports — `references/feature-coverage.md` lists which features are config keys and which are code-only. Read `references/package-map.md` for the package boundaries, and start from `startMonoAgentApp({ drivers, runtime, ... })` or `@mono-agent/agent-host` rather than re-writing lifecycle glue. For eval suites over the composed agent, use `@mono-agent/agent-evals`.
|
|
67
67
|
|
|
68
68
|
## Implementation References
|
|
69
69
|
|