@memnexus-ai/mx-agent-cli 0.1.208 → 0.1.210

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.
Files changed (56) hide show
  1. package/dist/__tests__/claude-sync.test.js +77 -5
  2. package/dist/__tests__/claude-sync.test.js.map +1 -1
  3. package/dist/__tests__/config-generation-gate.test.js +18 -9
  4. package/dist/__tests__/config-generation-gate.test.js.map +1 -1
  5. package/dist/__tests__/generate-claude.test.js +90 -6
  6. package/dist/__tests__/generate-claude.test.js.map +1 -1
  7. package/dist/__tests__/security-posture.test.d.ts +8 -0
  8. package/dist/__tests__/security-posture.test.d.ts.map +1 -0
  9. package/dist/__tests__/security-posture.test.js +82 -0
  10. package/dist/__tests__/security-posture.test.js.map +1 -0
  11. package/dist/__tests__/start-report-generation-capture.test.d.ts +17 -0
  12. package/dist/__tests__/start-report-generation-capture.test.d.ts.map +1 -0
  13. package/dist/__tests__/start-report-generation-capture.test.js +127 -0
  14. package/dist/__tests__/start-report-generation-capture.test.js.map +1 -0
  15. package/dist/__tests__/startup-health-render.test.d.ts +11 -0
  16. package/dist/__tests__/startup-health-render.test.d.ts.map +1 -0
  17. package/dist/__tests__/startup-health-render.test.js +60 -0
  18. package/dist/__tests__/startup-health-render.test.js.map +1 -0
  19. package/dist/__tests__/startup-report.test.js +34 -1
  20. package/dist/__tests__/startup-report.test.js.map +1 -1
  21. package/dist/__tests__/startup-shipper.test.d.ts +13 -0
  22. package/dist/__tests__/startup-shipper.test.d.ts.map +1 -0
  23. package/dist/__tests__/startup-shipper.test.js +149 -0
  24. package/dist/__tests__/startup-shipper.test.js.map +1 -0
  25. package/dist/agent-config/settings.json +3 -3
  26. package/dist/commands/dashboard.d.ts +21 -0
  27. package/dist/commands/dashboard.d.ts.map +1 -1
  28. package/dist/commands/dashboard.js +72 -1
  29. package/dist/commands/dashboard.js.map +1 -1
  30. package/dist/commands/start.d.ts.map +1 -1
  31. package/dist/commands/start.js +16 -0
  32. package/dist/commands/start.js.map +1 -1
  33. package/dist/commands/sync.d.ts.map +1 -1
  34. package/dist/commands/sync.js +17 -0
  35. package/dist/commands/sync.js.map +1 -1
  36. package/dist/lib/claude.d.ts.map +1 -1
  37. package/dist/lib/claude.js +31 -6
  38. package/dist/lib/claude.js.map +1 -1
  39. package/dist/lib/security-posture.d.ts +69 -0
  40. package/dist/lib/security-posture.d.ts.map +1 -0
  41. package/dist/lib/security-posture.js +102 -0
  42. package/dist/lib/security-posture.js.map +1 -0
  43. package/dist/lib/startup-report.d.ts +19 -3
  44. package/dist/lib/startup-report.d.ts.map +1 -1
  45. package/dist/lib/startup-report.js +66 -8
  46. package/dist/lib/startup-report.js.map +1 -1
  47. package/dist/lib/startup-shipper.d.ts +55 -0
  48. package/dist/lib/startup-shipper.d.ts.map +1 -0
  49. package/dist/lib/startup-shipper.js +177 -0
  50. package/dist/lib/startup-shipper.js.map +1 -0
  51. package/package.json +1 -1
  52. package/scripts/generate-claude.mjs +45 -1
  53. package/dist/__tests__/config-mirror-integrity.test.d.ts +0 -32
  54. package/dist/__tests__/config-mirror-integrity.test.d.ts.map +0 -1
  55. package/dist/__tests__/config-mirror-integrity.test.js +0 -248
  56. package/dist/__tests__/config-mirror-integrity.test.js.map +0 -1
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Unit tests for the shared self-protection posture contract (security-posture.ts,
3
+ * #4304 Phase 4). This is the single source of truth reused by the CI generation
4
+ * gate and by syncClaudeConfig's no-config hard-stop, so it is worth direct
5
+ * coverage independent of either consumer.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=security-posture.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-posture.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/security-posture.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Unit tests for the shared self-protection posture contract (security-posture.ts,
3
+ * #4304 Phase 4). This is the single source of truth reused by the CI generation
4
+ * gate and by syncClaudeConfig's no-config hard-stop, so it is worth direct
5
+ * coverage independent of either consumer.
6
+ */
7
+ import { describe, it, expect } from 'vitest';
8
+ import { REQUIRED_SOURCE_DENIES, SELF_PROTECTED_PATHS, unmatchedFilePathDenies, pathIsWriteProtected, assessSettingsPosture, } from '../lib/security-posture.js';
9
+ describe('REQUIRED_SOURCE_DENIES', () => {
10
+ it('is the Edit-form of every SELF_PROTECTED_PATHS entry (settings, hooks, staging, prev)', () => {
11
+ expect(REQUIRED_SOURCE_DENIES).toEqual([
12
+ 'Edit(.claude/settings.json)',
13
+ 'Edit(.claude/hooks/**)',
14
+ 'Edit(.claude.staging-*/**)',
15
+ 'Edit(.claude.prev-*/**)',
16
+ ]);
17
+ expect(REQUIRED_SOURCE_DENIES).toHaveLength(SELF_PROTECTED_PATHS.length);
18
+ });
19
+ it('contains no unmatched file-path form (Edit-only, canary syntax fix)', () => {
20
+ expect(unmatchedFilePathDenies(REQUIRED_SOURCE_DENIES)).toEqual([]);
21
+ });
22
+ });
23
+ describe('unmatchedFilePathDenies', () => {
24
+ it('flags Write(path)/NotebookEdit(path)/Glob(path) but not Edit/Read/Bash or bare tool names', () => {
25
+ const deny = [
26
+ 'Write(.claude/settings.json)', // flagged
27
+ 'NotebookEdit(nb/**)', // flagged
28
+ 'Glob(src/**)', // flagged
29
+ 'Edit(.claude/hooks/**)', // ok
30
+ 'Read(/secrets/**)', // ok
31
+ 'Bash(rm -rf /)', // ok (not a file-path tool form)
32
+ 'Write', // ok — bare tool name, matches everywhere, no warning
33
+ ];
34
+ expect(unmatchedFilePathDenies(deny)).toEqual([
35
+ 'Write(.claude/settings.json)',
36
+ 'NotebookEdit(nb/**)',
37
+ 'Glob(src/**)',
38
+ ]);
39
+ });
40
+ });
41
+ describe('pathIsWriteProtected', () => {
42
+ it('accepts either the Edit form or the legacy Write form', () => {
43
+ expect(pathIsWriteProtected(['Edit(.claude/settings.json)'], '.claude/settings.json')).toBe(true);
44
+ expect(pathIsWriteProtected(['Write(.claude/settings.json)'], '.claude/settings.json')).toBe(true);
45
+ expect(pathIsWriteProtected(['Edit(other)'], '.claude/settings.json')).toBe(false);
46
+ });
47
+ });
48
+ describe('assessSettingsPosture', () => {
49
+ const ok = JSON.stringify({
50
+ permissions: { deny: ['Edit(.claude/settings.json)', 'Edit(.claude/hooks/**)'] },
51
+ });
52
+ it('returns null for a valid posture', () => {
53
+ expect(assessSettingsPosture(ok)).toBeNull();
54
+ });
55
+ it('accepts the legacy Write(...) form (lenient on form)', () => {
56
+ const legacy = JSON.stringify({
57
+ permissions: { deny: ['Write(.claude/settings.json)', 'Write(.claude/hooks/**)'] },
58
+ });
59
+ expect(assessSettingsPosture(legacy)).toBeNull();
60
+ });
61
+ it('rejects a zero-byte / non-JSON file', () => {
62
+ expect(assessSettingsPosture('')).toMatch(/not valid JSON/);
63
+ expect(assessSettingsPosture('{ not json')).toMatch(/not valid JSON/);
64
+ });
65
+ it('rejects an empty or missing permissions.deny', () => {
66
+ expect(assessSettingsPosture('{"permissions":{"deny":[]}}')).toMatch(/deny is missing or empty/);
67
+ expect(assessSettingsPosture('{"permissions":{"allow":["Bash"]}}')).toMatch(/deny is missing or empty/);
68
+ expect(assessSettingsPosture('{}')).toMatch(/deny is missing or empty/);
69
+ });
70
+ it('rejects a deny list missing a required self-protection path', () => {
71
+ const halfProtected = JSON.stringify({
72
+ permissions: { deny: ['Edit(.claude/settings.json)'] }, // hooks/** missing
73
+ });
74
+ expect(assessSettingsPosture(halfProtected)).toMatch(/\.claude\/hooks/);
75
+ });
76
+ it('never throws on garbage shapes', () => {
77
+ expect(() => assessSettingsPosture('null')).not.toThrow();
78
+ expect(() => assessSettingsPosture('[]')).not.toThrow();
79
+ expect(() => assessSettingsPosture('42')).not.toThrow();
80
+ });
81
+ });
82
+ //# sourceMappingURL=security-posture.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-posture.test.js","sourceRoot":"","sources":["../../src/__tests__/security-posture.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Integration test (#4304 Phase 4, KI item 3d): the startup-report (v2.58, #4350)
3
+ * captures the config-generation lines of the REAL start path.
4
+ *
5
+ * The v2.58 startup report tees/records everything the start path prints. This
6
+ * test drives the actual `syncClaudeConfig` — the same function `mx-agent start`
7
+ * calls at §5 — against a REAL git origin so the REAL generator subprocess
8
+ * (`node scripts/generate-claude.mjs --from-git origin/main`) materializes
9
+ * `.claude/` from source, then asserts the durable JSONL records the generation
10
+ * lines. No production code changed for this deliverable: the confirmation is that
11
+ * the existing capture already records these lines end-to-end.
12
+ *
13
+ * This is the committed equivalent of the built-binary smoke: temp HOME, temp
14
+ * worktree clone, real generator, real durable log.
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=start-report-generation-capture.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-report-generation-capture.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/start-report-generation-capture.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Integration test (#4304 Phase 4, KI item 3d): the startup-report (v2.58, #4350)
3
+ * captures the config-generation lines of the REAL start path.
4
+ *
5
+ * The v2.58 startup report tees/records everything the start path prints. This
6
+ * test drives the actual `syncClaudeConfig` — the same function `mx-agent start`
7
+ * calls at §5 — against a REAL git origin so the REAL generator subprocess
8
+ * (`node scripts/generate-claude.mjs --from-git origin/main`) materializes
9
+ * `.claude/` from source, then asserts the durable JSONL records the generation
10
+ * lines. No production code changed for this deliverable: the confirmation is that
11
+ * the existing capture already records these lines end-to-end.
12
+ *
13
+ * This is the committed equivalent of the built-binary smoke: temp HOME, temp
14
+ * worktree clone, real generator, real durable log.
15
+ */
16
+ import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
17
+ import { cpSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, existsSync } from 'fs';
18
+ import { execFileSync } from 'child_process';
19
+ import { tmpdir } from 'os';
20
+ import { dirname, join } from 'path';
21
+ import { fileURLToPath } from 'url';
22
+ import { syncClaudeConfig } from '../lib/claude.js';
23
+ import { startupReport } from '../lib/startup-report.js';
24
+ const CONFIG_SOURCE = 'mx-agent-system/agent-config';
25
+ const HERE = dirname(fileURLToPath(import.meta.url));
26
+ /** Locate the repo root that holds the real agent-config source. */
27
+ function findRepoRoot() {
28
+ let dir = HERE;
29
+ for (let i = 0; i < 20; i++) {
30
+ if (existsSync(join(dir, CONFIG_SOURCE, 'settings.json')))
31
+ return dir;
32
+ const parent = dirname(dir);
33
+ if (parent === dir)
34
+ break;
35
+ dir = parent;
36
+ }
37
+ throw new Error('could not locate repo root from ' + HERE);
38
+ }
39
+ const REPO_ROOT = findRepoRoot();
40
+ let tmp;
41
+ let originDir;
42
+ let wt;
43
+ let home;
44
+ const OLD_HOME = process.env.HOME;
45
+ function git(cwd, ...args) {
46
+ execFileSync('git', args, { cwd, stdio: 'pipe' });
47
+ }
48
+ beforeAll(() => {
49
+ tmp = mkdtempSync(join(tmpdir(), 'mx-gencap-'));
50
+ originDir = join(tmp, 'origin.git');
51
+ wt = join(tmp, 'wt');
52
+ // Bare origin.
53
+ mkdirSync(originDir, { recursive: true });
54
+ git(originDir, 'init', '--bare', '-q');
55
+ // Working clone with the REAL agent-config source committed at CONFIG_SOURCE, so
56
+ // the generator has a faithful, generatable tree to archive from origin/main.
57
+ mkdirSync(wt, { recursive: true });
58
+ git(wt, 'init', '-q');
59
+ git(wt, 'config', 'user.email', 'test@example.com');
60
+ git(wt, 'config', 'user.name', 'Test');
61
+ git(wt, 'config', 'commit.gpgsign', 'false');
62
+ const dstSrc = join(wt, CONFIG_SOURCE);
63
+ mkdirSync(dirname(dstSrc), { recursive: true });
64
+ cpSync(join(REPO_ROOT, CONFIG_SOURCE), dstSrc, { recursive: true });
65
+ git(wt, 'add', '-A');
66
+ git(wt, 'commit', '-q', '-m', 'seed agent-config');
67
+ git(wt, 'branch', '-M', 'main');
68
+ git(wt, 'remote', 'add', 'origin', originDir);
69
+ git(wt, 'push', '-q', '-u', 'origin', 'main');
70
+ });
71
+ afterAll(() => {
72
+ rmSync(tmp, { recursive: true, force: true });
73
+ if (OLD_HOME === undefined)
74
+ delete process.env.HOME;
75
+ else
76
+ process.env.HOME = OLD_HOME;
77
+ });
78
+ beforeEach(() => {
79
+ home = mkdtempSync(join(tmpdir(), 'mx-gencap-home-'));
80
+ process.env.HOME = home;
81
+ startupReport._reset();
82
+ });
83
+ describe('startup report captures config-generation lines (real generator, real origin)', () => {
84
+ it('generates .claude/ from source and records the generation lines in the durable JSONL', () => {
85
+ startupReport.setContext({ project: 'proj', team: 'genteam', worktree: 'genwt' });
86
+ startupReport.installConsoleCapture();
87
+ // The real start-path config step: fetch origin, then run the generator
88
+ // subprocess against origin/main. No mocks — this spawns node on the actual
89
+ // scripts/generate-claude.mjs.
90
+ syncClaudeConfig(wt, { baseBranch: 'main', configSource: CONFIG_SOURCE });
91
+ startupReport.finalize('ok');
92
+ // The generator actually materialized .claude/ from source.
93
+ expect(existsSync(join(wt, '.claude', 'settings.json')), '.claude/ was not generated').toBe(true);
94
+ // The durable JSONL captured the generation lines.
95
+ const file = join(home, '.mx-agent', 'logs', 'startup', 'genwt.jsonl');
96
+ const lines = readFileSync(file, 'utf-8').trim().split('\n');
97
+ expect(lines).toHaveLength(1);
98
+ const report = JSON.parse(lines[0]);
99
+ expect(report.outcome).toBe('ok');
100
+ const messages = report.entries.map((e) => e.message).join('\n');
101
+ // syncClaudeConfig's generation lines (the start path's config step).
102
+ expect(messages).toContain('Syncing agent config');
103
+ expect(messages).toContain('Agent config generated from');
104
+ });
105
+ it('records a generator FAILURE warning (incl. generator stderr) when a valid backstop exists', () => {
106
+ // Prove generator WARNINGS also reach the JSONL: force generation to fail by
107
+ // pointing at a missing branch, with a valid existing .claude/ backstop so the
108
+ // path warn-and-continues (no hard stop) and the warning — which carries the
109
+ // generator's stderr — is recorded.
110
+ const claudeDir = join(wt, '.claude');
111
+ mkdirSync(claudeDir, { recursive: true });
112
+ writeFileSync(join(claudeDir, 'settings.json'), JSON.stringify({
113
+ permissions: { deny: ['Edit(.claude/settings.json)', 'Edit(.claude/hooks/**)'] },
114
+ }) + '\n');
115
+ startupReport.setContext({ project: 'proj', team: 'genteam', worktree: 'genwt2' });
116
+ startupReport.installConsoleCapture();
117
+ // baseBranch that does not exist in origin → git fetch fails → warn-and-continue
118
+ // on the valid backstop (hard stop only fires without a usable backstop).
119
+ syncClaudeConfig(wt, { baseBranch: 'no-such-branch', configSource: CONFIG_SOURCE });
120
+ startupReport.finalize('ok');
121
+ const file = join(home, '.mx-agent', 'logs', 'startup', 'genwt2.jsonl');
122
+ const report = JSON.parse(readFileSync(file, 'utf-8').trim());
123
+ const warnings = report.entries.filter((e) => e.level === 'warning');
124
+ expect(warnings.length).toBeGreaterThan(0);
125
+ });
126
+ });
127
+ //# sourceMappingURL=start-report-generation-capture.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start-report-generation-capture.test.js","sourceRoot":"","sources":["../../src/__tests__/start-report-generation-capture.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * CWE-150 render-layer test (#4350 security review).
3
+ *
4
+ * renderStartupHealth() prints fleet-supplied fields (team, latest_outcome,
5
+ * warning messages) to the operator's terminal. Any worktree can POST crafted
6
+ * control sequences straight to the API with the shared token, so the render
7
+ * layer must strip them before printing. This asserts the rendered output
8
+ * contains none of the injected sequences.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=startup-health-render.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startup-health-render.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/startup-health-render.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * CWE-150 render-layer test (#4350 security review).
3
+ *
4
+ * renderStartupHealth() prints fleet-supplied fields (team, latest_outcome,
5
+ * warning messages) to the operator's terminal. Any worktree can POST crafted
6
+ * control sequences straight to the API with the shared token, so the render
7
+ * layer must strip them before printing. This asserts the rendered output
8
+ * contains none of the injected sequences.
9
+ */
10
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
11
+ import chalk from 'chalk';
12
+ import { renderStartupHealth } from '../commands/dashboard.js';
13
+ const ESC = String.fromCharCode(27); // \x1b
14
+ const BEL = String.fromCharCode(7); // \x07
15
+ const SCREEN_CLEAR = ESC + '[2J';
16
+ const OSC_TITLE = ESC + ']0;OWNED' + BEL;
17
+ let logged;
18
+ const origLevel = chalk.level;
19
+ beforeEach(() => {
20
+ // Disable chalk styling so the only escape sequences that could appear in the
21
+ // output are ones that leaked through from the (hostile) input fields.
22
+ chalk.level = 0;
23
+ logged = '';
24
+ vi.spyOn(console, 'log').mockImplementation((...args) => {
25
+ logged += args.map((a) => String(a)).join(' ') + '\n';
26
+ });
27
+ });
28
+ afterEach(() => {
29
+ vi.restoreAllMocks();
30
+ chalk.level = origLevel;
31
+ });
32
+ describe('renderStartupHealth — control-sequence stripping', () => {
33
+ it('renders team, outcome, and warning message with the injected sequences absent', () => {
34
+ renderStartupHealth({
35
+ window_days: 7,
36
+ generated_at: new Date().toISOString(),
37
+ teams: [
38
+ {
39
+ team: `evil${SCREEN_CLEAR}team`,
40
+ latest_outcome: `ok${OSC_TITLE}`,
41
+ latest_started_at: new Date().toISOString(),
42
+ latest_warning_count: 1,
43
+ latest_error_count: 0,
44
+ report_count: 1,
45
+ total_warning_count: 1,
46
+ total_error_count: 0,
47
+ },
48
+ ],
49
+ top_warnings: [{ message: `boom${SCREEN_CLEAR}${OSC_TITLE}bar`, count: 3 }],
50
+ });
51
+ // No ESC byte, no screen-clear, no OSC payload anywhere in the printed output.
52
+ expect(logged.includes(ESC)).toBe(false);
53
+ expect(logged.includes('[2J')).toBe(false);
54
+ expect(logged.includes('OWNED')).toBe(false);
55
+ // The benign parts of each field still render.
56
+ expect(logged).toContain('evilteam');
57
+ expect(logged).toContain('boombar');
58
+ });
59
+ });
60
+ //# sourceMappingURL=startup-health-render.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startup-health-render.test.js","sourceRoot":"","sources":["../../src/__tests__/startup-health-render.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,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO;AAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO;AAC3C,MAAM,YAAY,GAAG,GAAG,GAAG,KAAK,CAAC;AACjC,MAAM,SAAS,GAAG,GAAG,GAAG,UAAU,GAAG,GAAG,CAAC;AAEzC,IAAI,MAAc,CAAC;AACnB,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC;AAE9B,UAAU,CAAC,GAAG,EAAE;IACd,8EAA8E;IAC9E,uEAAuE;IACvE,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;IAChB,MAAM,GAAG,EAAE,CAAC;IACZ,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,CAAC,GAAG,IAAe,EAAE,EAAE;QACjE,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,EAAE,CAAC,eAAe,EAAE,CAAC;IACrB,KAAK,CAAC,KAAK,GAAG,SAAS,CAAC;AAC1B,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAChE,EAAE,CAAC,+EAA+E,EAAE,GAAG,EAAE;QACvF,mBAAmB,CAAC;YAClB,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACtC,KAAK,EAAE;gBACL;oBACE,IAAI,EAAE,OAAO,YAAY,MAAM;oBAC/B,cAAc,EAAE,KAAK,SAAS,EAAE;oBAChC,iBAAiB,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBAC3C,oBAAoB,EAAE,CAAC;oBACvB,kBAAkB,EAAE,CAAC;oBACrB,YAAY,EAAE,CAAC;oBACf,mBAAmB,EAAE,CAAC;oBACtB,iBAAiB,EAAE,CAAC;iBACrB;aACF;YACD,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,YAAY,GAAG,SAAS,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;SAC5E,CAAC,CAAC;QAEH,+EAA+E;QAC/E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE7C,+CAA+C;QAC/C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -10,7 +10,7 @@
10
10
  * - the console-capture tee records every print without altering output
11
11
  */
12
12
  import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
13
- import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, existsSync, rmSync, chmodSync } from 'fs';
13
+ import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, readdirSync, existsSync, rmSync, chmodSync } from 'fs';
14
14
  import { tmpdir } from 'os';
15
15
  import { join } from 'path';
16
16
  import { startupReport, inferLevel, stripAnsi, redactUrlCredentials } from '../lib/startup-report.js';
@@ -126,6 +126,39 @@ describe('record + finalize', () => {
126
126
  expect(raw).toHaveLength(1);
127
127
  expect(JSON.parse(raw[0]).outcome).toBe('ok');
128
128
  });
129
+ it('persists messages with terminal control sequences stripped (CWE-150)', () => {
130
+ const ESC = String.fromCharCode(27);
131
+ const BEL = String.fromCharCode(7);
132
+ startupReport.setContext({ worktree: 'ctrl-wt' });
133
+ startupReport.record('warning', `boom${ESC}[2J${ESC}]0;OWNED${BEL}bar`);
134
+ startupReport.finalize('ok');
135
+ const raw = readFileSync(logPath('ctrl-wt'), 'utf-8').trim();
136
+ // The whole persisted line must be free of ESC, screen-clear, and OSC payload.
137
+ expect(raw.includes(ESC)).toBe(false);
138
+ expect(raw.includes('[2J')).toBe(false);
139
+ expect(raw.includes('OWNED')).toBe(false);
140
+ const report = JSON.parse(raw);
141
+ expect(report.entries[0].message).toBe('boombar');
142
+ });
143
+ it('spools a copy of the report for central shipping (#4350 Phase 2)', () => {
144
+ startupReport.setContext({ worktree: 'ship-wt', team: 'shipteam' });
145
+ startupReport.record('warning', 'w');
146
+ startupReport.finalize('ok');
147
+ const spool = join(home, '.mx-agent', 'logs', 'startup', 'spool');
148
+ const files = readdirSync(spool).filter((f) => f.endsWith('.json'));
149
+ expect(files).toHaveLength(1);
150
+ const spooled = JSON.parse(readFileSync(join(spool, files[0]), 'utf-8'));
151
+ expect(spooled.worktree).toBe('ship-wt');
152
+ expect(spooled.outcome).toBe('ok');
153
+ });
154
+ it('fires the ship hook once on finalize (fire-and-forget)', () => {
155
+ const hook = vi.fn();
156
+ startupReport.setShipHook(hook);
157
+ startupReport.setContext({ worktree: 'hook-wt' });
158
+ startupReport.finalize('ok');
159
+ startupReport.finalize('error'); // idempotent — hook must not fire twice
160
+ expect(hook).toHaveBeenCalledTimes(1);
161
+ });
129
162
  it('falls back to team, then "unknown", for the file name', () => {
130
163
  startupReport.setContext({ team: 'teamx' }); // no worktree
131
164
  startupReport.record('info', 'x');
@@ -1 +1 @@
1
- {"version":3,"file":"startup-report.test.js","sourceRoot":"","sources":["../../src/__tests__/startup-report.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"startup-report.test.js","sourceRoot":"","sources":["../../src/__tests__/startup-report.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACrH,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEtG,IAAI,IAAY,CAAC;AACjB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AAElC,qFAAqF;AACrF,SAAS,OAAO,CAAC,IAAY;IAC3B,OAAO,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,QAAQ,CAAC,CAAC;AACrE,CAAC;AAED,UAAU,CAAC,GAAG,EAAE;IACd,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC;IACxD,0EAA0E;IAC1E,8EAA8E;IAC9E,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,qCAAqC;IAC9D,aAAa,CAAC,MAAM,EAAE,CAAC;AACzB,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,aAAa,CAAC,MAAM,EAAE,CAAC;IACvB,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;;QAC/C,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,QAAQ,CAAC;AACnC,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,UAAU,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACpE,MAAM,CAAC,UAAU,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjE,MAAM,CAAC,UAAU,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,UAAU,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvE,MAAM,CAAC,UAAU,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtE,MAAM,CAAC,UAAU,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACnE,MAAM,CAAC,UAAU,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjE,MAAM,CAAC,UAAU,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrD,MAAM,CAAC,UAAU,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACpF,MAAM,CAAC,UAAU,CAAC,kBAAkB,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,oBAAoB,CAAC,uDAAuD,CAAC,CAAC;aAClF,IAAI,CAAC,qCAAqC,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,oBAAoB,CAAC,iCAAiC,CAAC,CAAC;aAC5D,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,CAAC,oBAAoB,CAAC,6BAA6B,CAAC,CAAC;aACxD,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE,8DAA8D,CAAC,CAAC;QAChG,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;QAC5F,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACzC,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,mBAAmB,CAAC,CAAC;QACjE,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;QACzE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACvG,MAAM,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,aAAa,CAAC,UAAU,CAAC;YACvB,OAAO,EAAE,UAAU;YACnB,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE,eAAe;YACzB,UAAU,EAAE,OAAO;YACnB,OAAO,EAAE,WAAW;SACrB,CAAC,CAAC;QACH,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACzC,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QAC5C,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE7B,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/E,MAAM,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,OAAO,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,aAAa,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAC3C,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACrC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7B,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB;QACnD,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtE,MAAM,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnC,aAAa,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QAClD,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,WAAW,GAAG,KAAK,CAAC,CAAC;QACxE,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE7B,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7D,+EAA+E;QAC/E,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,aAAa,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QACpE,aAAa,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACrC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAClE,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACpE,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QACzE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,IAAI,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACrB,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAChC,aAAa,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QAClD,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7B,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,wCAAwC;QACzE,MAAM,CAAC,IAAI,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,aAAa,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,cAAc;QAC3D,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAClC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,aAAa,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACtC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7B,aAAa,CAAC,MAAM,EAAE,CAAC;QACvB,aAAa,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACvC,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtE,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;QACvD,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,kCAAkC;QAClC,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;QAExD,aAAa,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9C,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;QAC/C,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE7B,MAAM,CAAC,UAAU,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,gEAAgE;QAChE,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,aAAa,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAChD,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAClC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,uEAAuE;QACvE,0EAA0E;QAC1E,yEAAyE;QACzE,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvB,aAAa,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,aAAa,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACtC,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAC5D,yDAAyD;QACzD,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IACjE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,aAAa,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAE9C,wEAAwE;QACxE,oDAAoD;QACpD,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;QAEvE,aAAa,CAAC,qBAAqB,EAAE,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,aAAa;QAC1C,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,yCAAyC;QAC7D,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;QACjE,aAAa,CAAC,oBAAoB,EAAE,CAAC;QAErC,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAChD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;QAEpF,yEAAyE;QACzE,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAExC,MAAM,CAAC,WAAW,EAAE,CAAC;QACrB,MAAM,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,0EAA0E;QAC1E,2EAA2E;QAC3E,0EAA0E;QAC1E,0EAA0E;QAC1E,uCAAuC;QACvC,aAAa,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;QAClD,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAClE,MAAM,IAAI,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,IAA8C,CAAC;QACtE,IAAI,CAAC;YACH,aAAa,CAAC,qBAAqB,EAAE,CAAC;YACtC,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;YAC3D,aAAa,CAAC,oBAAoB,EAAE,CAAC;QACvC,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,eAAe,CAAC;QACzC,CAAC;QAED,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;QAC3B,aAAa,CAAC,qBAAqB,EAAE,CAAC;QACtC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,aAAa,CAAC,oBAAoB,EAAE,CAAC;QACrC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Tests for the central StartupReport shipper (platform v2.58 Phase 2, #4350).
3
+ *
4
+ * Covers the spool lifecycle and never-throw discipline:
5
+ * - spoolReport writes one file; flush POSTs and deletes on 2xx
6
+ * - POST failure (non-2xx / network) leaves the file spooled
7
+ * - no token → flush skips the POST and leaves everything spooled
8
+ * - 50-file cap drops the oldest beyond 50
9
+ * - 14-day age drop happens at spool-write time
10
+ * - spoolReport never throws under a read-only spool dir
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=startup-shipper.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startup-shipper.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/startup-shipper.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Tests for the central StartupReport shipper (platform v2.58 Phase 2, #4350).
3
+ *
4
+ * Covers the spool lifecycle and never-throw discipline:
5
+ * - spoolReport writes one file; flush POSTs and deletes on 2xx
6
+ * - POST failure (non-2xx / network) leaves the file spooled
7
+ * - no token → flush skips the POST and leaves everything spooled
8
+ * - 50-file cap drops the oldest beyond 50
9
+ * - 14-day age drop happens at spool-write time
10
+ * - spoolReport never throws under a read-only spool dir
11
+ */
12
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
13
+ import { mkdtempSync, mkdirSync, writeFileSync, readdirSync, rmSync, chmodSync, utimesSync } from 'fs';
14
+ import { tmpdir } from 'os';
15
+ import { join } from 'path';
16
+ import { spoolReport, flushSpool, spoolDir } from '../lib/startup-shipper.js';
17
+ let home;
18
+ const OLD_HOME = process.env.HOME;
19
+ function report(over = {}) {
20
+ return JSON.stringify({
21
+ schema_version: 1,
22
+ project: 'memnexus',
23
+ team: 'platform',
24
+ worktree: 'platform-wt',
25
+ machine: 'host-a',
26
+ cli_version: '2.58.0',
27
+ outcome: 'ok',
28
+ started_at: new Date().toISOString(),
29
+ entries: [{ ts: '', level: 'warning', message: 'w' }],
30
+ ...over,
31
+ });
32
+ }
33
+ function spoolFiles() {
34
+ try {
35
+ return readdirSync(spoolDir()).filter((f) => f.endsWith('.json'));
36
+ }
37
+ catch {
38
+ return [];
39
+ }
40
+ }
41
+ beforeEach(() => {
42
+ home = mkdtempSync(join(tmpdir(), 'mx-shipper-home-'));
43
+ process.env.HOME = home;
44
+ vi.unstubAllGlobals();
45
+ });
46
+ afterEach(() => {
47
+ vi.unstubAllGlobals();
48
+ // Restore perms so cleanup can remove read-only dirs created by a test.
49
+ try {
50
+ chmodSync(spoolDir(), 0o755);
51
+ }
52
+ catch { /* ignore */ }
53
+ rmSync(home, { recursive: true, force: true });
54
+ if (OLD_HOME === undefined)
55
+ delete process.env.HOME;
56
+ else
57
+ process.env.HOME = OLD_HOME;
58
+ });
59
+ describe('spoolReport', () => {
60
+ it('writes one JSON file to the spool dir', () => {
61
+ const p = spoolReport(report());
62
+ expect(p).toBeTruthy();
63
+ expect(spoolFiles().length).toBe(1);
64
+ });
65
+ it('never throws under a read-only spool dir (returns null)', () => {
66
+ mkdirSync(spoolDir(), { recursive: true });
67
+ chmodSync(spoolDir(), 0o500); // read+execute, no write
68
+ let result = 'sentinel';
69
+ expect(() => { result = spoolReport(report()); }).not.toThrow();
70
+ // On most CI the write fails and returns null; if the platform ignores the
71
+ // mode (e.g. running as root), it may still succeed — either is acceptable
72
+ // as long as it did not throw.
73
+ expect(result === null || typeof result === 'string').toBe(true);
74
+ });
75
+ it('drops files older than 14 days at write time', () => {
76
+ mkdirSync(spoolDir(), { recursive: true });
77
+ const stale = join(spoolDir(), 'stale.json');
78
+ writeFileSync(stale, report());
79
+ const old = Date.now() / 1000 - 15 * 24 * 60 * 60; // 15 days ago
80
+ utimesSync(stale, old, old);
81
+ spoolReport(report()); // triggers the age sweep
82
+ const files = spoolFiles();
83
+ expect(files).not.toContain('stale.json');
84
+ expect(files.length).toBe(1); // only the freshly-written report remains
85
+ });
86
+ });
87
+ describe('flushSpool — POST lifecycle', () => {
88
+ it('POSTs each spooled report and deletes it on 2xx', async () => {
89
+ spoolReport(report());
90
+ spoolReport(report({ worktree: 'wt2' }));
91
+ expect(spoolFiles().length).toBe(2);
92
+ const fetchMock = vi.fn(() => Promise.resolve(new Response(JSON.stringify({ stored: 1 }), { status: 201 })));
93
+ vi.stubGlobal('fetch', fetchMock);
94
+ const res = await flushSpool({ apiUrl: 'http://obs.test', apiToken: 'tok' });
95
+ expect(fetchMock).toHaveBeenCalledTimes(2);
96
+ expect(res.shipped).toBe(2);
97
+ expect(res.remaining).toBe(0);
98
+ expect(spoolFiles().length).toBe(0);
99
+ });
100
+ it('leaves the file spooled when the POST is not 2xx', async () => {
101
+ spoolReport(report());
102
+ vi.stubGlobal('fetch', vi.fn(() => Promise.resolve(new Response('nope', { status: 500 }))));
103
+ const res = await flushSpool({ apiUrl: 'http://obs.test', apiToken: 'tok' });
104
+ expect(res.shipped).toBe(0);
105
+ expect(spoolFiles().length).toBe(1);
106
+ });
107
+ it('leaves the file spooled when the POST rejects (network error)', async () => {
108
+ spoolReport(report());
109
+ vi.stubGlobal('fetch', vi.fn(() => Promise.reject(new Error('ECONNREFUSED'))));
110
+ const res = await flushSpool({ apiUrl: 'http://obs.test', apiToken: 'tok' });
111
+ expect(res.shipped).toBe(0);
112
+ expect(spoolFiles().length).toBe(1);
113
+ });
114
+ it('skips the POST entirely when no token is configured', async () => {
115
+ spoolReport(report());
116
+ const fetchMock = vi.fn(() => Promise.resolve(new Response('', { status: 201 })));
117
+ vi.stubGlobal('fetch', fetchMock);
118
+ const res = await flushSpool({ apiUrl: 'http://obs.test', apiToken: undefined });
119
+ expect(fetchMock).not.toHaveBeenCalled();
120
+ expect(res.shipped).toBe(0);
121
+ expect(res.remaining).toBe(1);
122
+ expect(spoolFiles().length).toBe(1);
123
+ });
124
+ });
125
+ describe('flushSpool — 50-file cap', () => {
126
+ it('drops the oldest files beyond 50 before shipping', async () => {
127
+ mkdirSync(spoolDir(), { recursive: true });
128
+ // Write 55 files with strictly increasing mtimes so "oldest" is deterministic.
129
+ for (let i = 0; i < 55; i++) {
130
+ const p = join(spoolDir(), `f${String(i).padStart(3, '0')}.json`);
131
+ writeFileSync(p, report({ worktree: `wt${i}` }));
132
+ const t = Date.now() / 1000 - (55 - i) * 60; // older files first
133
+ utimesSync(p, t, t);
134
+ }
135
+ expect(spoolFiles().length).toBe(55);
136
+ const logs = [];
137
+ vi.stubGlobal('fetch', vi.fn(() => Promise.resolve(new Response('', { status: 201 }))));
138
+ const res = await flushSpool({
139
+ apiUrl: 'http://obs.test',
140
+ apiToken: 'tok',
141
+ log: (m) => logs.push(m),
142
+ });
143
+ // 5 oldest dropped, 50 shipped (and deleted on 2xx) → none remain.
144
+ expect(res.shipped).toBe(50);
145
+ expect(spoolFiles().length).toBe(0);
146
+ expect(logs.some((m) => m.includes('exceeded 50'))).toBe(true);
147
+ });
148
+ });
149
+ //# sourceMappingURL=startup-shipper.test.js.map