agent-nuvira 3.5.7 → 3.5.9
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/agents/agents/package-agent.d.ts +22 -0
- package/dist/agents/agents/package-agent.d.ts.map +1 -1
- package/dist/agents/agents/package-agent.js +92 -4
- package/dist/agents/agents/package-agent.js.map +1 -1
- package/dist/agents/release-preflight.d.ts +42 -5
- package/dist/agents/release-preflight.d.ts.map +1 -1
- package/dist/agents/release-preflight.js +82 -5
- package/dist/agents/release-preflight.js.map +1 -1
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +99 -9
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/code-map.d.ts +51 -0
- package/dist/cli/code-map.d.ts.map +1 -1
- package/dist/cli/code-map.js +174 -2
- package/dist/cli/code-map.js.map +1 -1
- package/dist/cli/credentials.d.ts.map +1 -1
- package/dist/cli/credentials.js +4 -1
- package/dist/cli/credentials.js.map +1 -1
- package/dist/cli/execute.js +5 -5
- package/dist/cli/execute.js.map +1 -1
- package/dist/cli/loop-executor.d.ts.map +1 -1
- package/dist/cli/loop-executor.js +76 -13
- package/dist/cli/loop-executor.js.map +1 -1
- package/dist/config/process-env.d.ts.map +1 -1
- package/dist/config/process-env.js +2 -2
- package/dist/config/process-env.js.map +1 -1
- package/dist/editing/types.d.ts +23 -1
- package/dist/editing/types.d.ts.map +1 -1
- package/dist/editing/types.js +51 -7
- package/dist/editing/types.js.map +1 -1
- package/dist/inference/route-resolver.d.ts +39 -0
- package/dist/inference/route-resolver.d.ts.map +1 -1
- package/dist/inference/route-resolver.js +51 -2
- package/dist/inference/route-resolver.js.map +1 -1
- package/dist/inference/thinking-replay.d.ts +86 -0
- package/dist/inference/thinking-replay.d.ts.map +1 -0
- package/dist/inference/thinking-replay.js +110 -0
- package/dist/inference/thinking-replay.js.map +1 -0
- package/dist/inference/tools.d.ts +9 -0
- package/dist/inference/tools.d.ts.map +1 -1
- package/dist/inference/tools.js +12 -1
- package/dist/inference/tools.js.map +1 -1
- package/dist/learning/assessment-protocol.d.ts +120 -0
- package/dist/learning/assessment-protocol.d.ts.map +1 -0
- package/dist/learning/assessment-protocol.js +236 -0
- package/dist/learning/assessment-protocol.js.map +1 -0
- package/dist/learning/assessment-turn-context.d.ts +54 -0
- package/dist/learning/assessment-turn-context.d.ts.map +1 -0
- package/dist/learning/assessment-turn-context.js +71 -0
- package/dist/learning/assessment-turn-context.js.map +1 -0
- package/dist/learning/exhaustion-report.d.ts +24 -1
- package/dist/learning/exhaustion-report.d.ts.map +1 -1
- package/dist/learning/exhaustion-report.js +18 -6
- package/dist/learning/exhaustion-report.js.map +1 -1
- package/dist/learning/perf-probe.d.ts +140 -0
- package/dist/learning/perf-probe.d.ts.map +1 -0
- package/dist/learning/perf-probe.js +316 -0
- package/dist/learning/perf-probe.js.map +1 -0
- package/dist/learning/self-check-discovery.d.ts +117 -0
- package/dist/learning/self-check-discovery.d.ts.map +1 -0
- package/dist/learning/self-check-discovery.js +334 -0
- package/dist/learning/self-check-discovery.js.map +1 -0
- package/dist/tools/child-agent-runtime.js +19 -1
- package/dist/tools/child-agent-runtime.js.map +1 -1
- package/dist/tools/credentials-tool.d.ts.map +1 -1
- package/dist/tools/credentials-tool.js +4 -1
- package/dist/tools/credentials-tool.js.map +1 -1
- package/dist/tools/loop-project-context.d.ts +7 -0
- package/dist/tools/loop-project-context.d.ts.map +1 -1
- package/dist/tools/loop-project-context.js +44 -0
- package/dist/tools/loop-project-context.js.map +1 -1
- package/dist/tools/pipeline-tool.d.ts.map +1 -1
- package/dist/tools/pipeline-tool.js +19 -1
- package/dist/tools/pipeline-tool.js.map +1 -1
- package/dist/tools/plan-store.d.ts +90 -6
- package/dist/tools/plan-store.d.ts.map +1 -1
- package/dist/tools/plan-store.js +140 -13
- package/dist/tools/plan-store.js.map +1 -1
- package/dist/tools/publish-tool.d.ts.map +1 -1
- package/dist/tools/publish-tool.js +9 -0
- package/dist/tools/publish-tool.js.map +1 -1
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +25 -3
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/tool-loop.d.ts +17 -0
- package/dist/tools/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +4 -1
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/web-dashboard/chat-console.d.ts.map +1 -1
- package/dist/web-dashboard/chat-console.js +11 -1
- package/dist/web-dashboard/chat-console.js.map +1 -1
- package/dist/web-dashboard/project-context.js +6 -0
- package/dist/web-dashboard/project-context.js.map +1 -1
- package/dist/web-dashboard/server.d.ts.map +1 -1
- package/dist/web-dashboard/server.js +25 -3
- package/dist/web-dashboard/server.js.map +1 -1
- package/package.json +1 -1
- package/src/web-dashboard/public/assets/{index-V0rIqVbg.js → index-CGYIlLpO.js} +3 -3
- package/src/web-dashboard/public/assets/index-CGYIlLpO.js.map +1 -0
- package/src/web-dashboard/public/index.html +1 -1
- package/src/web-dashboard/public/assets/index-V0rIqVbg.js.map +0 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PERF PROBE — name the three measurements an assessment is allowed to be silent
|
|
3
|
+
* about, and the exact bounded command for each.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS (R12, the head-to-head audit, 2026-10-16). Startup time, memory
|
|
6
|
+
* and throughput were the ONE class of claim NOBODY measured: the report that
|
|
7
|
+
* compared the two agents lists them as UNMEASURED on both sides, and on the
|
|
8
|
+
* repository under review every finding about them was an inference. A gap that
|
|
9
|
+
* both sides share is not a fair comparison — it is a blind spot in the rubric,
|
|
10
|
+
* and it is the cheapest one to close because the measurements are mechanical.
|
|
11
|
+
*
|
|
12
|
+
* THE THREE MEASUREMENTS, and why these three:
|
|
13
|
+
*
|
|
14
|
+
* 1. IMPORT / COLD-START COST — the import profiler, which names the individual
|
|
15
|
+
* expensive imports rather than one aggregate number. For a desktop app this
|
|
16
|
+
* is the user-visible "it takes N seconds to open".
|
|
17
|
+
* 2. PEAK ALLOCATION — `tracemalloc`. Stated honestly: it traces PYTHON
|
|
18
|
+
* allocations and does NOT see a native/CUDA/driver allocation, so a probe
|
|
19
|
+
* reporting 40 MB for a model loader is not a bug in the probe — it is the
|
|
20
|
+
* boundary of what this measurement can see, and the block says so.
|
|
21
|
+
* 3. WALL CLOCK OF THE HEAVIEST REALISTIC OPERATION — the one number a user
|
|
22
|
+
* actually feels. Deliberately NOT templated with a guessed input: the
|
|
23
|
+
* command is the project's own entry point or e2e script, because a
|
|
24
|
+
* synthetic input measures the synthetic input.
|
|
25
|
+
*
|
|
26
|
+
* EVERY TEMPLATE HERE WAS MEASURED AGAINST A REAL MACHINE, and two of the first
|
|
27
|
+
* drafts were wrong because of it:
|
|
28
|
+
*
|
|
29
|
+
* - `timeout` is ABSENT on macOS and `gtimeout` is not installed by default, so
|
|
30
|
+
* a template that assumed GNU `timeout` emitted commands that fail on the
|
|
31
|
+
* machine this was written on. The bound is therefore chosen from what the
|
|
32
|
+
* host HAS: the coreutils wrapper when present, else the interpreter's own
|
|
33
|
+
* `signal.alarm` — which is a real bound, not a comment (measured: the process
|
|
34
|
+
* is killed, and nothing after the alarm prints).
|
|
35
|
+
* - `python` is ABSENT on macOS too (only `python3` exists), so the interpreter
|
|
36
|
+
* name is detected rather than assumed. A probe block whose commands do not
|
|
37
|
+
* run is worse than no probe block, because it reads as one that ran.
|
|
38
|
+
*
|
|
39
|
+
* THE IMPORT PROFILER IS REACHED TWO WAYS for the same reason: `-X importtime`
|
|
40
|
+
* when the wrapper can bound the whole command, and `PYTHONPROFILEIMPORTTIME=1`
|
|
41
|
+
* when the bound has to come from inside the interpreter (so the `-X` flag has to
|
|
42
|
+
* give way to the env var). Measured: the env var produces the same profile.
|
|
43
|
+
*
|
|
44
|
+
* HARD TIMEOUTS, OR AN HONEST REFUSAL. When neither mechanism exists (Windows, in
|
|
45
|
+
* practice) the command is emitted UNBOUNDED and the block states plainly that the
|
|
46
|
+
* bound must come from the operator and that an unbound number is tagged
|
|
47
|
+
* UNMEASURED — the discipline rules 3 and 9 already apply to hang claims, moved
|
|
48
|
+
* one step earlier, to the place the numbers come from.
|
|
49
|
+
*
|
|
50
|
+
* WHY IT ONLY NAMES COMMANDS AND NEVER RUNS THEM — same reason as
|
|
51
|
+
* `self-check-discovery.ts`: these run the project's own code, which is exactly
|
|
52
|
+
* the thing that must pass the normal tool gate. Naming the command keeps the run
|
|
53
|
+
* as one consented tool call with a stated timeout; executing it here would hand
|
|
54
|
+
* any cloned repository arbitrary code execution at prompt-assembly time. This
|
|
55
|
+
* module is READ-ONLY over the filesystem, by design.
|
|
56
|
+
*
|
|
57
|
+
* DETERMINISTIC AND LLM-FREE, like everything else in `learning/`: no model
|
|
58
|
+
* decides what a project's startup cost is. Detection that finds nothing to probe
|
|
59
|
+
* yields an EMPTY string, so that turn's prompt is byte-identical to a build
|
|
60
|
+
* without this module.
|
|
61
|
+
*/
|
|
62
|
+
import { type MachineFacts } from './machine-facts.js';
|
|
63
|
+
/** Which runtime to probe. `none` means nothing detectable — emit nothing. */
|
|
64
|
+
export type PerfRuntime = 'python' | 'node' | 'none';
|
|
65
|
+
/** Everything the renderer needs, so it can be tested with no filesystem at all. */
|
|
66
|
+
export interface PerfProbeInput {
|
|
67
|
+
runtime: PerfRuntime;
|
|
68
|
+
/** Importable module/package name to time, e.g. `ai_voice_studio`. */
|
|
69
|
+
pythonModule?: string;
|
|
70
|
+
/** The python executable THIS machine has (`python3` on macOS, `python` on Windows). */
|
|
71
|
+
pythonCommand?: string;
|
|
72
|
+
/** Entry file to require/run for a cold-start number, repo-relative. */
|
|
73
|
+
nodeEntry?: string;
|
|
74
|
+
/** Timeout wrapper present on this machine (`timeout`, `gtimeout`), or ''. */
|
|
75
|
+
timeoutCommand?: string;
|
|
76
|
+
/** Host platform — decides whether the runtime's own alarm is available. */
|
|
77
|
+
platform?: string;
|
|
78
|
+
/** Which `/usr/bin/time` flavour exists, for the RSS probe. */
|
|
79
|
+
nativePerfTool?: 'bsd' | 'gnu' | 'none';
|
|
80
|
+
}
|
|
81
|
+
/** Seconds every emitted probe is bounded to. Long enough for a real import. */
|
|
82
|
+
export declare const PROBE_TIMEOUT_SECONDS = 60;
|
|
83
|
+
/** Hard cap on rendered probe lines — the block shares the context budget. */
|
|
84
|
+
export declare const MAX_PROBE_LINES = 26;
|
|
85
|
+
/**
|
|
86
|
+
* A module name that is safe to place inside a shell template. The name is
|
|
87
|
+
* derived from the REPOSITORY (a `pyproject.toml` field or a directory name), and
|
|
88
|
+
* a template that interpolates repo-controlled text into a shell command is an
|
|
89
|
+
* injection the harness would be performing on the user's behalf. Anything outside
|
|
90
|
+
* the identifier charset is dropped; an empty result means "no probe".
|
|
91
|
+
*/
|
|
92
|
+
export declare function safeIdentifier(name: string): string;
|
|
93
|
+
/**
|
|
94
|
+
* A repo-relative path safe inside a shell template — same reasoning as
|
|
95
|
+
* {@link safeIdentifier}, with `/` allowed. Quotes, backticks, `$` and newlines
|
|
96
|
+
* are refused outright rather than escaped, because a legitimate entry path never
|
|
97
|
+
* contains them.
|
|
98
|
+
*/
|
|
99
|
+
export declare function safeRelativePath(p: string): string;
|
|
100
|
+
/** Does this executable exist anywhere on PATH? (Never spawns a process.) */
|
|
101
|
+
export declare function executableOnPath(name: string, env?: NodeJS.ProcessEnv): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* A python one-liner, bounded by the best mechanism this host has.
|
|
104
|
+
*
|
|
105
|
+
* Returns `bounded: false` only when there is genuinely no way to bound it, and
|
|
106
|
+
* the caller then refuses to present the probe as if it were safe.
|
|
107
|
+
*/
|
|
108
|
+
export declare function pythonProbe(input: PerfProbeInput, program: string): {
|
|
109
|
+
command: string;
|
|
110
|
+
bounded: boolean;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* The import-cost probe: `-X importtime` under the coreutils wrapper, or the
|
|
114
|
+
* equivalent env var when the bound has to come from inside the interpreter.
|
|
115
|
+
* Measured: both produce the same `import time: ... imported package` profile.
|
|
116
|
+
*/
|
|
117
|
+
export declare function pythonImportProbe(input: PerfProbeInput, moduleName: string): {
|
|
118
|
+
command: string;
|
|
119
|
+
bounded: boolean;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Render the probe section for the prompt. Returns '' when there is nothing to
|
|
123
|
+
* probe, which is what keeps such a turn byte-identical to a build without this.
|
|
124
|
+
*
|
|
125
|
+
* Deliberately SHORT and imperative: three measurements, the boundary of each, and
|
|
126
|
+
* the rule for a platform that forbids one. It is not a methodology essay — the
|
|
127
|
+
* model already has rules 1, 3 and 9 for how to report.
|
|
128
|
+
*/
|
|
129
|
+
export declare function buildPerfProbeBlock(input: PerfProbeInput): string;
|
|
130
|
+
/**
|
|
131
|
+
* Detect what this project can be probed for.
|
|
132
|
+
*
|
|
133
|
+
* Deliberately shallow and cheap: two files read, one directory listing. The
|
|
134
|
+
* Python module name comes from `pyproject.toml`, else from a top-level package
|
|
135
|
+
* directory that has an `__init__.py` (the importable shape). The Node entry comes
|
|
136
|
+
* from `package.json`'s `main`, else its first `bin`. Best-effort by contract: any
|
|
137
|
+
* failure yields `runtime: 'none'`.
|
|
138
|
+
*/
|
|
139
|
+
export declare function detectPerfProbeInput(dir: string, facts?: MachineFacts): PerfProbeInput;
|
|
140
|
+
//# sourceMappingURL=perf-probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf-probe.d.ts","sourceRoot":"","sources":["../../src/learning/perf-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AAKH,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE3E,8EAA8E;AAC9E,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,WAAW,CAAC;IACrB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wFAAwF;IACxF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,cAAc,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;CACzC;AAED,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,8EAA8E;AAC9E,eAAO,MAAM,eAAe,KAAK,CAAC;AAMlC;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAW5F;AASD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAWzG;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,EACrB,UAAU,EAAE,MAAM,GACjB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAgBvC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CA+DjE;AAaD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,YAAY,GAAG,cAAc,CA4FtF"}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PERF PROBE — name the three measurements an assessment is allowed to be silent
|
|
3
|
+
* about, and the exact bounded command for each.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS (R12, the head-to-head audit, 2026-10-16). Startup time, memory
|
|
6
|
+
* and throughput were the ONE class of claim NOBODY measured: the report that
|
|
7
|
+
* compared the two agents lists them as UNMEASURED on both sides, and on the
|
|
8
|
+
* repository under review every finding about them was an inference. A gap that
|
|
9
|
+
* both sides share is not a fair comparison — it is a blind spot in the rubric,
|
|
10
|
+
* and it is the cheapest one to close because the measurements are mechanical.
|
|
11
|
+
*
|
|
12
|
+
* THE THREE MEASUREMENTS, and why these three:
|
|
13
|
+
*
|
|
14
|
+
* 1. IMPORT / COLD-START COST — the import profiler, which names the individual
|
|
15
|
+
* expensive imports rather than one aggregate number. For a desktop app this
|
|
16
|
+
* is the user-visible "it takes N seconds to open".
|
|
17
|
+
* 2. PEAK ALLOCATION — `tracemalloc`. Stated honestly: it traces PYTHON
|
|
18
|
+
* allocations and does NOT see a native/CUDA/driver allocation, so a probe
|
|
19
|
+
* reporting 40 MB for a model loader is not a bug in the probe — it is the
|
|
20
|
+
* boundary of what this measurement can see, and the block says so.
|
|
21
|
+
* 3. WALL CLOCK OF THE HEAVIEST REALISTIC OPERATION — the one number a user
|
|
22
|
+
* actually feels. Deliberately NOT templated with a guessed input: the
|
|
23
|
+
* command is the project's own entry point or e2e script, because a
|
|
24
|
+
* synthetic input measures the synthetic input.
|
|
25
|
+
*
|
|
26
|
+
* EVERY TEMPLATE HERE WAS MEASURED AGAINST A REAL MACHINE, and two of the first
|
|
27
|
+
* drafts were wrong because of it:
|
|
28
|
+
*
|
|
29
|
+
* - `timeout` is ABSENT on macOS and `gtimeout` is not installed by default, so
|
|
30
|
+
* a template that assumed GNU `timeout` emitted commands that fail on the
|
|
31
|
+
* machine this was written on. The bound is therefore chosen from what the
|
|
32
|
+
* host HAS: the coreutils wrapper when present, else the interpreter's own
|
|
33
|
+
* `signal.alarm` — which is a real bound, not a comment (measured: the process
|
|
34
|
+
* is killed, and nothing after the alarm prints).
|
|
35
|
+
* - `python` is ABSENT on macOS too (only `python3` exists), so the interpreter
|
|
36
|
+
* name is detected rather than assumed. A probe block whose commands do not
|
|
37
|
+
* run is worse than no probe block, because it reads as one that ran.
|
|
38
|
+
*
|
|
39
|
+
* THE IMPORT PROFILER IS REACHED TWO WAYS for the same reason: `-X importtime`
|
|
40
|
+
* when the wrapper can bound the whole command, and `PYTHONPROFILEIMPORTTIME=1`
|
|
41
|
+
* when the bound has to come from inside the interpreter (so the `-X` flag has to
|
|
42
|
+
* give way to the env var). Measured: the env var produces the same profile.
|
|
43
|
+
*
|
|
44
|
+
* HARD TIMEOUTS, OR AN HONEST REFUSAL. When neither mechanism exists (Windows, in
|
|
45
|
+
* practice) the command is emitted UNBOUNDED and the block states plainly that the
|
|
46
|
+
* bound must come from the operator and that an unbound number is tagged
|
|
47
|
+
* UNMEASURED — the discipline rules 3 and 9 already apply to hang claims, moved
|
|
48
|
+
* one step earlier, to the place the numbers come from.
|
|
49
|
+
*
|
|
50
|
+
* WHY IT ONLY NAMES COMMANDS AND NEVER RUNS THEM — same reason as
|
|
51
|
+
* `self-check-discovery.ts`: these run the project's own code, which is exactly
|
|
52
|
+
* the thing that must pass the normal tool gate. Naming the command keeps the run
|
|
53
|
+
* as one consented tool call with a stated timeout; executing it here would hand
|
|
54
|
+
* any cloned repository arbitrary code execution at prompt-assembly time. This
|
|
55
|
+
* module is READ-ONLY over the filesystem, by design.
|
|
56
|
+
*
|
|
57
|
+
* DETERMINISTIC AND LLM-FREE, like everything else in `learning/`: no model
|
|
58
|
+
* decides what a project's startup cost is. Detection that finds nothing to probe
|
|
59
|
+
* yields an EMPTY string, so that turn's prompt is byte-identical to a build
|
|
60
|
+
* without this module.
|
|
61
|
+
*/
|
|
62
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
63
|
+
import { delimiter, join } from 'node:path';
|
|
64
|
+
import { detectMachineFacts } from './machine-facts.js';
|
|
65
|
+
/** Seconds every emitted probe is bounded to. Long enough for a real import. */
|
|
66
|
+
export const PROBE_TIMEOUT_SECONDS = 60;
|
|
67
|
+
/** Hard cap on rendered probe lines — the block shares the context budget. */
|
|
68
|
+
export const MAX_PROBE_LINES = 26;
|
|
69
|
+
/** The one-line honesty rule, repeated in the block: no bound, no number. */
|
|
70
|
+
const UNMEASURED_RULE = 'If a number cannot be produced on this machine, tag it `UNMEASURED` and name the platform constraint — never estimate it.';
|
|
71
|
+
/**
|
|
72
|
+
* A module name that is safe to place inside a shell template. The name is
|
|
73
|
+
* derived from the REPOSITORY (a `pyproject.toml` field or a directory name), and
|
|
74
|
+
* a template that interpolates repo-controlled text into a shell command is an
|
|
75
|
+
* injection the harness would be performing on the user's behalf. Anything outside
|
|
76
|
+
* the identifier charset is dropped; an empty result means "no probe".
|
|
77
|
+
*/
|
|
78
|
+
export function safeIdentifier(name) {
|
|
79
|
+
return String(name ?? '').replace(/[^A-Za-z0-9_.-]/g, '');
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* A repo-relative path safe inside a shell template — same reasoning as
|
|
83
|
+
* {@link safeIdentifier}, with `/` allowed. Quotes, backticks, `$` and newlines
|
|
84
|
+
* are refused outright rather than escaped, because a legitimate entry path never
|
|
85
|
+
* contains them.
|
|
86
|
+
*/
|
|
87
|
+
export function safeRelativePath(p) {
|
|
88
|
+
const value = String(p ?? '').trim().replace(/^\.\//, '');
|
|
89
|
+
return /^[A-Za-z0-9_./@\- ]+$/.test(value) ? value : '';
|
|
90
|
+
}
|
|
91
|
+
/** Does this executable exist anywhere on PATH? (Never spawns a process.) */
|
|
92
|
+
export function executableOnPath(name, env = process.env) {
|
|
93
|
+
if (!name)
|
|
94
|
+
return false;
|
|
95
|
+
const dirs = (env.PATH || '').split(delimiter).filter(Boolean);
|
|
96
|
+
for (const dir of dirs) {
|
|
97
|
+
try {
|
|
98
|
+
if (existsSync(join(dir, name)))
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// An unreadable PATH entry tells us nothing — keep looking.
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
/** `[project] name` from a pyproject.toml, without a TOML parser. */
|
|
108
|
+
function pythonNameFromToml(text) {
|
|
109
|
+
const section = /\[project\]([\s\S]*?)(?:\n\[|$)/.exec(text)?.[1] ?? '';
|
|
110
|
+
const name = /^\s*name\s*=\s*["']([^"']+)["']/m.exec(section)?.[1] ?? '';
|
|
111
|
+
return name.trim();
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A python one-liner, bounded by the best mechanism this host has.
|
|
115
|
+
*
|
|
116
|
+
* Returns `bounded: false` only when there is genuinely no way to bound it, and
|
|
117
|
+
* the caller then refuses to present the probe as if it were safe.
|
|
118
|
+
*/
|
|
119
|
+
export function pythonProbe(input, program) {
|
|
120
|
+
const py = safeIdentifier(input.pythonCommand || 'python');
|
|
121
|
+
if (input.timeoutCommand) {
|
|
122
|
+
return { command: `${input.timeoutCommand} ${PROBE_TIMEOUT_SECONDS} ${py} -c "${program}"`, bounded: true };
|
|
123
|
+
}
|
|
124
|
+
if (input.platform !== 'win32') {
|
|
125
|
+
// The interpreter's own alarm — a real bound, and the reason the probe works
|
|
126
|
+
// at all on a machine without coreutils (measured on macOS: it kills the run).
|
|
127
|
+
return { command: `${py} -c "import signal; signal.alarm(${PROBE_TIMEOUT_SECONDS}); ${program}"`, bounded: true };
|
|
128
|
+
}
|
|
129
|
+
return { command: `${py} -c "${program}"`, bounded: false };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The import-cost probe: `-X importtime` under the coreutils wrapper, or the
|
|
133
|
+
* equivalent env var when the bound has to come from inside the interpreter.
|
|
134
|
+
* Measured: both produce the same `import time: ... imported package` profile.
|
|
135
|
+
*/
|
|
136
|
+
export function pythonImportProbe(input, moduleName) {
|
|
137
|
+
const py = safeIdentifier(input.pythonCommand || 'python');
|
|
138
|
+
const mod = safeIdentifier(moduleName);
|
|
139
|
+
if (input.timeoutCommand) {
|
|
140
|
+
return {
|
|
141
|
+
command: `${input.timeoutCommand} ${PROBE_TIMEOUT_SECONDS} ${py} -X importtime -c "import ${mod}" 2>&1 | tail -15`,
|
|
142
|
+
bounded: true,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (input.platform !== 'win32') {
|
|
146
|
+
return {
|
|
147
|
+
command: `PYTHONPROFILEIMPORTTIME=1 ${py} -c "import signal; signal.alarm(${PROBE_TIMEOUT_SECONDS}); import ${mod}" 2>&1 | tail -15`,
|
|
148
|
+
bounded: true,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return { command: `${py} -X importtime -c "import ${mod}" 2>&1 | tail -15`, bounded: false };
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Render the probe section for the prompt. Returns '' when there is nothing to
|
|
155
|
+
* probe, which is what keeps such a turn byte-identical to a build without this.
|
|
156
|
+
*
|
|
157
|
+
* Deliberately SHORT and imperative: three measurements, the boundary of each, and
|
|
158
|
+
* the rule for a platform that forbids one. It is not a methodology essay — the
|
|
159
|
+
* model already has rules 1, 3 and 9 for how to report.
|
|
160
|
+
*/
|
|
161
|
+
export function buildPerfProbeBlock(input) {
|
|
162
|
+
if (input.runtime === 'none')
|
|
163
|
+
return '';
|
|
164
|
+
const lines = [
|
|
165
|
+
'',
|
|
166
|
+
'## Performance probes — this class of claim went UNMEASURED last time',
|
|
167
|
+
'Every performance claim ("slow to start", "eats memory", "takes forever")',
|
|
168
|
+
'needs one of these numbers, produced by the command beside it:',
|
|
169
|
+
'',
|
|
170
|
+
];
|
|
171
|
+
let unbounded = false;
|
|
172
|
+
if (input.runtime === 'python') {
|
|
173
|
+
const mod = safeIdentifier(input.pythonModule || '');
|
|
174
|
+
const named = mod ? `\`${mod}\`` : 'the project\'s top-level package';
|
|
175
|
+
const importProbe = pythonImportProbe(input, mod || 'PACKAGE');
|
|
176
|
+
const memProbe = pythonProbe(input, `import tracemalloc; tracemalloc.start(); import ${mod || 'PACKAGE'}; cur, peak = tracemalloc.get_traced_memory(); print(f'peak {peak/1e6:.1f} MB python-alloc')`);
|
|
177
|
+
unbounded = !importProbe.bounded || !memProbe.bounded;
|
|
178
|
+
lines.push(`- Cold import cost of ${named}: \`${importProbe.command}\``, `- Peak PYTHON allocation: \`${memProbe.command}\``, ' (tracemalloc sees Python allocations only — a native/CUDA allocation is', ' outside it. Report that boundary rather than calling the number total.)', input.timeoutCommand
|
|
179
|
+
? `- Wall clock of the heaviest realistic operation: the project's own entry point or e2e script, run as \`${input.timeoutCommand} ${PROBE_TIMEOUT_SECONDS} python <its-own-entry>\`.`
|
|
180
|
+
: `- Wall clock of the heaviest realistic operation: the project's own entry point or e2e script, and bound it yourself.`);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
const entry = safeRelativePath(input.nodeEntry || '');
|
|
184
|
+
const named = entry ? `\`${entry}\`` : 'the project\'s own main entry';
|
|
185
|
+
const startProbe = entry
|
|
186
|
+
? pythonProbeStyleNode(input, entry)
|
|
187
|
+
: { command: 'node <the project\'s entry>', bounded: false };
|
|
188
|
+
unbounded = !startProbe.bounded;
|
|
189
|
+
const wrap = input.timeoutCommand ? `${input.timeoutCommand} ${PROBE_TIMEOUT_SECONDS} ` : '';
|
|
190
|
+
const rss = input.nativePerfTool === 'bsd'
|
|
191
|
+
? `\`${wrap}/usr/bin/time -l node ${entry || '<entry>'} 2>&1 | grep -i "maximum resident" | tail -2\``
|
|
192
|
+
: input.nativePerfTool === 'gnu'
|
|
193
|
+
? `\`${wrap}/usr/bin/time -v node ${entry || '<entry>'} 2>&1 | grep -i "maximum resident" | tail -2\``
|
|
194
|
+
: 'no `/usr/bin/time` on this platform — tag it `UNMEASURED`.';
|
|
195
|
+
lines.push(`- Cold require / startup of ${named}: \`${startProbe.command}\``, `- Peak RSS: ${rss}`, '- Wall clock of the heaviest realistic operation: the project\'s own largest', ' command or test, bounded the same way.');
|
|
196
|
+
}
|
|
197
|
+
if (unbounded) {
|
|
198
|
+
lines.push('', `No \`timeout\`/\`gtimeout\` on this machine and no interpreter-side bound`, `available, so the commands above are bounded only by you: if one has not`, `finished in ~${PROBE_TIMEOUT_SECONDS} s, interrupt it and tag the measurement UNMEASURED.`, `Do not report a number you had to kill to get.`);
|
|
199
|
+
}
|
|
200
|
+
lines.push('', UNMEASURED_RULE, 'Report each number next to the command that produced it.');
|
|
201
|
+
return lines.slice(0, MAX_PROBE_LINES).join('\n');
|
|
202
|
+
}
|
|
203
|
+
/** The node cold-require one-liner, bounded where the host allows (no Windows path). */
|
|
204
|
+
function pythonProbeStyleNode(input, entry) {
|
|
205
|
+
const program = `const t = Date.now(); require('./${entry}'); console.log((Date.now() - t) + ' ms cold require')`;
|
|
206
|
+
if (input.timeoutCommand) {
|
|
207
|
+
return { command: `${input.timeoutCommand} ${PROBE_TIMEOUT_SECONDS} node -e "${program}"`, bounded: true };
|
|
208
|
+
}
|
|
209
|
+
// No coreutils and no interpreter alarm for node: node's own `--eval` has no
|
|
210
|
+
// watchdog flag, so the bound is the caller's. Stated, not hidden.
|
|
211
|
+
return { command: `node -e "${program}"`, bounded: false };
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Detect what this project can be probed for.
|
|
215
|
+
*
|
|
216
|
+
* Deliberately shallow and cheap: two files read, one directory listing. The
|
|
217
|
+
* Python module name comes from `pyproject.toml`, else from a top-level package
|
|
218
|
+
* directory that has an `__init__.py` (the importable shape). The Node entry comes
|
|
219
|
+
* from `package.json`'s `main`, else its first `bin`. Best-effort by contract: any
|
|
220
|
+
* failure yields `runtime: 'none'`.
|
|
221
|
+
*/
|
|
222
|
+
export function detectPerfProbeInput(dir, facts) {
|
|
223
|
+
const machine = facts ?? detectMachineFacts();
|
|
224
|
+
const platform = machine.platform;
|
|
225
|
+
const timeoutCommand = executableOnPath('timeout') ? 'timeout' : executableOnPath('gtimeout') ? 'gtimeout' : '';
|
|
226
|
+
const pythonCommand = executableOnPath('python') ? 'python' : executableOnPath('python3') ? 'python3' : 'python';
|
|
227
|
+
const nativePerfTool = platform === 'darwin' ? 'bsd' : platform === 'linux' && existsSync('/usr/bin/time') ? 'gnu' : 'none';
|
|
228
|
+
const base = { timeoutCommand, platform, pythonCommand, nativePerfTool };
|
|
229
|
+
if (!dir)
|
|
230
|
+
return { runtime: 'none', ...base };
|
|
231
|
+
try {
|
|
232
|
+
if (!existsSync(dir) || !statSync(dir).isDirectory())
|
|
233
|
+
return { runtime: 'none', ...base };
|
|
234
|
+
// ── Python ────────────────────────────────────────────────────────────────
|
|
235
|
+
let pythonModule = '';
|
|
236
|
+
const pyproject = join(dir, 'pyproject.toml');
|
|
237
|
+
if (existsSync(pyproject)) {
|
|
238
|
+
try {
|
|
239
|
+
pythonModule = pythonNameFromToml(readFileSync(pyproject, 'utf8'));
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// Unreadable pyproject — fall through to the directory heuristic.
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (!pythonModule) {
|
|
246
|
+
try {
|
|
247
|
+
const packages = readdirSync(dir, { withFileTypes: true })
|
|
248
|
+
.filter((e) => e.isDirectory() &&
|
|
249
|
+
!e.name.startsWith('.') &&
|
|
250
|
+
!/^(tests?|docs?|build|dist|node_modules|venv|\.venv)$/i.test(e.name))
|
|
251
|
+
.map((e) => e.name)
|
|
252
|
+
.filter((name) => existsSync(join(dir, name, '__init__.py')))
|
|
253
|
+
.sort((a, b) => a.localeCompare(b));
|
|
254
|
+
if (packages.length > 0)
|
|
255
|
+
pythonModule = packages[0];
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// Unreadable directory — no python module.
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// ── Node ─────────────────────────────────────────────────────────────────
|
|
262
|
+
let nodeEntry = '';
|
|
263
|
+
const pkgPath = join(dir, 'package.json');
|
|
264
|
+
if (existsSync(pkgPath)) {
|
|
265
|
+
try {
|
|
266
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
267
|
+
if (typeof pkg.main === 'string' && pkg.main.trim())
|
|
268
|
+
nodeEntry = pkg.main.trim();
|
|
269
|
+
else if (typeof pkg.bin === 'string' && pkg.bin.trim())
|
|
270
|
+
nodeEntry = pkg.bin.trim();
|
|
271
|
+
else if (pkg.bin && typeof pkg.bin === 'object') {
|
|
272
|
+
const first = Object.keys(pkg.bin).sort((a, b) => a.localeCompare(b))[0];
|
|
273
|
+
if (first)
|
|
274
|
+
nodeEntry = String(pkg.bin[first]);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
// Malformed package.json — not a probe candidate.
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// WHICH RUNTIME IS THIS PROJECT'S. A top-level directory holding an
|
|
282
|
+
// `__init__.py` is NOT enough on its own: measured on this very repository,
|
|
283
|
+
// a stray fixture directory (`addon/__init__.py`) made a TypeScript project
|
|
284
|
+
// probe as Python, and the block would have told the model to time the import
|
|
285
|
+
// of a directory that is not the shipped program. Python therefore needs a
|
|
286
|
+
// PROJECT MARKER behind it — the same discipline `self-check-discovery.ts`
|
|
287
|
+
// applies before it calls something a check. A Python project that also has
|
|
288
|
+
// Node tooling is probed as Python: the runtime whose startup a user waits on
|
|
289
|
+
// is what matters, and a desktop app's is Python.
|
|
290
|
+
let hasPythonMarker = false;
|
|
291
|
+
for (const marker of ['pyproject.toml', 'setup.py', 'setup.cfg', 'Pipfile']) {
|
|
292
|
+
if (existsSync(join(dir, marker)))
|
|
293
|
+
hasPythonMarker = true;
|
|
294
|
+
}
|
|
295
|
+
if (!hasPythonMarker) {
|
|
296
|
+
try {
|
|
297
|
+
hasPythonMarker = readdirSync(dir).some((n) => /^requirements.*\.txt$/i.test(n));
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
// Unreadable directory — no marker.
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const safeModule = safeIdentifier(pythonModule);
|
|
304
|
+
const safeEntry = safeRelativePath(nodeEntry);
|
|
305
|
+
if (safeModule && (hasPythonMarker || !safeEntry)) {
|
|
306
|
+
return { runtime: 'python', pythonModule: safeModule, ...base };
|
|
307
|
+
}
|
|
308
|
+
if (safeEntry)
|
|
309
|
+
return { runtime: 'node', nodeEntry: safeEntry, ...base };
|
|
310
|
+
return { runtime: 'none', ...base };
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
return { runtime: 'none', ...base };
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
//# sourceMappingURL=perf-probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf-probe.js","sourceRoot":"","sources":["../../src/learning/perf-probe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SELF-CHECK DISCOVERY — name the project's OWN checks on an assessment turn.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS (the side-by-side audit, 2026-10-16). On an audit of a Python
|
|
5
|
+
* desktop app (`/Users/dheeraj/Documents/anuj_voice`, 60 modules) this CLI read
|
|
6
|
+
* the right modules, measured two real bugs, and still missed three findings
|
|
7
|
+
* that the other agent found — because it never RAN the repository's own
|
|
8
|
+
* tooling. The tree contained `tools/dead_code_audit.py` (an unreachable-code
|
|
9
|
+
* auditor, clean) and `tools/winget_validate.py` (a packaging-compliance
|
|
10
|
+
* checker, which is what reported the shipped manifest defect its test suite
|
|
11
|
+
* had been failing on). This CLI's plan mentioned `tools/` in its notes and
|
|
12
|
+
* never executed either one.
|
|
13
|
+
*
|
|
14
|
+
* That is a pure capability gap, and it is the cheapest kind to close: the
|
|
15
|
+
* project has already declared its own checks in files the agent can read, and
|
|
16
|
+
* running a check the repository itself ships produces evidence whose
|
|
17
|
+
* PROVENANCE the agent cannot fabricate. A finding that says "the project's own
|
|
18
|
+
* auditor reports X" costs one tool call and cannot be a hallucination.
|
|
19
|
+
*
|
|
20
|
+
* WHY THIS ONLY NAMES COMMANDS AND NEVER RUNS THEM. A repository's declared
|
|
21
|
+
* scripts are arbitrary code. Executing them because a prompt block suggested
|
|
22
|
+
* it would hand a cloned repository's `package.json` the ability to run
|
|
23
|
+
* anything of its choosing at audit time, with no gate and no consent — the
|
|
24
|
+
* exact class of surprise the write/shell gates exist to prevent. Naming the
|
|
25
|
+
* command keeps the decision where it belongs: the model proposes the run
|
|
26
|
+
* through the normal terminal tool, which keeps its own confirmation and
|
|
27
|
+
* sandbox rules. This module is READ-ONLY over the filesystem, by design.
|
|
28
|
+
*
|
|
29
|
+
* WHY IT IS BOUNDED, AND WHY THE CAP IS RANKED RATHER THAN ALPHABETICAL. The
|
|
30
|
+
* output is prompt text that competes with the actual file tree for the context
|
|
31
|
+
* budget, so it is capped (MAX_CHECKS) and the walk is depth-1 over known
|
|
32
|
+
* directories rather than a recursive scan. But a purely alphabetical cap is
|
|
33
|
+
* WRONG, and the audited project proves it: its `tools/` directory holds ~30
|
|
34
|
+
* scripts whose names start `a11y_`, so an alphabetical list of ten filled up
|
|
35
|
+
* before it ever reached `tools/winget_validate.py` — the checker whose output
|
|
36
|
+
* WAS the release defect the assessment missed. Ordering is therefore by
|
|
37
|
+
* RELEVANCE first (a name that says check/audit/validate/verify/lint/test…, and
|
|
38
|
+
* the project's own test suite) and alphabetical only as the tie-break inside
|
|
39
|
+
* each tier. Deterministic still, and stable across turns; just not arbitrary.
|
|
40
|
+
*
|
|
41
|
+
* WHY THE SUITE OUTRANKS LOOSE SCRIPTS. `pytest` / `npm test` is the check the
|
|
42
|
+
* project itself runs before shipping, and a directory of helper scripts is not.
|
|
43
|
+
* A cap that lets thirty utility scripts displace the test suite would give the
|
|
44
|
+
* agent the weakest evidence first.
|
|
45
|
+
*
|
|
46
|
+
* WHY IT IS DETERMINISTICALLY ORDERED. Same reason the tree walk is: a block
|
|
47
|
+
* whose contents reorder between turns breaks the prompt cache, and the whole
|
|
48
|
+
* point of an ambient block is that it is stable across the turns of one task.
|
|
49
|
+
*
|
|
50
|
+
* DETERMINISTIC AND LLM-FREE, like everything else in `learning/`: it decides
|
|
51
|
+
* from the filesystem, not from a model's idea of what a project "usually"
|
|
52
|
+
* has. A project with no discoverable checks yields an EMPTY string, so its
|
|
53
|
+
* turn is byte-identical to one from a build without this module.
|
|
54
|
+
*/
|
|
55
|
+
/** One command the project itself declares, and where it was declared. */
|
|
56
|
+
export interface SelfCheck {
|
|
57
|
+
/** The command to run, exactly as the project declares or ships it. */
|
|
58
|
+
command: string;
|
|
59
|
+
/** Where it came from (`package.json scripts`, `tools/`, CI…). */
|
|
60
|
+
source: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Everything the discovery needs, so the matching rules can be unit-tested
|
|
64
|
+
* with no filesystem at all. {@link readProjectSelfChecks} is the thin I/O
|
|
65
|
+
* wrapper that fills this in from a real directory.
|
|
66
|
+
*/
|
|
67
|
+
export interface SelfCheckInput {
|
|
68
|
+
/** `package.json` `scripts`, as declared. */
|
|
69
|
+
packageScripts?: Record<string, string>;
|
|
70
|
+
/** The package manager the repo uses — decides `npm run` vs `pnpm run` … */
|
|
71
|
+
packageManager?: string;
|
|
72
|
+
/** Repo-relative paths of the project's own tooling files (`tools/audit.py`). */
|
|
73
|
+
toolFiles?: string[];
|
|
74
|
+
/** Repo-relative paths of CI workflow files. */
|
|
75
|
+
ciWorkflows?: string[];
|
|
76
|
+
/** Repo-relative paths of top-level runner files (`Makefile`, `justfile`). */
|
|
77
|
+
markerFiles?: string[];
|
|
78
|
+
/** Makefile target names, already parsed (see {@link parseMakeTargets}). */
|
|
79
|
+
makeTargets?: string[];
|
|
80
|
+
/** Does a `tests/` tree with `test_*.py` files exist? */
|
|
81
|
+
hasPythonTests?: boolean;
|
|
82
|
+
}
|
|
83
|
+
/** Hard cap on the rendered list — the block shares the context budget. */
|
|
84
|
+
export declare const MAX_CHECKS = 10;
|
|
85
|
+
/**
|
|
86
|
+
* Makefile target names — the `name:` lines at the start of a line, excluding
|
|
87
|
+
* the special targets (`%`, `.PHONY`) and any name carrying a `=`/`$` (a
|
|
88
|
+
* variable assignment, not a target).
|
|
89
|
+
*/
|
|
90
|
+
export declare function parseMakeTargets(text: string): string[];
|
|
91
|
+
/**
|
|
92
|
+
* Turn a project's declared facts into an ordered, capped list of checks.
|
|
93
|
+
*
|
|
94
|
+
* Order is by SOURCE (scripts, then Make targets, then the shipped tools, then
|
|
95
|
+
* CI) and then alphabetically inside each source — stable across turns, and
|
|
96
|
+
* "the things the project officially declares" ahead of "the loose scripts in
|
|
97
|
+
* a folder", because the declared ones are the ones its own CI actually runs.
|
|
98
|
+
*/
|
|
99
|
+
export declare function discoverSelfChecks(input: SelfCheckInput): SelfCheck[];
|
|
100
|
+
/**
|
|
101
|
+
* Read a directory and discover its checks. Best-effort by contract: any
|
|
102
|
+
* failure (unreadable directory, malformed `package.json`, a race with a
|
|
103
|
+
* concurrent write) yields an empty list, never a throw — an ambient context
|
|
104
|
+
* must not be able to break a turn.
|
|
105
|
+
*/
|
|
106
|
+
export declare function readProjectSelfChecks(dir: string): SelfCheck[];
|
|
107
|
+
/**
|
|
108
|
+
* Render the checks as the prompt section the assessment protocol appends.
|
|
109
|
+
* Returns '' for an empty list, which is what keeps a project with no
|
|
110
|
+
* discoverable checks byte-identical to a build without this module.
|
|
111
|
+
*
|
|
112
|
+
* The wording carries the two rules the audit proved were missing: run these
|
|
113
|
+
* BEFORE concluding, and treat their output as the strongest evidence in the
|
|
114
|
+
* report — with the provenance named, so a reader can re-run it.
|
|
115
|
+
*/
|
|
116
|
+
export declare function buildSelfCheckBlock(checks: SelfCheck[]): string;
|
|
117
|
+
//# sourceMappingURL=self-check-discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self-check-discovery.d.ts","sourceRoot":"","sources":["../../src/learning/self-check-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAKH,0EAA0E;AAC1E,MAAM,WAAW,SAAS;IACxB,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,yDAAyD;IACzD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAwCD,2EAA2E;AAC3E,eAAO,MAAM,UAAU,KAAK,CAAC;AAuB7B;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAQvD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,SAAS,EAAE,CA0DrE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CAqG9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAkB/D"}
|