@memnexus-ai/mx-agent-cli 0.1.175 → 0.1.177
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/__tests__/config-command.test.js +20 -0
- package/dist/__tests__/config-command.test.js.map +1 -1
- package/dist/__tests__/coordination-brief.test.js +5 -1
- package/dist/__tests__/coordination-brief.test.js.map +1 -1
- package/dist/__tests__/coordination-command.test.js +2 -0
- package/dist/__tests__/coordination-command.test.js.map +1 -1
- package/dist/__tests__/coordination-history.test.js +5 -1
- package/dist/__tests__/coordination-history.test.js.map +1 -1
- package/dist/__tests__/coordination-memory.test.d.ts +14 -0
- package/dist/__tests__/coordination-memory.test.d.ts.map +1 -0
- package/dist/__tests__/coordination-memory.test.js +261 -0
- package/dist/__tests__/coordination-memory.test.js.map +1 -0
- package/dist/__tests__/coordination-provision.test.js +1 -0
- package/dist/__tests__/coordination-provision.test.js.map +1 -1
- package/dist/__tests__/coordination-token-multitenant.test.d.ts +11 -0
- package/dist/__tests__/coordination-token-multitenant.test.d.ts.map +1 -0
- package/dist/__tests__/coordination-token-multitenant.test.js +106 -0
- package/dist/__tests__/coordination-token-multitenant.test.js.map +1 -0
- package/dist/__tests__/coordination-token.test.js +8 -8
- package/dist/__tests__/coordination-token.test.js.map +1 -1
- package/dist/agent-config/coordination-rosters.generated.json +15 -0
- package/dist/agent-config/hooks/coordination-brief.sh +53 -16
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +12 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/coordination.d.ts +16 -17
- package/dist/commands/coordination.d.ts.map +1 -1
- package/dist/commands/coordination.js +71 -1
- package/dist/commands/coordination.js.map +1 -1
- package/dist/lib/coordination-client.d.ts +21 -0
- package/dist/lib/coordination-client.d.ts.map +1 -1
- package/dist/lib/coordination-client.js +24 -0
- package/dist/lib/coordination-client.js.map +1 -1
- package/dist/lib/coordination-memory.d.ts +125 -0
- package/dist/lib/coordination-memory.d.ts.map +1 -0
- package/dist/lib/coordination-memory.js +318 -0
- package/dist/lib/coordination-memory.js.map +1 -0
- package/dist/lib/coordination-token.d.ts +46 -15
- package/dist/lib/coordination-token.d.ts.map +1 -1
- package/dist/lib/coordination-token.js +108 -47
- package/dist/lib/coordination-token.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,34 +4,54 @@
|
|
|
4
4
|
* Ports the security-reviewed KV-fetch logic from the agent-config hook
|
|
5
5
|
* `coordination-brief.sh` into the CLI so that a bare `mx-agent coordination
|
|
6
6
|
* brief` (and drain/escalate/history) resolves its own token when none is
|
|
7
|
-
* configured
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* configured. MULTI-TENANT (Phase 1): identity is (project, team). `project`
|
|
8
|
+
* comes from resolveProductSlug() (config-derived, default 'memnexus'); `team`
|
|
9
|
+
* from the authoritative worktree marker. The isolation properties the security
|
|
10
|
+
* review required are preserved 1:1, now project-aware:
|
|
10
11
|
*
|
|
11
12
|
* - MF-2 The team slug is read from the authoritative worktree marker
|
|
12
13
|
* (.mx-coordination-team). It is NEVER derived from CLAUDE_TEAM_NAME
|
|
13
|
-
* or the worktree name.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* or the worktree name. The PROJECT is the committed project-config
|
|
15
|
+
* signal (resolveProductSlug), never a queue-mode client assertion.
|
|
16
|
+
* - SF-2 The (project, team) is validated against the per-project roster
|
|
17
|
+
* BEFORE any `az` call. A non-member fails CLOSED (no fetch).
|
|
18
|
+
* - MF-1 The token cache filename embeds BOTH slugs
|
|
19
|
+
* (.mx-coordination-token--<project>--<team>), per worktree. A worktree
|
|
20
|
+
* recycled to a different team/project can never read another tenant's
|
|
21
|
+
* cached token.
|
|
19
22
|
* - SF-3 The cache is created born 0600 (mode on create — no readable window).
|
|
20
|
-
* - No shell: the roster-validated
|
|
23
|
+
* - No shell: the roster-validated slugs are passed to `az` via execFile with an
|
|
21
24
|
* args array, never interpolated into a shell string.
|
|
22
|
-
* - The token is NEVER written to the global ~/.mx-agent config
|
|
23
|
-
* across worktrees — the MF-2 defect) and is NEVER logged.
|
|
25
|
+
* - The token is NEVER written to the global ~/.mx-agent config and NEVER logged.
|
|
24
26
|
* - Fail-OPEN on infra errors (no marker, az not logged in, KV unreachable):
|
|
25
27
|
* report "unprovisioned" so the caller degrades, never crash.
|
|
26
28
|
* - Fail-CLOSED only on a roster mismatch.
|
|
29
|
+
*
|
|
30
|
+
* ZERO-ORPHAN KV shim (Phase 1): the secret name is the parse-safe double-hyphen
|
|
31
|
+
* `coordination-token--<project>--<team>` (ND-1). For the DEFAULT project
|
|
32
|
+
* (memnexus) the live Key Vault still holds the PRE-migration single-hyphen
|
|
33
|
+
* `coordination-token-<team>` secrets, so the fetch falls back to the legacy name
|
|
34
|
+
* when the double-hyphen name is absent (the PRD migration grace-window dual-read).
|
|
35
|
+
* This keeps memnexus session-start working IDENTICALLY against the un-migrated
|
|
36
|
+
* vault; Phase 2 renames the secrets and the fallback is removed.
|
|
27
37
|
*/
|
|
28
38
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
39
|
+
* BUILTIN memnexus provisioned-team roster — the OFFLINE fallback used only when
|
|
40
|
+
* the generated roster file cannot be read. Mirrors PROVISIONED_ROSTERS in
|
|
41
|
+
* coordination-service/src/config/rosters.ts. Keeping it here preserves
|
|
42
|
+
* offline-safety (a missing file never breaks the memnexus gate) without a live
|
|
43
|
+
* HTTP dependency. Aliases mx-agent / mx-agent-system are intentionally excluded.
|
|
32
44
|
*/
|
|
33
45
|
export declare const COORD_ROSTER: readonly ["platform", "retrieval", "mcp", "pipeline", "marketing", "customer-portal", "eval", "product"];
|
|
34
46
|
export declare const KEYVAULT_NAME = "mx-dev-eastus2-kv-001";
|
|
47
|
+
/** Env override for the offline roster file path (test seam / operator override). */
|
|
48
|
+
export declare const ENV_KEY_ROSTER_FILE = "MX_COORD_ROSTER_FILE";
|
|
49
|
+
/**
|
|
50
|
+
* ND-1 single-source KV secret name shape — reproduced here (the CLI is a
|
|
51
|
+
* separate package from coordination-service). MUST stay byte-identical to
|
|
52
|
+
* kvSecretName() in coordination-service/src/types.ts.
|
|
53
|
+
*/
|
|
54
|
+
export declare function kvSecretName(project: string, team: string): string;
|
|
35
55
|
export type TokenResolveStatus =
|
|
36
56
|
/** A token was already in env/config; KV is skipped (hook path + manual override). */
|
|
37
57
|
'already-configured'
|
|
@@ -45,6 +65,8 @@ export interface TokenResolveResult {
|
|
|
45
65
|
status: TokenResolveStatus;
|
|
46
66
|
/** The resolved token — set only for 'already-configured' and 'resolved'. */
|
|
47
67
|
token?: string;
|
|
68
|
+
/** The resolved project (config-derived). */
|
|
69
|
+
project?: string;
|
|
48
70
|
/** The marker slug, when one was read (roster or not). */
|
|
49
71
|
slug?: string;
|
|
50
72
|
/** Where the token came from — for diagnostics; never includes the token. */
|
|
@@ -64,7 +86,16 @@ export interface TokenResolveDeps {
|
|
|
64
86
|
readFileText?: (path: string) => string | undefined;
|
|
65
87
|
/** Persist the fetched token to the per-worktree cache (born 0600). */
|
|
66
88
|
writeCache?: (path: string, value: string) => void;
|
|
89
|
+
/** Override the resolved project (test seam); defaults to resolveProductSlug(). */
|
|
90
|
+
project?: string;
|
|
67
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Resolve the per-project provisioned-team roster from the OFFLINE generated file
|
|
94
|
+
* (ND-2), falling back to the builtin roster when the file is unreadable or does
|
|
95
|
+
* not list the project. This is deliberately OFFLINE-SAFE: it never makes a
|
|
96
|
+
* session-start HTTP call to the coordination service (the shared SPOF).
|
|
97
|
+
*/
|
|
98
|
+
export declare function resolveRoster(project: string, env: NodeJS.ProcessEnv, readFileText: (path: string) => string | undefined): readonly string[];
|
|
68
99
|
/**
|
|
69
100
|
* Resolve the coordination token, self-provisioning from Key Vault when none is
|
|
70
101
|
* configured. Never throws — every failure is a typed result the caller acts on.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coordination-token.d.ts","sourceRoot":"","sources":["../../src/lib/coordination-token.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"coordination-token.d.ts","sourceRoot":"","sources":["../../src/lib/coordination-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AASH;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,0GASf,CAAC;AAMX,eAAO,MAAM,aAAa,0BAA0B,CAAC;AAErD,qFAAqF;AACrF,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAM1D;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAElE;AAYD,MAAM,MAAM,kBAAkB;AAC5B,sFAAsF;AACpF,oBAAoB;AACtB,iFAAiF;GAC/E,UAAU;AACZ,8EAA8E;GAC5E,eAAe;AACjB,+EAA+E;GAC7E,eAAe,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,MAAM,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;IACjD,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,iDAAiD;IACjD,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxE,oFAAoF;IACpF,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACpD,uEAAuE;IACvE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA8CD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GACjD,SAAS,MAAM,EAAE,CAkBnB;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,GAAE,gBAAqB,GAAG,kBAAkB,CAqExF"}
|
|
@@ -4,36 +4,49 @@
|
|
|
4
4
|
* Ports the security-reviewed KV-fetch logic from the agent-config hook
|
|
5
5
|
* `coordination-brief.sh` into the CLI so that a bare `mx-agent coordination
|
|
6
6
|
* brief` (and drain/escalate/history) resolves its own token when none is
|
|
7
|
-
* configured
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* configured. MULTI-TENANT (Phase 1): identity is (project, team). `project`
|
|
8
|
+
* comes from resolveProductSlug() (config-derived, default 'memnexus'); `team`
|
|
9
|
+
* from the authoritative worktree marker. The isolation properties the security
|
|
10
|
+
* review required are preserved 1:1, now project-aware:
|
|
10
11
|
*
|
|
11
12
|
* - MF-2 The team slug is read from the authoritative worktree marker
|
|
12
13
|
* (.mx-coordination-team). It is NEVER derived from CLAUDE_TEAM_NAME
|
|
13
|
-
* or the worktree name.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* or the worktree name. The PROJECT is the committed project-config
|
|
15
|
+
* signal (resolveProductSlug), never a queue-mode client assertion.
|
|
16
|
+
* - SF-2 The (project, team) is validated against the per-project roster
|
|
17
|
+
* BEFORE any `az` call. A non-member fails CLOSED (no fetch).
|
|
18
|
+
* - MF-1 The token cache filename embeds BOTH slugs
|
|
19
|
+
* (.mx-coordination-token--<project>--<team>), per worktree. A worktree
|
|
20
|
+
* recycled to a different team/project can never read another tenant's
|
|
21
|
+
* cached token.
|
|
19
22
|
* - SF-3 The cache is created born 0600 (mode on create — no readable window).
|
|
20
|
-
* - No shell: the roster-validated
|
|
23
|
+
* - No shell: the roster-validated slugs are passed to `az` via execFile with an
|
|
21
24
|
* args array, never interpolated into a shell string.
|
|
22
|
-
* - The token is NEVER written to the global ~/.mx-agent config
|
|
23
|
-
* across worktrees — the MF-2 defect) and is NEVER logged.
|
|
25
|
+
* - The token is NEVER written to the global ~/.mx-agent config and NEVER logged.
|
|
24
26
|
* - Fail-OPEN on infra errors (no marker, az not logged in, KV unreachable):
|
|
25
27
|
* report "unprovisioned" so the caller degrades, never crash.
|
|
26
28
|
* - Fail-CLOSED only on a roster mismatch.
|
|
29
|
+
*
|
|
30
|
+
* ZERO-ORPHAN KV shim (Phase 1): the secret name is the parse-safe double-hyphen
|
|
31
|
+
* `coordination-token--<project>--<team>` (ND-1). For the DEFAULT project
|
|
32
|
+
* (memnexus) the live Key Vault still holds the PRE-migration single-hyphen
|
|
33
|
+
* `coordination-token-<team>` secrets, so the fetch falls back to the legacy name
|
|
34
|
+
* when the double-hyphen name is absent (the PRD migration grace-window dual-read).
|
|
35
|
+
* This keeps memnexus session-start working IDENTICALLY against the un-migrated
|
|
36
|
+
* vault; Phase 2 renames the secrets and the fallback is removed.
|
|
27
37
|
*/
|
|
28
38
|
import { execFileSync } from 'node:child_process';
|
|
29
39
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
30
40
|
import { join } from 'node:path';
|
|
31
41
|
import { getConfigValue } from './config.js';
|
|
32
42
|
import { CONFIG_KEY_TOKEN } from './coordination-client.js';
|
|
43
|
+
import { resolveProductSlug, DEFAULT_PRODUCT_SLUG } from './coordination-memory.js';
|
|
33
44
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
45
|
+
* BUILTIN memnexus provisioned-team roster — the OFFLINE fallback used only when
|
|
46
|
+
* the generated roster file cannot be read. Mirrors PROVISIONED_ROSTERS in
|
|
47
|
+
* coordination-service/src/config/rosters.ts. Keeping it here preserves
|
|
48
|
+
* offline-safety (a missing file never breaks the memnexus gate) without a live
|
|
49
|
+
* HTTP dependency. Aliases mx-agent / mx-agent-system are intentionally excluded.
|
|
37
50
|
*/
|
|
38
51
|
export const COORD_ROSTER = [
|
|
39
52
|
'platform',
|
|
@@ -45,9 +58,31 @@ export const COORD_ROSTER = [
|
|
|
45
58
|
'eval',
|
|
46
59
|
'product',
|
|
47
60
|
];
|
|
61
|
+
const BUILTIN_ROSTERS = {
|
|
62
|
+
[DEFAULT_PRODUCT_SLUG]: COORD_ROSTER,
|
|
63
|
+
};
|
|
48
64
|
export const KEYVAULT_NAME = 'mx-dev-eastus2-kv-001';
|
|
65
|
+
/** Env override for the offline roster file path (test seam / operator override). */
|
|
66
|
+
export const ENV_KEY_ROSTER_FILE = 'MX_COORD_ROSTER_FILE';
|
|
67
|
+
/** Repo-relative location of the committed generated offline roster file (ND-2). */
|
|
68
|
+
const ROSTER_FILE_REL = join('mx-agent-system', 'agent-config', 'coordination-rosters.generated.json');
|
|
49
69
|
const MARKER_FILE = '.mx-coordination-team';
|
|
50
|
-
|
|
70
|
+
/**
|
|
71
|
+
* ND-1 single-source KV secret name shape — reproduced here (the CLI is a
|
|
72
|
+
* separate package from coordination-service). MUST stay byte-identical to
|
|
73
|
+
* kvSecretName() in coordination-service/src/types.ts.
|
|
74
|
+
*/
|
|
75
|
+
export function kvSecretName(project, team) {
|
|
76
|
+
return `coordination-token--${project}--${team}`;
|
|
77
|
+
}
|
|
78
|
+
/** Legacy (pre-migration) single-hyphen name — memnexus dual-read fallback only. */
|
|
79
|
+
function legacyKvSecretName(team) {
|
|
80
|
+
return `coordination-token-${team}`;
|
|
81
|
+
}
|
|
82
|
+
/** Per-worktree token cache filename, embedding BOTH slugs (MF-1). */
|
|
83
|
+
function cacheFileName(project, team) {
|
|
84
|
+
return `.mx-coordination-token--${project}--${team}`;
|
|
85
|
+
}
|
|
51
86
|
/** Default marker/cache reader: undefined on missing or unreadable file. */
|
|
52
87
|
function defaultReadFileText(path) {
|
|
53
88
|
try {
|
|
@@ -60,11 +95,9 @@ function defaultReadFileText(path) {
|
|
|
60
95
|
}
|
|
61
96
|
}
|
|
62
97
|
/**
|
|
63
|
-
* Default KV fetch. The
|
|
64
|
-
* caller;
|
|
65
|
-
*
|
|
66
|
-
* gate were bypassed. Any failure (az not logged in, KV unreachable, missing
|
|
67
|
-
* secret) returns undefined → fail-open.
|
|
98
|
+
* Default KV fetch. The slugs embedded in `secretName` are roster-validated by
|
|
99
|
+
* the caller; the name is passed to `az` as a single argv element via execFile
|
|
100
|
+
* (no shell). Any failure returns undefined → fail-open.
|
|
68
101
|
*/
|
|
69
102
|
function defaultFetchSecret(vault, secretName) {
|
|
70
103
|
try {
|
|
@@ -79,9 +112,6 @@ function defaultFetchSecret(vault, secretName) {
|
|
|
79
112
|
/** SF-3 born-0600 cache write. A write failure is tolerated (fail-open). */
|
|
80
113
|
function defaultWriteCache(path, value) {
|
|
81
114
|
try {
|
|
82
|
-
// mode 0600 on create — 0600 has no group/other bits, so no umask can widen
|
|
83
|
-
// it. The cache is only written when absent (see resolveCoordinationToken),
|
|
84
|
-
// so this is always a create.
|
|
85
115
|
writeFileSync(path, value, { mode: 0o600 });
|
|
86
116
|
}
|
|
87
117
|
catch {
|
|
@@ -93,6 +123,36 @@ function firstLineNoSpace(raw) {
|
|
|
93
123
|
const firstLine = raw.split(/\r?\n/, 1)[0] ?? '';
|
|
94
124
|
return firstLine.replace(/\s+/g, '');
|
|
95
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Resolve the per-project provisioned-team roster from the OFFLINE generated file
|
|
128
|
+
* (ND-2), falling back to the builtin roster when the file is unreadable or does
|
|
129
|
+
* not list the project. This is deliberately OFFLINE-SAFE: it never makes a
|
|
130
|
+
* session-start HTTP call to the coordination service (the shared SPOF).
|
|
131
|
+
*/
|
|
132
|
+
export function resolveRoster(project, env, readFileText) {
|
|
133
|
+
const candidates = [];
|
|
134
|
+
const override = env[ENV_KEY_ROSTER_FILE];
|
|
135
|
+
if (override)
|
|
136
|
+
candidates.push(override);
|
|
137
|
+
const worktree = env.CLAUDE_WORKTREE_PATH;
|
|
138
|
+
if (worktree)
|
|
139
|
+
candidates.push(join(worktree, ROSTER_FILE_REL));
|
|
140
|
+
for (const path of candidates) {
|
|
141
|
+
const raw = readFileText(path);
|
|
142
|
+
if (!raw)
|
|
143
|
+
continue;
|
|
144
|
+
try {
|
|
145
|
+
const parsed = JSON.parse(raw);
|
|
146
|
+
const teams = parsed.projects?.[project];
|
|
147
|
+
if (Array.isArray(teams))
|
|
148
|
+
return teams;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
/* malformed file → fall through to the builtin fallback (offline-safe) */
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return BUILTIN_ROSTERS[project] ?? [];
|
|
155
|
+
}
|
|
96
156
|
/**
|
|
97
157
|
* Resolve the coordination token, self-provisioning from Key Vault when none is
|
|
98
158
|
* configured. Never throws — every failure is a typed result the caller acts on.
|
|
@@ -103,15 +163,9 @@ export function resolveCoordinationToken(deps = {}) {
|
|
|
103
163
|
const env = deps.env ?? process.env;
|
|
104
164
|
const readFileText = deps.readFileText ?? defaultReadFileText;
|
|
105
165
|
// 1. Already configured → use it, skip KV. Env preferred, then global config.
|
|
106
|
-
// This keeps the hook path (which injects MX_COORD_SERVICE_TOKEN) and any
|
|
107
|
-
// manual `mx-agent config set coordination-service-token` working unchanged.
|
|
108
166
|
const envToken = env.MX_COORD_SERVICE_TOKEN;
|
|
109
167
|
if (envToken)
|
|
110
168
|
return { status: 'already-configured', token: envToken, source: 'env' };
|
|
111
|
-
// Belt-and-suspenders for the SF-A never-crash contract: getConfigValue →
|
|
112
|
-
// loadConfig → getConfigDir calls mkdirSync, which throws on an unwritable/
|
|
113
|
-
// read-only HOME (EACCES/EROFS/ENOSPC). Swallow it and treat the config token
|
|
114
|
-
// as absent so resolution continues to the marker/KV path instead of throwing.
|
|
115
169
|
let configToken;
|
|
116
170
|
try {
|
|
117
171
|
configToken = getConfigValue(CONFIG_KEY_TOKEN);
|
|
@@ -121,41 +175,48 @@ export function resolveCoordinationToken(deps = {}) {
|
|
|
121
175
|
}
|
|
122
176
|
if (configToken)
|
|
123
177
|
return { status: 'already-configured', token: configToken, source: 'config' };
|
|
124
|
-
// 2.
|
|
125
|
-
|
|
178
|
+
// 2. Resolve the PROJECT (config-derived, default memnexus). Never throws.
|
|
179
|
+
const project = deps.project ?? resolveProductSlug();
|
|
180
|
+
// 3. MF-2: read the authoritative team marker. No worktree/marker → fail-OPEN.
|
|
126
181
|
const worktree = env.CLAUDE_WORKTREE_PATH;
|
|
127
182
|
if (!worktree) {
|
|
128
|
-
return { status: 'unprovisioned', detail: 'CLAUDE_WORKTREE_PATH is unset — cannot locate the coordination marker' };
|
|
183
|
+
return { status: 'unprovisioned', project, detail: 'CLAUDE_WORKTREE_PATH is unset — cannot locate the coordination marker' };
|
|
129
184
|
}
|
|
130
185
|
const markerRaw = readFileText(join(worktree, MARKER_FILE));
|
|
131
186
|
if (markerRaw === undefined) {
|
|
132
|
-
return { status: 'unprovisioned', detail: 'no coordination marker (.mx-coordination-team) in this worktree' };
|
|
187
|
+
return { status: 'unprovisioned', project, detail: 'no coordination marker (.mx-coordination-team) in this worktree' };
|
|
133
188
|
}
|
|
134
189
|
const slug = firstLineNoSpace(markerRaw);
|
|
135
190
|
if (!slug) {
|
|
136
|
-
return { status: 'unprovisioned', detail: 'coordination marker is empty' };
|
|
191
|
+
return { status: 'unprovisioned', project, detail: 'coordination marker is empty' };
|
|
137
192
|
}
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
|
|
193
|
+
// 4. SF-2: roster-membership gate for THIS project BEFORE any az call. The
|
|
194
|
+
// roster comes from the OFFLINE file (single source), builtin fallback.
|
|
195
|
+
const roster = resolveRoster(project, env, readFileText);
|
|
196
|
+
if (!roster.includes(slug)) {
|
|
197
|
+
return { status: 'not-on-roster', project, slug };
|
|
141
198
|
}
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
-
// prior team's token — its cache path simply does not exist yet.
|
|
145
|
-
const cachePath = join(worktree, `${CACHE_PREFIX}${slug}`);
|
|
199
|
+
// 5. MF-1: (project, team)-bound per-worktree cache.
|
|
200
|
+
const cachePath = join(worktree, cacheFileName(project, slug));
|
|
146
201
|
const cachedRaw = readFileText(cachePath);
|
|
147
202
|
if (cachedRaw) {
|
|
148
203
|
const cached = firstLineNoSpace(cachedRaw);
|
|
149
204
|
if (cached)
|
|
150
|
-
return { status: 'resolved', token: cached, slug, source: 'cache' };
|
|
205
|
+
return { status: 'resolved', token: cached, project, slug, source: 'cache' };
|
|
151
206
|
}
|
|
152
|
-
//
|
|
153
|
-
//
|
|
207
|
+
// 6. Fetch from Key Vault. Primary: parse-safe double-hyphen name (ND-1).
|
|
208
|
+
// Fallback (memnexus only): legacy single-hyphen name — the zero-orphan
|
|
209
|
+
// dual-read against the un-migrated live vault (Phase 2 removes it).
|
|
154
210
|
const fetchSecret = deps.fetchSecret ?? defaultFetchSecret;
|
|
155
|
-
|
|
211
|
+
let fetched = fetchSecret(KEYVAULT_NAME, kvSecretName(project, slug));
|
|
212
|
+
let source = 'keyvault';
|
|
213
|
+
if (!fetched && project === DEFAULT_PRODUCT_SLUG) {
|
|
214
|
+
fetched = fetchSecret(KEYVAULT_NAME, legacyKvSecretName(slug));
|
|
215
|
+
}
|
|
156
216
|
if (!fetched) {
|
|
157
217
|
return {
|
|
158
218
|
status: 'unprovisioned',
|
|
219
|
+
project,
|
|
159
220
|
slug,
|
|
160
221
|
detail: 'Key Vault returned no token (az not logged in, KV unreachable, or secret missing)',
|
|
161
222
|
};
|
|
@@ -163,6 +224,6 @@ export function resolveCoordinationToken(deps = {}) {
|
|
|
163
224
|
// SF-3: cache born 0600. NEVER persisted to the global config.
|
|
164
225
|
const writeCache = deps.writeCache ?? defaultWriteCache;
|
|
165
226
|
writeCache(cachePath, fetched);
|
|
166
|
-
return { status: 'resolved', token: fetched, slug, source
|
|
227
|
+
return { status: 'resolved', token: fetched, project, slug, source };
|
|
167
228
|
}
|
|
168
229
|
//# sourceMappingURL=coordination-token.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coordination-token.js","sourceRoot":"","sources":["../../src/lib/coordination-token.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"coordination-token.js","sourceRoot":"","sources":["../../src/lib/coordination-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEpF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,UAAU;IACV,WAAW;IACX,KAAK;IACL,UAAU;IACV,WAAW;IACX,iBAAiB;IACjB,MAAM;IACN,SAAS;CACD,CAAC;AAEX,MAAM,eAAe,GAAsC;IACzD,CAAC,oBAAoB,CAAC,EAAE,YAAY;CACrC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,uBAAuB,CAAC;AAErD,qFAAqF;AACrF,MAAM,CAAC,MAAM,mBAAmB,GAAG,sBAAsB,CAAC;AAC1D,oFAAoF;AACpF,MAAM,eAAe,GAAG,IAAI,CAAC,iBAAiB,EAAE,cAAc,EAAE,qCAAqC,CAAC,CAAC;AAEvG,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAE5C;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,IAAY;IACxD,OAAO,uBAAuB,OAAO,KAAK,IAAI,EAAE,CAAC;AACnD,CAAC;AAED,oFAAoF;AACpF,SAAS,kBAAkB,CAAC,IAAY;IACtC,OAAO,sBAAsB,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,sEAAsE;AACtE,SAAS,aAAa,CAAC,OAAe,EAAE,IAAY;IAClD,OAAO,2BAA2B,OAAO,KAAK,IAAI,EAAE,CAAC;AACvD,CAAC;AA0CD,4EAA4E;AAC5E,SAAS,mBAAmB,CAAC,IAAY;IACvC,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,SAAS,CAAC;QACxC,OAAO,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,KAAa,EAAE,UAAkB;IAC3D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CACtB,IAAI,EACJ,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,EAC5G,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAC3D,CAAC;QACF,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3B,OAAO,OAAO,IAAI,SAAS,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,SAAS,iBAAiB,CAAC,IAAY,EAAE,KAAa;IACpD,IAAI,CAAC;QACH,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,sFAAsF;IACxF,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,SAAS,gBAAgB,CAAC,GAAW;IACnC,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACjD,OAAO,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,GAAsB,EACtB,YAAkD;IAElD,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,QAAQ,GAAG,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC1C,IAAI,QAAQ;QAAE,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,GAAG,CAAC,oBAAoB,CAAC;IAC1C,IAAI,QAAQ;QAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC;IAC/D,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4C,CAAC;YAC1E,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC;YACzC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,0EAA0E;QAC5E,CAAC;IACH,CAAC;IACD,OAAO,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;AACxC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAyB,EAAE;IAClE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,mBAAmB,CAAC;IAE9D,8EAA8E;IAC9E,MAAM,QAAQ,GAAG,GAAG,CAAC,sBAAsB,CAAC;IAC5C,IAAI,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACtF,IAAI,WAA+B,CAAC;IACpC,IAAI,CAAC;QACH,WAAW,GAAG,cAAc,CAAC,gBAAgB,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,WAAW,GAAG,SAAS,CAAC;IAC1B,CAAC;IACD,IAAI,WAAW;QAAE,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAE/F,2EAA2E;IAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,kBAAkB,EAAE,CAAC;IAErD,+EAA+E;IAC/E,MAAM,QAAQ,GAAG,GAAG,CAAC,oBAAoB,CAAC;IAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,uEAAuE,EAAE,CAAC;IAC/H,CAAC;IACD,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;IAC5D,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,iEAAiE,EAAE,CAAC;IACzH,CAAC;IACD,MAAM,IAAI,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC;IACtF,CAAC;IAED,2EAA2E;IAC3E,2EAA2E;IAC3E,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;IACzD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACpD,CAAC;IAED,qDAAqD;IACrD,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IAC1C,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAC3F,CAAC;IAED,0EAA0E;IAC1E,2EAA2E;IAC3E,wEAAwE;IACxE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,kBAAkB,CAAC;IAC3D,IAAI,OAAO,GAAG,WAAW,CAAC,aAAa,EAAE,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IACtE,IAAI,MAAM,GAAe,UAAU,CAAC;IACpC,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,oBAAoB,EAAE,CAAC;QACjD,OAAO,GAAG,WAAW,CAAC,aAAa,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,MAAM,EAAE,eAAe;YACvB,OAAO;YACP,IAAI;YACJ,MAAM,EAAE,mFAAmF;SAC5F,CAAC;IACJ,CAAC;IAED,+DAA+D;IAC/D,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,iBAAiB,CAAC;IACxD,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AACvE,CAAC"}
|