@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
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* coordination-token — multi-tenant (Phase 1).
|
|
3
|
+
*
|
|
4
|
+
* Verifies: a NON-default project keys its secret + cache separately; the
|
|
5
|
+
* DEFAULT project (memnexus) falls back to the legacy single-hyphen KV name (the
|
|
6
|
+
* zero-orphan dual-read against the un-migrated vault); and the roster resolves
|
|
7
|
+
* from the OFFLINE generated file with NO session-start HTTP (ND-2 — the resolver
|
|
8
|
+
* only ever touches readFileText + fetchSecret, never the coordination service).
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
11
|
+
vi.mock('../lib/config.js', () => ({ getConfigValue: vi.fn(() => undefined) }));
|
|
12
|
+
import { resolveCoordinationToken, resolveRoster, kvSecretName, KEYVAULT_NAME, ENV_KEY_ROSTER_FILE, } from '../lib/coordination-token.js';
|
|
13
|
+
const ROSTER_PATH = '/fake/coordination-rosters.generated.json';
|
|
14
|
+
const ROSTER_JSON = JSON.stringify({
|
|
15
|
+
version: 1,
|
|
16
|
+
projects: { memnexus: ['retrieval', 'mcp'], spearmint: ['retrieval', 'mcp'] },
|
|
17
|
+
});
|
|
18
|
+
/** In-memory readFileText backed by a path→contents map. */
|
|
19
|
+
function reader(files) {
|
|
20
|
+
return (p) => (p in files ? files[p] : undefined);
|
|
21
|
+
}
|
|
22
|
+
describe('coordination-token multi-tenant (Phase 1)', () => {
|
|
23
|
+
it('a NON-default project keys its secret + cache separately (spearmint)', () => {
|
|
24
|
+
const marker = '/wt/.mx-coordination-team';
|
|
25
|
+
const fetchSecret = vi.fn((_v, name) => (name === kvSecretName('spearmint', 'retrieval') ? 'spear-tok' : undefined));
|
|
26
|
+
const writeCache = vi.fn();
|
|
27
|
+
const res = resolveCoordinationToken({
|
|
28
|
+
project: 'spearmint',
|
|
29
|
+
env: { CLAUDE_WORKTREE_PATH: '/wt', [ENV_KEY_ROSTER_FILE]: ROSTER_PATH },
|
|
30
|
+
readFileText: reader({ [marker]: 'retrieval\n', [ROSTER_PATH]: ROSTER_JSON }),
|
|
31
|
+
fetchSecret,
|
|
32
|
+
writeCache,
|
|
33
|
+
});
|
|
34
|
+
expect(res.status).toBe('resolved');
|
|
35
|
+
expect(res.project).toBe('spearmint');
|
|
36
|
+
expect(res.token).toBe('spear-tok');
|
|
37
|
+
// Fetched the spearmint-namespaced secret, never a memnexus/legacy name.
|
|
38
|
+
expect(fetchSecret).toHaveBeenCalledWith(KEYVAULT_NAME, 'coordination-token--spearmint--retrieval');
|
|
39
|
+
expect(fetchSecret).not.toHaveBeenCalledWith(KEYVAULT_NAME, 'coordination-token-retrieval');
|
|
40
|
+
// Cache path embeds BOTH slugs.
|
|
41
|
+
expect(writeCache).toHaveBeenCalledWith('/wt/.mx-coordination-token--spearmint--retrieval', 'spear-tok');
|
|
42
|
+
});
|
|
43
|
+
it('memnexus falls back to the LEGACY single-hyphen KV name (zero-orphan dual-read)', () => {
|
|
44
|
+
const marker = '/wt/.mx-coordination-team';
|
|
45
|
+
// Primary double-hyphen name is ABSENT (un-migrated vault); legacy name present.
|
|
46
|
+
const fetchSecret = vi.fn((_v, name) => (name === 'coordination-token-retrieval' ? 'legacy-tok' : undefined));
|
|
47
|
+
const res = resolveCoordinationToken({
|
|
48
|
+
project: 'memnexus',
|
|
49
|
+
env: { CLAUDE_WORKTREE_PATH: '/wt', [ENV_KEY_ROSTER_FILE]: ROSTER_PATH },
|
|
50
|
+
readFileText: reader({ [marker]: 'retrieval\n', [ROSTER_PATH]: ROSTER_JSON }),
|
|
51
|
+
fetchSecret,
|
|
52
|
+
writeCache: vi.fn(),
|
|
53
|
+
});
|
|
54
|
+
expect(res.status).toBe('resolved');
|
|
55
|
+
expect(res.token).toBe('legacy-tok');
|
|
56
|
+
// It tried the parse-safe name FIRST, then fell back to the legacy name.
|
|
57
|
+
expect(fetchSecret).toHaveBeenNthCalledWith(1, KEYVAULT_NAME, 'coordination-token--memnexus--retrieval');
|
|
58
|
+
expect(fetchSecret).toHaveBeenNthCalledWith(2, KEYVAULT_NAME, 'coordination-token-retrieval');
|
|
59
|
+
});
|
|
60
|
+
it('a NON-default project does NOT fall back to the legacy name (only memnexus does)', () => {
|
|
61
|
+
const marker = '/wt/.mx-coordination-team';
|
|
62
|
+
const fetchSecret = vi.fn(() => undefined); // nothing found
|
|
63
|
+
const res = resolveCoordinationToken({
|
|
64
|
+
project: 'spearmint',
|
|
65
|
+
env: { CLAUDE_WORKTREE_PATH: '/wt', [ENV_KEY_ROSTER_FILE]: ROSTER_PATH },
|
|
66
|
+
readFileText: reader({ [marker]: 'retrieval\n', [ROSTER_PATH]: ROSTER_JSON }),
|
|
67
|
+
fetchSecret,
|
|
68
|
+
writeCache: vi.fn(),
|
|
69
|
+
});
|
|
70
|
+
expect(res.status).toBe('unprovisioned');
|
|
71
|
+
// Only the spearmint-namespaced name was tried — never the legacy fallback.
|
|
72
|
+
expect(fetchSecret).toHaveBeenCalledTimes(1);
|
|
73
|
+
expect(fetchSecret).toHaveBeenCalledWith(KEYVAULT_NAME, 'coordination-token--spearmint--retrieval');
|
|
74
|
+
});
|
|
75
|
+
it('fails CLOSED when the team is not in the TARGET project roster', () => {
|
|
76
|
+
const marker = '/wt/.mx-coordination-team';
|
|
77
|
+
const fetchSecret = vi.fn();
|
|
78
|
+
const res = resolveCoordinationToken({
|
|
79
|
+
project: 'spearmint',
|
|
80
|
+
env: { CLAUDE_WORKTREE_PATH: '/wt', [ENV_KEY_ROSTER_FILE]: ROSTER_PATH },
|
|
81
|
+
// 'platform' is in memnexus's roster but NOT spearmint's.
|
|
82
|
+
readFileText: reader({ [marker]: 'platform\n', [ROSTER_PATH]: ROSTER_JSON }),
|
|
83
|
+
fetchSecret,
|
|
84
|
+
writeCache: vi.fn(),
|
|
85
|
+
});
|
|
86
|
+
expect(res.status).toBe('not-on-roster');
|
|
87
|
+
expect(fetchSecret).not.toHaveBeenCalled();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
describe('offline roster resolution (ND-2 — no session-start HTTP)', () => {
|
|
91
|
+
it('resolves the roster from the OFFLINE file (service down is irrelevant — no HTTP is made)', () => {
|
|
92
|
+
const teams = resolveRoster('spearmint', { [ENV_KEY_ROSTER_FILE]: ROSTER_PATH }, reader({ [ROSTER_PATH]: ROSTER_JSON }));
|
|
93
|
+
expect(teams).toEqual(['retrieval', 'mcp']);
|
|
94
|
+
});
|
|
95
|
+
it('falls back to the BUILTIN memnexus roster when the file is unreadable (offline-safe)', () => {
|
|
96
|
+
// No file at all → builtin memnexus fallback, still no network.
|
|
97
|
+
const teams = resolveRoster('memnexus', {}, reader({}));
|
|
98
|
+
expect(teams).toContain('platform');
|
|
99
|
+
expect(teams).toContain('retrieval');
|
|
100
|
+
});
|
|
101
|
+
it('returns an empty roster for an unknown project with no file (fail-closed, offline)', () => {
|
|
102
|
+
const teams = resolveRoster('unknown-project', {}, reader({}));
|
|
103
|
+
expect(teams).toEqual([]);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
//# sourceMappingURL=coordination-token-multitenant.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordination-token-multitenant.test.js","sourceRoot":"","sources":["../../src/__tests__/coordination-token-multitenant.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -46,7 +46,7 @@ describe('resolveCoordinationToken', () => {
|
|
|
46
46
|
it('uses the per-worktree cache when present and never calls Key Vault', () => {
|
|
47
47
|
const fetchSecret = vi.fn();
|
|
48
48
|
const marker = join(dir, '.mx-coordination-team');
|
|
49
|
-
const cache = join(dir, '.mx-coordination-token
|
|
49
|
+
const cache = join(dir, '.mx-coordination-token--memnexus--eval');
|
|
50
50
|
const res = resolveCoordinationToken({
|
|
51
51
|
env: { CLAUDE_WORKTREE_PATH: dir },
|
|
52
52
|
readFileText: reader({ [marker]: 'eval\n', [cache]: 'cached-eval-tok\n' }),
|
|
@@ -61,15 +61,15 @@ describe('resolveCoordinationToken', () => {
|
|
|
61
61
|
// Real fs so we can assert the on-disk cache mode.
|
|
62
62
|
writeFileSync(join(dir, '.mx-coordination-team'), 'eval\n');
|
|
63
63
|
const fetchSecret = vi.fn((_vault, name) => {
|
|
64
|
-
expect(name).toBe('coordination-token
|
|
64
|
+
expect(name).toBe('coordination-token--memnexus--eval');
|
|
65
65
|
return 'kv-fetched-tok';
|
|
66
66
|
});
|
|
67
67
|
const res = resolveCoordinationToken({ env: { CLAUDE_WORKTREE_PATH: dir }, fetchSecret });
|
|
68
68
|
expect(res.status).toBe('resolved');
|
|
69
69
|
expect(res.source).toBe('keyvault');
|
|
70
70
|
expect(res.token).toBe('kv-fetched-tok');
|
|
71
|
-
expect(fetchSecret).toHaveBeenCalledWith(KEYVAULT_NAME, 'coordination-token
|
|
72
|
-
const cachePath = join(dir, '.mx-coordination-token
|
|
71
|
+
expect(fetchSecret).toHaveBeenCalledWith(KEYVAULT_NAME, 'coordination-token--memnexus--eval');
|
|
72
|
+
const cachePath = join(dir, '.mx-coordination-token--memnexus--eval');
|
|
73
73
|
expect(existsSync(cachePath)).toBe(true);
|
|
74
74
|
expect(readFileSync(cachePath, 'utf-8')).toBe('kv-fetched-tok');
|
|
75
75
|
// SF-3: born 0600 — no group/other bits.
|
|
@@ -92,7 +92,7 @@ describe('resolveCoordinationToken', () => {
|
|
|
92
92
|
// The worktree was recycled from eval to marketing: eval's cache lingers, but
|
|
93
93
|
// the marketing marker must fetch marketing's token, never reuse eval's.
|
|
94
94
|
const marker = join(dir, '.mx-coordination-team');
|
|
95
|
-
const evalCache = join(dir, '.mx-coordination-token
|
|
95
|
+
const evalCache = join(dir, '.mx-coordination-token--memnexus--eval');
|
|
96
96
|
const fetchSecret = vi.fn(() => 'marketing-tok');
|
|
97
97
|
const res = resolveCoordinationToken({
|
|
98
98
|
env: { CLAUDE_WORKTREE_PATH: dir },
|
|
@@ -103,7 +103,7 @@ describe('resolveCoordinationToken', () => {
|
|
|
103
103
|
expect(res.token).toBe('marketing-tok');
|
|
104
104
|
expect(res.token).not.toBe('STALE-EVAL-TOKEN');
|
|
105
105
|
// It fetched marketing's secret, never touched eval's.
|
|
106
|
-
expect(fetchSecret).toHaveBeenCalledWith(KEYVAULT_NAME, 'coordination-token
|
|
106
|
+
expect(fetchSecret).toHaveBeenCalledWith(KEYVAULT_NAME, 'coordination-token--memnexus--marketing');
|
|
107
107
|
});
|
|
108
108
|
it('fails OPEN when Key Vault / az errors — reports unprovisioned, never throws', () => {
|
|
109
109
|
const marker = join(dir, '.mx-coordination-team');
|
|
@@ -136,7 +136,7 @@ describe('resolveCoordinationToken', () => {
|
|
|
136
136
|
it('SF-A: never throws when the config read throws (unwritable HOME) — continues to the marker path', () => {
|
|
137
137
|
mockGetConfigValue.mockImplementation(() => { throw new Error("EACCES: permission denied, mkdir '/home/nobody/.mx-agent'"); });
|
|
138
138
|
const marker = join(dir, '.mx-coordination-team');
|
|
139
|
-
const cache = join(dir, '.mx-coordination-token
|
|
139
|
+
const cache = join(dir, '.mx-coordination-token--memnexus--eval');
|
|
140
140
|
let res;
|
|
141
141
|
expect(() => {
|
|
142
142
|
res = resolveCoordinationToken({
|
|
@@ -153,7 +153,7 @@ describe('resolveCoordinationToken', () => {
|
|
|
153
153
|
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
154
154
|
const errSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
155
155
|
const marker = join(dir, '.mx-coordination-team');
|
|
156
|
-
const cache = join(dir, '.mx-coordination-token
|
|
156
|
+
const cache = join(dir, '.mx-coordination-token--memnexus--eval');
|
|
157
157
|
resolveCoordinationToken({
|
|
158
158
|
env: { CLAUDE_WORKTREE_PATH: dir },
|
|
159
159
|
readFileText: reader({ [marker]: 'eval\n', [cache]: 'secret-token-value' }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coordination-token.test.js","sourceRoot":"","sources":["../../src/__tests__/coordination-token.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC5F,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAE5B,8EAA8E;AAC9E,+EAA+E;AAC/E,oFAAoF;AACpF,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;AAEhF,OAAO,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,kBAAkB,GAAG,cAAqD,CAAC;AAEjF,IAAI,GAAW,CAAC;AAEhB,UAAU,CAAC,GAAG,EAAE;IACd,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IAClD,kBAAkB,CAAC,SAAS,EAAE,CAAC;IAC/B,kBAAkB,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AACH,SAAS,CAAC,GAAG,EAAE;IACb,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,EAAE,CAAC,eAAe,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC;AAEH,4DAA4D;AAC5D,SAAS,MAAM,CAAC,KAA6B;IAC3C,OAAO,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAC5D,CAAC;AAED,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,wBAAwB,CAAC;YACnC,GAAG,EAAE,EAAE,sBAAsB,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,EAAE;YACrE,WAAW;SACZ,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC9C,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"coordination-token.test.js","sourceRoot":"","sources":["../../src/__tests__/coordination-token.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC5F,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAE5B,8EAA8E;AAC9E,+EAA+E;AAC/E,oFAAoF;AACpF,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;AAEhF,OAAO,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,kBAAkB,GAAG,cAAqD,CAAC;AAEjF,IAAI,GAAW,CAAC;AAEhB,UAAU,CAAC,GAAG,EAAE;IACd,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IAClD,kBAAkB,CAAC,SAAS,EAAE,CAAC;IAC/B,kBAAkB,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AACH,SAAS,CAAC,GAAG,EAAE;IACb,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,EAAE,CAAC,eAAe,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC;AAEH,4DAA4D;AAC5D,SAAS,MAAM,CAAC,KAA6B;IAC3C,OAAO,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAC5D,CAAC;AAED,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,wBAAwB,CAAC;YACnC,GAAG,EAAE,EAAE,sBAAsB,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,EAAE;YACrE,WAAW;SACZ,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC9C,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,wCAAwC,CAAC,CAAC;QAClE,MAAM,GAAG,GAAG,wBAAwB,CAAC;YACnC,GAAG,EAAE,EAAE,oBAAoB,EAAE,GAAG,EAAE;YAClC,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,mBAAmB,EAAE,CAAC;YAC1E,WAAW;SACZ,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC1C,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,mDAAmD;QACnD,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC5D,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,MAAc,EAAE,IAAY,EAAE,EAAE;YACzD,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;YACxD,OAAO,gBAAgB,CAAC;QAC1B,CAAC,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,wBAAwB,CAAC,EAAE,GAAG,EAAE,EAAE,oBAAoB,EAAE,GAAG,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;QAE1F,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACzC,MAAM,CAAC,WAAW,CAAC,CAAC,oBAAoB,CAAC,aAAa,EAAE,oCAAoC,CAAC,CAAC;QAE9F,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,wCAAwC,CAAC,CAAC;QACtE,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAChE,yCAAyC;QACzC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;QAClD,MAAM,GAAG,GAAG,wBAAwB,CAAC;YACnC,GAAG,EAAE,EAAE,oBAAoB,EAAE,GAAG,EAAE;YAClC,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,mBAAmB,EAAE,CAAC;YACvD,WAAW;SACZ,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;QAClC,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oFAAoF,EAAE,GAAG,EAAE;QAC5F,8EAA8E;QAC9E,yEAAyE;QACzE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,wCAAwC,CAAC,CAAC;QACtE,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,wBAAwB,CAAC;YACnC,GAAG,EAAE,EAAE,oBAAoB,EAAE,GAAG,EAAE;YAClC,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC,SAAS,CAAC,EAAE,kBAAkB,EAAE,CAAC;YAClF,WAAW;SACZ,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC/C,uDAAuD;QACvD,MAAM,CAAC,WAAW,CAAC,CAAC,oBAAoB,CAAC,aAAa,EAAE,yCAAyC,CAAC,CAAC;IACrG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6EAA6E,EAAE,GAAG,EAAE;QACrF,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;QAClD,+EAA+E;QAC/E,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,wBAAwB,CAAC;YACnC,GAAG,EAAE,EAAE,oBAAoB,EAAE,GAAG,EAAE;YAClC,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;YAC5C,WAAW;SACZ,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;QAClC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,GAAG,GAAG,wBAAwB,CAAC;YACnC,GAAG,EAAE,EAAE,oBAAoB,EAAE,GAAG,EAAE;YAClC,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC;YACxB,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE;SACrB,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,GAAG,GAAG,wBAAwB,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACxE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iGAAiG,EAAE,GAAG,EAAE;QACzG,kBAAkB,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/H,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,wCAAwC,CAAC,CAAC;QAClE,IAAI,GAA4D,CAAC;QACjE,MAAM,CAAC,GAAG,EAAE;YACV,GAAG,GAAG,wBAAwB,CAAC;gBAC7B,GAAG,EAAE,EAAE,oBAAoB,EAAE,GAAG,EAAE;gBAClC,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,iBAAiB,EAAE,CAAC;gBACxE,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE;aACrB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,sEAAsE;QACtE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACrE,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACvE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,wCAAwC,CAAC,CAAC;QAClE,wBAAwB,CAAC;YACvB,GAAG,EAAE,EAAE,oBAAoB,EAAE,GAAG,EAAE;YAClC,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,oBAAoB,EAAE,CAAC;YAC3E,WAAW,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC;SAC/C,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1E,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -53,11 +53,19 @@ KEYVAULT_NAME="mx-dev-eastus2-kv-001"
|
|
|
53
53
|
MIN_CLI_VERSION="0.1.172"
|
|
54
54
|
CLI_UPDATE_CMD="npm install -g @memnexus-ai/mx-agent-cli@latest"
|
|
55
55
|
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
|
|
56
|
+
# MULTI-TENANT (Phase 1). Identity is (project, team). `project` is the committed
|
|
57
|
+
# project-config signal (resolveProductSlug precedence: MX_PRODUCT_SLUG →
|
|
58
|
+
# mx-agent.config.json projectSlug → memnexus). `team` is the marker slug. The
|
|
59
|
+
# roster is resolved from the OFFLINE generated file (ND-2) — NEVER a live
|
|
60
|
+
# GET /roster at session start, so a coordination-service outage (the shared
|
|
61
|
+
# SPOF) can't break session start. For the DEFAULT project (memnexus) behavior is
|
|
62
|
+
# IDENTICAL to before: same roster membership, same token (via the legacy KV
|
|
63
|
+
# name fallback below).
|
|
64
|
+
DEFAULT_PROJECT="memnexus"
|
|
65
|
+
# BUILTIN memnexus roster — OFFLINE fallback used only when the generated file is
|
|
66
|
+
# unreadable (or node is unavailable). Mirrors PROVISIONED_ROSTERS in
|
|
67
|
+
# coordination-service/src/config/rosters.ts.
|
|
68
|
+
BUILTIN_MEMNEXUS_ROSTER="platform retrieval mcp pipeline marketing customer-portal eval product"
|
|
61
69
|
|
|
62
70
|
# ── MF-2: authoritative marker, hook NEVER derives the slug. ─────────────────
|
|
63
71
|
# The slug is an explicit assignment written into the worktree by an onboarding
|
|
@@ -80,22 +88,41 @@ if [ -z "$SLUG" ]; then
|
|
|
80
88
|
exit 0
|
|
81
89
|
fi
|
|
82
90
|
|
|
83
|
-
# ──
|
|
91
|
+
# ── Resolve the PROJECT (resolveProductSlug precedence, offline). ────────────
|
|
92
|
+
# 1) MX_PRODUCT_SLUG env; 2) mx-agent.config.json projectSlug at the worktree
|
|
93
|
+
# root; 3) default memnexus. No HTTP — reads local config only.
|
|
94
|
+
PROJECT="${MX_PRODUCT_SLUG:-}"
|
|
95
|
+
if [ -z "$PROJECT" ] && [ -f "${WORKTREE}/mx-agent.config.json" ]; then
|
|
96
|
+
PROJECT="$(node -e 'try{const c=require(process.argv[1]);const s=(c.projectSlug||(c.project&&c.project.slug)||"");process.stdout.write(String(s).trim())}catch(e){}' "${WORKTREE}/mx-agent.config.json" 2>/dev/null || true)"
|
|
97
|
+
fi
|
|
98
|
+
[ -z "$PROJECT" ] && PROJECT="$DEFAULT_PROJECT"
|
|
99
|
+
|
|
100
|
+
# ── SF-2: per-project roster-membership validation before any az call. ───────
|
|
101
|
+
# The roster is read from the OFFLINE generated file (ND-2), with the builtin
|
|
102
|
+
# memnexus roster as an offline fallback. NEVER a live GET /roster.
|
|
103
|
+
ROSTER_FILE="${MX_COORD_ROSTER_FILE:-${WORKTREE}/mx-agent-system/agent-config/coordination-rosters.generated.json}"
|
|
104
|
+
ROSTER_TEAMS=""
|
|
105
|
+
if [ -f "$ROSTER_FILE" ]; then
|
|
106
|
+
ROSTER_TEAMS="$(node -e 'try{const r=require(process.argv[1]);const t=(r.projects&&r.projects[process.argv[2]])||[];process.stdout.write(t.join(" "))}catch(e){}' "$ROSTER_FILE" "$PROJECT" 2>/dev/null || true)"
|
|
107
|
+
fi
|
|
108
|
+
if [ -z "$ROSTER_TEAMS" ] && [ "$PROJECT" = "$DEFAULT_PROJECT" ]; then
|
|
109
|
+
# Offline fallback: file missing/unparseable/node absent → builtin memnexus roster.
|
|
110
|
+
ROSTER_TEAMS="$BUILTIN_MEMNEXUS_ROSTER"
|
|
111
|
+
fi
|
|
84
112
|
in_roster=""
|
|
85
|
-
for t in
|
|
113
|
+
for t in $ROSTER_TEAMS; do
|
|
86
114
|
if [ "$SLUG" = "$t" ]; then in_roster="yes"; break; fi
|
|
87
115
|
done
|
|
88
116
|
if [ -z "$in_roster" ]; then
|
|
89
|
-
# Unknown/invalid
|
|
90
|
-
echo "coordination brief: team
|
|
117
|
+
# Unknown/invalid (project, team) → fail-closed. Never fetch a default token.
|
|
118
|
+
echo "coordination brief: (project \"$PROJECT\", team \"$SLUG\") not in roster — skipping" >&2
|
|
91
119
|
exit 0
|
|
92
120
|
fi
|
|
93
121
|
|
|
94
|
-
# ── MF-1:
|
|
95
|
-
# The cache filename embeds
|
|
96
|
-
#
|
|
97
|
-
|
|
98
|
-
CACHE="${WORKTREE}/.mx-coordination-token-${SLUG}"
|
|
122
|
+
# ── MF-1: (project, team)-bound per-worktree token cache. ────────────────────
|
|
123
|
+
# The cache filename embeds BOTH slugs, so a worktree recycled to another
|
|
124
|
+
# team/project can NEVER reuse the prior tenant's cached token.
|
|
125
|
+
CACHE="${WORKTREE}/.mx-coordination-token--${PROJECT}--${SLUG}"
|
|
99
126
|
TOKEN=""
|
|
100
127
|
if [ -s "$CACHE" ]; then
|
|
101
128
|
TOKEN="$(head -n1 "$CACHE" 2>/dev/null || true)"
|
|
@@ -104,11 +131,21 @@ fi
|
|
|
104
131
|
# ── Fetch from Key Vault once if not cached (SF-3 born-0600 write). ───────────
|
|
105
132
|
if [ -z "$TOKEN" ]; then
|
|
106
133
|
# Fail-OPEN on any fetch problem (not logged in, no access, missing secret).
|
|
107
|
-
# SLUG
|
|
134
|
+
# PROJECT/SLUG are roster-validated above; each is a single quoted argv element.
|
|
135
|
+
# ND-1: primary name is the parse-safe double-hyphen coordination-token--<p>--<t>.
|
|
108
136
|
fetched="$(az keyvault secret show \
|
|
109
137
|
--vault-name "$KEYVAULT_NAME" \
|
|
110
|
-
--name "coordination-token
|
|
138
|
+
--name "coordination-token--${PROJECT}--${SLUG}" \
|
|
111
139
|
--query value -o tsv 2>/dev/null || true)"
|
|
140
|
+
# ZERO-ORPHAN dual-read (memnexus only): the un-migrated live vault still holds
|
|
141
|
+
# the legacy single-hyphen secret. Fall back to it so memnexus session-start is
|
|
142
|
+
# identical to today. Phase 2 renames the secret and removes this fallback.
|
|
143
|
+
if [ -z "$fetched" ] && [ "$PROJECT" = "$DEFAULT_PROJECT" ]; then
|
|
144
|
+
fetched="$(az keyvault secret show \
|
|
145
|
+
--vault-name "$KEYVAULT_NAME" \
|
|
146
|
+
--name "coordination-token-${SLUG}" \
|
|
147
|
+
--query value -o tsv 2>/dev/null || true)"
|
|
148
|
+
fi
|
|
112
149
|
if [ -z "$fetched" ]; then
|
|
113
150
|
# No token available — tolerate and skip (fail-open).
|
|
114
151
|
exit 0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhE,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhE,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA8CD,wBAAgB,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAuFtD"}
|
package/dist/commands/config.js
CHANGED
|
@@ -18,6 +18,12 @@ const KNOWN_KEYS = {
|
|
|
18
18
|
'coordination-service-url': 'MX Agent Coordination Service base URL (https://...)',
|
|
19
19
|
'coordination-service-token': 'Per-team bearer token for the MX Agent Coordination Service',
|
|
20
20
|
'coordination-brief-enabled': 'Run `mx-agent coordination brief` at session start (true to opt in; default off)',
|
|
21
|
+
'coordination-mode': 'Coordination backend: queue | memory (default memory; `queue` routes escalate/brief to the coordination service)',
|
|
22
|
+
'coordination-team': 'Sender team for memory-mode coordination when no .mx-coordination-team marker is present',
|
|
23
|
+
};
|
|
24
|
+
/** Config keys constrained to a fixed set of values, validated on `set`. */
|
|
25
|
+
const ENUM_KEYS = {
|
|
26
|
+
'coordination-mode': ['queue', 'memory'],
|
|
21
27
|
};
|
|
22
28
|
/** Keys whose value is a secret and must never be echoed in the clear. */
|
|
23
29
|
const SECRET_KEYS = new Set(['observability-api-token', 'coordination-service-token']);
|
|
@@ -55,6 +61,12 @@ export function runConfig(options) {
|
|
|
55
61
|
process.exit(1);
|
|
56
62
|
}
|
|
57
63
|
validateKey(key);
|
|
64
|
+
// Validate enum-constrained keys (e.g. coordination-mode).
|
|
65
|
+
const allowed = ENUM_KEYS[key];
|
|
66
|
+
if (allowed && !allowed.includes(value)) {
|
|
67
|
+
console.error(chalk.red(`Error: ${key} must be one of: ${allowed.join(', ')} (got "${value}").`));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
58
70
|
// Validate HTTPS for webhook URLs
|
|
59
71
|
if (key === 'slack-webhook') {
|
|
60
72
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAUjG,MAAM,UAAU,GAA2B;IACzC,eAAe,EAAc,oDAAoD;IACjF,uBAAuB,EAAM,0EAA0E;IACvG,yBAAyB,EAAI,uFAAuF;IACpH,0BAA0B,EAAG,sDAAsD;IACnF,4BAA4B,EAAC,6DAA6D;IAC1F,4BAA4B,EAAC,kFAAkF;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* only a local durable fallback file and flushes it on the next success.
|
|
11
11
|
*/
|
|
12
12
|
import { type CoordinationClient } from '../lib/coordination-client.js';
|
|
13
|
+
import { type MemoryStore } from '../lib/coordination-memory.js';
|
|
13
14
|
/**
|
|
14
15
|
* Build the HTTP client, self-provisioning the coordination token from Key Vault
|
|
15
16
|
* when none is configured. This ports the coordination-brief hook's KV-fetch into
|
|
@@ -31,6 +32,15 @@ import { type CoordinationClient } from '../lib/coordination-client.js';
|
|
|
31
32
|
export declare function prepareClient(deps?: {
|
|
32
33
|
client?: CoordinationClient;
|
|
33
34
|
}): CoordinationClient | null;
|
|
35
|
+
/**
|
|
36
|
+
* Injectable dependencies for the coordination commands. `client` stubs the
|
|
37
|
+
* queue service (queue mode); `memoryStore` stubs the named-memory backend
|
|
38
|
+
* (memory mode). Tests inject one or both; production uses the real defaults.
|
|
39
|
+
*/
|
|
40
|
+
export interface CoordinationDeps {
|
|
41
|
+
client?: CoordinationClient;
|
|
42
|
+
memoryStore?: MemoryStore;
|
|
43
|
+
}
|
|
34
44
|
export interface EscalateOptions {
|
|
35
45
|
to: string;
|
|
36
46
|
priority: string;
|
|
@@ -43,9 +53,7 @@ export interface EscalateOptions {
|
|
|
43
53
|
* (exit 0, non-lossy). On success, any previously queued-locally entries are
|
|
44
54
|
* flushed first.
|
|
45
55
|
*/
|
|
46
|
-
export declare function runEscalate(opts: EscalateOptions, deps?:
|
|
47
|
-
client?: CoordinationClient;
|
|
48
|
-
}): Promise<void>;
|
|
56
|
+
export declare function runEscalate(opts: EscalateOptions, deps?: CoordinationDeps): Promise<void>;
|
|
49
57
|
export interface DrainOptions {
|
|
50
58
|
all?: boolean;
|
|
51
59
|
limit?: string;
|
|
@@ -65,9 +73,7 @@ export interface DrainOptions {
|
|
|
65
73
|
* flushed to stdout, the batch is confirmed (MAJOR-2); a mid-render crash leaves
|
|
66
74
|
* it pending for re-queue. `--no-confirm` leaves the batch unconfirmed.
|
|
67
75
|
*/
|
|
68
|
-
export declare function runDrain(opts: DrainOptions, deps?:
|
|
69
|
-
client?: CoordinationClient;
|
|
70
|
-
}): Promise<void>;
|
|
76
|
+
export declare function runDrain(opts: DrainOptions, deps?: CoordinationDeps): Promise<void>;
|
|
71
77
|
export interface BriefOptions {
|
|
72
78
|
limit?: number;
|
|
73
79
|
/**
|
|
@@ -86,9 +92,7 @@ export interface BriefOptions {
|
|
|
86
92
|
* (a mid-render crash leaves it pending → re-queued). Bodies are truncated to
|
|
87
93
|
* keep the block under the token ceiling for any backlog.
|
|
88
94
|
*/
|
|
89
|
-
export declare function runBrief(opts?: BriefOptions, deps?:
|
|
90
|
-
client?: CoordinationClient;
|
|
91
|
-
}): Promise<void>;
|
|
95
|
+
export declare function runBrief(opts?: BriefOptions, deps?: CoordinationDeps): Promise<void>;
|
|
92
96
|
export interface WatchOptions {
|
|
93
97
|
intervalMs?: number;
|
|
94
98
|
limit?: number;
|
|
@@ -119,14 +123,11 @@ export declare function redactSecrets(s: string): string;
|
|
|
119
123
|
* hint. Full harness onInject + the Redis blocking-read server push stay OUT of
|
|
120
124
|
* scope (see README).
|
|
121
125
|
*/
|
|
122
|
-
export declare function runWatch(opts?: WatchOptions, deps?: {
|
|
123
|
-
client?: CoordinationClient;
|
|
126
|
+
export declare function runWatch(opts?: WatchOptions, deps?: CoordinationDeps & {
|
|
124
127
|
sleep?: (ms: number) => Promise<void>;
|
|
125
128
|
}): Promise<void>;
|
|
126
129
|
/** FR-7 ack. */
|
|
127
|
-
export declare function runAck(messageId: string, deps?:
|
|
128
|
-
client?: CoordinationClient;
|
|
129
|
-
}): Promise<void>;
|
|
130
|
+
export declare function runAck(messageId: string, deps?: CoordinationDeps): Promise<void>;
|
|
130
131
|
export interface HistoryOptions {
|
|
131
132
|
/** Page size (service default 50, cap 200). */
|
|
132
133
|
limit?: string;
|
|
@@ -141,7 +142,5 @@ export interface HistoryOptions {
|
|
|
141
142
|
* payload in a body stays inside the fence and is never emitted raw. `--all`
|
|
142
143
|
* follows the `nextBefore` cursor to page the full history (most-recent-first).
|
|
143
144
|
*/
|
|
144
|
-
export declare function runHistory(opts?: HistoryOptions, deps?:
|
|
145
|
-
client?: CoordinationClient;
|
|
146
|
-
}): Promise<void>;
|
|
145
|
+
export declare function runHistory(opts?: HistoryOptions, deps?: CoordinationDeps): Promise<void>;
|
|
147
146
|
//# sourceMappingURL=coordination.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coordination.d.ts","sourceRoot":"","sources":["../../src/commands/coordination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"coordination.d.ts","sourceRoot":"","sources":["../../src/commands/coordination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAML,KAAK,kBAAkB,EAExB,MAAM,+BAA+B,CAAC;AAIvC,OAAO,EAML,KAAK,WAAW,EACjB,MAAM,+BAA+B,CAAC;AAiCvC;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,kBAAkB,CAAA;CAAE,GAAG,kBAAkB,GAAG,IAAI,CAqC/F;AAkCD;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AASD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkDD;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC/F;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wEAAwE;IACxE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,4EAA4E;IAC5E,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BzF;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,IAAI,GAAE,YAAiB,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+C9F;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,kFAAkF;AAClF,qBAAa,cAAe,SAAQ,KAAK;;CAKxC;AAQD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,GAAE,YAAiB,EACvB,IAAI,CAAC,EAAE,gBAAgB,GAAG;IAAE,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,GAClE,OAAO,CAAC,IAAI,CAAC,CAyCf;AAED,gBAAgB;AAChB,wBAAsB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAStF;AAED,MAAM,WAAW,cAAc;IAC7B,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAKD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,IAAI,GAAE,cAAmB,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBlG"}
|
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
* `escalate` degrades safely when the service is unreachable (FR-8): it writes
|
|
10
10
|
* only a local durable fallback file and flushes it on the next success.
|
|
11
11
|
*/
|
|
12
|
-
import { HttpCoordinationClient, resolveClientConfig, ServiceUnreachableError, ServiceHttpError, } from '../lib/coordination-client.js';
|
|
12
|
+
import { HttpCoordinationClient, resolveClientConfig, resolveCoordinationMode, ServiceUnreachableError, ServiceHttpError, } from '../lib/coordination-client.js';
|
|
13
13
|
import { resolveCoordinationToken } from '../lib/coordination-token.js';
|
|
14
14
|
import { appendFallbackEntry, flushFallback } from '../lib/coordination-fallback.js';
|
|
15
15
|
import { renderMessages } from '../lib/coordination-render.js';
|
|
16
|
+
import { escalateToOutbox, readEscalationsForTeam, renderEscalationBlocks, resolveMemoryTeam, resolveProductSlug, } from '../lib/coordination-memory.js';
|
|
16
17
|
const VALID_PRIORITIES = new Set(['p0', 'p1', 'p2', 'p3']);
|
|
17
18
|
/** Truncate each body to this many chars in the brief (token-ceiling control). */
|
|
18
19
|
const BRIEF_BODY_MAX_CHARS = 500;
|
|
@@ -126,6 +127,52 @@ function writeFallbackOrFail(entry) {
|
|
|
126
127
|
throw err;
|
|
127
128
|
}
|
|
128
129
|
}
|
|
130
|
+
/** One-line note printed when a queue-only subcommand runs in memory mode. */
|
|
131
|
+
function memoryModeQueueOnlyNote(subcommand) {
|
|
132
|
+
console.log(`coordination-mode=memory: ${subcommand} is queue-only; use \`mx-agent coordination brief\` to read the shared escalations doc`);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* memory-mode escalate: append the entry to the sender's outbox memory
|
|
136
|
+
* `<slug>-escalations-<from-team>-outbox` via fetch-edit-verify. No token, no
|
|
137
|
+
* queue service. A failed byte-verify is a hard error (exit 1) so a clobbered
|
|
138
|
+
* or dropped write is never silently reported as success.
|
|
139
|
+
*/
|
|
140
|
+
async function runEscalateMemory(opts, deps) {
|
|
141
|
+
const team = resolveMemoryTeam(opts.team);
|
|
142
|
+
const slug = resolveProductSlug();
|
|
143
|
+
let res;
|
|
144
|
+
try {
|
|
145
|
+
res = escalateToOutbox({ fromTeam: team, to: opts.to, priority: opts.priority, body: opts.body, productSlug: slug }, deps?.memoryStore);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
// A MemNexus write failure is surfaced (not swallowed) — the message is not
|
|
149
|
+
// queued, so the operator must see it. Exit non-zero.
|
|
150
|
+
console.error(`Error: memory-mode escalate failed to write the outbox: ${err instanceof Error ? err.message : String(err)}`);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (!res.verified) {
|
|
155
|
+
console.error(`Error: memory-mode escalate could not verify the outbox write (${res.name}) — the entry may not have persisted. Not marking as sent.`);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
console.log(`escalated to ${res.name} (memory mode) -> ${opts.to} [${opts.priority}]${res.created ? ' (outbox created)' : ''}`);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* memory-mode brief: read the shared escalations doc and render entries
|
|
163
|
+
* addressed to this team inside the provenance fence. Read-only — there is no
|
|
164
|
+
* drain/confirm in memory mode.
|
|
165
|
+
*/
|
|
166
|
+
async function runBriefMemory(opts, deps) {
|
|
167
|
+
const team = opts.expectedTeam ?? resolveMemoryTeam();
|
|
168
|
+
const slug = resolveProductSlug();
|
|
169
|
+
const { present, entries } = readEscalationsForTeam(team, slug, deps?.memoryStore);
|
|
170
|
+
if (!present || entries.length === 0) {
|
|
171
|
+
console.log('no cross-team coordination pending');
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
console.log(renderEscalationBlocks(entries));
|
|
175
|
+
}
|
|
129
176
|
/**
|
|
130
177
|
* FR-7 enqueue + FR-8 degraded fallback. On a transport failure the message is
|
|
131
178
|
* written to the local durable fallback file and reported as queued-locally
|
|
@@ -137,6 +184,10 @@ export async function runEscalate(opts, deps) {
|
|
|
137
184
|
console.error(`Error: --priority must be one of p0, p1, p2, p3 (got "${opts.priority}").`);
|
|
138
185
|
process.exit(1);
|
|
139
186
|
}
|
|
187
|
+
// Backend routing (PO one-interface design). memory mode requires NO token.
|
|
188
|
+
if (resolveCoordinationMode() === 'memory') {
|
|
189
|
+
return runEscalateMemory(opts, deps);
|
|
190
|
+
}
|
|
140
191
|
const team = resolveTeam(opts.team);
|
|
141
192
|
const entry = { team, to: opts.to, priority: opts.priority, body: opts.body, from: team };
|
|
142
193
|
const client = prepareClient(deps);
|
|
@@ -172,6 +223,10 @@ export async function runEscalate(opts, deps) {
|
|
|
172
223
|
* it pending for re-queue. `--no-confirm` leaves the batch unconfirmed.
|
|
173
224
|
*/
|
|
174
225
|
export async function runDrain(opts, deps) {
|
|
226
|
+
if (resolveCoordinationMode() === 'memory') {
|
|
227
|
+
memoryModeQueueOnlyNote('drain');
|
|
228
|
+
return; // exit 0 — no crash
|
|
229
|
+
}
|
|
175
230
|
const client = prepareClient(deps);
|
|
176
231
|
if (!client)
|
|
177
232
|
return; // could not provision — fall back (prepareClient printed why)
|
|
@@ -203,6 +258,9 @@ export async function runDrain(opts, deps) {
|
|
|
203
258
|
* keep the block under the token ceiling for any backlog.
|
|
204
259
|
*/
|
|
205
260
|
export async function runBrief(opts = {}, deps) {
|
|
261
|
+
if (resolveCoordinationMode() === 'memory') {
|
|
262
|
+
return runBriefMemory(opts, deps);
|
|
263
|
+
}
|
|
206
264
|
const client = prepareClient(deps);
|
|
207
265
|
if (!client)
|
|
208
266
|
return; // could not provision — fall back (prepareClient printed why)
|
|
@@ -279,6 +337,10 @@ export function redactSecrets(s) {
|
|
|
279
337
|
* scope (see README).
|
|
280
338
|
*/
|
|
281
339
|
export async function runWatch(opts = {}, deps) {
|
|
340
|
+
if (resolveCoordinationMode() === 'memory') {
|
|
341
|
+
memoryModeQueueOnlyNote('watch');
|
|
342
|
+
return; // exit 0 — no crash
|
|
343
|
+
}
|
|
282
344
|
const client = prepareClient(deps);
|
|
283
345
|
if (!client)
|
|
284
346
|
return; // could not provision — fall back (prepareClient printed why)
|
|
@@ -321,6 +383,10 @@ export async function runWatch(opts = {}, deps) {
|
|
|
321
383
|
}
|
|
322
384
|
/** FR-7 ack. */
|
|
323
385
|
export async function runAck(messageId, deps) {
|
|
386
|
+
if (resolveCoordinationMode() === 'memory') {
|
|
387
|
+
memoryModeQueueOnlyNote('ack');
|
|
388
|
+
return; // exit 0 — no crash
|
|
389
|
+
}
|
|
324
390
|
const client = prepareClient(deps);
|
|
325
391
|
if (!client)
|
|
326
392
|
return; // could not provision — fall back (prepareClient printed why)
|
|
@@ -338,6 +404,10 @@ const HISTORY_MAX_PAGES = 500;
|
|
|
338
404
|
* follows the `nextBefore` cursor to page the full history (most-recent-first).
|
|
339
405
|
*/
|
|
340
406
|
export async function runHistory(opts = {}, deps) {
|
|
407
|
+
if (resolveCoordinationMode() === 'memory') {
|
|
408
|
+
memoryModeQueueOnlyNote('history');
|
|
409
|
+
return; // exit 0 — no crash
|
|
410
|
+
}
|
|
341
411
|
const client = prepareClient(deps);
|
|
342
412
|
if (!client)
|
|
343
413
|
return; // could not provision — fall back (prepareClient printed why)
|