@mnemom/mnemom 0.17.39-next.2 → 0.17.39-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/host/commands.js +2 -1
- package/dist/host/owner.d.ts +2 -0
- package/dist/host/verbs.d.ts +10 -0
- package/dist/host/verbs.js +44 -2
- package/dist/vendor/durable-contract/index.js +4 -3
- package/dist/vendor/shared/durable-contract/cli-surface.js +3 -2
- package/dist/vendor/shared/durable-contract/doors.d.ts +7 -2
- package/dist/vendor/shared/durable-contract/doors.js +7 -2
- package/dist/vendor/shared/durable-contract/freeze-record.d.ts +1 -1
- package/package.json +1 -1
package/dist/host/commands.js
CHANGED
|
@@ -69,7 +69,8 @@ export function registerHostCommands(agent, hidden) {
|
|
|
69
69
|
.command("enroll")
|
|
70
70
|
.description("Enroll this machine as an executor (device step); `install` does this when needed")
|
|
71
71
|
.option("--org <org_id>", "Join this organization (you must be a member); defaults to the active org, else your personal org")
|
|
72
|
-
.
|
|
72
|
+
.option("--scope <scope>", "personal (default): run your own sessions. org: run the org's pool jobs (`mnemom agent run`); an org owner or admin approves it, and the org must have org runners turned on", "personal")
|
|
73
|
+
.action(async (o) => guarded(false, (io) => hostEnroll(io, { org: o.org, scope: o.scope })));
|
|
73
74
|
host
|
|
74
75
|
.command("renew")
|
|
75
76
|
.description("Renew this machine's executor grant (device step)")
|
package/dist/host/owner.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface OwnerApi {
|
|
|
13
13
|
machine_label?: string;
|
|
14
14
|
/** Ruling 34.03.4: the org this host joins; the api checks membership. */
|
|
15
15
|
org_id?: string;
|
|
16
|
+
/** The any-machine amendment: "org" enrolls this host as a runner of org_id's pool. */
|
|
17
|
+
scope?: "org";
|
|
16
18
|
}): Promise<OwnerHttp>;
|
|
17
19
|
enrollPoll(pollSecret: string, approvalId: string | null): Promise<OwnerHttp>;
|
|
18
20
|
list(): Promise<OwnerHttp>;
|
package/dist/host/verbs.d.ts
CHANGED
|
@@ -52,16 +52,26 @@ export declare function enrollOrg(io: VerbIo, opts: {
|
|
|
52
52
|
orgId: string;
|
|
53
53
|
from: "flag" | "active";
|
|
54
54
|
} | null;
|
|
55
|
+
/**
|
|
56
|
+
* `host enroll --scope`: personal (the default) enrolls this machine for its user's own sessions;
|
|
57
|
+
* org enrolls it as a runner of the org's pool (the any-machine amendment, Wassim 2026-11-09:
|
|
58
|
+
* S1 ORG_SCOPE_EXECUTOR_KINDS includes host). The org owner or admin's device-step approval is the
|
|
59
|
+
* guard, and the api also requires the org on DURABLE_POOL_CLAIM.
|
|
60
|
+
*/
|
|
61
|
+
export declare const ENROLL_SCOPES: readonly ["personal", "org"];
|
|
62
|
+
export type EnrollScope = (typeof ENROLL_SCOPES)[number];
|
|
55
63
|
/** The device step: start, show the code, poll, write the state file. Returns an exit code. */
|
|
56
64
|
export declare function enrollDevice(io: VerbIo, opts?: {
|
|
57
65
|
label?: string;
|
|
58
66
|
org?: string;
|
|
67
|
+
scope?: EnrollScope;
|
|
59
68
|
}): Promise<number>;
|
|
60
69
|
/** Write the plist and (re)load the job. */
|
|
61
70
|
export declare function writeAndLoad(io: VerbIo): Promise<number>;
|
|
62
71
|
export declare function hostInstall(io: VerbIo): Promise<number>;
|
|
63
72
|
export declare function hostEnroll(io: VerbIo, opts?: {
|
|
64
73
|
org?: string;
|
|
74
|
+
scope?: EnrollScope;
|
|
65
75
|
}): Promise<number>;
|
|
66
76
|
export declare function hostRenew(io: VerbIo): Promise<number>;
|
|
67
77
|
export declare function hostUninstall(io: VerbIo): Promise<number>;
|
package/dist/host/verbs.js
CHANGED
|
@@ -80,8 +80,26 @@ function errorCode(body) {
|
|
|
80
80
|
const code = e && typeof e === "object" ? e.code : undefined;
|
|
81
81
|
return typeof code === "string" ? code : null;
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* `host enroll --scope`: personal (the default) enrolls this machine for its user's own sessions;
|
|
85
|
+
* org enrolls it as a runner of the org's pool (the any-machine amendment, Wassim 2026-11-09:
|
|
86
|
+
* S1 ORG_SCOPE_EXECUTOR_KINDS includes host). The org owner or admin's device-step approval is the
|
|
87
|
+
* guard, and the api also requires the org on DURABLE_POOL_CLAIM.
|
|
88
|
+
*/
|
|
89
|
+
export const ENROLL_SCOPES = ["personal", "org"];
|
|
83
90
|
/** The device step: start, show the code, poll, write the state file. Returns an exit code. */
|
|
84
91
|
export async function enrollDevice(io, opts = {}) {
|
|
92
|
+
const orgScope = opts.scope === "org";
|
|
93
|
+
if (opts.scope !== undefined && !ENROLL_SCOPES.includes(opts.scope)) {
|
|
94
|
+
io.err(`mnemom agent host: --scope must be ${ENROLL_SCOPES.join(" or ")}`);
|
|
95
|
+
return 1;
|
|
96
|
+
}
|
|
97
|
+
// An org runner names its org: --org, else the active org. The api requires it (34.03.3).
|
|
98
|
+
if (orgScope && !enrollOrg(io, opts)) {
|
|
99
|
+
io.err("mnemom agent host: --scope org needs the organization this machine will run jobs for.");
|
|
100
|
+
io.err("fix: `mnemom agent host enroll --scope org --org <org_id>` (`mnemom org list` shows them)");
|
|
101
|
+
return 1;
|
|
102
|
+
}
|
|
85
103
|
const { paths } = ctx(io);
|
|
86
104
|
const lock = (io.acquireLock ?? acquireHostLock)(path.join(paths.durableDir, "enroll.lock"));
|
|
87
105
|
if (!lock.ok) {
|
|
@@ -96,13 +114,14 @@ export async function enrollDevice(io, opts = {}) {
|
|
|
96
114
|
contract_version: EXECUTOR_CONTRACT,
|
|
97
115
|
...(opts.label ? { machine_label: opts.label } : {}),
|
|
98
116
|
...(o ? { org_id: o.orgId } : {}),
|
|
117
|
+
...(orgScope ? { scope: "org" } : {}),
|
|
99
118
|
});
|
|
100
119
|
let st = await startWith(org);
|
|
101
120
|
// An api from before 34.03.4 refuses org_id on a host start with its plain 400 invalid_scope
|
|
102
121
|
// (34.03.2 (1); mnemom-api enroll.ts "org_id is only accepted with scope org"; recorded beside
|
|
103
122
|
// exec_enroll in S1 codes.ts). An org taken from the active org then falls back to the start this
|
|
104
123
|
// CLI made before; an explicit --org cannot.
|
|
105
|
-
if (org && st.status === 400 && errorCode(st.body) === "invalid_scope") {
|
|
124
|
+
if (!orgScope && org && st.status === 400 && errorCode(st.body) === "invalid_scope") {
|
|
106
125
|
if (org.from === "flag") {
|
|
107
126
|
io.err(`mnemom agent host: this Mnemom server cannot enroll a machine into ${org.orgId} yet.`);
|
|
108
127
|
io.err("fix: `mnemom agent host enroll` without --org (joins your personal org)");
|
|
@@ -115,6 +134,21 @@ export async function enrollDevice(io, opts = {}) {
|
|
|
115
134
|
const start = st.status === 202 || st.status === 200 || st.status === 201
|
|
116
135
|
? parseEnrollStart(st.body)
|
|
117
136
|
: null;
|
|
137
|
+
if (!start && orgScope && org) {
|
|
138
|
+
const code = errorCode(st.body);
|
|
139
|
+
if (code === CODE.durable_approval_not_eligible) {
|
|
140
|
+
// 34.03.3: only an owner or admin of the org may enroll an org runner.
|
|
141
|
+
io.err(`mnemom agent host: only an owner or admin of ${org.orgId} can enroll a machine as its runner.`);
|
|
142
|
+
io.err(`fix: ask an owner or admin of ${org.orgId} to run \`mnemom agent host enroll --scope org --org ${org.orgId}\` on this machine`);
|
|
143
|
+
return 1;
|
|
144
|
+
}
|
|
145
|
+
if (code === CODE.kind_not_allowed) {
|
|
146
|
+
// The org is not on the server's pool-claim list, or the server predates host org runners.
|
|
147
|
+
io.err(`mnemom agent host: this Mnemom server does not accept this machine as a runner for ${org.orgId} (org runners are not turned on for it, or the server does not take host runners yet).`);
|
|
148
|
+
io.err("fix: `mnemom agent host enroll` without --scope org enrolls it for your own sessions");
|
|
149
|
+
return 1;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
118
152
|
if (!start && org && errorCode(st.body) === CODE.durable_approval_not_eligible) {
|
|
119
153
|
// 34.03.4: only a member of the org may enroll a machine into it.
|
|
120
154
|
io.err(`mnemom agent host: you are not a member of ${org.orgId}, so this machine cannot join it.`);
|
|
@@ -173,7 +207,15 @@ export async function enrollDevice(io, opts = {}) {
|
|
|
173
207
|
boot_id: io.bootId(),
|
|
174
208
|
});
|
|
175
209
|
if (io.json)
|
|
176
|
-
io.out(JSON.stringify({
|
|
210
|
+
io.out(JSON.stringify({
|
|
211
|
+
event: "enrolled",
|
|
212
|
+
executor_id: p.executorId,
|
|
213
|
+
...(orgScope ? { scope: "org" } : {}),
|
|
214
|
+
}));
|
|
215
|
+
else if (orgScope && org) {
|
|
216
|
+
io.out(`Enrolled this machine as a runner for ${org.orgId} (executor ${p.executorId.slice(0, 8)}).`);
|
|
217
|
+
io.out(`To claim its pool jobs: \`mnemom agent run --watch\` with MNEMOM_EXECUTOR_KEY set to executor_key in ${paths.stateFile}`);
|
|
218
|
+
}
|
|
177
219
|
else
|
|
178
220
|
io.out(`Enrolled this machine (executor ${p.executorId.slice(0, 8)}).`);
|
|
179
221
|
return 0;
|
|
@@ -1664,8 +1664,9 @@ var M1_CLI_SURFACE = Object.freeze([
|
|
|
1664
1664
|
entry(["agent", "done"], ["--json"]),
|
|
1665
1665
|
// BACKBONE C2 (`mnemom agent host` replaces `mnemom host`, amendment 2; design-v3 row 7).
|
|
1666
1666
|
entry(["agent", "host"]),
|
|
1667
|
-
// BACKBONE C2 enroll (device step); --org: ruling 34.03.4 (a host joins an org its user belongs to)
|
|
1668
|
-
|
|
1667
|
+
// BACKBONE C2 enroll (device step); --org: ruling 34.03.4 (a host joins an org its user belongs to);
|
|
1668
|
+
// --scope: the any-machine amendment (Wassim 2026-11-09; `--scope org` enrolls an org runner).
|
|
1669
|
+
entry(["agent", "host", "enroll"], ["--org", "--scope"]),
|
|
1669
1670
|
// BACKBONE C2 install/status/uninstall; --json: C04 (`mnemom agent host install --json`),
|
|
1670
1671
|
// ruling 32.31.
|
|
1671
1672
|
entry(["agent", "host", "install"], ["--json"]),
|
|
@@ -2379,7 +2380,7 @@ function poolClaimOrgs(flagValue) {
|
|
|
2379
2380
|
return [...new Set(orgs)];
|
|
2380
2381
|
}
|
|
2381
2382
|
var EXECUTOR_SCOPES = ["user", "org"];
|
|
2382
|
-
var ORG_SCOPE_EXECUTOR_KINDS = ["container", "fleet"];
|
|
2383
|
+
var ORG_SCOPE_EXECUTOR_KINDS = ["container", "fleet", "host"];
|
|
2383
2384
|
var OIDC_EXCHANGE_REFUSALS = [
|
|
2384
2385
|
"bad_issuer",
|
|
2385
2386
|
"repo_not_enrolled",
|
|
@@ -36,8 +36,9 @@ export const M1_CLI_SURFACE = Object.freeze([
|
|
|
36
36
|
entry(["agent", "done"], ["--json"]),
|
|
37
37
|
// BACKBONE C2 (`mnemom agent host` replaces `mnemom host`, amendment 2; design-v3 row 7).
|
|
38
38
|
entry(["agent", "host"]),
|
|
39
|
-
// BACKBONE C2 enroll (device step); --org: ruling 34.03.4 (a host joins an org its user belongs to)
|
|
40
|
-
|
|
39
|
+
// BACKBONE C2 enroll (device step); --org: ruling 34.03.4 (a host joins an org its user belongs to);
|
|
40
|
+
// --scope: the any-machine amendment (Wassim 2026-11-09; `--scope org` enrolls an org runner).
|
|
41
|
+
entry(["agent", "host", "enroll"], ["--org", "--scope"]),
|
|
41
42
|
// BACKBONE C2 install/status/uninstall; --json: C04 (`mnemom agent host install --json`),
|
|
42
43
|
// ruling 32.31.
|
|
43
44
|
entry(["agent", "host", "install"], ["--json"]),
|
|
@@ -31,8 +31,13 @@ export declare function isPoolSession(s: PoolSessionFacts, flagValue: string | u
|
|
|
31
31
|
export declare function poolClaimOrgs(flagValue: string | undefined): string[];
|
|
32
32
|
export declare const EXECUTOR_SCOPES: readonly ["user", "org"];
|
|
33
33
|
export type ExecutorScope = (typeof EXECUTOR_SCOPES)[number];
|
|
34
|
-
/**
|
|
35
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Only these executor kinds may enroll with scope org. The any-machine amendment (Wassim, 2026-11-09):
|
|
36
|
+
* any enrolled machine may be an org runner, so `host` (a Mac mini, laptop or VM) joins container and
|
|
37
|
+
* fleet, appended. The guard is the org owner or admin's aal2 device-step approval at enrollment
|
|
38
|
+
* and the org's DURABLE_POOL_CLAIM entry, not the machine kind.
|
|
39
|
+
*/
|
|
40
|
+
export declare const ORG_SCOPE_EXECUTOR_KINDS: readonly ["container", "fleet", "host"];
|
|
36
41
|
/**
|
|
37
42
|
* exec_oidc_exchange refusals (ruling 34.03's S1 changes), each 403, checked in this order.
|
|
38
43
|
* Amendment 65 (mnemom-test#1331) appends the two single-use codes, checked in the same transaction
|
|
@@ -43,8 +43,13 @@ export function poolClaimOrgs(flagValue) {
|
|
|
43
43
|
}
|
|
44
44
|
// ---- Executor scope (ruling 34.03 (1)) ------------------------------------------------------
|
|
45
45
|
export const EXECUTOR_SCOPES = ["user", "org"];
|
|
46
|
-
/**
|
|
47
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Only these executor kinds may enroll with scope org. The any-machine amendment (Wassim, 2026-11-09):
|
|
48
|
+
* any enrolled machine may be an org runner, so `host` (a Mac mini, laptop or VM) joins container and
|
|
49
|
+
* fleet, appended. The guard is the org owner or admin's aal2 device-step approval at enrollment
|
|
50
|
+
* and the org's DURABLE_POOL_CLAIM entry, not the machine kind.
|
|
51
|
+
*/
|
|
52
|
+
export const ORG_SCOPE_EXECUTOR_KINDS = ["container", "fleet", "host"];
|
|
48
53
|
/**
|
|
49
54
|
* exec_oidc_exchange refusals (ruling 34.03's S1 changes), each 403, checked in this order.
|
|
50
55
|
* Amendment 65 (mnemom-test#1331) appends the two single-use codes, checked in the same transaction
|
|
@@ -750,7 +750,7 @@ export declare const FREEZE_STRUCTURED: Readonly<{
|
|
|
750
750
|
}>;
|
|
751
751
|
CLEAR_WAIT_OUTCOMES: readonly ["cleared", "stale_ref", "already_clear"];
|
|
752
752
|
EXECUTOR_SCOPES: readonly ["user", "org"];
|
|
753
|
-
ORG_SCOPE_EXECUTOR_KINDS: readonly ["container", "fleet"];
|
|
753
|
+
ORG_SCOPE_EXECUTOR_KINDS: readonly ["container", "fleet", "host"];
|
|
754
754
|
OIDC_EXCHANGE_REFUSALS: readonly ["bad_issuer", "repo_not_enrolled", "ref_not_allowed", "pool_flag_off", "adopt_ticket_invalid", "token_replayed", "run_already_exchanged"];
|
|
755
755
|
OIDC_EXCHANGE_BODY_KEYS: readonly ["oidc_token", "adopt_ticket"];
|
|
756
756
|
OIDC_EXCHANGE_RUN_CLAIMS: readonly ["jti", "run_id", "run_attempt"];
|