@mmnto/totem 1.5.6 → 1.5.8
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/ast-gate.js +2 -2
- package/dist/ast-gate.js.map +1 -1
- package/dist/ast-gate.test.js +2 -1
- package/dist/ast-gate.test.js.map +1 -1
- package/dist/ast-query.d.ts +1 -1
- package/dist/ast-query.d.ts.map +1 -1
- package/dist/ast-query.js +12 -2
- package/dist/ast-query.js.map +1 -1
- package/dist/ast-query.test.js +2 -1
- package/dist/ast-query.test.js.map +1 -1
- package/dist/compile-lesson.d.ts +8 -0
- package/dist/compile-lesson.d.ts.map +1 -1
- package/dist/compile-lesson.js +63 -2
- package/dist/compile-lesson.js.map +1 -1
- package/dist/compile-lesson.test.js +187 -1
- package/dist/compile-lesson.test.js.map +1 -1
- package/dist/compile-manifest.d.ts.map +1 -1
- package/dist/compile-manifest.js +18 -21
- package/dist/compile-manifest.js.map +1 -1
- package/dist/compile-manifest.test.js +5 -4
- package/dist/compile-manifest.test.js.map +1 -1
- package/dist/compiler.d.ts +1 -1
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +1 -1
- package/dist/compiler.js.map +1 -1
- package/dist/compiler.test.js +2 -1
- package/dist/compiler.test.js.map +1 -1
- package/dist/cursor-adapter.test.js +2 -1
- package/dist/cursor-adapter.test.js.map +1 -1
- package/dist/drift-detector.test.js +2 -1
- package/dist/drift-detector.test.js.map +1 -1
- package/dist/embedders/embedder.test.js +25 -3
- package/dist/embedders/embedder.test.js.map +1 -1
- package/dist/errors.d.ts +7 -7
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +15 -15
- package/dist/errors.js.map +1 -1
- package/dist/errors.test.d.ts +2 -0
- package/dist/errors.test.d.ts.map +1 -0
- package/dist/errors.test.js +28 -0
- package/dist/errors.test.js.map +1 -0
- package/dist/exporter.test.js +2 -1
- package/dist/exporter.test.js.map +1 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/dist/ingest/file-resolver.d.ts.map +1 -1
- package/dist/ingest/file-resolver.js +8 -19
- package/dist/ingest/file-resolver.js.map +1 -1
- package/dist/ingest/pipeline.test.js +2 -1
- package/dist/ingest/pipeline.test.js.map +1 -1
- package/dist/ledger.d.ts +1 -1
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +1 -1
- package/dist/ledger.js.map +1 -1
- package/dist/ledger.test.js +2 -1
- package/dist/ledger.test.js.map +1 -1
- package/dist/lesson-io.test.js +5 -4
- package/dist/lesson-io.test.js.map +1 -1
- package/dist/lesson-linter.d.ts.map +1 -1
- package/dist/lesson-linter.js +35 -3
- package/dist/lesson-linter.js.map +1 -1
- package/dist/lesson-linter.test.js +46 -0
- package/dist/lesson-linter.test.js.map +1 -1
- package/dist/lesson-pattern.d.ts +16 -0
- package/dist/lesson-pattern.d.ts.map +1 -1
- package/dist/lesson-pattern.js +24 -0
- package/dist/lesson-pattern.js.map +1 -1
- package/dist/lesson-pattern.test.js +48 -1
- package/dist/lesson-pattern.test.js.map +1 -1
- package/dist/lock.test.js +2 -1
- package/dist/lock.test.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +13 -19
- package/dist/registry.js.map +1 -1
- package/dist/registry.test.js +3 -2
- package/dist/registry.test.js.map +1 -1
- package/dist/rule-engine.d.ts +8 -0
- package/dist/rule-engine.d.ts.map +1 -1
- package/dist/rule-engine.js +57 -14
- package/dist/rule-engine.js.map +1 -1
- package/dist/rule-engine.test.js +83 -4
- package/dist/rule-engine.test.js.map +1 -1
- package/dist/rule-metrics.test.js +2 -1
- package/dist/rule-metrics.test.js.map +1 -1
- package/dist/secrets.test.js +2 -1
- package/dist/secrets.test.js.map +1 -1
- package/dist/store/lance-schema.d.ts +2 -2
- package/dist/store/lance-store.test.js +2 -1
- package/dist/store/lance-store.test.js.map +1 -1
- package/dist/sys/exec.d.ts +25 -0
- package/dist/sys/exec.d.ts.map +1 -0
- package/dist/sys/exec.js +38 -0
- package/dist/sys/exec.js.map +1 -0
- package/dist/sys/exec.test.d.ts +2 -0
- package/dist/sys/exec.test.d.ts.map +1 -0
- package/dist/sys/exec.test.js +55 -0
- package/dist/sys/exec.test.js.map +1 -0
- package/dist/sys/fs.d.ts +8 -0
- package/dist/sys/fs.d.ts.map +1 -0
- package/dist/sys/fs.js +35 -0
- package/dist/sys/fs.js.map +1 -0
- package/dist/sys/fs.test.d.ts +2 -0
- package/dist/sys/fs.test.d.ts.map +1 -0
- package/dist/sys/fs.test.js +72 -0
- package/dist/sys/fs.test.js.map +1 -0
- package/dist/sys/git.d.ts +42 -0
- package/dist/sys/git.d.ts.map +1 -0
- package/dist/sys/git.js +235 -0
- package/dist/sys/git.js.map +1 -0
- package/dist/sys/git.test.d.ts +2 -0
- package/dist/sys/git.test.d.ts.map +1 -0
- package/dist/sys/git.test.js +134 -0
- package/dist/sys/git.test.js.map +1 -0
- package/dist/test-utils.d.ts +6 -0
- package/dist/test-utils.d.ts.map +1 -0
- package/dist/test-utils.js +11 -0
- package/dist/test-utils.js.map +1 -0
- package/dist/test-utils.test.d.ts +2 -0
- package/dist/test-utils.test.d.ts.map +1 -0
- package/dist/test-utils.test.js +43 -0
- package/dist/test-utils.test.js.map +1 -0
- package/package.json +1 -1
package/dist/sys/exec.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
const IS_WIN = process.platform === 'win32';
|
|
3
|
+
const DEFAULT_MAX_BUFFER = 10 * 1024 * 1024; // 10 MB
|
|
4
|
+
/**
|
|
5
|
+
* Execute a command synchronously with cross-platform shell protections.
|
|
6
|
+
*
|
|
7
|
+
* - Windows: automatically sets `shell: true` to resolve .cmd/.bat executables
|
|
8
|
+
* - UTF-8 encoding enforced (always returns string, never Buffer)
|
|
9
|
+
* - 10MB maxBuffer default (prevents ENOBUFS on large git diffs)
|
|
10
|
+
* - Auto-trims output (disable with `trim: false`)
|
|
11
|
+
* - Error cause chains preserved (ES2022)
|
|
12
|
+
*/
|
|
13
|
+
export function safeExec(command, args = [], options = {}) {
|
|
14
|
+
const { trim: shouldTrim = true, ...rest } = options;
|
|
15
|
+
try {
|
|
16
|
+
const result = execFileSync(command, args, {
|
|
17
|
+
encoding: 'utf-8',
|
|
18
|
+
shell: IS_WIN,
|
|
19
|
+
maxBuffer: rest.maxBuffer ?? DEFAULT_MAX_BUFFER,
|
|
20
|
+
stdio: 'pipe',
|
|
21
|
+
cwd: rest.cwd,
|
|
22
|
+
env: rest.env,
|
|
23
|
+
timeout: rest.timeout,
|
|
24
|
+
input: rest.input,
|
|
25
|
+
});
|
|
26
|
+
const output = typeof result === 'string' ? result : '';
|
|
27
|
+
return shouldTrim ? output.trim() : output;
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
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 });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=exec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/sys/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;AAC5C,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ;AAiBrD;;;;;;;;GAQG;AACH,MAAM,UAAU,QAAQ,CACtB,OAAe,EACf,OAAiB,EAAE,EACnB,UAA2B,EAAE;IAE7B,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAErD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE;YACzC,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,MAAM;YACb,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,kBAAkB;YAC/C,KAAK,EAAE,MAAM;YACb,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,OAAO,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,uDAAuD;QACvD,MAAM,MAAM,GAAI,GAAoC,EAAE,MAAM,CAAC;QAC7D,MAAM,SAAS,GAAG,MAAM,YAAY,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC/E,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAEnE,MAAM,IAAI,KAAK,CACb,mBAAmB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,EAAE,EACjF,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.test.d.ts","sourceRoot":"","sources":["../../src/sys/exec.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { safeExec } from './exec.js';
|
|
3
|
+
describe('safeExec', () => {
|
|
4
|
+
it('executes a command and returns trimmed output', () => {
|
|
5
|
+
// Use single quotes inside the JS expression — cmd.exe strips double quotes
|
|
6
|
+
const result = safeExec('node', ['-e', "console.log('hello')"]);
|
|
7
|
+
expect(result).toBe('hello');
|
|
8
|
+
});
|
|
9
|
+
it('preserves trailing whitespace when trim is false', () => {
|
|
10
|
+
const result = safeExec('node', ['-e', "console.log('hello')"], { trim: false });
|
|
11
|
+
expect(result).toContain('hello');
|
|
12
|
+
expect(result.length).toBeGreaterThan('hello'.length);
|
|
13
|
+
});
|
|
14
|
+
it('throws with cause on non-zero exit', () => {
|
|
15
|
+
try {
|
|
16
|
+
safeExec('node', ['-e', 'process.exit(1)']);
|
|
17
|
+
expect.unreachable('should have thrown');
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
expect(err).toBeInstanceOf(Error);
|
|
21
|
+
expect(err.message).toContain('Command failed');
|
|
22
|
+
expect(err.cause).toBeDefined();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
it('throws with cause on command not found', () => {
|
|
26
|
+
try {
|
|
27
|
+
safeExec('totem-nonexistent-binary-12345', []);
|
|
28
|
+
expect.unreachable('should have thrown');
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
expect(err).toBeInstanceOf(Error);
|
|
32
|
+
expect(err.cause).toBeDefined();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
it('respects cwd option', () => {
|
|
36
|
+
const result = safeExec('node', ['-e', 'process.stdout.write(process.cwd())'], {
|
|
37
|
+
cwd: process.cwd(),
|
|
38
|
+
});
|
|
39
|
+
expect(result).toBeTruthy();
|
|
40
|
+
});
|
|
41
|
+
it('respects timeout option', () => {
|
|
42
|
+
try {
|
|
43
|
+
safeExec('node', ['-e', 'setTimeout(() => {}, 30000)'], { timeout: 100 });
|
|
44
|
+
expect.unreachable('should have thrown');
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
expect(err).toBeInstanceOf(Error);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
it('does not expose stdio option (always forces pipe mode)', () => {
|
|
51
|
+
const result = safeExec('node', ['-e', "console.log('pipe-ok')"]);
|
|
52
|
+
expect(result).toBe('pipe-ok');
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=exec.test.js.map
|
|
@@ -0,0 +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,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,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,6BAA6B,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;YAC1E,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;QACpC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,wBAAwB,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/sys/fs.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ZodSchema } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Read and parse a JSON file with optional Zod validation.
|
|
4
|
+
* Differentiates ENOENT, SyntaxError, and schema validation failures.
|
|
5
|
+
* All errors thrown as TotemParseError with ES2022 cause chains.
|
|
6
|
+
*/
|
|
7
|
+
export declare function readJsonSafe<T = unknown>(filePath: string, schema?: ZodSchema<T>): T;
|
|
8
|
+
//# sourceMappingURL=fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/sys/fs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAIrC;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CA2CpF"}
|
package/dist/sys/fs.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import { TotemParseError } from '../errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Read and parse a JSON file with optional Zod validation.
|
|
5
|
+
* Differentiates ENOENT, SyntaxError, and schema validation failures.
|
|
6
|
+
* All errors thrown as TotemParseError with ES2022 cause chains.
|
|
7
|
+
*/
|
|
8
|
+
export function readJsonSafe(filePath, schema) {
|
|
9
|
+
let raw;
|
|
10
|
+
try {
|
|
11
|
+
raw = fs.readFileSync(filePath, 'utf-8');
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
if (err.code === 'ENOENT') {
|
|
15
|
+
throw new TotemParseError(`File not found: ${filePath}`, `Check that ${filePath} exists.`, err);
|
|
16
|
+
}
|
|
17
|
+
throw new TotemParseError(`Cannot read file: ${filePath}`, `Check file permissions for ${filePath}.`, err);
|
|
18
|
+
}
|
|
19
|
+
let parsed;
|
|
20
|
+
try {
|
|
21
|
+
parsed = JSON.parse(raw);
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
throw new TotemParseError(`Invalid JSON in ${filePath}`, 'The file contains malformed JSON. Check for syntax errors.', err);
|
|
25
|
+
}
|
|
26
|
+
if (!schema)
|
|
27
|
+
return parsed;
|
|
28
|
+
const result = schema.safeParse(parsed);
|
|
29
|
+
if (!result.success) {
|
|
30
|
+
const issues = result.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join('; ');
|
|
31
|
+
throw new TotemParseError(`Schema validation failed for ${filePath}: ${issues}`, 'The file structure does not match the expected schema.', result.error);
|
|
32
|
+
}
|
|
33
|
+
return result.data;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/sys/fs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAI9B,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAc,QAAgB,EAAE,MAAqB;IAC/E,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,IAAI,eAAe,CACvB,mBAAmB,QAAQ,EAAE,EAC7B,cAAc,QAAQ,UAAU,EAChC,GAAG,CACJ,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,eAAe,CACvB,qBAAqB,QAAQ,EAAE,EAC/B,8BAA8B,QAAQ,GAAG,EACzC,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,eAAe,CACvB,mBAAmB,QAAQ,EAAE,EAC7B,4DAA4D,EAC5D,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM;QAAE,OAAO,MAAW,CAAC;IAEhC,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9F,MAAM,IAAI,eAAe,CACvB,gCAAgC,QAAQ,KAAK,MAAM,EAAE,EACrD,wDAAwD,EACxD,MAAM,CAAC,KAAK,CACb,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.test.d.ts","sourceRoot":"","sources":["../../src/sys/fs.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { TotemParseError } from '../errors.js';
|
|
7
|
+
import { cleanTmpDir } from '../test-utils.js';
|
|
8
|
+
import { readJsonSafe } from './fs.js';
|
|
9
|
+
describe('readJsonSafe', () => {
|
|
10
|
+
let tmpDir;
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-fs-'));
|
|
13
|
+
});
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
cleanTmpDir(tmpDir);
|
|
16
|
+
});
|
|
17
|
+
it('reads and parses valid JSON without schema', () => {
|
|
18
|
+
const filePath = path.join(tmpDir, 'data.json');
|
|
19
|
+
fs.writeFileSync(filePath, '{"key": "value"}');
|
|
20
|
+
const result = readJsonSafe(filePath);
|
|
21
|
+
expect(result).toEqual({ key: 'value' });
|
|
22
|
+
});
|
|
23
|
+
it('reads and validates with Zod schema', () => {
|
|
24
|
+
const filePath = path.join(tmpDir, 'data.json');
|
|
25
|
+
fs.writeFileSync(filePath, '{"name": "totem", "version": 1}');
|
|
26
|
+
const schema = z.object({ name: z.string(), version: z.number() });
|
|
27
|
+
const result = readJsonSafe(filePath, schema);
|
|
28
|
+
expect(result).toEqual({ name: 'totem', version: 1 });
|
|
29
|
+
});
|
|
30
|
+
it('throws TotemParseError on ENOENT', () => {
|
|
31
|
+
expect(() => readJsonSafe(path.join(tmpDir, 'missing.json'))).toThrow(TotemParseError);
|
|
32
|
+
try {
|
|
33
|
+
readJsonSafe(path.join(tmpDir, 'missing.json'));
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
expect(err.message).toContain('File not found');
|
|
37
|
+
expect(err.cause).toBeDefined();
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
it('throws TotemParseError on invalid JSON', () => {
|
|
41
|
+
const filePath = path.join(tmpDir, 'bad.json');
|
|
42
|
+
fs.writeFileSync(filePath, '{invalid json!!!}');
|
|
43
|
+
expect(() => readJsonSafe(filePath)).toThrow(TotemParseError);
|
|
44
|
+
try {
|
|
45
|
+
readJsonSafe(filePath);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
expect(err.message).toContain('Invalid JSON');
|
|
49
|
+
expect(err.cause).toBeDefined();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
it('throws TotemParseError on empty file', () => {
|
|
53
|
+
const filePath = path.join(tmpDir, 'empty.json');
|
|
54
|
+
fs.writeFileSync(filePath, '');
|
|
55
|
+
expect(() => readJsonSafe(filePath)).toThrow(TotemParseError);
|
|
56
|
+
});
|
|
57
|
+
it('throws TotemParseError with detailed paths on schema mismatch', () => {
|
|
58
|
+
const filePath = path.join(tmpDir, 'data.json');
|
|
59
|
+
fs.writeFileSync(filePath, '{"name": 123}');
|
|
60
|
+
const schema = z.object({ name: z.string() });
|
|
61
|
+
try {
|
|
62
|
+
readJsonSafe(filePath, schema);
|
|
63
|
+
expect.unreachable('should have thrown');
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
expect(err).toBeInstanceOf(TotemParseError);
|
|
67
|
+
expect(err.message).toContain('Schema validation failed');
|
|
68
|
+
expect(err.message).toContain('name');
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=fs.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.test.js","sourceRoot":"","sources":["../../src/sys/fs.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export declare function getGitBranch(cwd: string): string;
|
|
2
|
+
export declare function getGitStatus(cwd: string): string;
|
|
3
|
+
export declare function getGitDiff(mode: 'staged' | 'all', cwd: string): string;
|
|
4
|
+
export declare function getGitDiffStat(cwd: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Detect the default branch of the remote (e.g. main, master).
|
|
7
|
+
* Falls back to 'main' if detection fails.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getDefaultBranch(cwd: string): string;
|
|
10
|
+
export declare function getGitBranchDiff(cwd: string, base?: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Get the author date of a tag in YYYY-MM-DD format.
|
|
13
|
+
* Returns null if tag doesn't exist or lookup fails.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getTagDate(cwd: string, tag: string): string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Get the most recent semver tag (e.g., "v0.14.0").
|
|
18
|
+
* Returns null if no tags exist.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getLatestTag(cwd: string): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Get git log since a ref (tag or commit), or last N commits as fallback.
|
|
23
|
+
* Returns one-line-per-commit format: "hash subject".
|
|
24
|
+
*/
|
|
25
|
+
export declare function getGitLogSince(cwd: string, since?: string, maxCommits?: number): string;
|
|
26
|
+
/**
|
|
27
|
+
* Check if a specific file has uncommitted changes (staged or unstaged).
|
|
28
|
+
*/
|
|
29
|
+
export declare function isFileDirty(cwd: string, filePath: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve the git repository root from any subdirectory.
|
|
32
|
+
* Returns the normalized absolute path, or null if not in a git repo.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveGitRoot(cwd: string): string | null;
|
|
35
|
+
/**
|
|
36
|
+
* Filter a unified diff to exclude files matching ignore patterns.
|
|
37
|
+
* Splits on `diff --git` boundaries and removes sections for ignored files.
|
|
38
|
+
* Uses matchesGlob from core for consistent glob behavior.
|
|
39
|
+
*/
|
|
40
|
+
export declare function filterDiffByPatterns(diff: string, patterns: string[]): string;
|
|
41
|
+
export declare function extractChangedFiles(diff: string): string[];
|
|
42
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/sys/git.ts"],"names":[],"mappings":"AAwBA,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAiBtE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASlD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA+BpD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CA0BnE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUlE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWvD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,UAAU,SAAK,GAAG,MAAM,CAYnF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAUlE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWzD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAe7E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAgB1D"}
|
package/dist/sys/git.js
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import { matchesGlob } from '../compiler.js';
|
|
3
|
+
import { TotemGitError } from '../errors.js';
|
|
4
|
+
import { safeExec } from './exec.js';
|
|
5
|
+
// ─── Constants ──────────────────────────────────────────
|
|
6
|
+
const GIT_COMMAND_TIMEOUT_MS = 15_000;
|
|
7
|
+
const GIT_DIFF_MAX_BUFFER = 10 * 1024 * 1024; // 10MB — large diffs (e.g., compiled-rules.json)
|
|
8
|
+
function throwIfGitMissing(err) {
|
|
9
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10
|
+
if (msg.includes('ENOENT') || msg.includes('not found')) {
|
|
11
|
+
throw new TotemGitError("'git' command not found.", 'Ensure Git is installed and in your PATH.', err);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
// ─── Git helpers ────────────────────────────────────────
|
|
15
|
+
export function getGitBranch(cwd) {
|
|
16
|
+
try {
|
|
17
|
+
return safeExec('git', ['branch', '--show-current'], { cwd });
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return '(unknown)';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function getGitStatus(cwd) {
|
|
24
|
+
try {
|
|
25
|
+
return safeExec('git', ['status', '--porcelain'], { cwd });
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return '';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function getGitDiff(mode, cwd) {
|
|
32
|
+
const args = mode === 'staged' ? ['diff', '--staged'] : ['diff', 'HEAD'];
|
|
33
|
+
try {
|
|
34
|
+
return safeExec('git', args, {
|
|
35
|
+
cwd,
|
|
36
|
+
timeout: GIT_COMMAND_TIMEOUT_MS,
|
|
37
|
+
maxBuffer: GIT_DIFF_MAX_BUFFER,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
throwIfGitMissing(err);
|
|
42
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
43
|
+
throw new TotemGitError(`Failed to get git diff: ${msg}`, 'Check that you are inside a Git repository with at least one commit.', err);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function getGitDiffStat(cwd) {
|
|
47
|
+
try {
|
|
48
|
+
return safeExec('git', ['diff', 'HEAD', '--stat'], {
|
|
49
|
+
cwd,
|
|
50
|
+
timeout: GIT_COMMAND_TIMEOUT_MS,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Detect the default branch of the remote (e.g. main, master).
|
|
59
|
+
* Falls back to 'main' if detection fails.
|
|
60
|
+
*/
|
|
61
|
+
export function getDefaultBranch(cwd) {
|
|
62
|
+
try {
|
|
63
|
+
const ref = safeExec('git', ['symbolic-ref', 'refs/remotes/origin/HEAD', '--short'], {
|
|
64
|
+
cwd,
|
|
65
|
+
timeout: GIT_COMMAND_TIMEOUT_MS,
|
|
66
|
+
});
|
|
67
|
+
// ref is like "origin/main" — strip the remote prefix
|
|
68
|
+
return ref.replace(/^origin\//, '');
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
throwIfGitMissing(err);
|
|
72
|
+
// Fallback: check local then remote refs for 'main' / 'master'
|
|
73
|
+
for (const branch of ['main', 'master']) {
|
|
74
|
+
for (const ref of [branch, `origin/${branch}`]) {
|
|
75
|
+
try {
|
|
76
|
+
safeExec('git', ['rev-parse', '--verify', ref], {
|
|
77
|
+
cwd,
|
|
78
|
+
timeout: GIT_COMMAND_TIMEOUT_MS,
|
|
79
|
+
});
|
|
80
|
+
return branch;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Try next candidate
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
throw new TotemGitError("Could not determine default branch. Neither 'main' nor 'master' found locally, and 'git symbolic-ref' failed.", "Run 'git remote set-head origin --auto' to configure the default branch, or pass --base explicitly.", err);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export function getGitBranchDiff(cwd, base) {
|
|
91
|
+
const baseBranch = base ?? getDefaultBranch(cwd);
|
|
92
|
+
// Try local ref first, then remote — CI may only have origin/<branch>
|
|
93
|
+
const refs = [baseBranch, `origin/${baseBranch}`];
|
|
94
|
+
for (const ref of refs) {
|
|
95
|
+
try {
|
|
96
|
+
return safeExec('git', ['diff', `${ref}...HEAD`], {
|
|
97
|
+
cwd,
|
|
98
|
+
timeout: GIT_COMMAND_TIMEOUT_MS,
|
|
99
|
+
maxBuffer: GIT_DIFF_MAX_BUFFER,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
throwIfGitMissing(err);
|
|
104
|
+
// If this was the last ref, throw
|
|
105
|
+
if (ref === refs[refs.length - 1]) {
|
|
106
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
107
|
+
throw new TotemGitError(`Failed to get branch diff (${baseBranch}...HEAD): ${msg}`, `Ensure the base branch '${baseBranch}' exists locally or as a remote ref. Try 'git fetch origin ${baseBranch}'.`, err);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Unreachable — loop always returns or throws
|
|
112
|
+
return '';
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get the author date of a tag in YYYY-MM-DD format.
|
|
116
|
+
* Returns null if tag doesn't exist or lookup fails.
|
|
117
|
+
*/
|
|
118
|
+
export function getTagDate(cwd, tag) {
|
|
119
|
+
try {
|
|
120
|
+
const date = safeExec('git', ['log', '-1', '--format=%aI', tag], {
|
|
121
|
+
cwd,
|
|
122
|
+
timeout: GIT_COMMAND_TIMEOUT_MS,
|
|
123
|
+
});
|
|
124
|
+
return date.slice(0, 10) || null;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get the most recent semver tag (e.g., "v0.14.0").
|
|
132
|
+
* Returns null if no tags exist.
|
|
133
|
+
*/
|
|
134
|
+
export function getLatestTag(cwd) {
|
|
135
|
+
try {
|
|
136
|
+
return (safeExec('git', ['describe', '--tags', '--abbrev=0'], {
|
|
137
|
+
cwd,
|
|
138
|
+
timeout: GIT_COMMAND_TIMEOUT_MS,
|
|
139
|
+
}) || null);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Get git log since a ref (tag or commit), or last N commits as fallback.
|
|
147
|
+
* Returns one-line-per-commit format: "hash subject".
|
|
148
|
+
*/
|
|
149
|
+
export function getGitLogSince(cwd, since, maxCommits = 50) {
|
|
150
|
+
const args = since
|
|
151
|
+
? ['log', `${since}..HEAD`, '--oneline', `--max-count=${maxCommits}`]
|
|
152
|
+
: ['log', '--oneline', `-${maxCommits}`];
|
|
153
|
+
try {
|
|
154
|
+
return safeExec('git', args, {
|
|
155
|
+
cwd,
|
|
156
|
+
timeout: GIT_COMMAND_TIMEOUT_MS,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return '';
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Check if a specific file has uncommitted changes (staged or unstaged).
|
|
165
|
+
*/
|
|
166
|
+
export function isFileDirty(cwd, filePath) {
|
|
167
|
+
try {
|
|
168
|
+
const output = safeExec('git', ['status', '--porcelain', '--', filePath], {
|
|
169
|
+
cwd,
|
|
170
|
+
timeout: GIT_COMMAND_TIMEOUT_MS,
|
|
171
|
+
});
|
|
172
|
+
return output.length > 0;
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Resolve the git repository root from any subdirectory.
|
|
180
|
+
* Returns the normalized absolute path, or null if not in a git repo.
|
|
181
|
+
*/
|
|
182
|
+
export function resolveGitRoot(cwd) {
|
|
183
|
+
try {
|
|
184
|
+
const root = safeExec('git', ['rev-parse', '--show-toplevel'], {
|
|
185
|
+
cwd,
|
|
186
|
+
timeout: GIT_COMMAND_TIMEOUT_MS,
|
|
187
|
+
});
|
|
188
|
+
// git returns forward slashes even on Windows — normalize for fs operations
|
|
189
|
+
return path.normalize(root);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Filter a unified diff to exclude files matching ignore patterns.
|
|
197
|
+
* Splits on `diff --git` boundaries and removes sections for ignored files.
|
|
198
|
+
* Uses matchesGlob from core for consistent glob behavior.
|
|
199
|
+
*/
|
|
200
|
+
export function filterDiffByPatterns(diff, patterns) {
|
|
201
|
+
if (patterns.length === 0)
|
|
202
|
+
return diff;
|
|
203
|
+
const sections = diff.split(/^(?=diff --git )/m);
|
|
204
|
+
return sections
|
|
205
|
+
.filter((section) => {
|
|
206
|
+
// Extract destination path (b/) — handles renames correctly
|
|
207
|
+
const firstLine = section.substring(0, section.indexOf('\n'));
|
|
208
|
+
const quoted = firstLine.match(/^diff --git "a\/.*?" "b\/(.*?)"$/);
|
|
209
|
+
const unquoted = firstLine.match(/^diff --git a\/\S+ b\/(.+)$/);
|
|
210
|
+
const filePath = quoted?.[1] ?? unquoted?.[1];
|
|
211
|
+
if (!filePath)
|
|
212
|
+
return true;
|
|
213
|
+
return !patterns.some((p) => matchesGlob(filePath, p));
|
|
214
|
+
})
|
|
215
|
+
.join(''); // totem-ignore (#669) — joining diff sections, not text fragments
|
|
216
|
+
}
|
|
217
|
+
export function extractChangedFiles(diff) {
|
|
218
|
+
const files = [];
|
|
219
|
+
for (const line of diff.split('\n')) {
|
|
220
|
+
if (line.startsWith('diff --git')) {
|
|
221
|
+
// Handle quoted paths (spaces): diff --git "a/my file.ts" "b/my file.ts"
|
|
222
|
+
const quoted = line.match(/^diff --git "a\/.+" "b\/(.+)"$/); // totem-ignore — single line match, not iterating
|
|
223
|
+
if (quoted) {
|
|
224
|
+
files.push(quoted[1]);
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
// Standard unquoted paths: diff --git a/file.ts b/file.ts
|
|
228
|
+
const unquoted = line.match(/^diff --git a\/.+ b\/(.+)$/); // totem-ignore — single line match
|
|
229
|
+
if (unquoted)
|
|
230
|
+
files.push(unquoted[1]);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return files;
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/sys/git.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.test.d.ts","sourceRoot":"","sources":["../../src/sys/git.test.ts"],"names":[],"mappings":""}
|