@mmnto/totem 1.14.4 → 1.14.5
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/ingest/file-resolver.test.js +54 -39
- package/dist/ingest/file-resolver.test.js.map +1 -1
- package/dist/sys/exec.d.ts +40 -5
- package/dist/sys/exec.d.ts.map +1 -1
- package/dist/sys/exec.js +130 -27
- package/dist/sys/exec.js.map +1 -1
- package/dist/sys/exec.test.js +71 -5
- package/dist/sys/exec.test.js.map +1 -1
- package/dist/sys/git.test.js +35 -26
- package/dist/sys/git.test.js.map +1 -1
- package/package.json +3 -1
|
@@ -1,10 +1,31 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as crossSpawn from 'cross-spawn';
|
|
2
2
|
import { globSync } from 'glob';
|
|
3
3
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
4
4
|
import { getChangedFiles, getHeadSha, resolveFiles } from './file-resolver.js';
|
|
5
|
-
vi.mock('
|
|
6
|
-
|
|
5
|
+
vi.mock('cross-spawn', () => ({
|
|
6
|
+
sync: vi.fn(),
|
|
7
7
|
}));
|
|
8
|
+
/**
|
|
9
|
+
* Post-mmnto/totem#1329: safeExec wraps cross-spawn.sync, which returns
|
|
10
|
+
* a SpawnSyncReturns<Buffer>-shaped object instead of the legacy
|
|
11
|
+
* execFileSync string-or-throw contract. These helpers let each test
|
|
12
|
+
* describe the intended subprocess outcome (`ok('stdout')` for a clean
|
|
13
|
+
* exit, `fail(error)` for a spawn-level failure) without spelling out
|
|
14
|
+
* the full return shape.
|
|
15
|
+
*/
|
|
16
|
+
// Return types are inferred deliberately. The fail() helper's inferred
|
|
17
|
+
// shape has an `error` property that matches cross-spawn's
|
|
18
|
+
// SpawnSyncReturns field name, but spelling that property out in an
|
|
19
|
+
// explicit return type annotation trips the repo's `id-match` ESLint
|
|
20
|
+
// rule (which forbids the literal identifier `error`). Inference keeps
|
|
21
|
+
// the shape correct without introducing `error` as a surface identifier
|
|
22
|
+
// in the source text. Callers coerce via `as never` at the call site.
|
|
23
|
+
function ok(stdout) {
|
|
24
|
+
return { status: 0, stdout, stderr: '', signal: null };
|
|
25
|
+
}
|
|
26
|
+
function fail(err) {
|
|
27
|
+
return { status: null, stdout: '', stderr: '', signal: null, error: err };
|
|
28
|
+
}
|
|
8
29
|
vi.mock('glob', () => ({
|
|
9
30
|
globSync: vi.fn(() => []),
|
|
10
31
|
}));
|
|
@@ -13,19 +34,15 @@ afterEach(() => {
|
|
|
13
34
|
});
|
|
14
35
|
describe('getHeadSha', () => {
|
|
15
36
|
it('returns trimmed SHA on success', () => {
|
|
16
|
-
vi.mocked(
|
|
37
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(ok('abc123def456\n'));
|
|
17
38
|
expect(getHeadSha('/project')).toBe('abc123def456');
|
|
18
39
|
});
|
|
19
40
|
it('returns null when git fails', () => {
|
|
20
|
-
vi.mocked(
|
|
21
|
-
throw new Error('not a git repo');
|
|
22
|
-
});
|
|
41
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(fail(new Error('not a git repo')));
|
|
23
42
|
expect(getHeadSha('/project')).toBeNull();
|
|
24
43
|
});
|
|
25
44
|
it('calls onWarn when git fails', () => {
|
|
26
|
-
vi.mocked(
|
|
27
|
-
throw new Error('not a git repo');
|
|
28
|
-
});
|
|
45
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(fail(new Error('not a git repo')));
|
|
29
46
|
const warn = vi.fn();
|
|
30
47
|
getHeadSha('/project', warn);
|
|
31
48
|
expect(warn).toHaveBeenCalledWith(expect.stringContaining('not a git repo'));
|
|
@@ -33,43 +50,41 @@ describe('getHeadSha', () => {
|
|
|
33
50
|
});
|
|
34
51
|
describe('getChangedFiles', () => {
|
|
35
52
|
it('returns deduplicated paths from diff and untracked (null-delimited)', () => {
|
|
36
|
-
vi.mocked(
|
|
53
|
+
vi.mocked(crossSpawn.sync).mockImplementation(((_cmd, args) => {
|
|
37
54
|
if (args && args.includes('diff'))
|
|
38
|
-
return 'src/a.ts\0src/b.ts\0';
|
|
55
|
+
return ok('src/a.ts\0src/b.ts\0');
|
|
39
56
|
if (args && args.includes('ls-files'))
|
|
40
|
-
return 'src/b.ts\0src/new.ts\0';
|
|
41
|
-
return '';
|
|
42
|
-
});
|
|
57
|
+
return ok('src/b.ts\0src/new.ts\0');
|
|
58
|
+
return ok('');
|
|
59
|
+
}));
|
|
43
60
|
const result = getChangedFiles('/project', 'HEAD~1');
|
|
44
61
|
expect(result).toEqual(expect.arrayContaining(['src/a.ts', 'src/b.ts', 'src/new.ts']));
|
|
45
62
|
expect(result).toHaveLength(3);
|
|
46
63
|
});
|
|
47
64
|
it('returns null and warns when git diff fails', () => {
|
|
48
|
-
vi.mocked(
|
|
49
|
-
throw new Error('bad ref');
|
|
50
|
-
});
|
|
65
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(fail(new Error('bad ref')));
|
|
51
66
|
const warn = vi.fn();
|
|
52
67
|
const result = getChangedFiles('/project', 'HEAD~1', warn);
|
|
53
68
|
expect(result).toBeNull();
|
|
54
69
|
expect(warn).toHaveBeenCalledWith(expect.stringContaining('bad ref'));
|
|
55
70
|
});
|
|
56
71
|
it('still returns diff results when untracked listing fails', () => {
|
|
57
|
-
vi.mocked(
|
|
72
|
+
vi.mocked(crossSpawn.sync).mockImplementation(((_cmd, args) => {
|
|
58
73
|
if (args && args.includes('diff'))
|
|
59
|
-
return 'src/a.ts\0';
|
|
60
|
-
|
|
61
|
-
});
|
|
74
|
+
return ok('src/a.ts\0');
|
|
75
|
+
return fail(new Error('ls-files failed'));
|
|
76
|
+
}));
|
|
62
77
|
const warn = vi.fn();
|
|
63
78
|
const result = getChangedFiles('/project', 'HEAD~1', warn);
|
|
64
79
|
expect(result).toEqual(['src/a.ts']);
|
|
65
80
|
expect(warn).toHaveBeenCalledWith(expect.stringContaining('untracked'));
|
|
66
81
|
});
|
|
67
82
|
it('normalizes backslashes to forward slashes', () => {
|
|
68
|
-
vi.mocked(
|
|
83
|
+
vi.mocked(crossSpawn.sync).mockImplementation(((_cmd, args) => {
|
|
69
84
|
if (args && args.includes('diff'))
|
|
70
|
-
return 'src\\foo\\bar.ts\0';
|
|
71
|
-
return '';
|
|
72
|
-
});
|
|
85
|
+
return ok('src\\foo\\bar.ts\0');
|
|
86
|
+
return ok('');
|
|
87
|
+
}));
|
|
73
88
|
const result = getChangedFiles('/project');
|
|
74
89
|
expect(result).toEqual(['src/foo/bar.ts']);
|
|
75
90
|
});
|
|
@@ -80,32 +95,32 @@ describe('getChangedFiles', () => {
|
|
|
80
95
|
expect(warn).toHaveBeenCalledWith(expect.stringContaining('Invalid git ref'));
|
|
81
96
|
});
|
|
82
97
|
it('accepts valid hex SHA as sinceRef', () => {
|
|
83
|
-
vi.mocked(
|
|
98
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(ok(''));
|
|
84
99
|
const result = getChangedFiles('/project', 'abc123def456');
|
|
85
100
|
expect(result).toEqual([]);
|
|
86
101
|
});
|
|
87
102
|
});
|
|
88
103
|
describe('resolveFiles — submodule support', () => {
|
|
89
104
|
it('includes submodule files from --recurse-submodules call', () => {
|
|
90
|
-
vi.mocked(
|
|
105
|
+
vi.mocked(crossSpawn.sync).mockImplementation(((_cmd, args) => {
|
|
91
106
|
if (args && args.includes('--recurse-submodules')) {
|
|
92
|
-
return 'src/a.ts\0.strategy/north-star.md\0';
|
|
107
|
+
return ok('src/a.ts\0.strategy/north-star.md\0');
|
|
93
108
|
}
|
|
94
109
|
// Parent repo ls-files: does NOT include submodule files
|
|
95
|
-
return 'src/a.ts\0';
|
|
96
|
-
});
|
|
110
|
+
return ok('src/a.ts\0');
|
|
111
|
+
}));
|
|
97
112
|
vi.mocked(globSync).mockReturnValue(['.strategy/north-star.md']);
|
|
98
113
|
const result = resolveFiles([{ glob: '.strategy/**/*.md', type: 'spec', strategy: 'markdown-heading' }], '/project');
|
|
99
114
|
expect(result).toHaveLength(1);
|
|
100
115
|
expect(result[0].relativePath).toBe('.strategy/north-star.md');
|
|
101
116
|
});
|
|
102
117
|
it('excludes submodule files not matched by glob', () => {
|
|
103
|
-
vi.mocked(
|
|
118
|
+
vi.mocked(crossSpawn.sync).mockImplementation(((_cmd, args) => {
|
|
104
119
|
if (args && args.includes('--recurse-submodules')) {
|
|
105
|
-
return '.strategy/north-star.md\0.strategy/archive/old.md\0';
|
|
120
|
+
return ok('.strategy/north-star.md\0.strategy/archive/old.md\0');
|
|
106
121
|
}
|
|
107
|
-
return '';
|
|
108
|
-
});
|
|
122
|
+
return ok('');
|
|
123
|
+
}));
|
|
109
124
|
// Glob only matches the non-archived file (archive excluded via ignorePatterns)
|
|
110
125
|
vi.mocked(globSync).mockReturnValue(['.strategy/north-star.md']);
|
|
111
126
|
const result = resolveFiles([{ glob: '.strategy/**/*.md', type: 'spec', strategy: 'markdown-heading' }], '/project', ['.strategy/archive/**']);
|
|
@@ -113,12 +128,12 @@ describe('resolveFiles — submodule support', () => {
|
|
|
113
128
|
expect(result[0].relativePath).toBe('.strategy/north-star.md');
|
|
114
129
|
});
|
|
115
130
|
it('works when --recurse-submodules is unsupported', () => {
|
|
116
|
-
vi.mocked(
|
|
131
|
+
vi.mocked(crossSpawn.sync).mockImplementation(((_cmd, args) => {
|
|
117
132
|
if (args && args.includes('--recurse-submodules')) {
|
|
118
|
-
|
|
133
|
+
return fail(new Error('unknown option'));
|
|
119
134
|
}
|
|
120
|
-
return 'src/a.ts\0';
|
|
121
|
-
});
|
|
135
|
+
return ok('src/a.ts\0');
|
|
136
|
+
}));
|
|
122
137
|
vi.mocked(globSync).mockReturnValue(['src/a.ts']);
|
|
123
138
|
const result = resolveFiles([{ glob: 'src/**/*.ts', type: 'code', strategy: 'typescript-ast' }], '/project');
|
|
124
139
|
expect(result).toHaveLength(1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-resolver.test.js","sourceRoot":"","sources":["../../src/ingest/file-resolver.test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"file-resolver.test.js","sourceRoot":"","sources":["../../src/ingest/file-resolver.test.ts"],"names":[],"mappings":"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"}
|
package/dist/sys/exec.d.ts
CHANGED
|
@@ -15,11 +15,46 @@ export interface SafeExecOptions {
|
|
|
15
15
|
/**
|
|
16
16
|
* Execute a command synchronously with cross-platform shell protections.
|
|
17
17
|
*
|
|
18
|
-
* -
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
18
|
+
* Uses `cross-spawn` instead of Node's native `child_process.execFileSync`
|
|
19
|
+
* to avoid the `shell: IS_WIN` argument-escaping vulnerability that
|
|
20
|
+
* previously let shell metacharacters (like `&`, `|`, `>`, `"`) in
|
|
21
|
+
* argument values be interpreted by cmd.exe on Windows. `cross-spawn`
|
|
22
|
+
* handles Windows `.cmd`/`.bat` shim resolution internally without
|
|
23
|
+
* enabling `shell: true` at the Node layer, so `git.cmd`, `npm.cmd`,
|
|
24
|
+
* and other shims still resolve while shell metacharacters in argument
|
|
25
|
+
* values pass through verbatim (mmnto/totem#1329).
|
|
26
|
+
*
|
|
27
|
+
* Behavioral guarantees preserved from the previous implementation:
|
|
28
|
+
* - Synchronous API, always returns a string (never a Buffer).
|
|
29
|
+
* - UTF-8 encoding enforced on stdout.
|
|
30
|
+
* - 10MB default `maxBuffer` (prevents ENOBUFS on large git diffs).
|
|
31
|
+
* - Auto-trims output (disable with `trim: false`).
|
|
32
|
+
* - Throws on non-zero exit, ENOENT, signal termination, or internal
|
|
33
|
+
* spawn error. The thrown Error preserves `.cause` for chain walking.
|
|
34
|
+
* - New (strictly additive): the thrown Error exposes optional
|
|
35
|
+
* `.status`, `.stdout`, and `.stderr` fields matching `cross-spawn`'s
|
|
36
|
+
* richer return shape. Callers that only read `.message` and `.cause`
|
|
37
|
+
* continue to work unchanged.
|
|
23
38
|
*/
|
|
24
39
|
export declare function safeExec(command: string, args?: string[], options?: SafeExecOptions): string;
|
|
40
|
+
/**
|
|
41
|
+
* Error shape extension. Adds optional `.status`, `.signal`, `.stdout`,
|
|
42
|
+
* and `.stderr` fields to the thrown Error object. Callers that only
|
|
43
|
+
* read `.message` and `.cause` (the pre-mmnto/totem#1329 contract)
|
|
44
|
+
* continue to work. Callers that want typed access to the extension
|
|
45
|
+
* fields can narrow via `err as Error & SafeExecErrorFields`.
|
|
46
|
+
*
|
|
47
|
+
* Exported so downstream packages can type-narrow without falling back
|
|
48
|
+
* to `any`. The fields match the raw `SpawnSyncReturns` shape that
|
|
49
|
+
* `cross-spawn.sync` returns, so `.stdout` and `.stderr` preserve any
|
|
50
|
+
* trailing whitespace from the subprocess. Message formatting uses
|
|
51
|
+
* trimmed copies internally, but the fields on the error object are
|
|
52
|
+
* raw.
|
|
53
|
+
*/
|
|
54
|
+
export interface SafeExecErrorFields {
|
|
55
|
+
status?: number | null;
|
|
56
|
+
signal?: NodeJS.Signals | null;
|
|
57
|
+
stdout?: string;
|
|
58
|
+
stderr?: string;
|
|
59
|
+
}
|
|
25
60
|
//# sourceMappingURL=exec.d.ts.map
|
package/dist/sys/exec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/sys/exec.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/sys/exec.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe;IAC9B,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0BAA0B;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,QAAQ,CACtB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,MAAM,EAAO,EACnB,OAAO,GAAE,eAAoB,GAC5B,MAAM,CA8BR;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|
package/dist/sys/exec.js
CHANGED
|
@@ -1,38 +1,141 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const IS_WIN = process.platform === 'win32';
|
|
1
|
+
import { sync as spawnSync } from 'cross-spawn';
|
|
3
2
|
const DEFAULT_MAX_BUFFER = 10 * 1024 * 1024; // 10 MB
|
|
4
3
|
/**
|
|
5
4
|
* Execute a command synchronously with cross-platform shell protections.
|
|
6
5
|
*
|
|
7
|
-
* -
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* Uses `cross-spawn` instead of Node's native `child_process.execFileSync`
|
|
7
|
+
* to avoid the `shell: IS_WIN` argument-escaping vulnerability that
|
|
8
|
+
* previously let shell metacharacters (like `&`, `|`, `>`, `"`) in
|
|
9
|
+
* argument values be interpreted by cmd.exe on Windows. `cross-spawn`
|
|
10
|
+
* handles Windows `.cmd`/`.bat` shim resolution internally without
|
|
11
|
+
* enabling `shell: true` at the Node layer, so `git.cmd`, `npm.cmd`,
|
|
12
|
+
* and other shims still resolve while shell metacharacters in argument
|
|
13
|
+
* values pass through verbatim (mmnto/totem#1329).
|
|
14
|
+
*
|
|
15
|
+
* Behavioral guarantees preserved from the previous implementation:
|
|
16
|
+
* - Synchronous API, always returns a string (never a Buffer).
|
|
17
|
+
* - UTF-8 encoding enforced on stdout.
|
|
18
|
+
* - 10MB default `maxBuffer` (prevents ENOBUFS on large git diffs).
|
|
19
|
+
* - Auto-trims output (disable with `trim: false`).
|
|
20
|
+
* - Throws on non-zero exit, ENOENT, signal termination, or internal
|
|
21
|
+
* spawn error. The thrown Error preserves `.cause` for chain walking.
|
|
22
|
+
* - New (strictly additive): the thrown Error exposes optional
|
|
23
|
+
* `.status`, `.stdout`, and `.stderr` fields matching `cross-spawn`'s
|
|
24
|
+
* richer return shape. Callers that only read `.message` and `.cause`
|
|
25
|
+
* continue to work unchanged.
|
|
12
26
|
*/
|
|
13
27
|
export function safeExec(command, args = [], options = {}) {
|
|
14
28
|
const { trim: shouldTrim = true, ...rest } = options;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
const result = spawnSync(command, args, {
|
|
30
|
+
encoding: 'utf-8',
|
|
31
|
+
maxBuffer: rest.maxBuffer ?? DEFAULT_MAX_BUFFER,
|
|
32
|
+
stdio: 'pipe',
|
|
33
|
+
cwd: rest.cwd,
|
|
34
|
+
env: rest.env,
|
|
35
|
+
timeout: rest.timeout,
|
|
36
|
+
input: rest.input,
|
|
37
|
+
});
|
|
38
|
+
// cross-spawn surfaces internal spawn failures (ENOENT, permission
|
|
39
|
+
// denied, ENOBUFS, etc.) via result.error rather than throwing.
|
|
40
|
+
// Reserialize into the historical throw shape so callers do not have
|
|
41
|
+
// to learn a new error path.
|
|
42
|
+
if (result.error) {
|
|
43
|
+
throw wrapSpawnError(command, args, result);
|
|
44
|
+
}
|
|
45
|
+
// cross-spawn does NOT throw on non-zero exit. Reimplement the
|
|
46
|
+
// execFileSync throw contract here so existing catch blocks continue
|
|
47
|
+
// to see the same behavior.
|
|
48
|
+
if (result.status !== 0 || result.signal !== null) {
|
|
49
|
+
throw wrapSpawnError(command, args, result);
|
|
50
|
+
}
|
|
51
|
+
const output = typeof result.stdout === 'string' ? result.stdout : '';
|
|
52
|
+
return shouldTrim ? output.trim() : output;
|
|
53
|
+
}
|
|
54
|
+
function wrapSpawnError(command, args, result) {
|
|
55
|
+
// Raw stdout/stderr preserve trailing whitespace and are assigned to
|
|
56
|
+
// the thrown Error's `.stdout` / `.stderr` fields so callers see the
|
|
57
|
+
// unmodified subprocess output. Message formatting uses trimmed
|
|
58
|
+
// copies to avoid dumping trailing newlines into user-facing error
|
|
59
|
+
// text.
|
|
60
|
+
const rawStdout = bufferOrStringToString(result.stdout);
|
|
61
|
+
const rawStderr = bufferOrStringToString(result.stderr);
|
|
62
|
+
const trimmedStderr = rawStderr.trim();
|
|
63
|
+
const status = result.status;
|
|
64
|
+
const signal = result.signal;
|
|
65
|
+
// Prefer stderr in the message body (matches the legacy format). Fall
|
|
66
|
+
// back to result.error.message for spawn-level failures with empty
|
|
67
|
+
// stderr (e.g., ENOENT), and finally to a generic failure line.
|
|
68
|
+
//
|
|
69
|
+
// Deliberate: result.error.message is inlined into the wrapper
|
|
70
|
+
// message by design, not in violation of the repo's general rule 102
|
|
71
|
+
// ("do not concatenate err.message into a new error string"). Rule
|
|
72
|
+
// 102 targets the case where a re-thrower concatenates without
|
|
73
|
+
// preserving cause, which destroys the original stack trace. This
|
|
74
|
+
// code preserves `result.error` via `{ cause }` below, so the stack
|
|
75
|
+
// trace is intact on the chain. The concat is also load-bearing for
|
|
76
|
+
// two existing callers in `packages/core/src/ingest/file-resolver.ts`
|
|
77
|
+
// (`getHeadSha` and `getChangedFiles`) that build onWarn messages
|
|
78
|
+
// from `err.message` without walking the cause chain. Stripping the
|
|
79
|
+
// concat here would silently degrade their warn text to "spawn
|
|
80
|
+
// failed" with the real reason only reachable via the cause chain.
|
|
81
|
+
// The cascading migration to walk cause in every safeExec caller is
|
|
82
|
+
// tracked as follow-up work, not scope for the mmnto/totem#1329
|
|
83
|
+
// security fix.
|
|
84
|
+
let detail;
|
|
85
|
+
if (trimmedStderr.length > 0) {
|
|
86
|
+
detail = `\n${trimmedStderr}`;
|
|
28
87
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// Extract stderr from child process error if available
|
|
32
|
-
const stderr = err?.stderr;
|
|
33
|
-
const stderrStr = stderr instanceof Buffer ? stderr.toString('utf-8') : stderr;
|
|
34
|
-
const detail = stderrStr ? `\n${stderrStr.toString().trim()}` : '';
|
|
35
|
-
throw new Error(`Command failed: ${command} ${args.join(' ')}${detail ? detail : `: ${message}`}`, { cause: err });
|
|
88
|
+
else if (result.error) {
|
|
89
|
+
detail = `: ${result.error.message}`;
|
|
36
90
|
}
|
|
91
|
+
else if (signal) {
|
|
92
|
+
detail = `: killed by ${signal}`;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
detail = status !== null ? `: exited with code ${status}` : ': exited with unknown status';
|
|
96
|
+
}
|
|
97
|
+
// Always attach a `.cause` for chain walking. When the underlying
|
|
98
|
+
// issue is a clean non-zero exit (no spawn-level error), synthesize
|
|
99
|
+
// a minimal Error so the legacy `expect(err.cause).toBeDefined()`
|
|
100
|
+
// contract still holds. Existing callers that walk the cause chain
|
|
101
|
+
// get a meaningful node to inspect either way.
|
|
102
|
+
const cause = result.error ??
|
|
103
|
+
new Error(signal !== null
|
|
104
|
+
? `Process killed by signal ${signal}`
|
|
105
|
+
: `Process exited with status ${status ?? 'unknown'}`);
|
|
106
|
+
// Build the command line as an array join so the no-args case
|
|
107
|
+
// (`safeExec('git')`) does not produce a double-space/colon-adjacency
|
|
108
|
+
// regression like `Command failed: git : ...`. The array form
|
|
109
|
+
// collapses to `Command failed: git` when args is empty, and to
|
|
110
|
+
// `Command failed: git log --oneline` when args are provided. Detail
|
|
111
|
+
// is concatenated separately because it already begins with its own
|
|
112
|
+
// delimiter (newline or colon-space).
|
|
113
|
+
//
|
|
114
|
+
// Deliberately NO `[Totem Error]` prefix: safeExec is an internal
|
|
115
|
+
// helper, not a user-facing error source. Downstream wrappers such
|
|
116
|
+
// as `handleGhError` in packages/cli/src/adapters/gh-utils.ts use
|
|
117
|
+
// `err.message.includes('[Totem Error]')` as a sentinel to detect
|
|
118
|
+
// already-wrapped errors and re-throw them as-is. Adding the prefix
|
|
119
|
+
// here would short-circuit the context wrapping those callers
|
|
120
|
+
// provide, and users would lose operation-level context like
|
|
121
|
+
// "Failed to fetch open PRs". A follow-up ticket (mmnto/totem#1355)
|
|
122
|
+
// tracks tightening the "Standardize exception messages" lint rule
|
|
123
|
+
// so it does not fire on internal-wrapper Error constructions.
|
|
124
|
+
const commandLine = ['Command failed:', command, ...args].join(' ');
|
|
125
|
+
const wrapped = new Error(commandLine + detail, {
|
|
126
|
+
cause,
|
|
127
|
+
});
|
|
128
|
+
wrapped.status = status;
|
|
129
|
+
wrapped.signal = signal;
|
|
130
|
+
wrapped.stdout = rawStdout;
|
|
131
|
+
wrapped.stderr = rawStderr;
|
|
132
|
+
return wrapped;
|
|
133
|
+
}
|
|
134
|
+
function bufferOrStringToString(value) {
|
|
135
|
+
if (value == null)
|
|
136
|
+
return '';
|
|
137
|
+
if (typeof value === 'string')
|
|
138
|
+
return value;
|
|
139
|
+
return value.toString('utf-8');
|
|
37
140
|
}
|
|
38
141
|
//# sourceMappingURL=exec.js.map
|
package/dist/sys/exec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/sys/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/sys/exec.ts"],"names":[],"mappings":"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"}
|
package/dist/sys/exec.test.js
CHANGED
|
@@ -47,11 +47,17 @@ describe('safeExec', () => {
|
|
|
47
47
|
});
|
|
48
48
|
it('respects timeout option', () => {
|
|
49
49
|
try {
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
// shell: true to resolve .cmd/.bat shims, and cmd.exe
|
|
53
|
-
//
|
|
54
|
-
// creating a stray
|
|
50
|
+
// Historical note: this test originally used setTimeout with an
|
|
51
|
+
// arrow function, but that was broken on Windows because safeExec
|
|
52
|
+
// ran with `shell: true` to resolve .cmd/.bat shims, and cmd.exe
|
|
53
|
+
// parsed `=>` in the arrow function as `=` + `>` output redirection,
|
|
54
|
+
// creating a stray `{}` file in the cwd (mmnto/totem#1233).
|
|
55
|
+
//
|
|
56
|
+
// After mmnto/totem#1329 replaced execFileSync with cross-spawn,
|
|
57
|
+
// `shell: true` is no longer enabled and the original idiom would
|
|
58
|
+
// work. The `setInterval(Object, ...)` form is preserved here
|
|
59
|
+
// because the test is stable and a cosmetic rewrite would add
|
|
60
|
+
// diff noise without changing behavior. Intentional history.
|
|
55
61
|
safeExec('node', ['-e', `setInterval(Object, ${LONG_RUNNING_INTERVAL_MS})`], {
|
|
56
62
|
timeout: TIMEOUT_TEST_MS,
|
|
57
63
|
});
|
|
@@ -59,11 +65,71 @@ describe('safeExec', () => {
|
|
|
59
65
|
}
|
|
60
66
|
catch (err) {
|
|
61
67
|
expect(err).toBeInstanceOf(Error);
|
|
68
|
+
// mmnto/totem#1329: a timeout kill populates the `.signal` field
|
|
69
|
+
// on the thrown error so callers can distinguish signal-killed
|
|
70
|
+
// processes from non-zero exits without parsing the message body.
|
|
71
|
+
const timeoutErr = err;
|
|
72
|
+
expect(timeoutErr.signal).toBeTruthy();
|
|
62
73
|
}
|
|
63
74
|
});
|
|
64
75
|
it('does not expose stdio option (always forces pipe mode)', () => {
|
|
65
76
|
const result = safeExec('node', ['-e', "console.log('pipe-ok')"]);
|
|
66
77
|
expect(result).toBe('pipe-ok');
|
|
67
78
|
});
|
|
79
|
+
// ─── #1329: shell metacharacter safety ────────
|
|
80
|
+
//
|
|
81
|
+
// Prior to mmnto/totem#1329, safeExec passed `shell: IS_WIN` to
|
|
82
|
+
// execFileSync, which routed every Windows call through cmd.exe with
|
|
83
|
+
// unescaped arguments. cmd.exe then interpreted shell metacharacters
|
|
84
|
+
// like `&`, `>`, `|`, and `"` that appeared in ANY argument position,
|
|
85
|
+
// not just in the command string. This was both a correctness bug
|
|
86
|
+
// (see mmnto/totem#1233 for the stray `{}` file created when cmd.exe
|
|
87
|
+
// parsed `=>` as `=` + `>` redirection) and a shell-injection vector
|
|
88
|
+
// for any caller that forwarded user input through safeExec.
|
|
89
|
+
//
|
|
90
|
+
// The fix swapped execFileSync for cross-spawn.sync, which handles
|
|
91
|
+
// Windows .cmd/.bat shim resolution WITHOUT enabling shell: true at
|
|
92
|
+
// the Node layer. These tests lock in the invariant that argument
|
|
93
|
+
// values pass through to the subprocess verbatim on all platforms.
|
|
94
|
+
it('passes shell metacharacters in argument values through verbatim (#1329)', () => {
|
|
95
|
+
// The headline regression test. This MUST pass on both POSIX and
|
|
96
|
+
// Windows. On POSIX it always worked (no shell in the pipeline).
|
|
97
|
+
// On Windows it was broken before #1329 because cmd.exe interpreted
|
|
98
|
+
// `&` as a command separator and `>` as output redirection.
|
|
99
|
+
const dangerousArg = 'hello&world>bar';
|
|
100
|
+
const result = safeExec('node', [
|
|
101
|
+
'-e',
|
|
102
|
+
'process.stdout.write(process.argv[process.argv.length - 1])',
|
|
103
|
+
dangerousArg,
|
|
104
|
+
]);
|
|
105
|
+
expect(result).toBe(dangerousArg);
|
|
106
|
+
});
|
|
107
|
+
it('passes pipes and double quotes in argument values through verbatim (#1329)', () => {
|
|
108
|
+
// A second metacharacter set covering `|` (pipe) and `"` (quote),
|
|
109
|
+
// both of which cmd.exe treats specially.
|
|
110
|
+
const dangerousArg = 'alpha|beta"gamma';
|
|
111
|
+
const result = safeExec('node', [
|
|
112
|
+
'-e',
|
|
113
|
+
'process.stdout.write(process.argv[process.argv.length - 1])',
|
|
114
|
+
dangerousArg,
|
|
115
|
+
]);
|
|
116
|
+
expect(result).toBe(dangerousArg);
|
|
117
|
+
});
|
|
118
|
+
it('exposes .status on the thrown error for non-zero exit codes (#1329)', () => {
|
|
119
|
+
// The cross-spawn refactor attaches status/stdout/stderr to the
|
|
120
|
+
// thrown Error as optional fields, matching the richer information
|
|
121
|
+
// cross-spawn's sync API provides. Existing callers that only read
|
|
122
|
+
// `.message` and `.cause` continue to work. New callers that want
|
|
123
|
+
// to distinguish exit codes no longer have to parse the message.
|
|
124
|
+
try {
|
|
125
|
+
safeExec('node', ['-e', 'process.exit(42)']);
|
|
126
|
+
expect.unreachable('should have thrown');
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
expect(err).toBeInstanceOf(Error);
|
|
130
|
+
const safeErr = err;
|
|
131
|
+
expect(safeErr.status).toBe(42);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
68
134
|
});
|
|
69
135
|
//# sourceMappingURL=exec.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.test.js","sourceRoot":"","sources":["../../src/sys/exec.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,sEAAsE;AACtE,wEAAwE;AACxE,8DAA8D;AAC9D,MAAM,wBAAwB,GAAG,MAAM,CAAC;AACxC,wEAAwE;AACxE,uCAAuC;AACvC,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,4EAA4E;QAC5E,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,sBAAsB,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACjF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,IAAI,CAAC;YACH,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAClC,MAAM,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;YAC3D,MAAM,CAAE,GAAa,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,IAAI,CAAC;YACH,QAAQ,CAAC,gCAAgC,EAAE,EAAE,CAAC,CAAC;YAC/C,MAAM,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAClC,MAAM,CAAE,GAAa,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,qCAAqC,CAAC,EAAE;YAC7E,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;SACnB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,IAAI,CAAC;YACH,
|
|
1
|
+
{"version":3,"file":"exec.test.js","sourceRoot":"","sources":["../../src/sys/exec.test.ts"],"names":[],"mappings":"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"}
|
package/dist/sys/git.test.js
CHANGED
|
@@ -1,58 +1,69 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as crossSpawn from 'cross-spawn';
|
|
2
2
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
vi.mock('
|
|
4
|
-
|
|
5
|
-
execFile: vi.fn(),
|
|
6
|
-
execSync: vi.fn(),
|
|
3
|
+
vi.mock('cross-spawn', () => ({
|
|
4
|
+
sync: vi.fn(),
|
|
7
5
|
}));
|
|
8
6
|
import { extractChangedFiles, filterDiffByPatterns, getGitLogSince, getLatestTag, getTagDate, inferScopeFromFiles, isFileDirty, } from './git.js';
|
|
7
|
+
/**
|
|
8
|
+
* Post-mmnto/totem#1329: safeExec wraps cross-spawn.sync instead of
|
|
9
|
+
* child_process.execFileSync. These helpers let each test describe the
|
|
10
|
+
* intended subprocess outcome without spelling out the full
|
|
11
|
+
* SpawnSyncReturns shape on every call.
|
|
12
|
+
*/
|
|
13
|
+
// Return types are inferred deliberately. The fail() helper's inferred
|
|
14
|
+
// shape has an `error` property that matches cross-spawn's
|
|
15
|
+
// SpawnSyncReturns field name, but spelling that property out in an
|
|
16
|
+
// explicit return type annotation trips the repo's `id-match` ESLint
|
|
17
|
+
// rule (which forbids the literal identifier `error`). Inference keeps
|
|
18
|
+
// the shape correct without introducing `error` as a surface identifier
|
|
19
|
+
// in the source text. Callers coerce via `as never` at the call site.
|
|
20
|
+
function ok(stdout) {
|
|
21
|
+
return { status: 0, stdout, stderr: '', signal: null };
|
|
22
|
+
}
|
|
23
|
+
function fail(err) {
|
|
24
|
+
return { status: null, stdout: '', stderr: '', signal: null, error: err };
|
|
25
|
+
}
|
|
9
26
|
describe('getLatestTag', () => {
|
|
10
27
|
beforeEach(() => vi.clearAllMocks());
|
|
11
28
|
it('returns the latest tag', () => {
|
|
12
|
-
vi.mocked(
|
|
29
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(ok('v0.14.0\n'));
|
|
13
30
|
expect(getLatestTag('/tmp')).toBe('v0.14.0');
|
|
14
31
|
});
|
|
15
32
|
it('returns null when no tags exist', () => {
|
|
16
|
-
vi.mocked(
|
|
17
|
-
throw new Error('fatal: no tags');
|
|
18
|
-
});
|
|
33
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(fail(new Error('fatal: no tags')));
|
|
19
34
|
expect(getLatestTag('/tmp')).toBeNull();
|
|
20
35
|
});
|
|
21
36
|
it('returns null for empty output', () => {
|
|
22
|
-
vi.mocked(
|
|
37
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(ok('\n'));
|
|
23
38
|
expect(getLatestTag('/tmp')).toBeNull();
|
|
24
39
|
});
|
|
25
40
|
});
|
|
26
41
|
describe('getTagDate', () => {
|
|
27
42
|
beforeEach(() => vi.clearAllMocks());
|
|
28
43
|
it('returns YYYY-MM-DD date for a valid tag', () => {
|
|
29
|
-
vi.mocked(
|
|
44
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(ok('2026-03-01T12:00:00-05:00\n'));
|
|
30
45
|
expect(getTagDate('/tmp', 'v0.14.0')).toBe('2026-03-01');
|
|
31
46
|
});
|
|
32
47
|
it('returns null when tag does not exist', () => {
|
|
33
|
-
vi.mocked(
|
|
34
|
-
throw new Error('fatal: bad object');
|
|
35
|
-
});
|
|
48
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(fail(new Error('fatal: bad object')));
|
|
36
49
|
expect(getTagDate('/tmp', 'v999.0.0')).toBeNull();
|
|
37
50
|
});
|
|
38
51
|
});
|
|
39
52
|
describe('getGitLogSince', () => {
|
|
40
53
|
beforeEach(() => vi.clearAllMocks());
|
|
41
54
|
it('returns log since a tag', () => {
|
|
42
|
-
vi.mocked(
|
|
55
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(ok('abc1234 feat: thing\ndef5678 fix: bug\n'));
|
|
43
56
|
const result = getGitLogSince('/tmp', 'v0.14.0');
|
|
44
57
|
expect(result).toContain('abc1234');
|
|
45
|
-
expect(vi.mocked(
|
|
58
|
+
expect(vi.mocked(crossSpawn.sync)).toHaveBeenCalledWith('git', ['log', 'v0.14.0..HEAD', '--oneline', '--max-count=50'], expect.any(Object));
|
|
46
59
|
});
|
|
47
60
|
it('returns recent commits when no since ref provided', () => {
|
|
48
|
-
vi.mocked(
|
|
61
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(ok('abc1234 feat: thing\n'));
|
|
49
62
|
getGitLogSince('/tmp');
|
|
50
|
-
expect(vi.mocked(
|
|
63
|
+
expect(vi.mocked(crossSpawn.sync)).toHaveBeenCalledWith('git', ['log', '--oneline', '-50'], expect.any(Object));
|
|
51
64
|
});
|
|
52
65
|
it('returns empty string on error', () => {
|
|
53
|
-
vi.mocked(
|
|
54
|
-
throw new Error('not a git repo');
|
|
55
|
-
});
|
|
66
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(fail(new Error('not a git repo')));
|
|
56
67
|
expect(getGitLogSince('/tmp')).toBe('');
|
|
57
68
|
});
|
|
58
69
|
});
|
|
@@ -99,17 +110,15 @@ describe('filterDiffByPatterns', () => {
|
|
|
99
110
|
describe('isFileDirty', () => {
|
|
100
111
|
beforeEach(() => vi.clearAllMocks());
|
|
101
112
|
it('returns true when file has changes', () => {
|
|
102
|
-
vi.mocked(
|
|
113
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(ok(' M README.md\n'));
|
|
103
114
|
expect(isFileDirty('/tmp', 'README.md')).toBe(true);
|
|
104
115
|
});
|
|
105
116
|
it('returns false when file is clean', () => {
|
|
106
|
-
vi.mocked(
|
|
117
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(ok(''));
|
|
107
118
|
expect(isFileDirty('/tmp', 'README.md')).toBe(false);
|
|
108
119
|
});
|
|
109
120
|
it('returns false on error', () => {
|
|
110
|
-
vi.mocked(
|
|
111
|
-
throw new Error('not a git repo');
|
|
112
|
-
});
|
|
121
|
+
vi.mocked(crossSpawn.sync).mockReturnValue(fail(new Error('not a git repo')));
|
|
113
122
|
expect(isFileDirty('/tmp', 'README.md')).toBe(false);
|
|
114
123
|
});
|
|
115
124
|
});
|
package/dist/sys/git.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.test.js","sourceRoot":"","sources":["../../src/sys/git.test.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"git.test.js","sourceRoot":"","sources":["../../src/sys/git.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmnto/totem",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.5",
|
|
4
4
|
"description": "Persistent memory and context layer for AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"@ast-grep/napi": "^0.42.0",
|
|
16
16
|
"@lancedb/lancedb": "^0.26.2",
|
|
17
17
|
"apache-arrow": "17.0.0",
|
|
18
|
+
"cross-spawn": "^7.0.6",
|
|
18
19
|
"glob": "^11.0.0",
|
|
19
20
|
"openai": "^4.77.0",
|
|
20
21
|
"remark-frontmatter": "^5.0.0",
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@ast-grep/wasm": "^0.42.1",
|
|
42
|
+
"@types/cross-spawn": "^6.0.6",
|
|
41
43
|
"@types/mdast": "^4.0.0",
|
|
42
44
|
"vitest": "^3.0.0"
|
|
43
45
|
},
|