@mnemom/mnemom 0.17.32 → 0.17.34-next.1
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/commands/agent-fuel.d.ts +9 -0
- package/dist/commands/agent-fuel.js +36 -2
- package/dist/commands/agent-run.d.ts +50 -0
- package/dist/commands/agent-run.js +221 -0
- package/dist/commands/agent-setup.d.ts +8 -3
- package/dist/commands/agent-setup.js +32 -9
- package/dist/commands/agent-share-fixture.d.ts +3 -1
- package/dist/commands/agent-share-fixture.js +11 -7
- package/dist/commands/agent-share-render.d.ts +23 -0
- package/dist/commands/agent-share-render.js +72 -0
- package/dist/commands/agent-share.d.ts +15 -2
- package/dist/commands/agent-share.js +30 -9
- package/dist/commands/agent.d.ts +34 -4
- package/dist/commands/agent.js +116 -20
- package/dist/commands/protection.js +1 -1
- package/dist/commands/scan.d.ts +97 -0
- package/dist/commands/scan.js +238 -0
- package/dist/index.js +55 -0
- package/dist/lib/api.d.ts +13 -0
- package/dist/lib/api.js +25 -1
- package/dist/lib/auth.d.ts +6 -0
- package/dist/lib/auth.js +161 -14
- package/dist/lib/experimental.d.ts +1 -1
- package/dist/lib/experimental.js +13 -0
- package/dist/lib/oauth.d.ts +7 -0
- package/dist/lib/oauth.js +13 -0
- package/dist/lib/runner/bundle.d.ts +129 -0
- package/dist/lib/runner/bundle.js +319 -0
- package/dist/lib/runner/contract-header.d.ts +46 -0
- package/dist/lib/runner/contract-header.js +85 -0
- package/dist/lib/runner/executor-client.d.ts +71 -0
- package/dist/lib/runner/executor-client.js +97 -0
- package/dist/lib/runner/job.d.ts +70 -0
- package/dist/lib/runner/job.js +463 -0
- package/dist/lib/runner/loop.d.ts +45 -0
- package/dist/lib/runner/loop.js +104 -0
- package/dist/lib/runner/oidc.d.ts +38 -0
- package/dist/lib/runner/oidc.js +89 -0
- package/dist/lib/runner/options.d.ts +41 -0
- package/dist/lib/runner/options.js +47 -0
- package/dist/lib/runner/outcome.d.ts +47 -0
- package/dist/lib/runner/outcome.js +89 -0
- package/dist/lib/runner/phases.d.ts +49 -0
- package/dist/lib/runner/phases.js +99 -0
- package/dist/lib/runner/proxy.d.ts +45 -0
- package/dist/lib/runner/proxy.js +153 -0
- package/dist/lib/runner/settings.d.ts +31 -0
- package/dist/lib/runner/settings.js +44 -0
- package/dist/lib/scan/caps.d.ts +35 -0
- package/dist/lib/scan/caps.js +67 -0
- package/dist/lib/scan/credential.d.ts +37 -0
- package/dist/lib/scan/credential.js +104 -0
- package/dist/lib/scan/failure.d.ts +10 -0
- package/dist/lib/scan/failure.js +43 -0
- package/dist/lib/scan/pr-source.d.ts +57 -0
- package/dist/lib/scan/pr-source.js +130 -0
- package/dist/lib/scan/record.d.ts +49 -0
- package/dist/lib/scan/record.js +85 -0
- package/dist/lib/scan/report-email.d.ts +92 -0
- package/dist/lib/scan/report-email.js +136 -0
- package/dist/lib/scan/report.d.ts +13 -0
- package/dist/lib/scan/report.js +30 -0
- package/dist/lib/scan/scan.d.ts +64 -0
- package/dist/lib/scan/scan.js +182 -0
- package/dist/lib/scan/share.d.ts +38 -0
- package/dist/lib/scan/share.js +47 -0
- package/dist/lib/scan/spend/ai-tool-detect.d.ts +6 -0
- package/dist/lib/scan/spend/ai-tool-detect.js +18 -0
- package/dist/lib/scan/spend/anthropic-usage.d.ts +57 -0
- package/dist/lib/scan/spend/anthropic-usage.js +244 -0
- package/dist/lib/scan/spend/cost-corpus.v1.d.ts +56 -0
- package/dist/lib/scan/spend/cost-corpus.v1.js +64 -0
- package/dist/lib/scan/spend/prices.d.ts +33 -0
- package/dist/lib/scan/spend/prices.js +57 -0
- package/dist/lib/scan/spend/spend-estimate.d.ts +30 -0
- package/dist/lib/scan/spend/spend-estimate.js +70 -0
- package/dist/lib/scan/spend/spend-tiers.d.ts +25 -0
- package/dist/lib/scan/spend/spend-tiers.js +42 -0
- package/dist/lib/scan/spend/token-rate.d.ts +30 -0
- package/dist/lib/scan/spend/token-rate.js +54 -0
- package/dist/lib/session-key.d.ts +41 -0
- package/dist/lib/session-key.js +124 -0
- package/dist/lib/statusline-feed.js +10 -11
- package/dist/lib/statusline.d.ts +6 -0
- package/dist/lib/statusline.js +19 -9
- package/dist/rc-key-401.mjs +75 -0
- package/dist/rc-proxy.mjs +290 -30
- package/package.json +2 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The thin runner's executor client (ruling 34.12 (7)): S1's executor routes, the same protocol as
|
|
3
|
+
* C2's host client, plus the two post-claim reads outside S1 (the job, W-L15; the served bundle,
|
|
4
|
+
* W-L12) and the JWKS. Every executor route carries the executor key in X-Mnemom-Api-Key and
|
|
5
|
+
* never Authorization (ruling 33.28 (1)), and so does the job read (api#4165 authorizes the executor
|
|
6
|
+
* holding the lease); the bundle fetch carries the lease key the same way.
|
|
7
|
+
*
|
|
8
|
+
* Nothing here decides an outcome: each call returns its status, body and error code, and the job
|
|
9
|
+
* (job.ts) maps them to 34.12's reasons. Never throws: a network failure is status 0.
|
|
10
|
+
*/
|
|
11
|
+
export interface HttpResult {
|
|
12
|
+
readonly status: number;
|
|
13
|
+
readonly body: unknown;
|
|
14
|
+
/** The raw body text (the served bundle is verified against these exact bytes). */
|
|
15
|
+
readonly text: string;
|
|
16
|
+
/** The error code: `{error: {code}}`, `{error: "code"}` or `{code}`; null on success. */
|
|
17
|
+
readonly code: string | null;
|
|
18
|
+
readonly networkError?: string;
|
|
19
|
+
}
|
|
20
|
+
export type FetchFn = (url: string, init: {
|
|
21
|
+
method: string;
|
|
22
|
+
headers: Record<string, string>;
|
|
23
|
+
body?: string;
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}) => Promise<{
|
|
26
|
+
status: number;
|
|
27
|
+
text(): Promise<string>;
|
|
28
|
+
}>;
|
|
29
|
+
export declare function errorCode(body: unknown): string | null;
|
|
30
|
+
export declare function errorDetails(body: unknown): Record<string, unknown>;
|
|
31
|
+
/** The post-claim job read (W-L15), with the executor key. */
|
|
32
|
+
export declare const JOB_READ_PATH: (sessionId: string) => string;
|
|
33
|
+
/** The served bundle fetch, per claim (W-L12). */
|
|
34
|
+
export declare const BUNDLE_FETCH_PATH: (sessionId: string) => string;
|
|
35
|
+
export declare const JWKS_PATH = "/v1/.well-known/jwks.json";
|
|
36
|
+
export interface RunnerApi {
|
|
37
|
+
readyList(limit: number): Promise<HttpResult>;
|
|
38
|
+
attest(sessionId: string, nonce: string): Promise<HttpResult>;
|
|
39
|
+
claim(sessionId: string, body: {
|
|
40
|
+
nonce: string;
|
|
41
|
+
new_key?: true;
|
|
42
|
+
}): Promise<HttpResult>;
|
|
43
|
+
append(sessionId: string, body: Record<string, unknown>): Promise<HttpResult>;
|
|
44
|
+
hello(sessionId: string, body: {
|
|
45
|
+
epoch: number;
|
|
46
|
+
nonce: string;
|
|
47
|
+
spawn_id: string;
|
|
48
|
+
}): Promise<HttpResult>;
|
|
49
|
+
heartbeat(body: {
|
|
50
|
+
nonce: string;
|
|
51
|
+
entries: {
|
|
52
|
+
session_id: string;
|
|
53
|
+
epoch: number;
|
|
54
|
+
spawn_id: string;
|
|
55
|
+
}[];
|
|
56
|
+
}): Promise<HttpResult>;
|
|
57
|
+
release(sessionId: string, body: {
|
|
58
|
+
epoch: number;
|
|
59
|
+
nonce: string;
|
|
60
|
+
}): Promise<HttpResult>;
|
|
61
|
+
fail(sessionId: string, body: Record<string, unknown>): Promise<HttpResult>;
|
|
62
|
+
job(sessionId: string): Promise<HttpResult>;
|
|
63
|
+
bundle(sessionId: string, leaseKey: string): Promise<HttpResult>;
|
|
64
|
+
jwks(): Promise<HttpResult>;
|
|
65
|
+
}
|
|
66
|
+
export declare function runnerApi(opts: {
|
|
67
|
+
apiUrl: string;
|
|
68
|
+
executorKey: string;
|
|
69
|
+
fetch: FetchFn;
|
|
70
|
+
timeoutMs?: number;
|
|
71
|
+
}): RunnerApi;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The thin runner's executor client (ruling 34.12 (7)): S1's executor routes, the same protocol as
|
|
3
|
+
* C2's host client, plus the two post-claim reads outside S1 (the job, W-L15; the served bundle,
|
|
4
|
+
* W-L12) and the JWKS. Every executor route carries the executor key in X-Mnemom-Api-Key and
|
|
5
|
+
* never Authorization (ruling 33.28 (1)), and so does the job read (api#4165 authorizes the executor
|
|
6
|
+
* holding the lease); the bundle fetch carries the lease key the same way.
|
|
7
|
+
*
|
|
8
|
+
* Nothing here decides an outcome: each call returns its status, body and error code, and the job
|
|
9
|
+
* (job.ts) maps them to 34.12's reasons. Never throws: a network failure is status 0.
|
|
10
|
+
*/
|
|
11
|
+
import { EXECUTOR_KEY_HEADER, routePath } from "../../vendor/durable-contract/index.js";
|
|
12
|
+
export function errorCode(body) {
|
|
13
|
+
if (!body || typeof body !== "object")
|
|
14
|
+
return null;
|
|
15
|
+
const b = body;
|
|
16
|
+
if (b.error && typeof b.error === "object") {
|
|
17
|
+
const c = b.error.code;
|
|
18
|
+
if (typeof c === "string")
|
|
19
|
+
return c;
|
|
20
|
+
}
|
|
21
|
+
if (typeof b.error === "string")
|
|
22
|
+
return b.error;
|
|
23
|
+
return typeof b.code === "string" ? b.code : null;
|
|
24
|
+
}
|
|
25
|
+
export function errorDetails(body) {
|
|
26
|
+
if (!body || typeof body !== "object")
|
|
27
|
+
return {};
|
|
28
|
+
const e = body.error;
|
|
29
|
+
const d = e && typeof e === "object" ? e.details : undefined;
|
|
30
|
+
return d && typeof d === "object" && !Array.isArray(d) ? d : {};
|
|
31
|
+
}
|
|
32
|
+
/** The post-claim job read (W-L15), with the executor key. */
|
|
33
|
+
export const JOB_READ_PATH = (sessionId) => `/v1/executor/sessions/${sessionId}/job`;
|
|
34
|
+
/** The served bundle fetch, per claim (W-L12). */
|
|
35
|
+
export const BUNDLE_FETCH_PATH = (sessionId) => `/v1/executor/sessions/${sessionId}/bundle`;
|
|
36
|
+
export const JWKS_PATH = "/v1/.well-known/jwks.json";
|
|
37
|
+
const SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
38
|
+
export function runnerApi(opts) {
|
|
39
|
+
const base = opts.apiUrl.replace(/\/+$/, "");
|
|
40
|
+
const call = async (path, method, key, body) => {
|
|
41
|
+
const ctl = new AbortController();
|
|
42
|
+
const timer = setTimeout(() => ctl.abort(), opts.timeoutMs ?? 15_000);
|
|
43
|
+
const headers = { accept: "application/json" };
|
|
44
|
+
if (key !== null)
|
|
45
|
+
headers[EXECUTOR_KEY_HEADER] = key;
|
|
46
|
+
if (body !== undefined)
|
|
47
|
+
headers["content-type"] = "application/json";
|
|
48
|
+
try {
|
|
49
|
+
const res = await opts.fetch(`${base}${path}`, {
|
|
50
|
+
method,
|
|
51
|
+
headers,
|
|
52
|
+
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|
|
53
|
+
signal: ctl.signal,
|
|
54
|
+
});
|
|
55
|
+
const text = await res.text();
|
|
56
|
+
let parsed = null;
|
|
57
|
+
try {
|
|
58
|
+
parsed = text ? JSON.parse(text) : null;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
parsed = text;
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
status: res.status,
|
|
65
|
+
body: parsed,
|
|
66
|
+
text,
|
|
67
|
+
code: res.status >= 400 ? errorCode(parsed) : null,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
return { status: 0, body: null, text: "", code: null, networkError: e.message };
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
clearTimeout(timer);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
// A session id from the api goes into a path; refuse anything but a lowercase uuid.
|
|
78
|
+
const scoped = (id) => {
|
|
79
|
+
if (!SESSION_ID_RE.test(id))
|
|
80
|
+
throw new RangeError("session id must be a lowercase uuid");
|
|
81
|
+
return id;
|
|
82
|
+
};
|
|
83
|
+
const ex = opts.executorKey;
|
|
84
|
+
return {
|
|
85
|
+
readyList: (limit) => call(`${routePath("exec_ready_list")}?limit=${limit}`, "GET", ex),
|
|
86
|
+
attest: (id, nonce) => call(routePath("exec_attest", scoped(id)), "POST", ex, { nonce }),
|
|
87
|
+
claim: (id, body) => call(routePath("exec_claim", scoped(id)), "POST", ex, body),
|
|
88
|
+
append: (id, body) => call(routePath("exec_append", scoped(id)), "POST", ex, body),
|
|
89
|
+
hello: (id, body) => call(routePath("exec_hello", scoped(id)), "POST", ex, body),
|
|
90
|
+
heartbeat: (body) => call(routePath("exec_heartbeat"), "POST", ex, body),
|
|
91
|
+
release: (id, body) => call(routePath("exec_release", scoped(id)), "POST", ex, body),
|
|
92
|
+
fail: (id, body) => call(routePath("exec_fail", scoped(id)), "POST", ex, body),
|
|
93
|
+
job: (id) => call(JOB_READ_PATH(scoped(id)), "GET", ex),
|
|
94
|
+
bundle: (id, leaseKey) => call(BUNDLE_FETCH_PATH(scoped(id)), "GET", leaseKey),
|
|
95
|
+
jwks: () => call(JWKS_PATH, "GET", null),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One served-phase job, claim to outcome (ruling 34.12; Doors W-L13, W3.11 and W4.4).
|
|
3
|
+
*
|
|
4
|
+
* attest → claim (needs_key retry) → register the spawn → hello → heartbeats → served bundle
|
|
5
|
+
* (verified, bound to this claim) → job read (contract bytes bound to the claim's seal) → repo →
|
|
6
|
+
* phases through the runner's own proxy → PR → release. Every Mnemom error maps to one of S1's
|
|
7
|
+
* refused reasons and fails closed; under --fail-mode open, only bundle_unavailable,
|
|
8
|
+
* job_unavailable and api_unavailable are ridden through, and only once a verified bundle is held
|
|
9
|
+
* (34.12 (2)). A bundle that fails verification stops the job in every mode.
|
|
10
|
+
*
|
|
11
|
+
* Every side effect is in `JobDeps`, so each arm is tested; `liveJobDeps` (commands/agent-run.ts)
|
|
12
|
+
* is the thin driver.
|
|
13
|
+
*/
|
|
14
|
+
import { type HttpResult, type RunnerApi } from "./executor-client.js";
|
|
15
|
+
import { type OutcomeFields, type RefusedReason } from "./outcome.js";
|
|
16
|
+
import { type PhaseInvocation } from "./phases.js";
|
|
17
|
+
import type { ModelProxy, ProxyState } from "./proxy.js";
|
|
18
|
+
import { type RunnerFailMode } from "./settings.js";
|
|
19
|
+
/** A claimed job's working copy. */
|
|
20
|
+
export interface Workspace {
|
|
21
|
+
dir: string;
|
|
22
|
+
/** A fresh, empty HOME for the phases. */
|
|
23
|
+
home: string;
|
|
24
|
+
branch: string;
|
|
25
|
+
}
|
|
26
|
+
export interface JobDeps {
|
|
27
|
+
api: RunnerApi;
|
|
28
|
+
/** One nonce per runner process, reused on every call (A3 fences on it). */
|
|
29
|
+
nonce: string;
|
|
30
|
+
newSpawnId(): string;
|
|
31
|
+
now(): number;
|
|
32
|
+
sleep(ms: number): Promise<void>;
|
|
33
|
+
log(line: string): void;
|
|
34
|
+
gatewayUrl: string;
|
|
35
|
+
startProxy(state: ProxyState): Promise<ModelProxy>;
|
|
36
|
+
prepareWorkspace(repo: string, sessionId: string): Promise<Workspace>;
|
|
37
|
+
/** Run one phase's process; resolves its exit code. Rejects only when it could not start. */
|
|
38
|
+
runPhase(inv: PhaseInvocation, ws: Workspace, modelUrl: string, signal: AbortSignal): Promise<number>;
|
|
39
|
+
/** Push the job branch and open its PR; resolves the PR URL. */
|
|
40
|
+
openPr(repo: string, ws: Workspace, title: string): Promise<string>;
|
|
41
|
+
enableAutoMerge(prUrl: string): Promise<void>;
|
|
42
|
+
cleanup(ws: Workspace): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
export interface JobOptions {
|
|
45
|
+
failMode: RunnerFailMode;
|
|
46
|
+
/** Aborted by SIGTERM or SIGINT: release the lease, print no outcome line. */
|
|
47
|
+
stop: AbortSignal;
|
|
48
|
+
}
|
|
49
|
+
/** What one claim attempt came to. */
|
|
50
|
+
export type JobResult = {
|
|
51
|
+
kind: "next";
|
|
52
|
+
} | {
|
|
53
|
+
kind: "outcome";
|
|
54
|
+
outcome: OutcomeFields;
|
|
55
|
+
} | {
|
|
56
|
+
kind: "stopped";
|
|
57
|
+
};
|
|
58
|
+
/** A3's executor auth rejections, on whichever executor route comes first (34.12 (8), (10)). */
|
|
59
|
+
export declare function authRefusal(r: HttpResult): RefusedReason | null;
|
|
60
|
+
/**
|
|
61
|
+
* Run one candidate session to an outcome. Never throws for a Mnemom error: every one is an
|
|
62
|
+
* outcome. Throws only on a runner bug.
|
|
63
|
+
*/
|
|
64
|
+
export declare function runJob(sessionId: string, opts: JobOptions, deps: JobDeps): Promise<JobResult>;
|
|
65
|
+
/**
|
|
66
|
+
* Report a failed or refused job after claim (34.12 (6), (10)). The fail reason vocabulary is the
|
|
67
|
+
* Durable lead's to rule (A3 accepts only transcript_lost today); a refused report is logged and
|
|
68
|
+
* never changes the outcome, because the lease lapses on its own.
|
|
69
|
+
*/
|
|
70
|
+
export declare function reportFail(deps: JobDeps, sessionId: string, epoch: number, kind: "runner_failed" | "runner_refused", reason: string): Promise<void>;
|