@mnemom/mnemom 0.17.34-next.1 → 0.17.34-next.3
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/base-url-proxy.mjs +18 -4
- package/dist/commands/agent-config.js +5 -1
- package/dist/commands/agent-doctor.d.ts +9 -0
- package/dist/commands/agent-doctor.js +4 -0
- package/dist/commands/agent-run.d.ts +14 -6
- package/dist/commands/agent-run.js +44 -27
- package/dist/commands/agent-session.d.ts +1 -2
- package/dist/commands/agent-session.js +1 -2
- package/dist/commands/agent-setup.d.ts +6 -0
- package/dist/commands/agent-setup.js +12 -1
- package/dist/commands/agent-share-test-issuer.d.ts +67 -0
- package/dist/commands/agent-share-test-issuer.js +139 -0
- package/dist/commands/agent-share.d.ts +7 -1
- package/dist/commands/agent-share.js +14 -4
- package/dist/commands/agent.d.ts +18 -5
- package/dist/commands/agent.js +186 -59
- package/dist/commands/durable-doctor.d.ts +50 -0
- package/dist/commands/durable-doctor.js +186 -0
- package/dist/commands/durable-lock.d.ts +261 -0
- package/dist/commands/durable-lock.js +600 -0
- package/dist/commands/durable-sessions.d.ts +87 -0
- package/dist/commands/durable-sessions.js +303 -0
- package/dist/commands/durable-verbs.d.ts +116 -0
- package/dist/commands/durable-verbs.js +393 -0
- package/dist/commands/scan.d.ts +12 -1
- package/dist/commands/scan.js +22 -3
- package/dist/commands/wrap.js +1 -1
- package/dist/durable/adopt-live.js +5 -8
- package/dist/durable/adopt.d.ts +8 -0
- package/dist/durable/adopt.js +27 -6
- package/dist/durable/cwd-rule.d.ts +9 -1
- package/dist/durable/cwd-rule.js +18 -0
- package/dist/durable/flock.d.ts +26 -0
- package/dist/durable/flock.js +80 -0
- package/dist/durable/launch-spec.d.ts +9 -1
- package/dist/durable/launch-spec.js +11 -4
- package/dist/durable/seat-proxy-entry.d.ts +11 -0
- package/dist/durable/seat-proxy-entry.js +25 -0
- package/dist/durable/seat-proxy.d.ts +107 -0
- package/dist/durable/seat-proxy.js +599 -0
- package/dist/durable/seat-socket.d.ts +46 -0
- package/dist/durable/seat-socket.js +179 -0
- package/dist/durable/seat-spec-validator.d.ts +28 -0
- package/dist/durable/seat-spec-validator.js +59 -0
- package/dist/durable/test-mode.mjs +105 -0
- package/dist/durable/turn-chain.d.ts +55 -0
- package/dist/durable/turn-chain.js +178 -0
- package/dist/host/auto-continue.d.ts +67 -0
- package/dist/host/auto-continue.js +118 -0
- package/dist/host/bootid.d.ts +13 -0
- package/dist/host/bootid.js +41 -0
- package/dist/host/client.d.ts +125 -0
- package/dist/host/client.js +171 -0
- package/dist/host/commands.d.ts +2 -0
- package/dist/host/commands.js +122 -0
- package/dist/host/control.d.ts +33 -0
- package/dist/host/control.js +144 -0
- package/dist/host/daemon.d.ts +221 -0
- package/dist/host/daemon.js +616 -0
- package/dist/host/gate.d.ts +46 -0
- package/dist/host/gate.js +82 -0
- package/dist/host/grant.d.ts +24 -0
- package/dist/host/grant.js +24 -0
- package/dist/host/instance.d.ts +35 -0
- package/dist/host/instance.js +62 -0
- package/dist/host/integrity.d.ts +35 -0
- package/dist/host/integrity.js +115 -0
- package/dist/host/launchd.d.ts +16 -0
- package/dist/host/launchd.js +45 -0
- package/dist/host/lock.d.ts +20 -0
- package/dist/host/lock.js +63 -0
- package/dist/host/owner.d.ts +58 -0
- package/dist/host/owner.js +123 -0
- package/dist/host/plist.d.ts +16 -0
- package/dist/host/plist.js +85 -0
- package/dist/host/procs.d.ts +27 -0
- package/dist/host/procs.js +105 -0
- package/dist/host/run.d.ts +65 -0
- package/dist/host/run.js +299 -0
- package/dist/host/runtime.d.ts +8 -0
- package/dist/host/runtime.js +22 -0
- package/dist/host/s1-names.d.ts +23 -0
- package/dist/host/s1-names.js +22 -0
- package/dist/host/seat-credential.d.ts +27 -0
- package/dist/host/seat-credential.js +41 -0
- package/dist/host/seat-launch-main.d.ts +1 -0
- package/dist/host/seat-launch-main.js +59 -0
- package/dist/host/seat-launch.d.ts +116 -0
- package/dist/host/seat-launch.js +302 -0
- package/dist/host/seat.d.ts +48 -0
- package/dist/host/seat.js +149 -0
- package/dist/host/state.d.ts +33 -0
- package/dist/host/state.js +117 -0
- package/dist/host/status.d.ts +101 -0
- package/dist/host/status.js +307 -0
- package/dist/host/tmux.d.ts +56 -0
- package/dist/host/tmux.js +182 -0
- package/dist/host/transcript.d.ts +30 -0
- package/dist/host/transcript.js +130 -0
- package/dist/host/verbs.d.ts +52 -0
- package/dist/host/verbs.js +282 -0
- package/dist/index.d.ts +8 -6
- package/dist/index.js +209 -43
- package/dist/lib/agent.d.ts +13 -29
- package/dist/lib/agent.js +17 -29
- package/dist/lib/claude-bin.d.ts +6 -0
- package/dist/lib/claude-bin.js +26 -0
- package/dist/lib/claude-plugin.d.ts +11 -2
- package/dist/lib/claude-plugin.js +10 -1
- package/dist/lib/commit-report.d.ts +5 -4
- package/dist/lib/commit-report.js +6 -9
- package/dist/lib/config.d.ts +8 -1
- package/dist/lib/config.js +28 -0
- package/dist/lib/durable/api.d.ts +136 -0
- package/dist/lib/durable/api.js +220 -0
- package/dist/lib/durable/codes.d.ts +8 -0
- package/dist/lib/durable/codes.js +2 -0
- package/dist/lib/durable/gate.d.ts +48 -0
- package/dist/lib/durable/gate.js +122 -0
- package/dist/lib/durable/handover.d.ts +101 -0
- package/dist/lib/durable/handover.js +175 -0
- package/dist/lib/durable/launch.d.ts +199 -0
- package/dist/lib/durable/launch.js +461 -0
- package/dist/lib/durable/launching.d.ts +15 -0
- package/dist/lib/durable/launching.js +70 -0
- package/dist/lib/durable/live.d.ts +190 -0
- package/dist/lib/durable/live.js +633 -0
- package/dist/lib/durable/refusal.d.ts +57 -0
- package/dist/lib/durable/refusal.js +78 -0
- package/dist/lib/durable/view.d.ts +83 -0
- package/dist/lib/durable/view.js +244 -0
- package/dist/lib/experimental.d.ts +0 -9
- package/dist/lib/experimental.js +18 -17
- package/dist/lib/launcher-config.d.ts +13 -0
- package/dist/lib/launcher-config.js +32 -0
- package/dist/lib/runner/exec-append.d.ts +15 -0
- package/dist/lib/runner/exec-append.js +2 -0
- package/dist/lib/runner/executor-client.d.ts +2 -1
- package/dist/lib/runner/executor-state.d.ts +10 -0
- package/dist/lib/runner/executor-state.js +24 -0
- package/dist/lib/runner/github-base.d.ts +24 -0
- package/dist/lib/runner/github-base.js +27 -0
- package/dist/lib/runner/job.d.ts +9 -4
- package/dist/lib/runner/job.js +43 -15
- package/dist/lib/runner/oidc.d.ts +3 -2
- package/dist/lib/runner/oidc.js +7 -4
- package/dist/lib/runner/options.d.ts +6 -0
- package/dist/lib/runner/options.js +19 -1
- package/dist/lib/runner/phases.d.ts +7 -4
- package/dist/lib/runner/phases.js +8 -4
- package/dist/lib/runner/proxy.d.ts +5 -1
- package/dist/lib/runner/proxy.js +7 -1
- package/dist/lib/scan/cost-per-pr.d.ts +93 -0
- package/dist/lib/scan/cost-per-pr.js +101 -0
- package/dist/lib/scan/record.d.ts +27 -1
- package/dist/lib/scan/record.js +114 -16
- package/dist/lib/scan/report-email.d.ts +26 -6
- package/dist/lib/scan/report-email.js +32 -3
- package/dist/lib/scan/scan.d.ts +3 -0
- package/dist/lib/scan/scan.js +13 -1
- package/dist/lib/subscription-login.d.ts +15 -0
- package/dist/lib/subscription-login.js +28 -1
- package/dist/vendor/durable-contract/index.js +240 -18
- package/dist/vendor/shared/durable-contract/admission.d.ts +240 -0
- package/dist/vendor/shared/durable-contract/admission.js +533 -0
- package/dist/vendor/shared/durable-contract/arm.d.ts +51 -0
- package/dist/vendor/shared/durable-contract/arm.js +133 -0
- package/dist/vendor/shared/durable-contract/canonical.d.ts +29 -0
- package/dist/vendor/shared/durable-contract/canonical.js +98 -0
- package/dist/vendor/shared/durable-contract/cell-id.d.ts +22 -0
- package/dist/vendor/shared/durable-contract/cell-id.js +38 -0
- package/dist/vendor/shared/durable-contract/cli-output.d.ts +342 -0
- package/dist/vendor/shared/durable-contract/cli-output.js +201 -0
- package/dist/vendor/shared/durable-contract/cli-surface.d.ts +119 -0
- package/dist/vendor/shared/durable-contract/cli-surface.js +270 -0
- package/dist/vendor/shared/durable-contract/codes.d.ts +537 -0
- package/dist/vendor/shared/durable-contract/codes.js +475 -0
- package/dist/vendor/shared/durable-contract/constants.d.ts +153 -0
- package/dist/vendor/shared/durable-contract/constants.js +179 -0
- package/dist/vendor/shared/durable-contract/doors.d.ts +119 -0
- package/dist/vendor/shared/durable-contract/doors.js +249 -0
- package/dist/vendor/shared/durable-contract/envelope.d.ts +103 -0
- package/dist/vendor/shared/durable-contract/envelope.js +317 -0
- package/dist/vendor/shared/durable-contract/events.d.ts +147 -0
- package/dist/vendor/shared/durable-contract/events.js +630 -0
- package/dist/vendor/shared/durable-contract/executor-state.d.ts +41 -0
- package/dist/vendor/shared/durable-contract/executor-state.js +32 -0
- package/dist/vendor/shared/durable-contract/fixlines.d.ts +318 -0
- package/dist/vendor/shared/durable-contract/fixlines.js +483 -0
- package/dist/vendor/shared/durable-contract/freeze-record.d.ts +787 -0
- package/dist/vendor/shared/durable-contract/freeze-record.js +361 -0
- package/dist/vendor/shared/durable-contract/index.d.ts +36 -0
- package/dist/vendor/shared/durable-contract/index.js +37 -0
- package/dist/vendor/shared/durable-contract/journal-approvals.d.ts +29 -0
- package/dist/vendor/shared/durable-contract/journal-approvals.js +60 -0
- package/dist/vendor/shared/durable-contract/keys.d.ts +24 -0
- package/dist/vendor/shared/durable-contract/keys.js +66 -0
- package/dist/vendor/shared/durable-contract/lock.d.ts +128 -0
- package/dist/vendor/shared/durable-contract/lock.js +151 -0
- package/dist/vendor/shared/durable-contract/names.d.ts +25 -0
- package/dist/vendor/shared/durable-contract/names.js +78 -0
- package/dist/vendor/shared/durable-contract/owner-verbs.d.ts +175 -0
- package/dist/vendor/shared/durable-contract/owner-verbs.js +403 -0
- package/dist/vendor/shared/durable-contract/paths.d.ts +23 -0
- package/dist/vendor/shared/durable-contract/paths.js +35 -0
- package/dist/vendor/shared/durable-contract/pure-fn.d.ts +48 -0
- package/dist/vendor/shared/durable-contract/pure-fn.js +89 -0
- package/dist/vendor/shared/durable-contract/routes.d.ts +205 -0
- package/dist/vendor/shared/durable-contract/routes.js +315 -0
- package/dist/vendor/shared/durable-contract/schema.d.ts +126 -0
- package/dist/vendor/shared/durable-contract/schema.js +441 -0
- package/dist/vendor/shared/durable-contract/seal.d.ts +54 -0
- package/dist/vendor/shared/durable-contract/seal.js +99 -0
- package/dist/vendor/shared/durable-contract/secret-scope.d.ts +28 -0
- package/dist/vendor/shared/durable-contract/secret-scope.js +76 -0
- package/dist/vendor/shared/durable-contract/session-id.d.ts +21 -0
- package/dist/vendor/shared/durable-contract/session-id.js +58 -0
- package/dist/vendor/shared/durable-contract/spec.d.ts +162 -0
- package/dist/vendor/shared/durable-contract/spec.js +286 -0
- package/dist/vendor/shared/durable-contract/states.d.ts +96 -0
- package/dist/vendor/shared/durable-contract/states.js +218 -0
- package/dist/vendor/shared/durable-contract/telemetry.d.ts +94 -0
- package/dist/vendor/shared/durable-contract/telemetry.js +180 -0
- package/dist/vendor/shared/durable-contract/test-mode.d.ts +62 -0
- package/dist/vendor/shared/durable-contract/test-mode.js +140 -0
- package/dist/vendor/shared/durable-contract/turn.d.ts +57 -0
- package/dist/vendor/shared/durable-contract/turn.js +81 -0
- package/dist/vendor/shared/durable-contract/vectors.d.ts +191 -0
- package/dist/vendor/shared/durable-contract/vectors.js +208 -0
- package/package.json +3 -2
- package/plugins/integrity-manifest.json +35 -0
- package/plugins/mnemom/hooks/hooks.json +15 -1
- package/plugins/mnemom/hooks/register.tsx +60 -2
- package/plugins/mnemom/hooks/seat-hello.mjs +116 -0
- package/dist/commands/agent-implicit-notice.d.ts +0 -31
- package/dist/commands/agent-implicit-notice.js +0 -73
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which claude to run, shared by the host (seats) and `agent run` (served phases) so both pick
|
|
3
|
+
* the same binary. Kept apart from host/run.ts so the runner does not load the host daemon.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
/** The pinned claude: MNEMOM_AGENT_CLI when absolute, else `claude` on PATH, else null. */
|
|
8
|
+
export function resolveClaudeBin(env) {
|
|
9
|
+
const v = (env.MNEMOM_AGENT_CLI ?? "").trim();
|
|
10
|
+
if (v.startsWith("/"))
|
|
11
|
+
return v;
|
|
12
|
+
const name = v || "claude";
|
|
13
|
+
for (const dir of (env.PATH ?? "").split(":")) {
|
|
14
|
+
if (!dir)
|
|
15
|
+
continue;
|
|
16
|
+
const p = path.join(dir, name);
|
|
17
|
+
try {
|
|
18
|
+
fs.accessSync(p, fs.constants.X_OK);
|
|
19
|
+
return p;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
/* next */
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
@@ -65,11 +65,16 @@ export declare const PLUGIN_ENV: {
|
|
|
65
65
|
readonly launcherVersion: "MNEMOM_CC_LAUNCHER_VERSION";
|
|
66
66
|
};
|
|
67
67
|
export type PluginEnvName = (typeof PLUGIN_ENV)[keyof typeof PLUGIN_ENV];
|
|
68
|
+
/**
|
|
69
|
+
* Set to "1" only on a launch with the `durable` experimental gate on (BACKBONE C1): the mod then
|
|
70
|
+
* offers `/mnemom lock`. Absent otherwise, so a launch with durable off has the same env as before.
|
|
71
|
+
*/
|
|
72
|
+
export declare const PLUGIN_DURABLE_ENV = "MNEMOM_CC_DURABLE";
|
|
68
73
|
/**
|
|
69
74
|
* Whether this launch loads the plugin: `--plugin` / `--no-plugin` (an explicit boolean) wins,
|
|
70
75
|
* then MNEMOM_AGENT_PLUGIN (1/true/yes/on ⇒ on), else OFF: the plugin lands dark.
|
|
71
76
|
*/
|
|
72
|
-
export declare function pluginEnabled(optionPlugin: boolean | undefined, env: NodeJS.ProcessEnv): boolean;
|
|
77
|
+
export declare function pluginEnabled(optionPlugin: boolean | undefined, env: NodeJS.ProcessEnv, durable?: boolean): boolean;
|
|
73
78
|
/**
|
|
74
79
|
* The bundled plugin's folder (the one holding `.claude-plugin/plugin.json`), or null when it is
|
|
75
80
|
* missing. Lives at `<package>/plugins/mnemom`, next to `dist/` and `src/`, so it is
|
|
@@ -97,12 +102,16 @@ export interface PluginLaunch {
|
|
|
97
102
|
launcherExec?: readonly string[];
|
|
98
103
|
scenario: string;
|
|
99
104
|
launcherVersion: string;
|
|
105
|
+
/** The `durable` gate is on for this launch (adds PLUGIN_DURABLE_ENV=1). */
|
|
106
|
+
durable?: boolean;
|
|
100
107
|
}
|
|
101
108
|
/**
|
|
102
109
|
* The `MNEMOM_CC_*` block for the child env. Pure: no key, no header, nothing the gateway
|
|
103
110
|
* authenticates with — just what the launch log already prints to stderr.
|
|
104
111
|
*/
|
|
105
|
-
export declare function buildPluginEnv(launch: PluginLaunch): Record<PluginEnvName, string
|
|
112
|
+
export declare function buildPluginEnv(launch: PluginLaunch): Record<PluginEnvName, string> & {
|
|
113
|
+
[PLUGIN_DURABLE_ENV]?: "1";
|
|
114
|
+
};
|
|
106
115
|
/** Writes the block onto a child env in place (the launch shapes all build their env first). */
|
|
107
116
|
export declare function applyPluginEnv(childEnv: NodeJS.ProcessEnv, launch: PluginLaunch): void;
|
|
108
117
|
/**
|
|
@@ -67,14 +67,22 @@ export const PLUGIN_ENV = {
|
|
|
67
67
|
session: "MNEMOM_CC_SESSION",
|
|
68
68
|
launcherVersion: "MNEMOM_CC_LAUNCHER_VERSION",
|
|
69
69
|
};
|
|
70
|
+
/**
|
|
71
|
+
* Set to "1" only on a launch with the `durable` experimental gate on (BACKBONE C1): the mod then
|
|
72
|
+
* offers `/mnemom lock`. Absent otherwise, so a launch with durable off has the same env as before.
|
|
73
|
+
*/
|
|
74
|
+
export const PLUGIN_DURABLE_ENV = "MNEMOM_CC_DURABLE";
|
|
70
75
|
const TRUTHY = new Set(["1", "true", "yes", "on"]);
|
|
71
76
|
/**
|
|
72
77
|
* Whether this launch loads the plugin: `--plugin` / `--no-plugin` (an explicit boolean) wins,
|
|
73
78
|
* then MNEMOM_AGENT_PLUGIN (1/true/yes/on ⇒ on), else OFF: the plugin lands dark.
|
|
74
79
|
*/
|
|
75
|
-
export function pluginEnabled(optionPlugin, env) {
|
|
80
|
+
export function pluginEnabled(optionPlugin, env, durable = false) {
|
|
76
81
|
if (optionPlugin !== undefined)
|
|
77
82
|
return optionPlugin;
|
|
83
|
+
// BACKBONE C1 "plugin on for durable sessions": with the durable gate on it defaults on.
|
|
84
|
+
if (durable)
|
|
85
|
+
return true;
|
|
78
86
|
const raw = (env.MNEMOM_AGENT_PLUGIN ?? "").trim().toLowerCase();
|
|
79
87
|
return TRUTHY.has(raw);
|
|
80
88
|
}
|
|
@@ -121,6 +129,7 @@ export function buildPluginEnv(launch) {
|
|
|
121
129
|
[PLUGIN_ENV.launcherExec]: exec.length > 0 ? JSON.stringify(exec) : "",
|
|
122
130
|
[PLUGIN_ENV.session]: clean(launch.scenario),
|
|
123
131
|
[PLUGIN_ENV.launcherVersion]: clean(launch.launcherVersion),
|
|
132
|
+
...(launch.durable ? { [PLUGIN_DURABLE_ENV]: "1" } : {}),
|
|
124
133
|
};
|
|
125
134
|
}
|
|
126
135
|
/** Writes the block onto a child env in place (the launch shapes all build their env first). */
|
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
* reported, trailer or not: a commit is bound when the index holds its sha or
|
|
20
20
|
* patch-id, never by its trailer alone.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
22
|
+
* ON BY DEFAULT, stable and prerelease alike, so a PR from any `mnemom agent`
|
|
23
|
+
* session gets its commits bound in the record. MNEMOM_AGENT_COMMIT_REPORT=off
|
|
24
|
+
* (or 0, false, no) turns it off; any other value reads on.
|
|
24
25
|
*
|
|
25
26
|
* FAIL OPEN. Nothing here throws into the launch or changes its exit code. A
|
|
26
27
|
* dark route (404) stops reporting for the session; a failed POST is retried on
|
|
@@ -36,8 +37,8 @@ export declare const CC_DEFAULT_COMMIT_ATTRIBUTION = "Co-Authored-By: Claude <no
|
|
|
36
37
|
export declare const COMMIT_POLL_MS = 5000;
|
|
37
38
|
/** The final sweep at exit shares W1.3's 2 s exit budget with the conduct receipt. */
|
|
38
39
|
export declare const COMMIT_FINAL_DEADLINE_MS = 1500;
|
|
39
|
-
/**
|
|
40
|
-
export declare function commitReportEnabled(raw: string | undefined
|
|
40
|
+
/** On unless MNEMOM_AGENT_COMMIT_REPORT says off (off, 0, false, no). */
|
|
41
|
+
export declare function commitReportEnabled(raw: string | undefined): boolean;
|
|
41
42
|
/**
|
|
42
43
|
* The `--settings` fragment carrying the trailer. `user` is the commit attribution
|
|
43
44
|
* the user's settings files give (highest precedence first; `false` hides all
|
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
* reported, trailer or not: a commit is bound when the index holds its sha or
|
|
20
20
|
* patch-id, never by its trailer alone.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
22
|
+
* ON BY DEFAULT, stable and prerelease alike, so a PR from any `mnemom agent`
|
|
23
|
+
* session gets its commits bound in the record. MNEMOM_AGENT_COMMIT_REPORT=off
|
|
24
|
+
* (or 0, false, no) turns it off; any other value reads on.
|
|
24
25
|
*
|
|
25
26
|
* FAIL OPEN. Nothing here throws into the launch or changes its exit code. A
|
|
26
27
|
* dark route (404) stops reporting for the session; a failed POST is retried on
|
|
@@ -31,7 +32,6 @@
|
|
|
31
32
|
import { spawnSync } from "node:child_process";
|
|
32
33
|
import { postRecordCommit } from "./api.js";
|
|
33
34
|
import { readLineage } from "./statusline-feed.js";
|
|
34
|
-
import { isPrerelease } from "./update/semver.js";
|
|
35
35
|
export const COMMIT_REPORT_ENV = "MNEMOM_AGENT_COMMIT_REPORT";
|
|
36
36
|
export const TRAILER_KEY = "Mnemom-Conversation";
|
|
37
37
|
/** Claude Code's own commit attribution when none is configured (settings reference, `attribution`). */
|
|
@@ -43,12 +43,9 @@ export const COMMIT_FINAL_DEADLINE_MS = 1_500;
|
|
|
43
43
|
const HEX40 = /^[0-9a-f]{40}$/;
|
|
44
44
|
const REPO_SLUG = /^[A-Za-z0-9_.-]{1,100}\/[A-Za-z0-9_.-]{1,100}$/;
|
|
45
45
|
const BRANCH_MAX = 255;
|
|
46
|
-
/**
|
|
47
|
-
export function commitReportEnabled(raw
|
|
48
|
-
|
|
49
|
-
if (v === "")
|
|
50
|
-
return isPrerelease(version);
|
|
51
|
-
return ["on", "1", "true", "yes"].includes(v);
|
|
46
|
+
/** On unless MNEMOM_AGENT_COMMIT_REPORT says off (off, 0, false, no). */
|
|
47
|
+
export function commitReportEnabled(raw) {
|
|
48
|
+
return !["off", "0", "false", "no"].includes((raw ?? "").trim().toLowerCase());
|
|
52
49
|
}
|
|
53
50
|
/**
|
|
54
51
|
* The `--settings` fragment carrying the trailer. `user` is the commit attribution
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export declare class RetiredEnvironmentError extends Error {
|
|
|
30
30
|
* Defaults to production. `staging` throws (see RetiredEnvironmentError).
|
|
31
31
|
*/
|
|
32
32
|
export declare function getEnvironment(): Environment;
|
|
33
|
-
export type CellRing = "us-1";
|
|
33
|
+
export type CellRing = "us-1" | "test";
|
|
34
34
|
/** Explicitly select a ring for this process (clears on undefined). Wins over MNEMOM_RING. */
|
|
35
35
|
export declare function setRing(ring: CellRing | undefined): void;
|
|
36
36
|
/**
|
|
@@ -45,3 +45,10 @@ export declare function setApiUrlOverride(url: string | undefined): void;
|
|
|
45
45
|
export declare function getApiUrl(): string;
|
|
46
46
|
export declare function getGatewayUrl(): string;
|
|
47
47
|
export declare function getWebsiteUrl(): string;
|
|
48
|
+
/**
|
|
49
|
+
* Website base for links the CLI PRINTS (e.g. `agent share`). Same as getWebsiteUrl(), except
|
|
50
|
+
* when the CLI targets the test cell through its API alone (MNEMOM_API_URL / `--api`) and no
|
|
51
|
+
* website was chosen explicitly: then the link points at test.mnemom.ai, never www. An explicit
|
|
52
|
+
* MNEMOM_WEBSITE_URL or ring always wins; prod output is unchanged.
|
|
53
|
+
*/
|
|
54
|
+
export declare function getShareWebsiteUrl(): string;
|
package/dist/lib/config.js
CHANGED
|
@@ -60,6 +60,13 @@ const RING_URLS = {
|
|
|
60
60
|
gateway: "https://gateway-us1.mnemom.ai",
|
|
61
61
|
website: "https://preview.mnemom.ai",
|
|
62
62
|
},
|
|
63
|
+
// The durable Azure TEST cell (tools/gateway-tester/README.md: api-az-test / gateway-az-test;
|
|
64
|
+
// test.mnemom.ai serves the website). Never a prod host.
|
|
65
|
+
test: {
|
|
66
|
+
api: "https://api-az-test.mnemom.ai",
|
|
67
|
+
gateway: "https://gateway-az-test.mnemom.ai",
|
|
68
|
+
website: "https://test.mnemom.ai",
|
|
69
|
+
},
|
|
63
70
|
};
|
|
64
71
|
function isCellRing(value) {
|
|
65
72
|
return Object.prototype.hasOwnProperty.call(RING_URLS, value);
|
|
@@ -115,3 +122,24 @@ export function getGatewayUrl() {
|
|
|
115
122
|
export function getWebsiteUrl() {
|
|
116
123
|
return envBase("MNEMOM_WEBSITE_URL") ?? ringUrls()?.website ?? WEBSITE_URLS[getEnvironment()];
|
|
117
124
|
}
|
|
125
|
+
const TEST_CELL_API_HOST = "api-az-test.mnemom.ai";
|
|
126
|
+
/**
|
|
127
|
+
* Website base for links the CLI PRINTS (e.g. `agent share`). Same as getWebsiteUrl(), except
|
|
128
|
+
* when the CLI targets the test cell through its API alone (MNEMOM_API_URL / `--api`) and no
|
|
129
|
+
* website was chosen explicitly: then the link points at test.mnemom.ai, never www. An explicit
|
|
130
|
+
* MNEMOM_WEBSITE_URL or ring always wins; prod output is unchanged.
|
|
131
|
+
*/
|
|
132
|
+
export function getShareWebsiteUrl() {
|
|
133
|
+
const website = getWebsiteUrl();
|
|
134
|
+
if (envBase("MNEMOM_WEBSITE_URL") || getRing())
|
|
135
|
+
return website;
|
|
136
|
+
try {
|
|
137
|
+
if (new URL(getApiUrl()).hostname.toLowerCase() === TEST_CELL_API_HOST) {
|
|
138
|
+
return RING_URLS.test.website;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
/* unparseable API base: keep the default */
|
|
143
|
+
}
|
|
144
|
+
return website;
|
|
145
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The durable registry and owner-verb client (BACKBONE C1, A2; S1 routes.ts ROUTES.own_*).
|
|
3
|
+
*
|
|
4
|
+
* Every call returns `{status, body}` and never throws on an HTTP answer: the commands decide from
|
|
5
|
+
* the status and the S1 code. A transport failure, a timeout or a 5xx (other than a durable 503 the
|
|
6
|
+
* caller must surface, which keeps its body) is a `RegistryUnavailable`, so a launch fails closed
|
|
7
|
+
* with `session_registry_unavailable` (C01-R18) instead of minting a conversation it could not
|
|
8
|
+
* resolve. The timeout is fixed in code: REGISTRY_TIMEOUT_MS covers connect plus total.
|
|
9
|
+
*
|
|
10
|
+
* Credentials (S1 owner-credential rule; BACKBONE owner Q6): the owner's JWT, else the personal
|
|
11
|
+
* org `mnm_` API key (MNEMOM_API_KEY). Org containment and device-step polls are JWT-only; the
|
|
12
|
+
* caller asks for that with `jwtOnly`.
|
|
13
|
+
*
|
|
14
|
+
* Not frozen by S1 (A2 owns them; recorded in notes-c1.md as the cross-piece assumption):
|
|
15
|
+
* GET /v1/agent/sessions?name=&agent_id=&org_id= -> {sessions: Row[]} (or a bare array)
|
|
16
|
+
* POST /v1/agent/sessions/{cid}?agent_id= -> 201/200 Row (create)
|
|
17
|
+
* GET /v1/agent/sessions/{cid}/lock?agent_id=&dry_run=true -> the doctor's lock preflight
|
|
18
|
+
*/
|
|
19
|
+
import { type RouteName } from "../../vendor/shared/durable-contract/routes.js";
|
|
20
|
+
/** CLI registry timeout, connect plus total (C01-R18: at most 10 s). */
|
|
21
|
+
export declare const REGISTRY_TIMEOUT_MS = 10000;
|
|
22
|
+
export type DurableCredential = {
|
|
23
|
+
type: "jwt";
|
|
24
|
+
token: string;
|
|
25
|
+
} | {
|
|
26
|
+
type: "api-key";
|
|
27
|
+
key: string;
|
|
28
|
+
} | {
|
|
29
|
+
type: "none";
|
|
30
|
+
};
|
|
31
|
+
export interface DurableHttpDeps {
|
|
32
|
+
fetch: typeof fetch;
|
|
33
|
+
apiBase: () => string;
|
|
34
|
+
credential: () => Promise<DurableCredential>;
|
|
35
|
+
/** The active org id (`mnemom org use`), or undefined. */
|
|
36
|
+
activeOrgId: () => string | undefined;
|
|
37
|
+
/** Agents named `name` in the caller's org fleets (lib/api.ts listOrgAgents); none when absent. */
|
|
38
|
+
agentsByName?: (name: string) => Promise<Array<{
|
|
39
|
+
id: string;
|
|
40
|
+
org_id: string;
|
|
41
|
+
}>>;
|
|
42
|
+
}
|
|
43
|
+
export interface ApiAnswer {
|
|
44
|
+
status: number;
|
|
45
|
+
body: unknown;
|
|
46
|
+
}
|
|
47
|
+
/** The registry could not be read: transport error, timeout or a non-durable 5xx. */
|
|
48
|
+
export declare class RegistryUnavailable extends Error {
|
|
49
|
+
constructor(detail: string);
|
|
50
|
+
}
|
|
51
|
+
/** A registry row as the CLI reads it. Every field but the name and cid is optional. */
|
|
52
|
+
export interface RegistryRow {
|
|
53
|
+
id?: string;
|
|
54
|
+
conversation_id: string;
|
|
55
|
+
name: string | null;
|
|
56
|
+
agent_id: string;
|
|
57
|
+
org_id?: string | null;
|
|
58
|
+
agent_name?: string | null;
|
|
59
|
+
durable_mode?: "tracked" | "locked";
|
|
60
|
+
state: string;
|
|
61
|
+
state_reason?: string | null;
|
|
62
|
+
effective_state?: string;
|
|
63
|
+
cc_session_id?: string | null;
|
|
64
|
+
cwd?: string | null;
|
|
65
|
+
home_executor_id?: string | null;
|
|
66
|
+
home_executor?: {
|
|
67
|
+
id?: string;
|
|
68
|
+
machine_label?: string | null;
|
|
69
|
+
hostname?: string | null;
|
|
70
|
+
last_seen_at?: string | null;
|
|
71
|
+
revoked_at?: string | null;
|
|
72
|
+
grant_expires_at?: string | null;
|
|
73
|
+
} | null;
|
|
74
|
+
machine?: string | null;
|
|
75
|
+
spend_usd?: number | null;
|
|
76
|
+
guard_state?: {
|
|
77
|
+
spend_usd?: number | null;
|
|
78
|
+
budget_usd?: number | null;
|
|
79
|
+
} | null;
|
|
80
|
+
budget_usd?: number | null;
|
|
81
|
+
last_activity_at?: string | null;
|
|
82
|
+
updated_at?: string | null;
|
|
83
|
+
created_at?: string | null;
|
|
84
|
+
created_by?: string | null;
|
|
85
|
+
owner?: string | null;
|
|
86
|
+
agent_containment?: string | null;
|
|
87
|
+
[k: string]: unknown;
|
|
88
|
+
}
|
|
89
|
+
export declare function errorCodeOf(body: unknown): string | null;
|
|
90
|
+
export declare function errorDetailsOf(body: unknown): Record<string, unknown>;
|
|
91
|
+
export declare function errorMessageOf(body: unknown): string | null;
|
|
92
|
+
export declare class DurableApi {
|
|
93
|
+
private readonly deps;
|
|
94
|
+
constructor(deps: DurableHttpDeps);
|
|
95
|
+
private request;
|
|
96
|
+
private q;
|
|
97
|
+
/** The caller's own sessions in the active org, optionally by name and agent. */
|
|
98
|
+
listSessions(filter?: {
|
|
99
|
+
name?: string;
|
|
100
|
+
agentId?: string;
|
|
101
|
+
}): Promise<RegistryRow[]>;
|
|
102
|
+
/**
|
|
103
|
+
* GET /v1/code/entitlement in the active org (C01-R26): its `durable` field says whether this
|
|
104
|
+
* caller has the registry at all. The answer as is; the launcher decides (launch.ts).
|
|
105
|
+
*/
|
|
106
|
+
entitlement(): Promise<ApiAnswer>;
|
|
107
|
+
getSession(cid: string, agentId: string, include?: "goal"): Promise<ApiAnswer>;
|
|
108
|
+
createSession(cid: string, agentId: string, body: Record<string, unknown>): Promise<ApiAnswer>;
|
|
109
|
+
/** An owner session verb (S1 ROUTES.own_*). */
|
|
110
|
+
ownerVerb(route: RouteName, cid: string, agentId: string, body?: unknown): Promise<ApiAnswer>;
|
|
111
|
+
/** POST ROUTES.own_lock with the closed S1 lock body (spec, executor_id, own_agent). */
|
|
112
|
+
lock(cid: string, agentId: string, body: unknown): Promise<ApiAnswer>;
|
|
113
|
+
/**
|
|
114
|
+
* The read-only lock preflight for `mnemom agent doctor` (C02-R19): a GET on the lock route with
|
|
115
|
+
* dry_run, so it never mutates (A2 owns the route; see commands/durable-doctor.ts).
|
|
116
|
+
*/
|
|
117
|
+
lockPreflight(cid: string, agentId: string): Promise<ApiAnswer>;
|
|
118
|
+
/** The existing org containment route; JWT only (the route refuses API keys). */
|
|
119
|
+
containment(orgId: string, agentId: string, verb: "pause" | "resume"): Promise<ApiAnswer>;
|
|
120
|
+
/** The agent record (for its org id). */
|
|
121
|
+
getAgent(agentId: string): Promise<ApiAnswer>;
|
|
122
|
+
/** Agents by name across the caller's orgs (containment by name). */
|
|
123
|
+
agentsByName(name: string): Promise<Array<{
|
|
124
|
+
id: string;
|
|
125
|
+
org_id: string;
|
|
126
|
+
}>>;
|
|
127
|
+
/** RFC 8628 device token poll for an owner_mutation device step (issues no token). */
|
|
128
|
+
devicePoll(deviceCode: string, clientId: string): Promise<ApiAnswer>;
|
|
129
|
+
credentialType(): Promise<DurableCredential["type"]>;
|
|
130
|
+
}
|
|
131
|
+
/** A non-200 list answer the caller turns into a refusal. */
|
|
132
|
+
export declare class RegistryAnswerError extends Error {
|
|
133
|
+
readonly answer: ApiAnswer;
|
|
134
|
+
constructor(answer: ApiAnswer);
|
|
135
|
+
}
|
|
136
|
+
export declare function rowsOf(body: unknown): RegistryRow[];
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The durable registry and owner-verb client (BACKBONE C1, A2; S1 routes.ts ROUTES.own_*).
|
|
3
|
+
*
|
|
4
|
+
* Every call returns `{status, body}` and never throws on an HTTP answer: the commands decide from
|
|
5
|
+
* the status and the S1 code. A transport failure, a timeout or a 5xx (other than a durable 503 the
|
|
6
|
+
* caller must surface, which keeps its body) is a `RegistryUnavailable`, so a launch fails closed
|
|
7
|
+
* with `session_registry_unavailable` (C01-R18) instead of minting a conversation it could not
|
|
8
|
+
* resolve. The timeout is fixed in code: REGISTRY_TIMEOUT_MS covers connect plus total.
|
|
9
|
+
*
|
|
10
|
+
* Credentials (S1 owner-credential rule; BACKBONE owner Q6): the owner's JWT, else the personal
|
|
11
|
+
* org `mnm_` API key (MNEMOM_API_KEY). Org containment and device-step polls are JWT-only; the
|
|
12
|
+
* caller asks for that with `jwtOnly`.
|
|
13
|
+
*
|
|
14
|
+
* Not frozen by S1 (A2 owns them; recorded in notes-c1.md as the cross-piece assumption):
|
|
15
|
+
* GET /v1/agent/sessions?name=&agent_id=&org_id= -> {sessions: Row[]} (or a bare array)
|
|
16
|
+
* POST /v1/agent/sessions/{cid}?agent_id= -> 201/200 Row (create)
|
|
17
|
+
* GET /v1/agent/sessions/{cid}/lock?agent_id=&dry_run=true -> the doctor's lock preflight
|
|
18
|
+
*/
|
|
19
|
+
import { randomUUID } from "node:crypto";
|
|
20
|
+
import { routePath } from "../../vendor/shared/durable-contract/routes.js";
|
|
21
|
+
/** CLI registry timeout, connect plus total (C01-R18: at most 10 s). */
|
|
22
|
+
export const REGISTRY_TIMEOUT_MS = 10_000;
|
|
23
|
+
/** The registry could not be read: transport error, timeout or a non-durable 5xx. */
|
|
24
|
+
export class RegistryUnavailable extends Error {
|
|
25
|
+
constructor(detail) {
|
|
26
|
+
super(detail);
|
|
27
|
+
this.name = "RegistryUnavailable";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function errorCodeOf(body) {
|
|
31
|
+
if (body === null || typeof body !== "object")
|
|
32
|
+
return null;
|
|
33
|
+
const b = body;
|
|
34
|
+
const e = b.error;
|
|
35
|
+
if (e !== null &&
|
|
36
|
+
typeof e === "object" &&
|
|
37
|
+
typeof e.code === "string")
|
|
38
|
+
return e.code;
|
|
39
|
+
if (typeof b.code === "string")
|
|
40
|
+
return b.code;
|
|
41
|
+
if (typeof e === "string")
|
|
42
|
+
return e;
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
export function errorDetailsOf(body) {
|
|
46
|
+
if (body === null || typeof body !== "object")
|
|
47
|
+
return {};
|
|
48
|
+
const b = body;
|
|
49
|
+
const e = b.error;
|
|
50
|
+
if (e !== null && typeof e === "object") {
|
|
51
|
+
const d = e.details;
|
|
52
|
+
if (d !== null && typeof d === "object")
|
|
53
|
+
return d;
|
|
54
|
+
}
|
|
55
|
+
if (b.details !== null && typeof b.details === "object")
|
|
56
|
+
return b.details;
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
export function errorMessageOf(body) {
|
|
60
|
+
if (body === null || typeof body !== "object")
|
|
61
|
+
return null;
|
|
62
|
+
const b = body;
|
|
63
|
+
const e = b.error;
|
|
64
|
+
if (e !== null &&
|
|
65
|
+
typeof e === "object" &&
|
|
66
|
+
typeof e.message === "string")
|
|
67
|
+
return e.message;
|
|
68
|
+
if (typeof b.message === "string")
|
|
69
|
+
return b.message;
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
export class DurableApi {
|
|
73
|
+
deps;
|
|
74
|
+
constructor(deps) {
|
|
75
|
+
this.deps = deps;
|
|
76
|
+
}
|
|
77
|
+
async request(method, path, opts = {}) {
|
|
78
|
+
const cred = await this.deps.credential();
|
|
79
|
+
const headers = { Accept: "application/json" };
|
|
80
|
+
if (cred.type === "jwt")
|
|
81
|
+
headers.Authorization = `Bearer ${cred.token.trim()}`;
|
|
82
|
+
else if (cred.type === "api-key" && !opts.jwtOnly)
|
|
83
|
+
headers["X-Mnemom-Api-Key"] = cred.key.trim();
|
|
84
|
+
let body;
|
|
85
|
+
if (opts.form) {
|
|
86
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
87
|
+
body = new URLSearchParams(opts.form).toString();
|
|
88
|
+
}
|
|
89
|
+
else if (opts.body !== undefined) {
|
|
90
|
+
headers["Content-Type"] = "application/json";
|
|
91
|
+
body = JSON.stringify(opts.body);
|
|
92
|
+
}
|
|
93
|
+
if (method === "POST")
|
|
94
|
+
headers["Idempotency-Key"] = randomUUID();
|
|
95
|
+
const url = new URL(path, this.deps.apiBase().replace(/\/+$/, "") + "/").href;
|
|
96
|
+
const ctrl = new AbortController();
|
|
97
|
+
const timer = setTimeout(() => ctrl.abort(), REGISTRY_TIMEOUT_MS);
|
|
98
|
+
let res;
|
|
99
|
+
let text;
|
|
100
|
+
try {
|
|
101
|
+
res = await this.deps.fetch(url, { method, headers, body, signal: ctrl.signal });
|
|
102
|
+
// The body read is inside the same budget: a stalled (aborted) body is a timeout too.
|
|
103
|
+
text = await res.text();
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
throw new RegistryUnavailable(e instanceof Error ? e.message : String(e));
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
clearTimeout(timer);
|
|
110
|
+
}
|
|
111
|
+
let parsed = null;
|
|
112
|
+
if (text) {
|
|
113
|
+
try {
|
|
114
|
+
parsed = JSON.parse(text);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
parsed = { error: { code: "unparseable_body", message: text.slice(0, 200) } };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// A 5xx is the registry being down unless it carries a durable code the caller surfaces.
|
|
121
|
+
if (res.status >= 500 && !(errorCodeOf(parsed) ?? "").startsWith("durable_")) {
|
|
122
|
+
throw new RegistryUnavailable(`HTTP ${res.status}`);
|
|
123
|
+
}
|
|
124
|
+
return { status: res.status, body: parsed };
|
|
125
|
+
}
|
|
126
|
+
q(params) {
|
|
127
|
+
const s = new URLSearchParams();
|
|
128
|
+
for (const [k, v] of Object.entries(params))
|
|
129
|
+
if (v !== undefined && v !== "")
|
|
130
|
+
s.set(k, v);
|
|
131
|
+
const t = s.toString();
|
|
132
|
+
return t ? `?${t}` : "";
|
|
133
|
+
}
|
|
134
|
+
/** The caller's own sessions in the active org, optionally by name and agent. */
|
|
135
|
+
async listSessions(filter = {}) {
|
|
136
|
+
const a = await this.request("GET", `/v1/agent/sessions${this.q({ name: filter.name, agent_id: filter.agentId, org_id: this.deps.activeOrgId() })}`);
|
|
137
|
+
// Every non-200, a bare 404 (the route absent: API flag off) included, goes to the caller,
|
|
138
|
+
// which maps 403/404 to the legacy launch (launch.ts registryRows).
|
|
139
|
+
if (a.status !== 200)
|
|
140
|
+
throw new RegistryAnswerError(a);
|
|
141
|
+
return rowsOf(a.body);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* GET /v1/code/entitlement in the active org (C01-R26): its `durable` field says whether this
|
|
145
|
+
* caller has the registry at all. The answer as is; the launcher decides (launch.ts).
|
|
146
|
+
*/
|
|
147
|
+
async entitlement() {
|
|
148
|
+
return this.request("GET", `/v1/code/entitlement${this.q({ org_id: this.deps.activeOrgId() })}`);
|
|
149
|
+
}
|
|
150
|
+
async getSession(cid, agentId, include) {
|
|
151
|
+
return this.request("GET", `/v1/agent/sessions/${encodeURIComponent(cid)}${this.q({ agent_id: agentId, include })}`);
|
|
152
|
+
}
|
|
153
|
+
async createSession(cid, agentId, body) {
|
|
154
|
+
return this.request("POST", `/v1/agent/sessions/${encodeURIComponent(cid)}${this.q({ agent_id: agentId })}`, { body });
|
|
155
|
+
}
|
|
156
|
+
/** An owner session verb (S1 ROUTES.own_*). */
|
|
157
|
+
async ownerVerb(route, cid, agentId, body = {}) {
|
|
158
|
+
return this.request("POST", `${routePath(route, cid)}${this.q({ agent_id: agentId })}`, {
|
|
159
|
+
body,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/** POST ROUTES.own_lock with the closed S1 lock body (spec, executor_id, own_agent). */
|
|
163
|
+
async lock(cid, agentId, body) {
|
|
164
|
+
return this.ownerVerb("own_lock", cid, agentId, body);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* The read-only lock preflight for `mnemom agent doctor` (C02-R19): a GET on the lock route with
|
|
168
|
+
* dry_run, so it never mutates (A2 owns the route; see commands/durable-doctor.ts).
|
|
169
|
+
*/
|
|
170
|
+
async lockPreflight(cid, agentId) {
|
|
171
|
+
return this.request("GET", `${routePath("own_lock", cid)}${this.q({ agent_id: agentId, dry_run: "true" })}`);
|
|
172
|
+
}
|
|
173
|
+
/** The existing org containment route; JWT only (the route refuses API keys). */
|
|
174
|
+
async containment(orgId, agentId, verb) {
|
|
175
|
+
return this.request("POST", `/v1/orgs/${encodeURIComponent(orgId)}/agents/${encodeURIComponent(agentId)}/${verb}`, { body: {}, jwtOnly: true });
|
|
176
|
+
}
|
|
177
|
+
/** The agent record (for its org id). */
|
|
178
|
+
async getAgent(agentId) {
|
|
179
|
+
return this.request("GET", `/v1/agents/${encodeURIComponent(agentId)}`);
|
|
180
|
+
}
|
|
181
|
+
/** Agents by name across the caller's orgs (containment by name). */
|
|
182
|
+
async agentsByName(name) {
|
|
183
|
+
return this.deps.agentsByName ? this.deps.agentsByName(name) : [];
|
|
184
|
+
}
|
|
185
|
+
/** RFC 8628 device token poll for an owner_mutation device step (issues no token). */
|
|
186
|
+
async devicePoll(deviceCode, clientId) {
|
|
187
|
+
return this.request("POST", "/v1/oauth/token", {
|
|
188
|
+
form: {
|
|
189
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
190
|
+
device_code: deviceCode,
|
|
191
|
+
client_id: clientId,
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
async credentialType() {
|
|
196
|
+
return (await this.deps.credential()).type;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/** A non-200 list answer the caller turns into a refusal. */
|
|
200
|
+
export class RegistryAnswerError extends Error {
|
|
201
|
+
answer;
|
|
202
|
+
constructor(answer) {
|
|
203
|
+
super(errorMessageOf(answer.body) ?? `HTTP ${answer.status}`);
|
|
204
|
+
this.answer = answer;
|
|
205
|
+
this.name = "RegistryAnswerError";
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
export function rowsOf(body) {
|
|
209
|
+
const isRow = (r) => r !== null && typeof r === "object" && typeof r.conversation_id === "string";
|
|
210
|
+
if (Array.isArray(body))
|
|
211
|
+
return body.filter(isRow);
|
|
212
|
+
if (body !== null && typeof body === "object") {
|
|
213
|
+
for (const k of ["sessions", "rows", "items", "data"]) {
|
|
214
|
+
const v = body[k];
|
|
215
|
+
if (Array.isArray(v))
|
|
216
|
+
return v.filter(isRow);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every S1 durable code keyed by itself, typed to its literal: `CODE.durable_session_ended` is that
|
|
3
|
+
* code's string. C1 names durable codes only through this map (S1
|
|
4
|
+
* FREEZE_STRUCTURED.CODES, built from DURABLE_CODES), so a code S1 does not freeze fails to compile
|
|
5
|
+
* and no durable code is restated as a quoted literal outside S1 (C10-STATIC-001).
|
|
6
|
+
*/
|
|
7
|
+
import type { DurableCode } from "../../vendor/shared/durable-contract/codes.js";
|
|
8
|
+
export declare const CODE: { readonly [K in DurableCode]: K; };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CLI `durable` gate (BACKBONE Flags/CLI; C17-R10; amendments 26, 35).
|
|
3
|
+
*
|
|
4
|
+
* While `durable` is off every durable verb word exits 2 with `gatedMessage(…, 'durable')`, sends
|
|
5
|
+
* no HTTP, writes nothing under HOME and starts no process — `--help` and `--json` included, which
|
|
6
|
+
* is why the check runs on raw argv before commander parses it (commander answers `--help` before
|
|
7
|
+
* any preAction hook). The words are the declared allowlisted difference: a session named `lock`
|
|
8
|
+
* or `containment` is not launched by name while durable is off.
|
|
9
|
+
*
|
|
10
|
+
* `mnemom agent host run` is gated like every other word until C2 registers its handler (C2 then
|
|
11
|
+
* reads the gate from config.json only, C12-R25); ungated, it would fall through to the launcher as
|
|
12
|
+
* a session named "host". The pre-existing `mnemom agent sessions` / `show` are not gated.
|
|
13
|
+
*/
|
|
14
|
+
import { type ExperimentalId } from "../experimental.js";
|
|
15
|
+
export declare const DURABLE_ID: "durable";
|
|
16
|
+
/** `mnemom agent <word>` words that exist only with durable on. */
|
|
17
|
+
export declare const DURABLE_VERB_WORDS: readonly ["lock", "pause", "resume", "done", "kill", "amend", "host", "containment"];
|
|
18
|
+
/** `mnemom agent sessions <sub>` sub-verbs that exist only with durable on. */
|
|
19
|
+
export declare const DURABLE_SESSIONS_SUBVERBS: readonly ["unlock", "adopt"];
|
|
20
|
+
export declare function durableOn(enabled: readonly ExperimentalId[]): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The options that take a value, by flag spelling, as commander parses them: a `required` one always
|
|
23
|
+
* takes the next word; an `optional` one takes it only when it does not start with `-`. Every other
|
|
24
|
+
* option is a bare flag. The scan uses them to step over options placed before the verb word.
|
|
25
|
+
*/
|
|
26
|
+
export interface OptionShapes {
|
|
27
|
+
required: ReadonlySet<string>;
|
|
28
|
+
optional: ReadonlySet<string>;
|
|
29
|
+
}
|
|
30
|
+
/** The value-taking options of `commands` (commander `Command#options`), merged. */
|
|
31
|
+
export declare function optionShapesOf(commands: ReadonlyArray<{
|
|
32
|
+
options: readonly unknown[];
|
|
33
|
+
}>): OptionShapes;
|
|
34
|
+
/**
|
|
35
|
+
* The gated use `argv` (process.argv.slice(2)) makes, as the `what` of the gate message, or null
|
|
36
|
+
* when argv names no durable verb. The verb is the first operand after `agent`, with options (and
|
|
37
|
+
* their values, per `shapes`) stepped over exactly as commander would before it dispatches the
|
|
38
|
+
* subcommand, so `agent --new lock x` is gated like `agent lock x`. A word after `--` or as a later
|
|
39
|
+
* positional is not a verb use.
|
|
40
|
+
*/
|
|
41
|
+
export declare function durableVerbUse(argv: readonly string[], shapes?: OptionShapes): string | null;
|
|
42
|
+
/**
|
|
43
|
+
* The guard inside every durable verb's action: the pointer (exit 2) while durable is off, else
|
|
44
|
+
* null. The argv gate above runs first; this one holds for any argv shape that reaches commander.
|
|
45
|
+
*/
|
|
46
|
+
export declare function durableActionGate(what: string, enabled: readonly ExperimentalId[]): string | null;
|
|
47
|
+
/** The gate decision for argv: null when allowed, else the stderr message (exit 2). */
|
|
48
|
+
export declare function durableGate(argv: readonly string[], enabled: readonly ExperimentalId[], shapes?: OptionShapes): string | null;
|