yuurei 0.0.1
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/LICENSE +21 -0
- package/README.md +231 -0
- package/dist/artifact/collector.d.ts +15 -0
- package/dist/artifact/collector.d.ts.map +1 -0
- package/dist/artifact/collector.js +87 -0
- package/dist/artifact/collector.js.map +1 -0
- package/dist/artifact/types.d.ts +10 -0
- package/dist/artifact/types.d.ts.map +1 -0
- package/dist/artifact/types.js +2 -0
- package/dist/artifact/types.js.map +1 -0
- package/dist/cell/digest.d.ts +10 -0
- package/dist/cell/digest.d.ts.map +1 -0
- package/dist/cell/digest.js +13 -0
- package/dist/cell/digest.js.map +1 -0
- package/dist/cell/resolver.d.ts +18 -0
- package/dist/cell/resolver.d.ts.map +1 -0
- package/dist/cell/resolver.js +41 -0
- package/dist/cell/resolver.js.map +1 -0
- package/dist/cell/types.d.ts +48 -0
- package/dist/cell/types.d.ts.map +1 -0
- package/dist/cell/types.js +2 -0
- package/dist/cell/types.js.map +1 -0
- package/dist/cli/clean.d.ts +16 -0
- package/dist/cli/clean.d.ts.map +1 -0
- package/dist/cli/clean.js +24 -0
- package/dist/cli/clean.js.map +1 -0
- package/dist/cli/doctor.d.ts +29 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +160 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/exit-codes.d.ts +15 -0
- package/dist/cli/exit-codes.d.ts.map +1 -0
- package/dist/cli/exit-codes.js +18 -0
- package/dist/cli/exit-codes.js.map +1 -0
- package/dist/cli/init.d.ts +32 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +143 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/inspect.d.ts +4 -0
- package/dist/cli/inspect.d.ts.map +1 -0
- package/dist/cli/inspect.js +24 -0
- package/dist/cli/inspect.js.map +1 -0
- package/dist/cli/output.d.ts +5 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +5 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/profile-list.d.ts +3 -0
- package/dist/cli/profile-list.d.ts.map +1 -0
- package/dist/cli/profile-list.js +14 -0
- package/dist/cli/profile-list.js.map +1 -0
- package/dist/cli/run.d.ts +22 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +95 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/trace-show.d.ts +3 -0
- package/dist/cli/trace-show.d.ts.map +1 -0
- package/dist/cli/trace-show.js +22 -0
- package/dist/cli/trace-show.js.map +1 -0
- package/dist/config/discovery.d.ts +3 -0
- package/dist/config/discovery.d.ts.map +1 -0
- package/dist/config/discovery.js +18 -0
- package/dist/config/discovery.js.map +1 -0
- package/dist/config/schema.d.ts +21 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +19 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/yuurei-config.d.ts +4 -0
- package/dist/config/yuurei-config.d.ts.map +1 -0
- package/dist/config/yuurei-config.js +10 -0
- package/dist/config/yuurei-config.js.map +1 -0
- package/dist/cost/noop.d.ts +7 -0
- package/dist/cost/noop.d.ts.map +1 -0
- package/dist/cost/noop.js +10 -0
- package/dist/cost/noop.js.map +1 -0
- package/dist/cost/types.d.ts +21 -0
- package/dist/cost/types.d.ts.map +1 -0
- package/dist/cost/types.js +2 -0
- package/dist/cost/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +111 -0
- package/dist/index.js.map +1 -0
- package/dist/isolation/config-root.d.ts +9 -0
- package/dist/isolation/config-root.d.ts.map +1 -0
- package/dist/isolation/config-root.js +10 -0
- package/dist/isolation/config-root.js.map +1 -0
- package/dist/isolation/env.d.ts +2 -0
- package/dist/isolation/env.d.ts.map +1 -0
- package/dist/isolation/env.js +17 -0
- package/dist/isolation/env.js.map +1 -0
- package/dist/isolation/index.d.ts +9 -0
- package/dist/isolation/index.d.ts.map +1 -0
- package/dist/isolation/index.js +21 -0
- package/dist/isolation/index.js.map +1 -0
- package/dist/isolation/level0.d.ts +20 -0
- package/dist/isolation/level0.d.ts.map +1 -0
- package/dist/isolation/level0.js +51 -0
- package/dist/isolation/level0.js.map +1 -0
- package/dist/isolation/level1.d.ts +13 -0
- package/dist/isolation/level1.d.ts.map +1 -0
- package/dist/isolation/level1.js +58 -0
- package/dist/isolation/level1.js.map +1 -0
- package/dist/isolation/tempdir.d.ts +53 -0
- package/dist/isolation/tempdir.d.ts.map +1 -0
- package/dist/isolation/tempdir.js +87 -0
- package/dist/isolation/tempdir.js.map +1 -0
- package/dist/isolation/types.d.ts +37 -0
- package/dist/isolation/types.d.ts.map +1 -0
- package/dist/isolation/types.js +2 -0
- package/dist/isolation/types.js.map +1 -0
- package/dist/profile/loader.d.ts +9 -0
- package/dist/profile/loader.d.ts.map +1 -0
- package/dist/profile/loader.js +95 -0
- package/dist/profile/loader.js.map +1 -0
- package/dist/profile/manifest.d.ts +29 -0
- package/dist/profile/manifest.d.ts.map +1 -0
- package/dist/profile/manifest.js +28 -0
- package/dist/profile/manifest.js.map +1 -0
- package/dist/profile/types.d.ts +31 -0
- package/dist/profile/types.d.ts.map +1 -0
- package/dist/profile/types.js +2 -0
- package/dist/profile/types.js.map +1 -0
- package/dist/run/id.d.ts +7 -0
- package/dist/run/id.d.ts.map +1 -0
- package/dist/run/id.js +15 -0
- package/dist/run/id.js.map +1 -0
- package/dist/run/layout.d.ts +27 -0
- package/dist/run/layout.d.ts.map +1 -0
- package/dist/run/layout.js +45 -0
- package/dist/run/layout.js.map +1 -0
- package/dist/run/pipeline.d.ts +45 -0
- package/dist/run/pipeline.d.ts.map +1 -0
- package/dist/run/pipeline.js +246 -0
- package/dist/run/pipeline.js.map +1 -0
- package/dist/run/signals.d.ts +53 -0
- package/dist/run/signals.d.ts.map +1 -0
- package/dist/run/signals.js +74 -0
- package/dist/run/signals.js.map +1 -0
- package/dist/runtime/claude-code/args.d.ts +8 -0
- package/dist/runtime/claude-code/args.d.ts.map +1 -0
- package/dist/runtime/claude-code/args.js +13 -0
- package/dist/runtime/claude-code/args.js.map +1 -0
- package/dist/runtime/claude-code/index.d.ts +11 -0
- package/dist/runtime/claude-code/index.d.ts.map +1 -0
- package/dist/runtime/claude-code/index.js +167 -0
- package/dist/runtime/claude-code/index.js.map +1 -0
- package/dist/runtime/claude-code/paths.d.ts +3 -0
- package/dist/runtime/claude-code/paths.d.ts.map +1 -0
- package/dist/runtime/claude-code/paths.js +6 -0
- package/dist/runtime/claude-code/paths.js.map +1 -0
- package/dist/runtime/codex/args.d.ts +21 -0
- package/dist/runtime/codex/args.d.ts.map +1 -0
- package/dist/runtime/codex/args.js +35 -0
- package/dist/runtime/codex/args.js.map +1 -0
- package/dist/runtime/codex/index.d.ts +13 -0
- package/dist/runtime/codex/index.d.ts.map +1 -0
- package/dist/runtime/codex/index.js +299 -0
- package/dist/runtime/codex/index.js.map +1 -0
- package/dist/runtime/codex/paths.d.ts +3 -0
- package/dist/runtime/codex/paths.d.ts.map +1 -0
- package/dist/runtime/codex/paths.js +6 -0
- package/dist/runtime/codex/paths.js.map +1 -0
- package/dist/runtime/detect.d.ts +5 -0
- package/dist/runtime/detect.d.ts.map +1 -0
- package/dist/runtime/detect.js +42 -0
- package/dist/runtime/detect.js.map +1 -0
- package/dist/runtime/exec.d.ts +24 -0
- package/dist/runtime/exec.d.ts.map +1 -0
- package/dist/runtime/exec.js +132 -0
- package/dist/runtime/exec.js.map +1 -0
- package/dist/runtime/registry.d.ts +4 -0
- package/dist/runtime/registry.d.ts.map +1 -0
- package/dist/runtime/registry.js +23 -0
- package/dist/runtime/registry.js.map +1 -0
- package/dist/runtime/reserved-paths.d.ts +22 -0
- package/dist/runtime/reserved-paths.d.ts.map +1 -0
- package/dist/runtime/reserved-paths.js +30 -0
- package/dist/runtime/reserved-paths.js.map +1 -0
- package/dist/runtime/types.d.ts +105 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/trace/reader.d.ts +4 -0
- package/dist/trace/reader.d.ts.map +1 -0
- package/dist/trace/reader.js +9 -0
- package/dist/trace/reader.js.map +1 -0
- package/dist/trace/redact.d.ts +22 -0
- package/dist/trace/redact.d.ts.map +1 -0
- package/dist/trace/redact.js +124 -0
- package/dist/trace/redact.js.map +1 -0
- package/dist/trace/schema.d.ts +49 -0
- package/dist/trace/schema.d.ts.map +1 -0
- package/dist/trace/schema.js +53 -0
- package/dist/trace/schema.js.map +1 -0
- package/dist/trace/writer.d.ts +17 -0
- package/dist/trace/writer.d.ts.map +1 -0
- package/dist/trace/writer.js +45 -0
- package/dist/trace/writer.js.map +1 -0
- package/dist/util/fs.d.ts +17 -0
- package/dist/util/fs.d.ts.map +1 -0
- package/dist/util/fs.js +61 -0
- package/dist/util/fs.js.map +1 -0
- package/dist/util/hash.d.ts +3 -0
- package/dist/util/hash.d.ts.map +1 -0
- package/dist/util/hash.js +7 -0
- package/dist/util/hash.js.map +1 -0
- package/dist/util/json.d.ts +8 -0
- package/dist/util/json.d.ts.map +1 -0
- package/dist/util/json.js +24 -0
- package/dist/util/json.js.map +1 -0
- package/dist/util/logger.d.ts +8 -0
- package/dist/util/logger.d.ts.map +1 -0
- package/dist/util/logger.js +16 -0
- package/dist/util/logger.js.map +1 -0
- package/dist/version.d.ts +24 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +26 -0
- package/dist/version.js.map +1 -0
- package/docs/assets/yuurei-top.jpg +0 -0
- package/package.json +61 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/runtime/exec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/runtime/registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAY1C,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAM9C;AAED,wBAAgB,cAAc,IAAI,MAAM,EAAE,CAEzC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { EXIT_CODES, YuureiError } from '../cli/exit-codes.js';
|
|
2
|
+
import { ClaudeCodeRuntime } from './claude-code/index.js';
|
|
3
|
+
import { CodexRuntime } from './codex/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* The only module allowed to import concrete Runtime adapters. Everything
|
|
6
|
+
* else must go through `getRuntime(id)` so the core stays adapter-agnostic
|
|
7
|
+
* (design doc §6.1).
|
|
8
|
+
*/
|
|
9
|
+
const RUNTIMES = {
|
|
10
|
+
'claude-code': () => new ClaudeCodeRuntime(),
|
|
11
|
+
codex: () => new CodexRuntime(),
|
|
12
|
+
};
|
|
13
|
+
export function getRuntime(id) {
|
|
14
|
+
const factory = RUNTIMES[id];
|
|
15
|
+
if (!factory) {
|
|
16
|
+
throw new YuureiError(`unknown runtime: ${id}`, EXIT_CODES.RUNTIME_UNSUPPORTED);
|
|
17
|
+
}
|
|
18
|
+
return factory();
|
|
19
|
+
}
|
|
20
|
+
export function listRuntimeIds() {
|
|
21
|
+
return Object.keys(RUNTIMES);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/runtime/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD;;;;GAIG;AACH,MAAM,QAAQ,GAAkC;IAC9C,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE;IAC5C,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,YAAY,EAAE;CAChC,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,EAAU;IACnC,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,WAAW,CAAC,oBAAoB,EAAE,EAAE,EAAE,UAAU,CAAC,mBAAmB,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rejects profile config entries that would land on a path the runtime reads
|
|
3
|
+
* its own credential from (design doc §9.2). Without this, a profile shipping
|
|
4
|
+
* its own credential file would survive untouched whenever bridging no-ops or
|
|
5
|
+
* fails -- including simply being disabled -- and the run would silently
|
|
6
|
+
* authenticate as whoever wrote the profile rather than as the operator.
|
|
7
|
+
*
|
|
8
|
+
* Enforced regardless of whether credential bridging is enabled for this run:
|
|
9
|
+
* the isolated environment usually holds no credential of its own, so a
|
|
10
|
+
* profile-supplied one competes with nothing and is used unconditionally.
|
|
11
|
+
*
|
|
12
|
+
* Comparison is on the *resolved destination*, via the same `join` the write
|
|
13
|
+
* sink uses, rather than on the raw key. A guard that compares the raw key
|
|
14
|
+
* lets `./auth.json` and `sub/../auth.json` through while `join` still lands
|
|
15
|
+
* them on the reserved path. Lower-cased because a runtime resolves these
|
|
16
|
+
* files by name on a filesystem that may not be case-sensitive.
|
|
17
|
+
*/
|
|
18
|
+
export declare function assertNoReservedConfigPath(destDir: string, configFiles: Record<string, {
|
|
19
|
+
content: Buffer;
|
|
20
|
+
mode: number;
|
|
21
|
+
}>, reservedNames: readonly string[]): void;
|
|
22
|
+
//# sourceMappingURL=reserved-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reserved-paths.d.ts","sourceRoot":"","sources":["../../src/runtime/reserved-paths.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAC9D,aAAa,EAAE,SAAS,MAAM,EAAE,GAC/B,IAAI,CAeN"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { EXIT_CODES, YuureiError } from '../cli/exit-codes.js';
|
|
3
|
+
/**
|
|
4
|
+
* Rejects profile config entries that would land on a path the runtime reads
|
|
5
|
+
* its own credential from (design doc §9.2). Without this, a profile shipping
|
|
6
|
+
* its own credential file would survive untouched whenever bridging no-ops or
|
|
7
|
+
* fails -- including simply being disabled -- and the run would silently
|
|
8
|
+
* authenticate as whoever wrote the profile rather than as the operator.
|
|
9
|
+
*
|
|
10
|
+
* Enforced regardless of whether credential bridging is enabled for this run:
|
|
11
|
+
* the isolated environment usually holds no credential of its own, so a
|
|
12
|
+
* profile-supplied one competes with nothing and is used unconditionally.
|
|
13
|
+
*
|
|
14
|
+
* Comparison is on the *resolved destination*, via the same `join` the write
|
|
15
|
+
* sink uses, rather than on the raw key. A guard that compares the raw key
|
|
16
|
+
* lets `./auth.json` and `sub/../auth.json` through while `join` still lands
|
|
17
|
+
* them on the reserved path. Lower-cased because a runtime resolves these
|
|
18
|
+
* files by name on a filesystem that may not be case-sensitive.
|
|
19
|
+
*/
|
|
20
|
+
export function assertNoReservedConfigPath(destDir, configFiles, reservedNames) {
|
|
21
|
+
const reservedTargets = new Map(reservedNames.map((name) => [join(destDir, name).toLowerCase(), name]));
|
|
22
|
+
for (const key of Object.keys(configFiles)) {
|
|
23
|
+
const reserved = reservedTargets.get(join(destDir, key).toLowerCase());
|
|
24
|
+
if (reserved !== undefined) {
|
|
25
|
+
const alias = key === reserved ? '' : ` (resolves to "${reserved}")`;
|
|
26
|
+
throw new YuureiError(`profile config may not provide "${key}"${alias}: this path is reserved for the runtime's own credential`, EXIT_CODES.CONFIG_ERROR);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=reserved-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reserved-paths.js","sourceRoot":"","sources":["../../src/runtime/reserved-paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE/D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAe,EACf,WAA8D,EAC9D,aAAgC;IAEhC,MAAM,eAAe,GAAG,IAAI,GAAG,CAC7B,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,CAAC,CACvE,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QACvE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB,QAAQ,IAAI,CAAC;YACrE,MAAM,IAAI,WAAW,CACnB,mCAAmC,GAAG,IAAI,KAAK,0DAA0D,EACzG,UAAU,CAAC,YAAY,CACxB,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { ResolvedCell } from '../cell/types.js';
|
|
2
|
+
import type { IsolationContext } from '../isolation/types.js';
|
|
3
|
+
export interface RuntimeDetection {
|
|
4
|
+
installed: boolean;
|
|
5
|
+
/** null = version could not be determined; never guess a fallback value. */
|
|
6
|
+
version: string | null;
|
|
7
|
+
/** null = version could not be determined; otherwise whether this version is supported. */
|
|
8
|
+
versionSupported: boolean | null;
|
|
9
|
+
executablePath: string | null;
|
|
10
|
+
/** null = auth usability was not checked. */
|
|
11
|
+
authUsable: boolean | null;
|
|
12
|
+
/**
|
|
13
|
+
* Safe next-step guidance for the operator when authUsable is false.
|
|
14
|
+
* Only populated when installed && authUsable === false. Never contains
|
|
15
|
+
* credential values, paths, or recommendations to persist tokens.
|
|
16
|
+
*/
|
|
17
|
+
authGuidance?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface PreparedRun {
|
|
20
|
+
runtimeId: string;
|
|
21
|
+
command: string;
|
|
22
|
+
args: string[];
|
|
23
|
+
env: Record<string, string>;
|
|
24
|
+
cwd: string;
|
|
25
|
+
isolation: IsolationContext;
|
|
26
|
+
cell: ResolvedCell;
|
|
27
|
+
/** null = version could not be determined at prepare() time; never a hardcoded fallback. */
|
|
28
|
+
runtimeVersion: string | null;
|
|
29
|
+
/**
|
|
30
|
+
* The actual real credential values this adapter forwarded or wrote,
|
|
31
|
+
* regardless of where they ended up (an env var, or a field inside a
|
|
32
|
+
* bridged file like Codex's auth.json). The pipeline redacts each of
|
|
33
|
+
* these, by exact match, from persisted stdout/stderr — reporting values
|
|
34
|
+
* rather than env var *names* is deliberate: a name-based list can never
|
|
35
|
+
* reach a secret embedded inside file content, only one inside `env`.
|
|
36
|
+
*/
|
|
37
|
+
credentialValuesToRedact: string[];
|
|
38
|
+
}
|
|
39
|
+
export interface RuntimeResult {
|
|
40
|
+
/** null = process was killed by signal or the exit code was never observed. */
|
|
41
|
+
exitCode: number | null;
|
|
42
|
+
signal: NodeJS.Signals | null;
|
|
43
|
+
startedAt: string;
|
|
44
|
+
finishedAt: string;
|
|
45
|
+
stdoutPath: string;
|
|
46
|
+
stderrPath: string;
|
|
47
|
+
timedOut: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Minimal context passed from prepare() to normalize() — only the fields
|
|
51
|
+
* normalize() actually needs. Keeps normalize() from depending on the full
|
|
52
|
+
* PreparedRun (which includes credentials, env vars, cwd) and makes the
|
|
53
|
+
* boundary explicit.
|
|
54
|
+
*/
|
|
55
|
+
export interface NormalizationContext {
|
|
56
|
+
/** null = version could not be determined at prepare() time. */
|
|
57
|
+
runtimeVersion: string | null;
|
|
58
|
+
}
|
|
59
|
+
export interface NormalizedTraceFragment {
|
|
60
|
+
runtime: {
|
|
61
|
+
id: string;
|
|
62
|
+
version: string | null;
|
|
63
|
+
};
|
|
64
|
+
model: {
|
|
65
|
+
requested: string;
|
|
66
|
+
resolved: string | null;
|
|
67
|
+
};
|
|
68
|
+
execution: {
|
|
69
|
+
exitCode: number | null;
|
|
70
|
+
signal: string | null;
|
|
71
|
+
durationMs: number | null;
|
|
72
|
+
};
|
|
73
|
+
/** null = usage metric was not observed; never default to 0. */
|
|
74
|
+
usage: Record<string, number | null>;
|
|
75
|
+
/**
|
|
76
|
+
* Non-fatal issues encountered during normalization (e.g. usage parse
|
|
77
|
+
* failure). Empty array and absent are equivalent — the pipeline reports
|
|
78
|
+
* each entry via onWarning and does not write them to trace.json.
|
|
79
|
+
*/
|
|
80
|
+
warnings?: string[];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The pipeline passes this to `prepare()` so an adapter can register each
|
|
84
|
+
* credential path on disk at the moment it writes it — not when prepare()
|
|
85
|
+
* returns. The scrub list is therefore populated by the write, so a signal or
|
|
86
|
+
* throw between the write and the return cannot strand credential material
|
|
87
|
+
* (design doc §9.2). `rm(path, { force: true })` on a never-written path is a
|
|
88
|
+
* no-op, so registering before an attempted write is safe.
|
|
89
|
+
*/
|
|
90
|
+
export type RegisterCredentialPath = (path: string) => void;
|
|
91
|
+
/**
|
|
92
|
+
* Hides runtime-specific launch/inspect/exit handling. Implementations
|
|
93
|
+
* (ClaudeCodeRuntime, CodexRuntime) must keep their config path/CLI-arg/
|
|
94
|
+
* env-var conventions encapsulated internally — nothing runtime-specific
|
|
95
|
+
* should leak into the core (design doc §6.1).
|
|
96
|
+
*/
|
|
97
|
+
export interface Runtime {
|
|
98
|
+
id(): string;
|
|
99
|
+
detect(): Promise<RuntimeDetection>;
|
|
100
|
+
prepare(cell: ResolvedCell, isolation: IsolationContext, registerCredentialPath: RegisterCredentialPath): Promise<PreparedRun>;
|
|
101
|
+
/** `timeoutMs` null means no timeout is enforced. */
|
|
102
|
+
execute(run: PreparedRun, timeoutMs: number | null): Promise<RuntimeResult>;
|
|
103
|
+
normalize(result: RuntimeResult, context: NormalizationContext): Promise<NormalizedTraceFragment>;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,2FAA2F;IAC3F,gBAAgB,EAAE,OAAO,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,6CAA6C;IAC7C,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,gBAAgB,CAAC;IAC5B,IAAI,EAAE,YAAY,CAAC;IACnB,4FAA4F;IAC5F,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;;;;;;;OAOG;IACH,wBAAwB,EAAE,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,gEAAgE;IAChE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAChD,KAAK,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACtD,SAAS,EAAE;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACzF,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACtB,EAAE,IAAI,MAAM,CAAC;IACb,MAAM,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACpC,OAAO,CACL,IAAI,EAAE,YAAY,EAClB,SAAS,EAAE,gBAAgB,EAC3B,sBAAsB,EAAE,sBAAsB,GAC7C,OAAO,CAAC,WAAW,CAAC,CAAC;IACxB,qDAAqD;IACrD,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5E,SAAS,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAC;CACnG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.d.ts","sourceRoot":"","sources":["../../src/trace/reader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEtD,iDAAiD;AACjD,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAG9D"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { TraceSchema } from './schema.js';
|
|
4
|
+
/** Loads and validates `<runDir>/trace.json`. */
|
|
5
|
+
export async function readTrace(runDir) {
|
|
6
|
+
const raw = await readFile(join(runDir, 'trace.json'), 'utf8');
|
|
7
|
+
return TraceSchema.parse(JSON.parse(raw));
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../src/trace/reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAc,MAAM,aAAa,CAAC;AAEtD,iDAAiD;AACjD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAAc;IAC5C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/D,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare function redactSecrets(text: string): string;
|
|
2
|
+
/**
|
|
3
|
+
* Exact-match redaction of specific known secret values reported by the
|
|
4
|
+
* runtime adapter that produced them (as opposed to redactSecrets' generic
|
|
5
|
+
* shape-based patterns, which won't catch a credential that doesn't happen
|
|
6
|
+
* to look like `sk-...` or `Bearer ...` — an OAuth access/refresh token
|
|
7
|
+
* embedded in a bridged Codex auth.json, for instance). Literal split/join
|
|
8
|
+
* rather than a constructed RegExp, since a credential value may itself
|
|
9
|
+
* contain regex metacharacters.
|
|
10
|
+
*/
|
|
11
|
+
export declare function redactKnownValues(text: string, values: readonly string[]): string;
|
|
12
|
+
/**
|
|
13
|
+
* Redacts and persists a log without retaining the complete input in
|
|
14
|
+
* memory. Raw input is buffered only until the byte cap is exceeded (plus
|
|
15
|
+
* at most one read chunk), so memory usage is bounded by `maxBytes`
|
|
16
|
+
* regardless of log length or credential length. Redaction runs over the
|
|
17
|
+
* whole buffered prefix, so a known value or secret pattern that spans any
|
|
18
|
+
* number of read chunks is still removed; when the byte cap cuts a stream
|
|
19
|
+
* mid-credential, the surviving prefix is additionally redacted.
|
|
20
|
+
*/
|
|
21
|
+
export declare function redactFile(inputPath: string, outputPath: string, values: readonly string[], maxBytes?: number): Promise<boolean>;
|
|
22
|
+
//# sourceMappingURL=redact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../src/trace/redact.ts"],"names":[],"mappings":"AAmBA,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD;AAWD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAOjF;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,QAAQ,SAAwB,GAC/B,OAAO,CAAC,OAAO,CAAC,CAqBlB"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createReadStream } from 'node:fs';
|
|
2
|
+
import { writeFile } from 'node:fs/promises';
|
|
3
|
+
/**
|
|
4
|
+
* Patterns for common secret shapes (API keys, bearer tokens, generic
|
|
5
|
+
* long hex/base64 blobs following an assignment). This is a best-effort
|
|
6
|
+
* safety net, not a guarantee — adapters must still avoid writing secrets
|
|
7
|
+
* into anything that flows through here (design doc §10.2).
|
|
8
|
+
*/
|
|
9
|
+
const SECRET_PATTERNS = [
|
|
10
|
+
/\b(sk-[a-zA-Z0-9]{16,})\b/g,
|
|
11
|
+
/\bBearer\s+[a-zA-Z0-9._-]{16,}\b/gi,
|
|
12
|
+
/\b(?:api[_-]?key|token|secret|password)\s*[:=]\s*['"]?[a-zA-Z0-9._-]{8,}['"]?/gi,
|
|
13
|
+
];
|
|
14
|
+
const REDACTED = '[REDACTED]';
|
|
15
|
+
const DEFAULT_LOG_MAX_BYTES = 1024 * 1024;
|
|
16
|
+
export function redactSecrets(text) {
|
|
17
|
+
let result = text;
|
|
18
|
+
for (const pattern of SECRET_PATTERNS) {
|
|
19
|
+
result = result.replace(pattern, REDACTED);
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Below this length, a "known value" is refused rather than redacted: a
|
|
25
|
+
* malformed or truncated credential file could otherwise hand this function
|
|
26
|
+
* a one- or two-character string, which would then blank out every
|
|
27
|
+
* occurrence of that character across the whole log. Real API keys and
|
|
28
|
+
* OAuth tokens are always far longer than this.
|
|
29
|
+
*/
|
|
30
|
+
const MIN_REDACTABLE_LENGTH = 8;
|
|
31
|
+
/**
|
|
32
|
+
* Exact-match redaction of specific known secret values reported by the
|
|
33
|
+
* runtime adapter that produced them (as opposed to redactSecrets' generic
|
|
34
|
+
* shape-based patterns, which won't catch a credential that doesn't happen
|
|
35
|
+
* to look like `sk-...` or `Bearer ...` — an OAuth access/refresh token
|
|
36
|
+
* embedded in a bridged Codex auth.json, for instance). Literal split/join
|
|
37
|
+
* rather than a constructed RegExp, since a credential value may itself
|
|
38
|
+
* contain regex metacharacters.
|
|
39
|
+
*/
|
|
40
|
+
export function redactKnownValues(text, values) {
|
|
41
|
+
let result = text;
|
|
42
|
+
for (const value of values) {
|
|
43
|
+
if (value.length < MIN_REDACTABLE_LENGTH)
|
|
44
|
+
continue;
|
|
45
|
+
result = result.split(value).join(REDACTED);
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Redacts and persists a log without retaining the complete input in
|
|
51
|
+
* memory. Raw input is buffered only until the byte cap is exceeded (plus
|
|
52
|
+
* at most one read chunk), so memory usage is bounded by `maxBytes`
|
|
53
|
+
* regardless of log length or credential length. Redaction runs over the
|
|
54
|
+
* whole buffered prefix, so a known value or secret pattern that spans any
|
|
55
|
+
* number of read chunks is still removed; when the byte cap cuts a stream
|
|
56
|
+
* mid-credential, the surviving prefix is additionally redacted.
|
|
57
|
+
*/
|
|
58
|
+
export async function redactFile(inputPath, outputPath, values, maxBytes = DEFAULT_LOG_MAX_BYTES) {
|
|
59
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) {
|
|
60
|
+
throw new RangeError('maxBytes must be a non-negative safe integer');
|
|
61
|
+
}
|
|
62
|
+
let output = '';
|
|
63
|
+
let stoppedEarly = false;
|
|
64
|
+
for await (const chunk of createReadStream(inputPath, { encoding: 'utf8' })) {
|
|
65
|
+
output += chunk;
|
|
66
|
+
if (Buffer.byteLength(output, 'utf8') > maxBytes) {
|
|
67
|
+
stoppedEarly = true;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
output = redactSecrets(redactKnownValues(output, values));
|
|
72
|
+
output = redactTerminalKnownPrefix(output, values);
|
|
73
|
+
const truncated = stoppedEarly || Buffer.byteLength(output, 'utf8') > maxBytes;
|
|
74
|
+
await writeFile(outputPath, utf8Prefix(output, maxBytes), 'utf8');
|
|
75
|
+
return truncated;
|
|
76
|
+
}
|
|
77
|
+
function utf8Prefix(text, maxBytes) {
|
|
78
|
+
let bytes = 0;
|
|
79
|
+
let prefix = '';
|
|
80
|
+
for (const character of text) {
|
|
81
|
+
const characterBytes = Buffer.byteLength(character, 'utf8');
|
|
82
|
+
if (bytes + characterBytes > maxBytes)
|
|
83
|
+
break;
|
|
84
|
+
prefix += character;
|
|
85
|
+
bytes += characterBytes;
|
|
86
|
+
}
|
|
87
|
+
return prefix;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Redacts the tail of a stream when it ends with the prefix of a known
|
|
91
|
+
* value — i.e. the stream was cut (by the byte cap or a crashed writer)
|
|
92
|
+
* while a credential was still being written. Only prefixes that already
|
|
93
|
+
* meet the minimum redactable length are considered, so clean log endings
|
|
94
|
+
* are untouched. Each value's first character is used to locate candidate
|
|
95
|
+
* alignments, so the cost is negligible for logs that do not end in a
|
|
96
|
+
* credential.
|
|
97
|
+
*/
|
|
98
|
+
function redactTerminalKnownPrefix(text, values) {
|
|
99
|
+
let longest = 0;
|
|
100
|
+
for (const value of values) {
|
|
101
|
+
if (value.length < MIN_REDACTABLE_LENGTH)
|
|
102
|
+
continue;
|
|
103
|
+
const maxPrefix = Math.min(value.length - 1, text.length);
|
|
104
|
+
if (maxPrefix < MIN_REDACTABLE_LENGTH)
|
|
105
|
+
continue;
|
|
106
|
+
const first = value[0];
|
|
107
|
+
for (let start = text.length - maxPrefix; start <= text.length - MIN_REDACTABLE_LENGTH; start += 1) {
|
|
108
|
+
if (text[start] !== first)
|
|
109
|
+
continue;
|
|
110
|
+
const length = text.length - start;
|
|
111
|
+
let i = 0;
|
|
112
|
+
while (i < length && text[start + i] === value[i])
|
|
113
|
+
i += 1;
|
|
114
|
+
if (i === length) {
|
|
115
|
+
longest = Math.max(longest, length);
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (longest === 0)
|
|
121
|
+
return text;
|
|
122
|
+
return `${text.slice(0, text.length - longest)}${REDACTED}`;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/trace/redact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Independent of the yuurei package version — this only changes when the
|
|
4
|
+
* on-disk trace.json shape changes (design doc §6.3).
|
|
5
|
+
*/
|
|
6
|
+
export declare const TRACE_SCHEMA_VERSION = "0.3";
|
|
7
|
+
export declare const TraceSchema: z.ZodObject<{
|
|
8
|
+
schema_version: z.ZodLiteral<"0.3">;
|
|
9
|
+
run_id: z.ZodString;
|
|
10
|
+
started_at: z.ZodString;
|
|
11
|
+
finished_at: z.ZodString;
|
|
12
|
+
runtime: z.ZodObject<{
|
|
13
|
+
id: z.ZodString;
|
|
14
|
+
version: z.ZodNullable<z.ZodString>;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
model: z.ZodObject<{
|
|
17
|
+
requested: z.ZodString;
|
|
18
|
+
resolved: z.ZodNullable<z.ZodString>;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
profile: z.ZodObject<{
|
|
21
|
+
name: z.ZodString;
|
|
22
|
+
digest: z.ZodString;
|
|
23
|
+
}, z.core.$strip>;
|
|
24
|
+
task: z.ZodObject<{
|
|
25
|
+
source: z.ZodString;
|
|
26
|
+
digest: z.ZodString;
|
|
27
|
+
}, z.core.$strip>;
|
|
28
|
+
isolation: z.ZodObject<{
|
|
29
|
+
strategy: z.ZodString;
|
|
30
|
+
verified: z.ZodBoolean;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
execution: z.ZodObject<{
|
|
33
|
+
exit_code: z.ZodNullable<z.ZodNumber>;
|
|
34
|
+
signal: z.ZodNullable<z.ZodString>;
|
|
35
|
+
duration_ms: z.ZodNullable<z.ZodNumber>;
|
|
36
|
+
timed_out: z.ZodBoolean;
|
|
37
|
+
}, z.core.$strip>;
|
|
38
|
+
usage: z.ZodRecord<z.ZodString, z.ZodNullable<z.ZodNumber>>;
|
|
39
|
+
cost: z.ZodNullable<z.ZodObject<{
|
|
40
|
+
amount: z.ZodNumber;
|
|
41
|
+
currency: z.ZodString;
|
|
42
|
+
}, z.core.$strip>>;
|
|
43
|
+
artifacts: z.ZodArray<z.ZodObject<{
|
|
44
|
+
path: z.ZodString;
|
|
45
|
+
kind: z.ZodString;
|
|
46
|
+
}, z.core.$strip>>;
|
|
47
|
+
}, z.core.$strip>;
|
|
48
|
+
export type Trace = z.infer<typeof TraceSchema>;
|
|
49
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/trace/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAE1C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+CtB,CAAC;AAEH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Independent of the yuurei package version — this only changes when the
|
|
4
|
+
* on-disk trace.json shape changes (design doc §6.3).
|
|
5
|
+
*/
|
|
6
|
+
export const TRACE_SCHEMA_VERSION = '0.3';
|
|
7
|
+
export const TraceSchema = z.object({
|
|
8
|
+
schema_version: z.literal(TRACE_SCHEMA_VERSION),
|
|
9
|
+
run_id: z.string(),
|
|
10
|
+
started_at: z.string(),
|
|
11
|
+
finished_at: z.string(),
|
|
12
|
+
runtime: z.object({
|
|
13
|
+
id: z.string(),
|
|
14
|
+
version: z.string().nullable(),
|
|
15
|
+
}),
|
|
16
|
+
model: z.object({
|
|
17
|
+
requested: z.string(),
|
|
18
|
+
resolved: z.string().nullable(),
|
|
19
|
+
}),
|
|
20
|
+
profile: z.object({
|
|
21
|
+
name: z.string(),
|
|
22
|
+
digest: z.string(),
|
|
23
|
+
}),
|
|
24
|
+
task: z.object({
|
|
25
|
+
source: z.string(),
|
|
26
|
+
digest: z.string(),
|
|
27
|
+
}),
|
|
28
|
+
isolation: z.object({
|
|
29
|
+
strategy: z.string(),
|
|
30
|
+
verified: z.boolean(),
|
|
31
|
+
}),
|
|
32
|
+
execution: z.object({
|
|
33
|
+
exit_code: z.number().nullable(),
|
|
34
|
+
signal: z.string().nullable(),
|
|
35
|
+
duration_ms: z.number().nullable(),
|
|
36
|
+
timed_out: z.boolean(),
|
|
37
|
+
}),
|
|
38
|
+
// An observed value not present in `usage` (rather than present as null)
|
|
39
|
+
// means it was never even attempted; null means attempted but unobserved.
|
|
40
|
+
usage: z.record(z.string(), z.number().nullable()),
|
|
41
|
+
// null = cost was not estimated for this run (CostModel is a no-op in v0.3).
|
|
42
|
+
cost: z
|
|
43
|
+
.object({
|
|
44
|
+
amount: z.number(),
|
|
45
|
+
currency: z.string(),
|
|
46
|
+
})
|
|
47
|
+
.nullable(),
|
|
48
|
+
artifacts: z.array(z.object({
|
|
49
|
+
path: z.string(),
|
|
50
|
+
kind: z.string(),
|
|
51
|
+
})),
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/trace/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAE1C,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC;IAC/C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;QAChB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;QACd,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC/B,CAAC;IACF,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;QACrB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAChC,CAAC;IACF,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;QAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;KACnB,CAAC;IACF,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACb,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;KACnB,CAAC;IACF,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC;QAClB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;QACpB,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;KACtB,CAAC;IACF,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC;QAClB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAChC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC7B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAClC,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;KACvB,CAAC;IACF,yEAAyE;IACzE,0EAA0E;IAC1E,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC;IAClD,6EAA6E;IAC7E,IAAI,EAAE,CAAC;SACJ,MAAM,CAAC;QACN,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;KACrB,CAAC;SACD,QAAQ,EAAE;IACb,SAAS,EAAE,CAAC,CAAC,KAAK,CAChB,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;KACjB,CAAC,CACH;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Trace } from './schema.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validates and persists a trace to `<runDir>/trace.json`.
|
|
4
|
+
*
|
|
5
|
+
* `trace.json` is the completion marker (#111): its presence means the run
|
|
6
|
+
* finished and every durable output succeeded. A direct write could leave a
|
|
7
|
+
* truncated or malformed file after a crash mid-write, which the
|
|
8
|
+
* completion-marker logic would then treat as complete and that `trace show`
|
|
9
|
+
* would fail to parse. The trace is therefore written to a same-directory
|
|
10
|
+
* temporary file, fsynced, and atomically renamed into place, so `trace.json`
|
|
11
|
+
* only ever appears in a complete, valid state. On an ordinary failure the
|
|
12
|
+
* temporary file is removed; one left behind by a hard crash shares the run
|
|
13
|
+
* directory and is dropped together with it, and is never read as a trace
|
|
14
|
+
* (readers address `trace.json` exactly).
|
|
15
|
+
*/
|
|
16
|
+
export declare function writeTrace(runDir: string, trace: Trace): Promise<void>;
|
|
17
|
+
//# sourceMappingURL=writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/trace/writer.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEtD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB5E"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { open, rename, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { redactSecrets } from './redact.js';
|
|
5
|
+
import { TraceSchema } from './schema.js';
|
|
6
|
+
/**
|
|
7
|
+
* Validates and persists a trace to `<runDir>/trace.json`.
|
|
8
|
+
*
|
|
9
|
+
* `trace.json` is the completion marker (#111): its presence means the run
|
|
10
|
+
* finished and every durable output succeeded. A direct write could leave a
|
|
11
|
+
* truncated or malformed file after a crash mid-write, which the
|
|
12
|
+
* completion-marker logic would then treat as complete and that `trace show`
|
|
13
|
+
* would fail to parse. The trace is therefore written to a same-directory
|
|
14
|
+
* temporary file, fsynced, and atomically renamed into place, so `trace.json`
|
|
15
|
+
* only ever appears in a complete, valid state. On an ordinary failure the
|
|
16
|
+
* temporary file is removed; one left behind by a hard crash shares the run
|
|
17
|
+
* directory and is dropped together with it, and is never read as a trace
|
|
18
|
+
* (readers address `trace.json` exactly).
|
|
19
|
+
*/
|
|
20
|
+
export async function writeTrace(runDir, trace) {
|
|
21
|
+
const parsed = TraceSchema.parse(trace);
|
|
22
|
+
const serialized = redactSecrets(JSON.stringify(parsed, null, 2));
|
|
23
|
+
const tracePath = join(runDir, 'trace.json');
|
|
24
|
+
const tempPath = join(runDir, `.trace.json.tmp-${randomUUID()}`);
|
|
25
|
+
try {
|
|
26
|
+
await writeFile(tempPath, serialized, 'utf8');
|
|
27
|
+
const handle = await open(tempPath, 'r+');
|
|
28
|
+
try {
|
|
29
|
+
// Flush data to disk before the rename, so a crash right after the
|
|
30
|
+
// atomic name flip cannot expose a zero-length trace.json.
|
|
31
|
+
await handle.sync();
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
await handle.close();
|
|
35
|
+
}
|
|
36
|
+
await rename(tempPath, tracePath);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
// A failed write/fsync/rename publishes nothing; leave neither a partial
|
|
40
|
+
// trace nor its temporary sibling behind.
|
|
41
|
+
await rm(tempPath, { force: true }).catch(() => { });
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/trace/writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAc,MAAM,aAAa,CAAC;AAEtD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAc,EAAE,KAAY;IAC3D,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,mBAAmB,UAAU,EAAE,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC;YACH,mEAAmE;YACnE,2DAA2D;YAC3D,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACtB,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QACD,MAAM,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,yEAAyE;QACzE,0CAA0C;QAC1C,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACpD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Whether `child` is `parent` itself or nested inside it, resolving symlinks on both sides. */
|
|
2
|
+
export declare function isPathWithin(parent: string, child: string): Promise<boolean>;
|
|
3
|
+
export declare function pathExists(path: string): Promise<boolean>;
|
|
4
|
+
/**
|
|
5
|
+
* Writes an in-memory file tree under `destDir`, creating parent directories.
|
|
6
|
+
* Keys are relative paths, normally produced by `loadProfile`'s guarded walk —
|
|
7
|
+
* but this is the actual filesystem-write sink, so it re-validates every key
|
|
8
|
+
* itself rather than trusting a caller-side invariant it cannot enforce.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately sets no modes beyond the default: `destDir` and its
|
|
11
|
+
* permissions are the caller's policy (the adapter creates it 0700).
|
|
12
|
+
*/
|
|
13
|
+
export declare function writeFileTree(destDir: string, files: Record<string, {
|
|
14
|
+
content: Buffer;
|
|
15
|
+
mode: number;
|
|
16
|
+
}>): Promise<void>;
|
|
17
|
+
//# sourceMappingURL=fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/util/fs.ts"],"names":[],"mappings":"AAuBA,gGAAgG;AAChG,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMlF;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO/D;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GACvD,OAAO,CAAC,IAAI,CAAC,CAaf"}
|