looply-cli 0.5.3 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.src-hash +1 -1
- package/dist/agent-exec.d.ts +10 -5
- package/dist/agent-exec.d.ts.map +1 -1
- package/dist/agent-exec.js.map +1 -1
- package/dist/autonomy-controller.d.ts +14 -1
- package/dist/autonomy-controller.d.ts.map +1 -1
- package/dist/autonomy-controller.js +55 -2
- package/dist/autonomy-controller.js.map +1 -1
- package/dist/autonomy-store.d.ts +35 -2
- package/dist/autonomy-store.d.ts.map +1 -1
- package/dist/autonomy-store.js +27 -2
- package/dist/autonomy-store.js.map +1 -1
- package/dist/autonomy-tick.d.ts +25 -2
- package/dist/autonomy-tick.d.ts.map +1 -1
- package/dist/autonomy-tick.js +145 -4
- package/dist/autonomy-tick.js.map +1 -1
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +112 -82
- package/dist/bin.js.map +1 -1
- package/dist/checkout-carry.d.ts.map +1 -1
- package/dist/checkout-carry.js +12 -0
- package/dist/checkout-carry.js.map +1 -1
- package/dist/config.d.ts +41 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +64 -8
- package/dist/config.js.map +1 -1
- package/dist/coordinator-state.d.ts +14 -0
- package/dist/coordinator-state.d.ts.map +1 -1
- package/dist/coordinator-state.js +29 -0
- package/dist/coordinator-state.js.map +1 -1
- package/dist/daemon-cmd.d.ts +1 -1
- package/dist/daemon-cmd.d.ts.map +1 -1
- package/dist/daemon-cmd.js +69 -33
- package/dist/daemon-cmd.js.map +1 -1
- package/dist/daemon.d.ts +15 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +21 -3
- package/dist/daemon.js.map +1 -1
- package/dist/git-driver.d.ts +6 -0
- package/dist/git-driver.d.ts.map +1 -1
- package/dist/git-driver.js +12 -0
- package/dist/git-driver.js.map +1 -1
- package/dist/index-for-head.js +1 -1
- package/dist/index-for-head.js.map +1 -1
- package/dist/init-detect.d.ts.map +1 -1
- package/dist/init-detect.js +1 -1
- package/dist/init-detect.js.map +1 -1
- package/dist/machine-run-slots.d.ts +59 -0
- package/dist/machine-run-slots.d.ts.map +1 -0
- package/dist/machine-run-slots.js +140 -0
- package/dist/machine-run-slots.js.map +1 -0
- package/dist/model-routing.d.ts +52 -7
- package/dist/model-routing.d.ts.map +1 -1
- package/dist/model-routing.js +84 -14
- package/dist/model-routing.js.map +1 -1
- package/dist/model-settings.d.ts +67 -0
- package/dist/model-settings.d.ts.map +1 -0
- package/dist/model-settings.js +177 -0
- package/dist/model-settings.js.map +1 -0
- package/dist/model-transport.d.ts +8 -0
- package/dist/model-transport.d.ts.map +1 -1
- package/dist/model-transport.js +6 -3
- package/dist/model-transport.js.map +1 -1
- package/dist/programme-mode.d.ts +6 -0
- package/dist/programme-mode.d.ts.map +1 -1
- package/dist/programme-mode.js +23 -0
- package/dist/programme-mode.js.map +1 -1
- package/dist/project-index-store.d.ts +19 -1
- package/dist/project-index-store.d.ts.map +1 -1
- package/dist/project-index-store.js +40 -5
- package/dist/project-index-store.js.map +1 -1
- package/dist/project-terminal.d.ts +25 -0
- package/dist/project-terminal.d.ts.map +1 -0
- package/dist/project-terminal.js +46 -0
- package/dist/project-terminal.js.map +1 -0
- package/dist/provider-cmd.d.ts +13 -4
- package/dist/provider-cmd.d.ts.map +1 -1
- package/dist/provider-cmd.js +111 -11
- package/dist/provider-cmd.js.map +1 -1
- package/dist/provider-ready.d.ts +15 -2
- package/dist/provider-ready.d.ts.map +1 -1
- package/dist/provider-ready.js +46 -2
- package/dist/provider-ready.js.map +1 -1
- package/dist/providers.d.ts.map +1 -1
- package/dist/providers.js +4 -0
- package/dist/providers.js.map +1 -1
- package/dist/pursuit-ending.d.ts +57 -0
- package/dist/pursuit-ending.d.ts.map +1 -0
- package/dist/pursuit-ending.js +128 -0
- package/dist/pursuit-ending.js.map +1 -0
- package/dist/run-base.d.ts +84 -0
- package/dist/run-base.d.ts.map +1 -0
- package/dist/run-base.js +142 -0
- package/dist/run-base.js.map +1 -0
- package/dist/run-cmd.d.ts.map +1 -1
- package/dist/run-cmd.js +46 -5
- package/dist/run-cmd.js.map +1 -1
- package/dist/run-ended.d.ts +16 -0
- package/dist/run-ended.d.ts.map +1 -1
- package/dist/run-ended.js +30 -0
- package/dist/run-ended.js.map +1 -1
- package/dist/run-ending-locator.d.ts +10 -0
- package/dist/run-ending-locator.d.ts.map +1 -1
- package/dist/run-ending-locator.js +45 -0
- package/dist/run-ending-locator.js.map +1 -1
- package/dist/run-launcher.d.ts +30 -1
- package/dist/run-launcher.d.ts.map +1 -1
- package/dist/run-launcher.js +60 -2
- package/dist/run-launcher.js.map +1 -1
- package/dist/server-client.d.ts +16 -2
- package/dist/server-client.d.ts.map +1 -1
- package/dist/server-client.js +9 -0
- package/dist/server-client.js.map +1 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +17 -0
- package/dist/setup.js.map +1 -1
- package/dist/workspace-provisioner.d.ts +2 -0
- package/dist/workspace-provisioner.d.ts.map +1 -1
- package/dist/workspace-provisioner.js +27 -1
- package/dist/workspace-provisioner.js.map +1 -1
- package/package.json +54 -54
- package/win/HandleProbe.cs +116 -116
package/dist/init-detect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-detect.js","sourceRoot":"","sources":["../src/init-detect.ts"],"names":[],"mappings":";;AAgHA,gCAiBC;AAWD,oCAUC;AAQD,
|
|
1
|
+
{"version":3,"file":"init-detect.js","sourceRoot":"","sources":["../src/init-detect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type ProbeFn } from './run-lease';
|
|
2
|
+
/**
|
|
3
|
+
* HOW MANY AUTONOMOUS RUNS THIS COMPUTER HAS, ACROSS EVERY REPOSITORY IT SERVES.
|
|
4
|
+
*
|
|
5
|
+
* `looply serve` runs one daemon per repository, and each daemon's coordinator
|
|
6
|
+
* bounds only its own project (`machine.max_parallel_runs`). A PC serving 27
|
|
7
|
+
* repositories at 3 each could otherwise launch 81 agent sessions at once. This
|
|
8
|
+
* is the one number they share: `machine.max_runs_on_machine` (default 4).
|
|
9
|
+
*
|
|
10
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
11
|
+
* ONE FILE PER SLOT, IN `~/.looply/machine-runs/`.
|
|
12
|
+
*
|
|
13
|
+
* A slot is CLAIMED before a launch (pending, holding the daemon's pid) and
|
|
14
|
+
* BOUND to the child's pid once it is spawned. A slot frees itself: a bound
|
|
15
|
+
* slot whose pid is dead, or a pending slot older than `PENDING_TTL_MS`, is not
|
|
16
|
+
* counted and is swept on the next claim. Nothing has to remember to release,
|
|
17
|
+
* so a crashed run or daemon cannot leak capacity for longer than one probe.
|
|
18
|
+
*
|
|
19
|
+
* Claims are serialised by the shared exclusive lock, so two daemons cannot
|
|
20
|
+
* both see the last free slot and both take it.
|
|
21
|
+
*
|
|
22
|
+
* ⚠️ A CLAIM IS ASKED BEFORE A TRY IS SPENT. The launcher's `busyFor` takes it
|
|
23
|
+
* (see `run-launcher.ts`), and `busyFor` runs before `reserveLaunch` in the
|
|
24
|
+
* tick, so "the machine is full" is a queue — never a failed attempt. A claim
|
|
25
|
+
* is idempotent per request: asking again for the same request refreshes it.
|
|
26
|
+
*
|
|
27
|
+
* ⚠️ AN UNKNOWN LIVENESS COUNTS AS ALIVE, the direction that cannot overshoot.
|
|
28
|
+
*/
|
|
29
|
+
/** A claim that never became a run stops holding a slot after this. */
|
|
30
|
+
export declare const PENDING_TTL_MS: number;
|
|
31
|
+
export interface MachineSlot {
|
|
32
|
+
readonly key: string;
|
|
33
|
+
readonly pid: number;
|
|
34
|
+
readonly pending: boolean;
|
|
35
|
+
readonly at: string;
|
|
36
|
+
/** Which repository the run is for — for a person reading the directory. */
|
|
37
|
+
readonly repo?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface MachineRunSlots {
|
|
40
|
+
/** Take (or refresh) a slot for `key`; null when taken, else why the machine is full. */
|
|
41
|
+
claim(key: string): string | null;
|
|
42
|
+
/** The launch happened: the slot now lives as long as `pid` does. */
|
|
43
|
+
bind(key: string, pid: number): void;
|
|
44
|
+
/** The launch did not happen. */
|
|
45
|
+
release(key: string): void;
|
|
46
|
+
/** Live slots right now, `key` excluded when given. */
|
|
47
|
+
inUse(except?: string): number;
|
|
48
|
+
readonly cap: number;
|
|
49
|
+
}
|
|
50
|
+
export interface MachineRunSlotDeps {
|
|
51
|
+
readonly home?: string;
|
|
52
|
+
readonly now?: () => number;
|
|
53
|
+
readonly probe?: ProbeFn;
|
|
54
|
+
readonly pid?: number;
|
|
55
|
+
readonly repo?: string;
|
|
56
|
+
}
|
|
57
|
+
export declare function machineSlotsDir(home?: string): string;
|
|
58
|
+
export declare function machineRunSlots(cap: number, deps?: MachineRunSlotDeps): MachineRunSlots;
|
|
59
|
+
//# sourceMappingURL=machine-run-slots.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine-run-slots.d.ts","sourceRoot":"","sources":["../src/machine-run-slots.ts"],"names":[],"mappings":"AAKA,OAAO,EAAa,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,uEAAuE;AACvE,eAAO,MAAM,cAAc,QAAa,CAAC;AAEzC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,yFAAyF;IACzF,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAClC,qEAAqE;IACrE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,iCAAiC;IACjC,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,uDAAuD;IACvD,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,CAEhE;AAID,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,eAAe,CA8F3F"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PENDING_TTL_MS = void 0;
|
|
4
|
+
exports.machineSlotsDir = machineSlotsDir;
|
|
5
|
+
exports.machineRunSlots = machineRunSlots;
|
|
6
|
+
const node_crypto_1 = require("node:crypto");
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_os_1 = require("node:os");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const exclusive_lock_1 = require("./exclusive-lock");
|
|
11
|
+
const run_lease_1 = require("./run-lease");
|
|
12
|
+
/**
|
|
13
|
+
* HOW MANY AUTONOMOUS RUNS THIS COMPUTER HAS, ACROSS EVERY REPOSITORY IT SERVES.
|
|
14
|
+
*
|
|
15
|
+
* `looply serve` runs one daemon per repository, and each daemon's coordinator
|
|
16
|
+
* bounds only its own project (`machine.max_parallel_runs`). A PC serving 27
|
|
17
|
+
* repositories at 3 each could otherwise launch 81 agent sessions at once. This
|
|
18
|
+
* is the one number they share: `machine.max_runs_on_machine` (default 4).
|
|
19
|
+
*
|
|
20
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
21
|
+
* ONE FILE PER SLOT, IN `~/.looply/machine-runs/`.
|
|
22
|
+
*
|
|
23
|
+
* A slot is CLAIMED before a launch (pending, holding the daemon's pid) and
|
|
24
|
+
* BOUND to the child's pid once it is spawned. A slot frees itself: a bound
|
|
25
|
+
* slot whose pid is dead, or a pending slot older than `PENDING_TTL_MS`, is not
|
|
26
|
+
* counted and is swept on the next claim. Nothing has to remember to release,
|
|
27
|
+
* so a crashed run or daemon cannot leak capacity for longer than one probe.
|
|
28
|
+
*
|
|
29
|
+
* Claims are serialised by the shared exclusive lock, so two daemons cannot
|
|
30
|
+
* both see the last free slot and both take it.
|
|
31
|
+
*
|
|
32
|
+
* ⚠️ A CLAIM IS ASKED BEFORE A TRY IS SPENT. The launcher's `busyFor` takes it
|
|
33
|
+
* (see `run-launcher.ts`), and `busyFor` runs before `reserveLaunch` in the
|
|
34
|
+
* tick, so "the machine is full" is a queue — never a failed attempt. A claim
|
|
35
|
+
* is idempotent per request: asking again for the same request refreshes it.
|
|
36
|
+
*
|
|
37
|
+
* ⚠️ AN UNKNOWN LIVENESS COUNTS AS ALIVE, the direction that cannot overshoot.
|
|
38
|
+
*/
|
|
39
|
+
/** A claim that never became a run stops holding a slot after this. */
|
|
40
|
+
exports.PENDING_TTL_MS = 3 * 60_000;
|
|
41
|
+
function machineSlotsDir(home = (0, node_os_1.homedir)()) {
|
|
42
|
+
return (0, node_path_1.join)(home, '.looply', 'machine-runs');
|
|
43
|
+
}
|
|
44
|
+
const fileOf = (key) => `${(0, node_crypto_1.createHash)('sha256').update(key).digest('hex').slice(0, 32)}.json`;
|
|
45
|
+
function machineRunSlots(cap, deps = {}) {
|
|
46
|
+
const dir = machineSlotsDir(deps.home);
|
|
47
|
+
const now = deps.now ?? (() => Date.now());
|
|
48
|
+
const probe = deps.probe ?? run_lease_1.nodeProbe;
|
|
49
|
+
const me = deps.pid ?? process.pid;
|
|
50
|
+
const limit = Math.max(1, Math.floor(cap));
|
|
51
|
+
const read = () => {
|
|
52
|
+
let names;
|
|
53
|
+
try {
|
|
54
|
+
names = (0, node_fs_1.readdirSync)(dir).filter((n) => n.endsWith('.json'));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
const out = [];
|
|
60
|
+
for (const file of names) {
|
|
61
|
+
try {
|
|
62
|
+
const raw = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(dir, file), 'utf8'));
|
|
63
|
+
if (typeof raw.key !== 'string' || typeof raw.pid !== 'number' || typeof raw.at !== 'string')
|
|
64
|
+
continue;
|
|
65
|
+
out.push({ file, slot: { key: raw.key, pid: raw.pid, pending: raw.pending === true, at: raw.at, ...(raw.repo === undefined ? {} : { repo: raw.repo }) } });
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// A torn write is not a run. The claim that wrote it rewrites it.
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
};
|
|
73
|
+
const live = (s) => {
|
|
74
|
+
if (s.pending) {
|
|
75
|
+
const at = Date.parse(s.at);
|
|
76
|
+
if (!Number.isFinite(at) || now() - at > exports.PENDING_TTL_MS)
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return probe(s.pid) !== 'dead';
|
|
80
|
+
};
|
|
81
|
+
const write = (slot) => {
|
|
82
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
83
|
+
const target = (0, node_path_1.join)(dir, fileOf(slot.key));
|
|
84
|
+
const tmp = `${target}.${me}.tmp`;
|
|
85
|
+
(0, node_fs_1.writeFileSync)(tmp, `${JSON.stringify(slot)}\n`, 'utf8');
|
|
86
|
+
(0, node_fs_1.renameSync)(tmp, target);
|
|
87
|
+
};
|
|
88
|
+
const inUse = (except) => read().filter(({ slot }) => slot.key !== except && live(slot)).length;
|
|
89
|
+
return {
|
|
90
|
+
cap: limit,
|
|
91
|
+
inUse,
|
|
92
|
+
claim(key) {
|
|
93
|
+
try {
|
|
94
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Fall through: the lock below refuses, and a refusal is a wait.
|
|
98
|
+
}
|
|
99
|
+
return (0, exclusive_lock_1.withExclusiveLock)((0, node_path_1.join)(dir, 'claim.lock'), () => {
|
|
100
|
+
const all = read();
|
|
101
|
+
for (const { file, slot } of all) {
|
|
102
|
+
if (!live(slot)) {
|
|
103
|
+
try {
|
|
104
|
+
(0, node_fs_1.rmSync)((0, node_path_1.join)(dir, file), { force: true });
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
/* swept next time */
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const mine = all.find(({ slot }) => slot.key === key);
|
|
112
|
+
if (mine !== undefined && !mine.slot.pending && live(mine.slot))
|
|
113
|
+
return null; // already running
|
|
114
|
+
const others = all.filter(({ slot }) => slot.key !== key && live(slot)).length;
|
|
115
|
+
if (others >= limit) {
|
|
116
|
+
return `this computer already has ${others} autonomous run(s) going across its repositories and its ceiling is ${limit} (machine.max_runs_on_machine)`;
|
|
117
|
+
}
|
|
118
|
+
write({ key, pid: me, pending: true, at: new Date(now()).toISOString(), ...(deps.repo === undefined ? {} : { repo: deps.repo }) });
|
|
119
|
+
return null;
|
|
120
|
+
}, (why) => `the machine-wide run count could not be checked (${why})`);
|
|
121
|
+
},
|
|
122
|
+
bind(key, pid) {
|
|
123
|
+
try {
|
|
124
|
+
write({ key, pid, pending: false, at: new Date(now()).toISOString(), ...(deps.repo === undefined ? {} : { repo: deps.repo }) });
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// A slot that cannot be bound expires as pending; the run goes on.
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
release(key) {
|
|
131
|
+
try {
|
|
132
|
+
(0, node_fs_1.rmSync)((0, node_path_1.join)(dir, fileOf(key)), { force: true });
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
/* expires on its own */
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=machine-run-slots.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"machine-run-slots.js","sourceRoot":"","sources":["../src/machine-run-slots.ts"],"names":[],"mappings":"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"}
|
package/dist/model-routing.d.ts
CHANGED
|
@@ -23,15 +23,21 @@
|
|
|
23
23
|
* time, before a run starts, with the reason — not at round one after the first
|
|
24
24
|
* call has been paid for.
|
|
25
25
|
*/
|
|
26
|
+
import { type AgentEffort, type AgentSettings } from '@looply/core';
|
|
26
27
|
/** The roles that drive a model, in the order a round meets them. */
|
|
27
28
|
export declare const MODEL_ROLES: readonly ["implementer", "verifier", "scanner", "brain"];
|
|
28
29
|
export type ModelRole = (typeof MODEL_ROLES)[number];
|
|
29
30
|
/** The keys `agent.models` may carry: every role, plus the one that covers the rest. */
|
|
30
31
|
export declare const MODEL_KEYS: readonly ["default", "implementer", "verifier", "scanner", "brain"];
|
|
31
32
|
export type ModelKey = (typeof MODEL_KEYS)[number];
|
|
32
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* `--effort`, as Claude Code spells it. Checked against `claude --help` on
|
|
35
|
+
* 2026-09-13. Declared in core, so the server refuses exactly what this does.
|
|
36
|
+
*/
|
|
33
37
|
export declare const EFFORT_LEVELS: readonly ["low", "medium", "high", "xhigh", "max"];
|
|
34
|
-
export type Effort =
|
|
38
|
+
export type Effort = AgentEffort;
|
|
39
|
+
/** `agent.effort` written as a map: `default` covers any role not named. */
|
|
40
|
+
export type RoleEfforts = Partial<Record<ModelKey, Effort>>;
|
|
35
41
|
/**
|
|
36
42
|
* Role → model id. `default` covers any role not named; a role named here wins.
|
|
37
43
|
* Every value is one model id, passed as one argument — never a flag string.
|
|
@@ -46,17 +52,56 @@ export type RoleModels = Partial<Record<ModelKey, string>>;
|
|
|
46
52
|
* one should not be able to step around a cost rule with a capital letter.
|
|
47
53
|
*/
|
|
48
54
|
export declare function isBrainOnlyModel(model: string): boolean;
|
|
49
|
-
/** The model
|
|
55
|
+
/** The model config.yaml names for a role, or undefined when it names none. */
|
|
50
56
|
export declare function modelFor(role: ModelRole, models: RoleModels | undefined): string | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* The effort config.yaml names for a role. `agent.effort` is either one level
|
|
59
|
+
* for every role (the original shape, still byte-compatible) or a map with an
|
|
60
|
+
* optional `default`.
|
|
61
|
+
*/
|
|
62
|
+
export declare function effortFor(role: ModelRole, effort: Effort | RoleEfforts | undefined): Effort | undefined;
|
|
63
|
+
/** Where a resolved value came from, as `looply doctor` prints it. */
|
|
64
|
+
export type SettingSource = 'config.yaml' | 'remote' | 'default';
|
|
65
|
+
export interface ResolvedRole {
|
|
66
|
+
model: string;
|
|
67
|
+
effort: Effort;
|
|
68
|
+
modelFrom: SettingSource;
|
|
69
|
+
effortFrom: SettingSource;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The model and effort a role runs on the BUILT-IN provider, field by field:
|
|
73
|
+
*
|
|
74
|
+
* config.yaml > remote project settings > DEFAULT_AGENT_SETTINGS
|
|
75
|
+
*
|
|
76
|
+
* config.yaml wins because it is a person's decision written in the repository
|
|
77
|
+
* on the machine itself; remote settings (console, integrations) fill what the
|
|
78
|
+
* file leaves unsaid; the built-in table fills the rest. Model and effort are
|
|
79
|
+
* resolved independently, so a file naming only an effort still takes the
|
|
80
|
+
* remote or default model.
|
|
81
|
+
*
|
|
82
|
+
* ⚠️ A remote Fable model for a non-brain role is ignored here even though the
|
|
83
|
+
* validator refuses it at the API: the cache is a file on disk, and the rule
|
|
84
|
+
* is cheap to hold twice.
|
|
85
|
+
*/
|
|
86
|
+
export declare function resolveRole(role: ModelRole, spec: {
|
|
87
|
+
models?: RoleModels;
|
|
88
|
+
effort?: Effort | RoleEfforts;
|
|
89
|
+
}, remote?: AgentSettings | null): ResolvedRole;
|
|
51
90
|
/**
|
|
52
91
|
* The arguments that put a role on its model, ready to splice into a Claude
|
|
53
|
-
* Code command line.
|
|
54
|
-
*
|
|
92
|
+
* Code command line.
|
|
93
|
+
*
|
|
94
|
+
* ⚠️ CHANGED DELIBERATELY: this used to be EMPTY when nothing was configured,
|
|
95
|
+
* so the provider's own default ran (whatever Claude Code happened to pick on
|
|
96
|
+
* that machine). Every built-in turn now names its model and effort — from
|
|
97
|
+
* config.yaml, the project's remote settings, or `DEFAULT_AGENT_SETTINGS` — so
|
|
98
|
+
* what a role runs is a Looply decision that `looply doctor` can print, not an
|
|
99
|
+
* accident of the machine. Only ever called on the built-in branch.
|
|
55
100
|
*/
|
|
56
101
|
export declare function modelArgs(role: ModelRole, spec: {
|
|
57
102
|
models?: RoleModels;
|
|
58
|
-
effort?: Effort;
|
|
59
|
-
}): string[];
|
|
103
|
+
effort?: Effort | RoleEfforts;
|
|
104
|
+
}, remote?: AgentSettings | null): string[];
|
|
60
105
|
export type RoleModelsCheck = {
|
|
61
106
|
ok: true;
|
|
62
107
|
} | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-routing.d.ts","sourceRoot":"","sources":["../src/model-routing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,qEAAqE;AACrE,eAAO,MAAM,WAAW,0DAA2D,CAAC;AACpF,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,wFAAwF;AACxF,eAAO,MAAM,UAAU,qEAAuC,CAAC;AAC/D,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD
|
|
1
|
+
{"version":3,"file":"model-routing.d.ts","sourceRoot":"","sources":["../src/model-routing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,aAAa,EACnB,MAAM,cAAc,CAAC;AAEtB,qEAAqE;AACrE,eAAO,MAAM,WAAW,0DAA2D,CAAC;AACpF,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,wFAAwF;AACxF,eAAO,MAAM,UAAU,qEAAuC,CAAC;AAC/D,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,aAAa,oDAAgB,CAAC;AAC3C,MAAM,MAAM,MAAM,GAAG,WAAW,CAAC;AAEjC,4EAA4E;AAC5E,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;AAE5D;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;AAE3D;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,+EAA+E;AAC/E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAE5F;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAIvG;AAED,sEAAsE;AACtE,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,aAAa,CAAC;IACzB,UAAU,EAAE,aAAa,CAAC;CAC3B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW,CAAA;CAAE,EAC5D,MAAM,CAAC,EAAE,aAAa,GAAG,IAAI,GAC5B,YAAY,CAkCd;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW,CAAA;CAAE,EAC5D,MAAM,CAAC,EAAE,aAAa,GAAG,IAAI,GAC5B,MAAM,EAAE,CAGV;AAED,MAAM,MAAM,eAAe,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,eAAe,CAiCnE"}
|
package/dist/model-routing.js
CHANGED
|
@@ -28,14 +28,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
28
28
|
exports.EFFORT_LEVELS = exports.MODEL_KEYS = exports.MODEL_ROLES = void 0;
|
|
29
29
|
exports.isBrainOnlyModel = isBrainOnlyModel;
|
|
30
30
|
exports.modelFor = modelFor;
|
|
31
|
+
exports.effortFor = effortFor;
|
|
32
|
+
exports.resolveRole = resolveRole;
|
|
31
33
|
exports.modelArgs = modelArgs;
|
|
32
34
|
exports.checkRoleModels = checkRoleModels;
|
|
35
|
+
const core_1 = require("@looply/core");
|
|
33
36
|
/** The roles that drive a model, in the order a round meets them. */
|
|
34
37
|
exports.MODEL_ROLES = ['implementer', 'verifier', 'scanner', 'brain'];
|
|
35
38
|
/** The keys `agent.models` may carry: every role, plus the one that covers the rest. */
|
|
36
39
|
exports.MODEL_KEYS = ['default', ...exports.MODEL_ROLES];
|
|
37
|
-
/**
|
|
38
|
-
|
|
40
|
+
/**
|
|
41
|
+
* `--effort`, as Claude Code spells it. Checked against `claude --help` on
|
|
42
|
+
* 2026-09-13. Declared in core, so the server refuses exactly what this does.
|
|
43
|
+
*/
|
|
44
|
+
exports.EFFORT_LEVELS = core_1.AGENT_EFFORTS;
|
|
39
45
|
/**
|
|
40
46
|
* Which model ids may only be the brain's.
|
|
41
47
|
*
|
|
@@ -45,25 +51,89 @@ exports.EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max'];
|
|
|
45
51
|
* one should not be able to step around a cost rule with a capital letter.
|
|
46
52
|
*/
|
|
47
53
|
function isBrainOnlyModel(model) {
|
|
48
|
-
return
|
|
54
|
+
return (0, core_1.isBrainOnlyModelId)(model);
|
|
49
55
|
}
|
|
50
|
-
/** The model
|
|
56
|
+
/** The model config.yaml names for a role, or undefined when it names none. */
|
|
51
57
|
function modelFor(role, models) {
|
|
52
58
|
return models?.[role] ?? models?.default;
|
|
53
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* The effort config.yaml names for a role. `agent.effort` is either one level
|
|
62
|
+
* for every role (the original shape, still byte-compatible) or a map with an
|
|
63
|
+
* optional `default`.
|
|
64
|
+
*/
|
|
65
|
+
function effortFor(role, effort) {
|
|
66
|
+
if (effort === undefined)
|
|
67
|
+
return undefined;
|
|
68
|
+
if (typeof effort === 'string')
|
|
69
|
+
return effort;
|
|
70
|
+
return effort[role] ?? effort.default;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The model and effort a role runs on the BUILT-IN provider, field by field:
|
|
74
|
+
*
|
|
75
|
+
* config.yaml > remote project settings > DEFAULT_AGENT_SETTINGS
|
|
76
|
+
*
|
|
77
|
+
* config.yaml wins because it is a person's decision written in the repository
|
|
78
|
+
* on the machine itself; remote settings (console, integrations) fill what the
|
|
79
|
+
* file leaves unsaid; the built-in table fills the rest. Model and effort are
|
|
80
|
+
* resolved independently, so a file naming only an effort still takes the
|
|
81
|
+
* remote or default model.
|
|
82
|
+
*
|
|
83
|
+
* ⚠️ A remote Fable model for a non-brain role is ignored here even though the
|
|
84
|
+
* validator refuses it at the API: the cache is a file on disk, and the rule
|
|
85
|
+
* is cheap to hold twice.
|
|
86
|
+
*/
|
|
87
|
+
function resolveRole(role, spec, remote) {
|
|
88
|
+
const fallback = core_1.DEFAULT_AGENT_SETTINGS[role];
|
|
89
|
+
const fromRemote = remote?.[role];
|
|
90
|
+
let model;
|
|
91
|
+
let modelFrom;
|
|
92
|
+
const configured = modelFor(role, spec.models);
|
|
93
|
+
const remoteModel = fromRemote?.model;
|
|
94
|
+
if (configured !== undefined) {
|
|
95
|
+
model = configured;
|
|
96
|
+
modelFrom = 'config.yaml';
|
|
97
|
+
}
|
|
98
|
+
else if (remoteModel !== undefined && (role === 'brain' || !(0, core_1.isBrainOnlyModelId)(remoteModel))) {
|
|
99
|
+
model = remoteModel;
|
|
100
|
+
modelFrom = 'remote';
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
model = fallback.model;
|
|
104
|
+
modelFrom = 'default';
|
|
105
|
+
}
|
|
106
|
+
let effort;
|
|
107
|
+
let effortFrom;
|
|
108
|
+
const configuredEffort = effortFor(role, spec.effort);
|
|
109
|
+
if (configuredEffort !== undefined) {
|
|
110
|
+
effort = configuredEffort;
|
|
111
|
+
effortFrom = 'config.yaml';
|
|
112
|
+
}
|
|
113
|
+
else if (fromRemote?.effort !== undefined) {
|
|
114
|
+
effort = fromRemote.effort;
|
|
115
|
+
effortFrom = 'remote';
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
effort = fallback.effort;
|
|
119
|
+
effortFrom = 'default';
|
|
120
|
+
}
|
|
121
|
+
return { model, effort, modelFrom, effortFrom };
|
|
122
|
+
}
|
|
54
123
|
/**
|
|
55
124
|
* The arguments that put a role on its model, ready to splice into a Claude
|
|
56
|
-
* Code command line.
|
|
57
|
-
*
|
|
125
|
+
* Code command line.
|
|
126
|
+
*
|
|
127
|
+
* ⚠️ CHANGED DELIBERATELY: this used to be EMPTY when nothing was configured,
|
|
128
|
+
* so the provider's own default ran (whatever Claude Code happened to pick on
|
|
129
|
+
* that machine). Every built-in turn now names its model and effort — from
|
|
130
|
+
* config.yaml, the project's remote settings, or `DEFAULT_AGENT_SETTINGS` — so
|
|
131
|
+
* what a role runs is a Looply decision that `looply doctor` can print, not an
|
|
132
|
+
* accident of the machine. Only ever called on the built-in branch.
|
|
58
133
|
*/
|
|
59
|
-
function modelArgs(role, spec) {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
if (model !== undefined)
|
|
63
|
-
out.push('--model', model);
|
|
64
|
-
if (spec.effort !== undefined)
|
|
65
|
-
out.push('--effort', spec.effort);
|
|
66
|
-
return out;
|
|
134
|
+
function modelArgs(role, spec, remote) {
|
|
135
|
+
const r = resolveRole(role, spec, remote);
|
|
136
|
+
return ['--model', r.model, '--effort', r.effort];
|
|
67
137
|
}
|
|
68
138
|
/**
|
|
69
139
|
* Is this `agent.models` block one looply will drive?
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-routing.js","sourceRoot":"","sources":["../src/model-routing.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;
|
|
1
|
+
{"version":3,"file":"model-routing.js","sourceRoot":"","sources":["../src/model-routing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type AgentSettings } from '@looply/core';
|
|
2
|
+
import { type Effort, type RoleEfforts, type RoleModels } from './model-routing';
|
|
3
|
+
/**
|
|
4
|
+
* THE PROJECT'S REMOTE MODEL SETTINGS, AS THIS MACHINE LAST HEARD THEM.
|
|
5
|
+
*
|
|
6
|
+
* The server holds per-project model/effort choices (set from the console or
|
|
7
|
+
* by an integration). The standalone daemon pulls them on start and every few
|
|
8
|
+
* minutes and writes them HERE; every built-in model turn — a daemon-launched
|
|
9
|
+
* run, `looply run`, `scan`, `verify` — reads this file at launch time.
|
|
10
|
+
*
|
|
11
|
+
* Why a cached file rather than a field on a payload the run already fetches:
|
|
12
|
+
* a run may start with the server unreachable, and a machine that goes offline
|
|
13
|
+
* must keep running the models it was last told to — not silently fall back to
|
|
14
|
+
* the defaults mid-night. One writer (the daemon), many readers, and a reader
|
|
15
|
+
* that finds nothing, or something malformed, gets the defaults.
|
|
16
|
+
*
|
|
17
|
+
* The value is re-validated on every read with the same core rule the server
|
|
18
|
+
* applies on write, so a hand-edited or corrupted file cannot put a Fable
|
|
19
|
+
* model on an agent role or smuggle a flag into the command line.
|
|
20
|
+
*/
|
|
21
|
+
export declare const AGENT_SETTINGS_FILE = "agent-settings.json";
|
|
22
|
+
/** How often the daemon asks the server. */
|
|
23
|
+
export declare const DEFAULT_AGENT_SETTINGS_POLL_MS: number;
|
|
24
|
+
export interface AgentSettingsCache {
|
|
25
|
+
/** Null means "back to defaults", which is an answer, not an absence. */
|
|
26
|
+
settings: AgentSettings | null;
|
|
27
|
+
/** When the server says the settings last changed. */
|
|
28
|
+
updatedAt: string | null;
|
|
29
|
+
/** When this machine last heard it. */
|
|
30
|
+
fetchedAt: string;
|
|
31
|
+
}
|
|
32
|
+
/** The cached answer, or null when there is none or it does not validate. */
|
|
33
|
+
export declare function readAgentSettingsCache(stateDir: string): AgentSettingsCache | null;
|
|
34
|
+
/** Atomic: a reader never sees half a file. */
|
|
35
|
+
export declare function writeAgentSettingsCache(stateDir: string, value: AgentSettingsCache): void;
|
|
36
|
+
/**
|
|
37
|
+
* The remote settings that apply to a project directory (a worktree resolves
|
|
38
|
+
* to its repository's shared state), or null. Never throws: a model turn must
|
|
39
|
+
* not fail because a cache could not be read — it runs the defaults instead.
|
|
40
|
+
*/
|
|
41
|
+
export declare function remoteAgentSettingsFor(projectDir: string): AgentSettings | null;
|
|
42
|
+
export interface AgentSettingsPullDeps {
|
|
43
|
+
/** `GET /v1/projects/:id/agent-settings`. */
|
|
44
|
+
fetch(): Promise<unknown>;
|
|
45
|
+
stateDir: string;
|
|
46
|
+
log(line: string): void;
|
|
47
|
+
now(): number;
|
|
48
|
+
}
|
|
49
|
+
export type AgentSettingsPullResult = 'updated' | 'unchanged' | 'failed';
|
|
50
|
+
/**
|
|
51
|
+
* One pull: ask the server, and write the cache when the answer changed.
|
|
52
|
+
*
|
|
53
|
+
* A failure keeps whatever the cache holds — an outage must not reset a
|
|
54
|
+
* machine to defaults. Offline is reported by the heartbeat already; anything
|
|
55
|
+
* else (an older server without the route, a malformed answer) is said once
|
|
56
|
+
* per outage rather than every five minutes.
|
|
57
|
+
*/
|
|
58
|
+
export declare function makeAgentSettingsPull(deps: AgentSettingsPullDeps): () => Promise<AgentSettingsPullResult>;
|
|
59
|
+
/**
|
|
60
|
+
* The lines `looply doctor` and `looply status` print: per role, the model and
|
|
61
|
+
* effort and where each came from.
|
|
62
|
+
*/
|
|
63
|
+
export declare function describeModelRouting(spec: {
|
|
64
|
+
models?: RoleModels;
|
|
65
|
+
effort?: Effort | RoleEfforts;
|
|
66
|
+
}, builtIn: boolean, remote: AgentSettings | null): string[];
|
|
67
|
+
//# sourceMappingURL=model-settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-settings.d.ts","sourceRoot":"","sources":["../src/model-settings.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAEzE,OAAO,EAA4B,KAAK,MAAM,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG3G;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AAEzD,4CAA4C;AAC5C,eAAO,MAAM,8BAA8B,QAAa,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,sDAAsD;IACtD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,6EAA6E;AAC7E,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAoBlF;AAED,+CAA+C;AAC/C,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAMzF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAM/E;AAED,MAAM,WAAW,qBAAqB;IACpC,6CAA6C;IAC7C,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,IAAI,MAAM,CAAC;CACf;AAED,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEzE;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,qBAAqB,GAAG,MAAM,OAAO,CAAC,uBAAuB,CAAC,CA4DzG;AAYD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW,CAAA;CAAE,EAC5D,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,aAAa,GAAG,IAAI,GAC3B,MAAM,EAAE,CAeV"}
|