bareloop 0.5.1 → 0.7.0
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/CHANGELOG.md +1129 -1
- package/README.md +40 -13
- package/bareloop.context.md +799 -245
- package/package.json +3 -3
- package/src/bridges.js +571 -0
- package/src/clock.js +233 -0
- package/src/exits.js +8 -2
- package/src/index.js +52 -17
- package/src/job.js +231 -108
- package/src/ladder.js +196 -0
- package/src/ledger.js +55 -3
- package/src/plan.js +334 -20
- package/src/planrun.js +1519 -134
- package/src/ralph.js +373 -34
- package/src/reuse.js +1602 -0
- package/src/root.js +32 -12
- package/src/run.js +129 -391
- package/src/selection.js +160 -0
- package/src/spine.js +7 -2
- package/src/stall.js +252 -0
- package/src/tools.js +611 -0
- package/src/trend.js +405 -0
- package/src/validate.js +35 -250
- package/types/bridges.d.ts +198 -0
- package/types/clock.d.ts +131 -0
- package/types/index.d.ts +7 -6
- package/types/job.d.ts +83 -8
- package/types/ladder.d.ts +86 -0
- package/types/ledger.d.ts +3 -1
- package/types/plan.d.ts +86 -7
- package/types/planrun.d.ts +142 -5
- package/types/ralph.d.ts +143 -7
- package/types/reuse.d.ts +388 -0
- package/types/root.d.ts +10 -2
- package/types/run.d.ts +56 -17
- package/types/selection.d.ts +46 -0
- package/types/spine.d.ts +8 -1
- package/types/stall.d.ts +80 -0
- package/types/tools.d.ts +262 -0
- package/types/trend.d.ts +108 -0
- package/types/validate.d.ts +21 -38
- package/src/extract.js +0 -103
- package/src/interpret.js +0 -887
- package/types/extract.d.ts +0 -25
- package/types/interpret.d.ts +0 -201
package/types/run.d.ts
CHANGED
|
@@ -27,32 +27,68 @@
|
|
|
27
27
|
* @param {object} opts
|
|
28
28
|
* @param {unknown} opts.approvals `{ specHash, signer, ts }` records (from OUTSIDE the spec)
|
|
29
29
|
* @param {string} opts.workdir the run directory (the fence's root)
|
|
30
|
-
* @param {string} [opts.target] the step artifact path (text-mode steps; unused by tool-mode steps)
|
|
31
30
|
* @param {any} opts.provider shell-owned LLM binding (never the config's; the Loop path)
|
|
32
31
|
* @param {(o: {policy: Function, onTurn?: Function, maxTurns: number, hasTools: boolean}) => any} [opts.nativeProvider]
|
|
33
32
|
* native clipipe provider factory (BA-16), required for a `clipipe-subscription` plan-shape job —
|
|
34
33
|
* threaded to runPlan, which builds one per worker (native tool mode when `hasTools`, else a
|
|
35
34
|
* metered claude-json text provider for the toolless drafter); ignored on every Loop-driven provider
|
|
36
35
|
* @param {(type: string, data?: object) => object} opts.emit spine emitter
|
|
37
|
-
* @param {
|
|
36
|
+
* @param {(tier: string) => any} [opts.providerFor] P: per-step model-tier provider factory (forwarded to the plan flow)
|
|
37
|
+
* @param {number} [opts.capRuns] shell-owned iteration cap for the plan flow's
|
|
38
|
+
* CLOSE-FIX loop (a plan STEP runs under the strike ladder instead)
|
|
39
|
+
* @param {number} [opts.strikeLimit] shell-owned strike ceiling for a plan step's ladder
|
|
38
40
|
* @param {number} [opts.shellCapUsd] the shell's hard USD ceiling
|
|
39
41
|
* @param {number} [opts.closeTimeoutMs] close wall-clock cap (shell territory)
|
|
40
|
-
* @param {
|
|
42
|
+
* @param {unknown} [opts.bridge] Layer 3 — a bridge-v1 entry to reuse as the drafter's
|
|
43
|
+
* STARTING DRAFT (design record 2026-08-01, D4), forwarded to the plan flow. Omitted is
|
|
44
|
+
* the cold path and is byte-identical to a pre-Layer-3 run. WHICH entry (the listing, an
|
|
45
|
+
* operator pin, the LLM's pick) is the caller's decision, and so is what to do when the
|
|
46
|
+
* load gate refuses one: a refusal returns the distinct `recipe-stale` outcome with zero
|
|
47
|
+
* spend rather than silently drafting cold, because starting a paid run on a decision
|
|
48
|
+
* nobody made is the same class of error as widening a cap to manufacture a green.
|
|
49
|
+
* @param {number} [opts.priorSpentUsd=0] RESUME (module C) — money a PREVIOUS, killed
|
|
50
|
+
* attempt of this same try already spent. It seeds the ledger, so the restarted
|
|
51
|
+
* attempt runs under the REMAINDER of the signed `budgetUsd` and the terminal
|
|
52
|
+
* `job-end` states the try's WHOLE spend across both attempts. hamr's ruling: "a
|
|
53
|
+
* budget ceiling folds in prior spend so re-invoking cannot silently widen it" —
|
|
54
|
+
* the fold is the seam precisely because the CAP is in the spec hash, so
|
|
55
|
+
* tightening the cap instead would make a new spec version needing a signature
|
|
56
|
+
* nobody typed. The caller reconstructs the figure from the dead run's own spine.
|
|
57
|
+
* @param {boolean} [opts.priorSpendComplete=true] RESUME — was that fold EXACT?
|
|
58
|
+
* `readResume` reports false when any round inside the dead attempt came back
|
|
59
|
+
* unpriced, which makes the fold a FLOOR. The unknown does not heal by being carried
|
|
60
|
+
* forward, so it rides one-way onto every `job-end` this run emits: a total built on
|
|
61
|
+
* a floor is a floor, and reporting it as exact is F6 in a resume's coat.
|
|
62
|
+
* @param {number} [opts.priorWallMs=0] RESUME — the same ruling in a time coat: wall
|
|
63
|
+
* time the killed attempt already consumed, folded into the run clock so the
|
|
64
|
+
* restart gets the remainder of the SIGNED wall, never a fresh allotment.
|
|
65
|
+
* @param {any} [opts.resumeSeed] RESUME (module C v2) — WHERE inside the killed attempt
|
|
66
|
+
* the kill landed, read off its own spine by `readResume`: the plan it accepted and the
|
|
67
|
+
* steps that reached their exits. Forwarded verbatim to the plan flow, which reloads
|
|
68
|
+
* the plan instead of re-scouting and re-drafting, and skips the finished steps.
|
|
69
|
+
* hamr's ruling: *"start last step instead from the beginning, why would i want to
|
|
70
|
+
* waste more money on something i already started"*. Absent is the ordinary path.
|
|
71
|
+
* @param {{stage?: string|null, value?: number|null}[]} [opts.resumeGrades] RESUME — the
|
|
72
|
+
* close grades the killed leg recorded (`readResume`'s `restart.grades`), forwarded to
|
|
73
|
+
* the plan flow as the trend's BASELINES. A resumed run's halt readout judges the whole
|
|
74
|
+
* chain, not just the leg: without them a leg that re-grades an unchanged tree reports
|
|
75
|
+
* `flat` — "revise the goal" — on a run that was converging when the money ran out.
|
|
76
|
+
* Counts and stage names only; no close bytes cross this seam. Absent is the cold path.
|
|
41
77
|
* @param {boolean} [opts.layerRoot=false] Layer R (within-run ratchet) — shell
|
|
42
|
-
* territory, threaded to
|
|
78
|
+
* territory, threaded to the plan flow. Defaults OFF
|
|
43
79
|
* (decided 2026-07-21): fixation is extinct on every current job (F41), so
|
|
44
80
|
* ON has never won its own A/B — the acceptance read defers to Layer 2 (or
|
|
45
81
|
* a manufactured-fixation probe). `true` is the ON/experimental arm; the
|
|
46
82
|
* default is the OFF arm. (Shell-owned seam, same doctrine as the provider
|
|
47
83
|
* binding.)
|
|
48
|
-
* @returns {Promise<string>} outcome: 'green' | '
|
|
49
|
-
* '
|
|
50
|
-
* '
|
|
84
|
+
* @returns {Promise<string>} outcome: 'green' | 'already-green' | 'escalated' |
|
|
85
|
+
* 'unapproved-spec' | 'job-red' | 'smoke-red' | 'plan-red' | 'check-red' |
|
|
86
|
+
* 'close-red' | 'close-unsupported' | 'recipe-stale' | 'pricing-red' | 'provider-red' |
|
|
87
|
+
* 'interpreter-red' | 'cap-halt' | 'wall-halt' | 'step-stalled' | `step-red:<id>`
|
|
51
88
|
*/
|
|
52
|
-
export function runJob(rawSpec: object | string, { approvals, workdir,
|
|
89
|
+
export function runJob(rawSpec: object | string, { approvals, workdir, provider, nativeProvider, providerFor, emit, capRuns, strikeLimit, shellCapUsd, closeTimeoutMs, layerRoot, bridge, priorSpentUsd, priorSpendComplete, priorWallMs, resumeSeed, resumeGrades }: {
|
|
53
90
|
approvals: unknown;
|
|
54
91
|
workdir: string;
|
|
55
|
-
target?: string | undefined;
|
|
56
92
|
provider: any;
|
|
57
93
|
nativeProvider?: ((o: {
|
|
58
94
|
policy: Function;
|
|
@@ -61,10 +97,20 @@ export function runJob(rawSpec: object | string, { approvals, workdir, target, p
|
|
|
61
97
|
hasTools: boolean;
|
|
62
98
|
}) => any) | undefined;
|
|
63
99
|
emit: (type: string, data?: object) => object;
|
|
100
|
+
providerFor?: ((tier: string) => any) | undefined;
|
|
64
101
|
capRuns?: number | undefined;
|
|
102
|
+
strikeLimit?: number | undefined;
|
|
65
103
|
shellCapUsd?: number | undefined;
|
|
66
104
|
closeTimeoutMs?: number | undefined;
|
|
67
|
-
|
|
105
|
+
bridge?: unknown;
|
|
106
|
+
priorSpentUsd?: number | undefined;
|
|
107
|
+
priorSpendComplete?: boolean | undefined;
|
|
108
|
+
priorWallMs?: number | undefined;
|
|
109
|
+
resumeSeed?: any;
|
|
110
|
+
resumeGrades?: {
|
|
111
|
+
stage?: string | null;
|
|
112
|
+
value?: number | null;
|
|
113
|
+
}[] | undefined;
|
|
68
114
|
layerRoot?: boolean | undefined;
|
|
69
115
|
}): Promise<string>;
|
|
70
116
|
export type Red = {
|
|
@@ -72,10 +118,3 @@ export type Red = {
|
|
|
72
118
|
path: string;
|
|
73
119
|
detail?: string;
|
|
74
120
|
};
|
|
75
|
-
export type ExecCmd = (argv: string[], opts?: {
|
|
76
|
-
cwd?: string;
|
|
77
|
-
}) => {
|
|
78
|
-
status: number | null;
|
|
79
|
-
stdout: string;
|
|
80
|
-
stderr: string;
|
|
81
|
-
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D3's listing: what the operator inspects and what the selecting model reads — the SAME
|
|
3
|
+
* text, so the two can never be choosing from different sets.
|
|
4
|
+
*
|
|
5
|
+
* Per bridge, one compact block: name, the job sentence it greened, status, greens/reds
|
|
6
|
+
* with the last outcome, and the cost/time band of its greens.
|
|
7
|
+
*
|
|
8
|
+
* Total and never throws: a listing is a display surface, and one malformed entry must
|
|
9
|
+
* not take the whole listing down (`listingRow` holds the same contract). Deterministic
|
|
10
|
+
* by name, whatever order the entries arrived in — a set that reshuffles between calls
|
|
11
|
+
* would make one picker's answer unreadable against another's.
|
|
12
|
+
*
|
|
13
|
+
* @param {unknown} registry `loadRegistry`'s result (`{ok, reds, bridges}`) or a bare
|
|
14
|
+
* array of entries. The RESULT form is preferred: it carries the skip reds, and the
|
|
15
|
+
* skips are the half a bare array cannot tell you about.
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
export function renderListing(registry: unknown): string;
|
|
19
|
+
/**
|
|
20
|
+
* The SELECT-WORKFLOW prompt: the text a later module sends to ask which workflow (if
|
|
21
|
+
* any) the run should start from. Pure — it sends nothing and parses nothing.
|
|
22
|
+
*
|
|
23
|
+
* D3's two standing rules are IN the prompt rather than enforced after the fact:
|
|
24
|
+
* - *"none matches"* is a first-class answer, and it means the agent drafts new. A picker
|
|
25
|
+
* with no way to decline would return the closest thing on the shelf every time, which
|
|
26
|
+
* is how a registry becomes a lookup table.
|
|
27
|
+
* - a PINNED workflow may be refused **only explicitly, with a reason** — never silently
|
|
28
|
+
* ignored or quietly substituted. The operator's pick is the operator's; overriding it
|
|
29
|
+
* invisibly is the one thing a picker must not be able to do.
|
|
30
|
+
*
|
|
31
|
+
* The output contract is stated so the answer is machine-readable, but the PARSE belongs
|
|
32
|
+
* to the runner that sends this (modules 4/5) — and the runner's parser and this shape are
|
|
33
|
+
* one contract in two places, which is why the shape is spelled out here rather than left
|
|
34
|
+
* to the model.
|
|
35
|
+
*
|
|
36
|
+
* @param {string} listing `renderListing`'s text — verbatim, so the picker sees exactly
|
|
37
|
+
* what the human inspecting the registry sees
|
|
38
|
+
* @param {string} ask the job's goal sentence, in the operator's own words
|
|
39
|
+
* @param {string|null} [pinned] the operator's PIN, stated IN the call. D3 rules that a
|
|
40
|
+
* pin is never bypassed and never silently overridden — so the pin does not skip the
|
|
41
|
+
* call, it enters it, and the model's only legal ways out are confirming it or
|
|
42
|
+
* refusing it by name with a reason. Stated here rather than assembled by the runner:
|
|
43
|
+
* a second spelling of the pin sentence is a second prompt, and the two would drift.
|
|
44
|
+
* @returns {string}
|
|
45
|
+
*/
|
|
46
|
+
export function selectionPrompt(listing: string, ask: string, pinned?: string | null): string;
|
package/types/spine.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Create an emitter bound to one JSONL file.
|
|
3
3
|
* @param {string} file absolute path; created on first emit
|
|
4
|
+
* @param {{startSeq?: number}} [opts] `startSeq`: the last `seq` already IN the file, for a
|
|
5
|
+
* process that CONTINUES an existing spine (a resumed run appends to the dead run's own
|
|
6
|
+
* log — module C). `seq` is monotonic per SPINE, so a second series restarting at 1
|
|
7
|
+
* would give one append-only log two rows with the same number and silently break every
|
|
8
|
+
* reader that orders by it. Default 0: a fresh file, which is every other caller.
|
|
4
9
|
* @returns {(type: string, data?: object) => object} emit — returns the event as written
|
|
5
10
|
*/
|
|
6
|
-
export function makeSpine(file: string
|
|
11
|
+
export function makeSpine(file: string, { startSeq }?: {
|
|
12
|
+
startSeq?: number;
|
|
13
|
+
}): (type: string, data?: object) => object;
|
package/types/stall.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} StallWatch
|
|
3
|
+
* @property {<T>(call: (gen: number) => Promise<T>) => Promise<T>} watch run `call`,
|
|
4
|
+
* reissuing it whenever it goes `stallMs` without a beat; rejects `StallError` past
|
|
5
|
+
* `maxStalls`. Each issue is handed its GENERATION — the token every callback that
|
|
6
|
+
* call installs must carry back, so a corpse's callbacks cannot touch the live call.
|
|
7
|
+
* @property {(gen: number) => void} beat a round completed on generation `gen` — reset
|
|
8
|
+
* the window. From any other generation it is inert.
|
|
9
|
+
* @property {(gen: number) => boolean} isCurrent is `gen` still the call this watch is
|
|
10
|
+
* waiting on? The caller reads it to withhold everything else a dead call would do.
|
|
11
|
+
* @property {() => number} stalls how many stalls this watch has absorbed
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Start a stall watchdog.
|
|
15
|
+
* @param {{ stallMs?: number, maxStalls?: number, onStall?: (n: number) => void,
|
|
16
|
+
* expired?: () => boolean,
|
|
17
|
+
* setTimer?: (fn: () => void, ms: number) => any,
|
|
18
|
+
* clearTimer?: (id: any) => void }} [opts]
|
|
19
|
+
* `onStall` is announced for EVERY stall including the last — a trim or a
|
|
20
|
+
* recovery that happens silently is indistinguishable from one that never
|
|
21
|
+
* happened (F28's rule, applied to time).
|
|
22
|
+
* `expired` is the run's WALL, read at the one moment this module decides to
|
|
23
|
+
* spend again (L4). Omitted, the watch behaves exactly as it did before the wall
|
|
24
|
+
* existed — a caller with no clock reissues on the same rules.
|
|
25
|
+
* @returns {StallWatch}
|
|
26
|
+
*/
|
|
27
|
+
export function createStallWatch({ stallMs, maxStalls, onStall, expired, setTimer, clearTimer, }?: {
|
|
28
|
+
stallMs?: number;
|
|
29
|
+
maxStalls?: number;
|
|
30
|
+
onStall?: (n: number) => void;
|
|
31
|
+
expired?: () => boolean;
|
|
32
|
+
setTimer?: (fn: () => void, ms: number) => any;
|
|
33
|
+
clearTimer?: (id: any) => void;
|
|
34
|
+
}): StallWatch;
|
|
35
|
+
/** hamr's number: no completed round for five minutes is a stall. */
|
|
36
|
+
export const STALL_MS: 300000;
|
|
37
|
+
/** hamr's number: three stalls, then stop reissuing and replan. The count is
|
|
38
|
+
* CUMULATIVE over the watch's whole life and `watch()` never resets it — planrun
|
|
39
|
+
* builds one watch per WORKER, so the ceiling is spent across the STEP, not per
|
|
40
|
+
* call: two stalls on one call and one on the next give up just the same. That
|
|
41
|
+
* is deliberate (a step that keeps hanging is a step to replan, not a call to
|
|
42
|
+
* retry forever), and it is why nothing here says "on one call". */
|
|
43
|
+
export const MAX_STALLS: 3;
|
|
44
|
+
/**
|
|
45
|
+
* A stall gave up. Carries the category the step loop's replan trigger reads and
|
|
46
|
+
* the `lib` attribution stamped AT THE THROW SITE (never sniffed from prose).
|
|
47
|
+
*/
|
|
48
|
+
export class StallError extends Error {
|
|
49
|
+
/** @param {string} message @param {number} stalls */
|
|
50
|
+
constructor(message: string, stalls: number);
|
|
51
|
+
/** @type {string} */
|
|
52
|
+
category: string;
|
|
53
|
+
/** @type {string} */
|
|
54
|
+
lib: string;
|
|
55
|
+
/** @type {number} */
|
|
56
|
+
stalls: number;
|
|
57
|
+
}
|
|
58
|
+
export type StallWatch = {
|
|
59
|
+
/**
|
|
60
|
+
* run `call`,
|
|
61
|
+
* reissuing it whenever it goes `stallMs` without a beat; rejects `StallError` past
|
|
62
|
+
* `maxStalls`. Each issue is handed its GENERATION — the token every callback that
|
|
63
|
+
* call installs must carry back, so a corpse's callbacks cannot touch the live call.
|
|
64
|
+
*/
|
|
65
|
+
watch: <T>(call: (gen: number) => Promise<T>) => Promise<T>;
|
|
66
|
+
/**
|
|
67
|
+
* a round completed on generation `gen` — reset
|
|
68
|
+
* the window. From any other generation it is inert.
|
|
69
|
+
*/
|
|
70
|
+
beat: (gen: number) => void;
|
|
71
|
+
/**
|
|
72
|
+
* is `gen` still the call this watch is
|
|
73
|
+
* waiting on? The caller reads it to withhold everything else a dead call would do.
|
|
74
|
+
*/
|
|
75
|
+
isCurrent: (gen: number) => boolean;
|
|
76
|
+
/**
|
|
77
|
+
* how many stalls this watch has absorbed
|
|
78
|
+
*/
|
|
79
|
+
stalls: () => number;
|
|
80
|
+
};
|
package/types/tools.d.ts
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The strategy suffix for ONE worker's grant: every sentence that survives names
|
|
3
|
+
* only tools this worker can actually call. Reproduces the exported paragraphs
|
|
4
|
+
* exactly on a full grant.
|
|
5
|
+
* @param {string[]} granted the step's granted VERBS (the menu IS the grant, 2b)
|
|
6
|
+
* @returns {string} the system-prompt suffix, '' when nothing is granted
|
|
7
|
+
*/
|
|
8
|
+
export function strategyFor(granted: string[]): string;
|
|
9
|
+
/**
|
|
10
|
+
* The retrieval pair (F19). `shell_read` cannot seek — it starts at byte zero — so a
|
|
11
|
+
* pointer at a symbol was inert and the worker paged whole files to reach one function.
|
|
12
|
+
* `ctx_recall` hands back a POINTER (no body: a search index returns pointers, and bodies
|
|
13
|
+
* on every hit rebuild the bloat — measured, a 5-hit recall dumps ~15k tokens unbidden);
|
|
14
|
+
* `ctx_get` trades that pointer for ONE chunk. A chunk starts at its doc-comment, so the
|
|
15
|
+
* body arrives WITH the docstring that says what it was supposed to do.
|
|
16
|
+
* @param {any} lc the run's LiteCtx (rooted at workdir)
|
|
17
|
+
* @param {string} workdir
|
|
18
|
+
* @param {(type: string, data: object) => void} emit the spine — a retrieval verb whose
|
|
19
|
+
* RESULT is invisible cannot be judged: a `ctx_get` that silently reds (stale pointer,
|
|
20
|
+
* bad range) looks exactly like one that worked, and the worker's fallback to a
|
|
21
|
+
* whole-file read looks like a free choice instead of a forced one.
|
|
22
|
+
*/
|
|
23
|
+
export function createCtxTools(lc: any, workdir: string, emit: (type: string, data: object) => void): ({
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
parameters: {
|
|
27
|
+
type: string;
|
|
28
|
+
properties: {
|
|
29
|
+
query: {
|
|
30
|
+
type: string;
|
|
31
|
+
description: string;
|
|
32
|
+
};
|
|
33
|
+
n: {
|
|
34
|
+
type: string;
|
|
35
|
+
description: string;
|
|
36
|
+
};
|
|
37
|
+
path?: undefined;
|
|
38
|
+
startLine?: undefined;
|
|
39
|
+
endLine?: undefined;
|
|
40
|
+
symbol?: undefined;
|
|
41
|
+
id?: undefined;
|
|
42
|
+
text?: undefined;
|
|
43
|
+
};
|
|
44
|
+
required: string[];
|
|
45
|
+
};
|
|
46
|
+
execute: ({ query, n }: {
|
|
47
|
+
query: string;
|
|
48
|
+
n?: number;
|
|
49
|
+
}) => Promise<any>;
|
|
50
|
+
} | {
|
|
51
|
+
name: string;
|
|
52
|
+
description: string;
|
|
53
|
+
parameters: {
|
|
54
|
+
type: string;
|
|
55
|
+
properties: {
|
|
56
|
+
path: {
|
|
57
|
+
type: string;
|
|
58
|
+
description: string;
|
|
59
|
+
};
|
|
60
|
+
startLine: {
|
|
61
|
+
type: string;
|
|
62
|
+
description: string;
|
|
63
|
+
};
|
|
64
|
+
endLine: {
|
|
65
|
+
type: string;
|
|
66
|
+
description: string;
|
|
67
|
+
};
|
|
68
|
+
query?: undefined;
|
|
69
|
+
n?: undefined;
|
|
70
|
+
symbol?: undefined;
|
|
71
|
+
id?: undefined;
|
|
72
|
+
text?: undefined;
|
|
73
|
+
};
|
|
74
|
+
required: string[];
|
|
75
|
+
};
|
|
76
|
+
execute: ({ path: p, startLine, endLine }: {
|
|
77
|
+
path: string;
|
|
78
|
+
startLine: number;
|
|
79
|
+
endLine: number;
|
|
80
|
+
}) => Promise<any>;
|
|
81
|
+
} | {
|
|
82
|
+
name: string;
|
|
83
|
+
description: string;
|
|
84
|
+
parameters: {
|
|
85
|
+
type: string;
|
|
86
|
+
properties: {
|
|
87
|
+
symbol: {
|
|
88
|
+
type: string;
|
|
89
|
+
description: string;
|
|
90
|
+
};
|
|
91
|
+
query?: undefined;
|
|
92
|
+
n?: undefined;
|
|
93
|
+
path?: undefined;
|
|
94
|
+
startLine?: undefined;
|
|
95
|
+
endLine?: undefined;
|
|
96
|
+
id?: undefined;
|
|
97
|
+
text?: undefined;
|
|
98
|
+
};
|
|
99
|
+
required: string[];
|
|
100
|
+
};
|
|
101
|
+
execute: (args: any) => Promise<string>;
|
|
102
|
+
} | {
|
|
103
|
+
name: string;
|
|
104
|
+
description: string;
|
|
105
|
+
parameters: {
|
|
106
|
+
type: string;
|
|
107
|
+
properties: {
|
|
108
|
+
path: {
|
|
109
|
+
type: string;
|
|
110
|
+
description: string;
|
|
111
|
+
};
|
|
112
|
+
query?: undefined;
|
|
113
|
+
n?: undefined;
|
|
114
|
+
startLine?: undefined;
|
|
115
|
+
endLine?: undefined;
|
|
116
|
+
symbol?: undefined;
|
|
117
|
+
id?: undefined;
|
|
118
|
+
text?: undefined;
|
|
119
|
+
};
|
|
120
|
+
required: string[];
|
|
121
|
+
};
|
|
122
|
+
execute: (args: any) => Promise<string>;
|
|
123
|
+
} | {
|
|
124
|
+
name: string;
|
|
125
|
+
description: string;
|
|
126
|
+
parameters: {
|
|
127
|
+
type: string;
|
|
128
|
+
properties: {
|
|
129
|
+
query?: undefined;
|
|
130
|
+
n?: undefined;
|
|
131
|
+
path?: undefined;
|
|
132
|
+
startLine?: undefined;
|
|
133
|
+
endLine?: undefined;
|
|
134
|
+
symbol?: undefined;
|
|
135
|
+
id?: undefined;
|
|
136
|
+
text?: undefined;
|
|
137
|
+
};
|
|
138
|
+
required?: undefined;
|
|
139
|
+
};
|
|
140
|
+
execute: (args: any) => Promise<string>;
|
|
141
|
+
} | {
|
|
142
|
+
name: string;
|
|
143
|
+
description: string;
|
|
144
|
+
parameters: {
|
|
145
|
+
type: string;
|
|
146
|
+
properties: {
|
|
147
|
+
path: {
|
|
148
|
+
type: string;
|
|
149
|
+
description: string;
|
|
150
|
+
};
|
|
151
|
+
symbol: {
|
|
152
|
+
type: string;
|
|
153
|
+
description: string;
|
|
154
|
+
};
|
|
155
|
+
query?: undefined;
|
|
156
|
+
n?: undefined;
|
|
157
|
+
startLine?: undefined;
|
|
158
|
+
endLine?: undefined;
|
|
159
|
+
id?: undefined;
|
|
160
|
+
text?: undefined;
|
|
161
|
+
};
|
|
162
|
+
required: string[];
|
|
163
|
+
};
|
|
164
|
+
execute: (args: any) => Promise<string>;
|
|
165
|
+
} | {
|
|
166
|
+
name: string;
|
|
167
|
+
description: string;
|
|
168
|
+
parameters: {
|
|
169
|
+
type: string;
|
|
170
|
+
properties: {
|
|
171
|
+
id: {
|
|
172
|
+
type: string;
|
|
173
|
+
description: string;
|
|
174
|
+
};
|
|
175
|
+
text: {
|
|
176
|
+
type: string;
|
|
177
|
+
description: string;
|
|
178
|
+
};
|
|
179
|
+
query?: undefined;
|
|
180
|
+
n?: undefined;
|
|
181
|
+
path?: undefined;
|
|
182
|
+
startLine?: undefined;
|
|
183
|
+
endLine?: undefined;
|
|
184
|
+
symbol?: undefined;
|
|
185
|
+
};
|
|
186
|
+
required: string[];
|
|
187
|
+
};
|
|
188
|
+
execute: (args: any) => Promise<string>;
|
|
189
|
+
} | {
|
|
190
|
+
name: string;
|
|
191
|
+
description: string;
|
|
192
|
+
parameters: {
|
|
193
|
+
type: string;
|
|
194
|
+
properties: {
|
|
195
|
+
id: {
|
|
196
|
+
type: string;
|
|
197
|
+
description: string;
|
|
198
|
+
};
|
|
199
|
+
query?: undefined;
|
|
200
|
+
n?: undefined;
|
|
201
|
+
path?: undefined;
|
|
202
|
+
startLine?: undefined;
|
|
203
|
+
endLine?: undefined;
|
|
204
|
+
symbol?: undefined;
|
|
205
|
+
text?: undefined;
|
|
206
|
+
};
|
|
207
|
+
required: string[];
|
|
208
|
+
};
|
|
209
|
+
execute: (args: any) => Promise<string>;
|
|
210
|
+
})[];
|
|
211
|
+
export const PERSONA_TOOLS: string;
|
|
212
|
+
export const RETRIEVAL_STRATEGY: string;
|
|
213
|
+
export const EDIT_STRATEGY: string;
|
|
214
|
+
export const TOOL_BY_VERB: Readonly<{
|
|
215
|
+
read: "shell_read";
|
|
216
|
+
grep: "shell_grep";
|
|
217
|
+
write: "shell_write";
|
|
218
|
+
edit: "shell_edit";
|
|
219
|
+
recall: "ctx_recall";
|
|
220
|
+
get: "ctx_get";
|
|
221
|
+
impact: "ctx_impact";
|
|
222
|
+
related: "ctx_related";
|
|
223
|
+
recent: "ctx_recent";
|
|
224
|
+
compress: "ctx_compress";
|
|
225
|
+
peek: "ctx_peek";
|
|
226
|
+
stash: "ctx_stash";
|
|
227
|
+
remember: "ctx_remember";
|
|
228
|
+
forget: "ctx_forget";
|
|
229
|
+
}>;
|
|
230
|
+
export const ISOLATE_MAX_BYTES: 65536;
|
|
231
|
+
export const CTX_TOOLS: readonly string[];
|
|
232
|
+
export const COMPONENT_STRATEGIES: Readonly<{
|
|
233
|
+
select: string;
|
|
234
|
+
compress: string;
|
|
235
|
+
isolate: string;
|
|
236
|
+
}>;
|
|
237
|
+
export function toolAction(name: string, args: any, workdir?: string): {
|
|
238
|
+
type: string;
|
|
239
|
+
path: string;
|
|
240
|
+
args: {
|
|
241
|
+
bytes: number;
|
|
242
|
+
tool?: undefined;
|
|
243
|
+
};
|
|
244
|
+
} | {
|
|
245
|
+
type: string;
|
|
246
|
+
path: string;
|
|
247
|
+
args: {
|
|
248
|
+
tool: string;
|
|
249
|
+
bytes?: undefined;
|
|
250
|
+
};
|
|
251
|
+
} | {
|
|
252
|
+
type: string;
|
|
253
|
+
args: any;
|
|
254
|
+
path?: undefined;
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* litectx recall hit — body present only with `{body: true}`
|
|
258
|
+
*/
|
|
259
|
+
export type RecallHit = {
|
|
260
|
+
body?: string | null;
|
|
261
|
+
text?: string | null;
|
|
262
|
+
};
|
package/types/trend.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read one close gap into its stage and its count. Pure, and both halves are
|
|
3
|
+
* independently nullable: a gap with no header still yields its count, a gap
|
|
4
|
+
* with no red-marked line still yields its stage.
|
|
5
|
+
* @param {string} [gap] the close's gap, exactly as `runStages` built it
|
|
6
|
+
* @returns {{stage: string|null, value: number|null}}
|
|
7
|
+
*/
|
|
8
|
+
export function readGrade(gap?: string): {
|
|
9
|
+
stage: string | null;
|
|
10
|
+
value: number | null;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Build one trend reader. ONE PER SERIES: the money readout wants the whole run's
|
|
14
|
+
* close grades (the precheck is the seed the work is measured against), while the
|
|
15
|
+
* fix governor wants only the grades its own loop produced. Two instances, one
|
|
16
|
+
* rule — never one instance with a phase field, which is how a shared reader comes
|
|
17
|
+
* to answer two questions with one number.
|
|
18
|
+
*
|
|
19
|
+
* @param {object} [opts]
|
|
20
|
+
* @param {string[]} [opts.stageOrder] the staged close's stage names IN ORDER, so
|
|
21
|
+
* "the run got further than it ever had" is readable. Empty disables that signal
|
|
22
|
+
* entirely (an unknown ordering is unknown, never assumed).
|
|
23
|
+
* @param {number} [opts.limit] consecutive no-progress readings that strike the
|
|
24
|
+
* loop out (default `FIX_STRIKE_LIMIT`).
|
|
25
|
+
* @param {number|null} [opts.blindCap] the RETIRED count, kept as the bound for
|
|
26
|
+
* the case the instrument cannot read at all. Counted in iterations PAST the
|
|
27
|
+
* baseline, so a blind loop runs exactly the number of attempts the old fixed
|
|
28
|
+
* count bought it. `null` = no fallback bound (money and the wall still apply).
|
|
29
|
+
* @param {{stage?: string|null, value?: number|null}[]} [opts.seed] RESUME — the
|
|
30
|
+
* grades a PREVIOUS leg of this same run already recorded, oldest first, read off
|
|
31
|
+
* its own spine. Baselines only (see THE SEED above). Empty/omitted is the cold
|
|
32
|
+
* path and is byte-identical to the pre-resume reader.
|
|
33
|
+
*/
|
|
34
|
+
export function createTrend({ stageOrder, limit, blindCap, seed }?: {
|
|
35
|
+
stageOrder?: string[] | undefined;
|
|
36
|
+
limit?: number | undefined;
|
|
37
|
+
blindCap?: number | null | undefined;
|
|
38
|
+
seed?: {
|
|
39
|
+
stage?: string | null;
|
|
40
|
+
value?: number | null;
|
|
41
|
+
}[] | undefined;
|
|
42
|
+
}): {
|
|
43
|
+
/**
|
|
44
|
+
* Read one RED close grade. A green never reaches here (both callers stop on
|
|
45
|
+
* satisfied), so every reading is a failing grade by construction.
|
|
46
|
+
* @param {{gap?: string, stage?: string|null, value?: number|null}} o either a
|
|
47
|
+
* raw gap (parsed here) or an already-read `{stage, value}` — never both
|
|
48
|
+
* spellings of the same reading in one call.
|
|
49
|
+
* @returns {{iteration: number, stage: string, value: number|null, improved: boolean,
|
|
50
|
+
* comparable: boolean, noProgress: number, limit: number, stageIndex: number}}
|
|
51
|
+
*/
|
|
52
|
+
record({ gap, stage, value }?: {
|
|
53
|
+
gap?: string;
|
|
54
|
+
stage?: string | null;
|
|
55
|
+
value?: number | null;
|
|
56
|
+
}): {
|
|
57
|
+
iteration: number;
|
|
58
|
+
stage: string;
|
|
59
|
+
value: number | null;
|
|
60
|
+
improved: boolean;
|
|
61
|
+
comparable: boolean;
|
|
62
|
+
noProgress: number;
|
|
63
|
+
limit: number;
|
|
64
|
+
stageIndex: number;
|
|
65
|
+
};
|
|
66
|
+
/** has the loop run out of ideas — or, while the instrument is blind, out of
|
|
67
|
+
* the count it replaced? Money and the wall are unchanged and bound it either way.
|
|
68
|
+
* The blind arm counts the streak PAST its own first reading, the same `- 1` the
|
|
69
|
+
* blind-from-birth path always used: a streak's opening grade is the baseline the
|
|
70
|
+
* blind iterations are measured from, so a never-comparable run binds on exactly
|
|
71
|
+
* the reading it always did. */
|
|
72
|
+
struckOut: () => boolean;
|
|
73
|
+
/** the reader's own books. COUNTS AND STAGE NAMES ONLY — no close bytes ever
|
|
74
|
+
* enter a record from here, because the spine is append-only forever. */
|
|
75
|
+
report: () => {
|
|
76
|
+
iterations: number;
|
|
77
|
+
strikes: number;
|
|
78
|
+
limit: number;
|
|
79
|
+
blind: boolean;
|
|
80
|
+
stages: {
|
|
81
|
+
stage: string;
|
|
82
|
+
values: number[];
|
|
83
|
+
}[];
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* The DECISION-READY readout (PRD v1.46 §2): which way the run was going when
|
|
87
|
+
* something cut it, in the three verdicts hamr named, and the lever each
|
|
88
|
+
* implies. The library only reports — it never adjusts a budget (hard line).
|
|
89
|
+
* @returns {{trend: 'converging'|'flat'|'unknown', motion: 'changed'|'unchanged'|null,
|
|
90
|
+
* reading: string, lever: string, series: {stage: string, values: number[]}[]}}
|
|
91
|
+
*/
|
|
92
|
+
verdict(): {
|
|
93
|
+
trend: "converging" | "flat" | "unknown";
|
|
94
|
+
motion: "changed" | "unchanged" | null;
|
|
95
|
+
reading: string;
|
|
96
|
+
lever: string;
|
|
97
|
+
series: {
|
|
98
|
+
stage: string;
|
|
99
|
+
values: number[];
|
|
100
|
+
}[];
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
/** The strikes that end the close-fix loop. Shell-owned, exactly where the fixed
|
|
104
|
+
* count was, and the SAME number the step ladder uses — hamr's 2. Validated by a
|
|
105
|
+
* $0 replay over all 8 archived fix loops: 0 greens harmed (every historical
|
|
106
|
+
* fix-loop green converted in <= 2 verdicts) and 1 real waste case caught
|
|
107
|
+
* (reuse-msc6w93z, dead flat at 2 errors for 7 verdicts until the wall). */
|
|
108
|
+
export const FIX_STRIKE_LIMIT: 2;
|