@corenel/harness 0.2.0 → 0.4.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/dist/acp/agentMap.d.ts +34 -0
- package/dist/acp/agentMap.d.ts.map +1 -0
- package/dist/acp/agentMap.js +110 -0
- package/dist/acp/agentMap.js.map +1 -0
- package/dist/acp/index.d.ts +4 -0
- package/dist/acp/index.d.ts.map +1 -0
- package/dist/acp/index.js +6 -0
- package/dist/acp/index.js.map +1 -0
- package/dist/acp/policyMap.d.ts +55 -0
- package/dist/acp/policyMap.d.ts.map +1 -0
- package/dist/acp/policyMap.js +121 -0
- package/dist/acp/policyMap.js.map +1 -0
- package/dist/acp/types.d.ts +41 -0
- package/dist/acp/types.d.ts.map +1 -0
- package/dist/acp/types.js +14 -0
- package/dist/acp/types.js.map +1 -0
- package/dist/api/backend.d.ts +39 -0
- package/dist/api/backend.d.ts.map +1 -0
- package/dist/api/backend.js +126 -0
- package/dist/api/backend.js.map +1 -0
- package/dist/api/client.d.ts +95 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +212 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/fileMirrorSource.d.ts +24 -0
- package/dist/api/fileMirrorSource.d.ts.map +1 -0
- package/dist/api/fileMirrorSource.js +59 -0
- package/dist/api/fileMirrorSource.js.map +1 -0
- package/dist/api/mirror.d.ts +102 -0
- package/dist/api/mirror.d.ts.map +1 -0
- package/dist/api/mirror.js +204 -0
- package/dist/api/mirror.js.map +1 -0
- package/dist/api/mirrorScheduler.d.ts +56 -0
- package/dist/api/mirrorScheduler.d.ts.map +1 -0
- package/dist/api/mirrorScheduler.js +167 -0
- package/dist/api/mirrorScheduler.js.map +1 -0
- package/dist/compression.d.ts +15 -1
- package/dist/compression.d.ts.map +1 -1
- package/dist/compression.js +32 -1
- package/dist/compression.js.map +1 -1
- package/dist/core/loop.d.ts +12 -0
- package/dist/core/loop.d.ts.map +1 -1
- package/dist/core/loop.js +138 -14
- package/dist/core/loop.js.map +1 -1
- package/dist/core/spawn.d.ts +54 -0
- package/dist/core/spawn.d.ts.map +1 -0
- package/dist/core/spawn.js +58 -0
- package/dist/core/spawn.js.map +1 -0
- package/dist/dag/executeNode.js +2 -2
- package/dist/fileSchema.js +1 -1
- package/dist/guardrail/guardrail.js +1 -1
- package/dist/guardrail/index.js +7 -7
- package/dist/guardrail/permission-service.js +1 -1
- package/dist/guardrail/serialize.js +1 -1
- package/dist/guardrail/store.js +2 -2
- package/dist/install/lockfile.d.ts +79 -0
- package/dist/install/lockfile.d.ts.map +1 -0
- package/dist/install/lockfile.js +155 -0
- package/dist/install/lockfile.js.map +1 -0
- package/dist/install/store.d.ts +13 -0
- package/dist/install/store.d.ts.map +1 -0
- package/dist/install/store.js +38 -0
- package/dist/install/store.js.map +1 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +6 -1
- package/dist/log.js.map +1 -1
- package/dist/prompts/config.js +2 -2
- package/dist/prompts/host.d.ts +4 -0
- package/dist/prompts/host.d.ts.map +1 -1
- package/dist/prompts/host.js.map +1 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +13 -6
- package/dist/prompts/index.js.map +1 -1
- package/dist/prompts/library/defaults.generated.js +2 -2
- package/dist/prompts/library/defaults.generated.js.map +1 -1
- package/dist/prompts/library/index.js +1 -1
- package/dist/providers/contextWindow.d.ts +19 -0
- package/dist/providers/contextWindow.d.ts.map +1 -0
- package/dist/providers/contextWindow.js +68 -0
- package/dist/providers/contextWindow.js.map +1 -0
- package/dist/providers/gateway.d.ts +3 -0
- package/dist/providers/gateway.d.ts.map +1 -1
- package/dist/providers/gateway.js +4 -1
- package/dist/providers/gateway.js.map +1 -1
- package/dist/sessions/apiLeaseStore.d.ts +10 -0
- package/dist/sessions/apiLeaseStore.d.ts.map +1 -0
- package/dist/sessions/apiLeaseStore.js +41 -0
- package/dist/sessions/apiLeaseStore.js.map +1 -0
- package/dist/sessions/blobGc.d.ts +62 -0
- package/dist/sessions/blobGc.d.ts.map +1 -0
- package/dist/sessions/blobGc.js +154 -0
- package/dist/sessions/blobGc.js.map +1 -0
- package/dist/sessions/fileRecallStore.js +1 -1
- package/dist/sessions/fileSessionStore.js +1 -1
- package/dist/sessions/head.d.ts +90 -0
- package/dist/sessions/head.d.ts.map +1 -0
- package/dist/sessions/head.js +82 -0
- package/dist/sessions/head.js.map +1 -0
- package/dist/sessions/inflight.d.ts +58 -0
- package/dist/sessions/inflight.d.ts.map +1 -0
- package/dist/sessions/inflight.js +0 -0
- package/dist/sessions/inflight.js.map +1 -0
- package/dist/sessions/lease.d.ts +59 -0
- package/dist/sessions/lease.d.ts.map +1 -0
- package/dist/sessions/lease.js +115 -0
- package/dist/sessions/lease.js.map +1 -0
- package/dist/sessions/leaseStore.d.ts +46 -0
- package/dist/sessions/leaseStore.d.ts.map +1 -0
- package/dist/sessions/leaseStore.js +58 -0
- package/dist/sessions/leaseStore.js.map +1 -0
- package/dist/sessions/timeline.d.ts +134 -0
- package/dist/sessions/timeline.d.ts.map +1 -0
- package/dist/sessions/timeline.js +127 -0
- package/dist/sessions/timeline.js.map +1 -0
- package/dist/sidecar/host.d.ts +241 -5
- package/dist/sidecar/host.d.ts.map +1 -1
- package/dist/sidecar/host.js +630 -5
- package/dist/sidecar/host.js.map +1 -1
- package/dist/sidecar/server.d.ts +124 -2
- package/dist/sidecar/server.d.ts.map +1 -1
- package/dist/sidecar/server.js +620 -9
- package/dist/sidecar/server.js.map +1 -1
- package/dist/sidecar/wsChannel.d.ts +4 -0
- package/dist/sidecar/wsChannel.d.ts.map +1 -0
- package/dist/sidecar/wsChannel.js +62 -0
- package/dist/sidecar/wsChannel.js.map +1 -0
- package/dist/skills.js +2 -2
- package/dist/snapshot/effects.d.ts +69 -0
- package/dist/snapshot/effects.d.ts.map +1 -0
- package/dist/snapshot/effects.js +67 -0
- package/dist/snapshot/effects.js.map +1 -0
- package/dist/snapshot/manifest.d.ts +73 -0
- package/dist/snapshot/manifest.d.ts.map +1 -0
- package/dist/snapshot/manifest.js +141 -0
- package/dist/snapshot/manifest.js.map +1 -0
- package/dist/snapshot/tree.d.ts +62 -0
- package/dist/snapshot/tree.d.ts.map +1 -0
- package/dist/snapshot/tree.js +147 -0
- package/dist/snapshot/tree.js.map +1 -0
- package/dist/tools/builtins.d.ts.map +1 -1
- package/dist/tools/builtins.js +67 -8
- package/dist/tools/builtins.js.map +1 -1
- package/dist/tools/callAgent.d.ts +16 -0
- package/dist/tools/callAgent.d.ts.map +1 -0
- package/dist/tools/callAgent.js +53 -0
- package/dist/tools/callAgent.js.map +1 -0
- package/dist/tools/files.d.ts +10 -0
- package/dist/tools/files.d.ts.map +1 -1
- package/dist/tools/files.js +159 -8
- package/dist/tools/files.js.map +1 -1
- package/dist/tools/http.js +1 -1
- package/dist/tools/namespaces.d.ts +1 -1
- package/dist/tools/namespaces.d.ts.map +1 -1
- package/dist/tools/namespaces.js +40 -2
- package/dist/tools/namespaces.js.map +1 -1
- package/dist/tools/procs.d.ts +18 -0
- package/dist/tools/procs.d.ts.map +1 -0
- package/dist/tools/procs.js +281 -0
- package/dist/tools/procs.js.map +1 -0
- package/dist/tools/todo.d.ts.map +1 -1
- package/dist/tools/todo.js +12 -0
- package/dist/tools/todo.js.map +1 -1
- package/package.json +18 -7
package/dist/tools/files.js
CHANGED
|
@@ -15,26 +15,177 @@ function ensureWritable(path) {
|
|
|
15
15
|
throw new Error(`${PROMPD_INSTALL_DIR}/ install dirs are read-only (managed by package install). Refusing to modify "${path}". Install or remove packages instead of editing them directly.`);
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
function describe(n) {
|
|
19
|
+
return `${n.kind === 'directory' ? '[dir] ' : ''}${n.path}${n.kind === 'file' && n.size != null ? ` (${n.size}b)` : ''}`;
|
|
20
|
+
}
|
|
21
|
+
/** Every node in the ALREADY-MATERIALIZED tree, in BFS (level) order: every
|
|
22
|
+
* depth-0 node before ANY depth-1 node, every depth-1 before any depth-2, and
|
|
23
|
+
* so on. Used only to decide WHICH nodes survive the cap (see
|
|
24
|
+
* `selectByBreadthFirstCap` below) — never to render, because that reordering
|
|
25
|
+
* has its own cost (see the doc comment there). Also doubles as the total
|
|
26
|
+
* node count.
|
|
27
|
+
*
|
|
28
|
+
* IMPORTANT — what `maxDepth` does and does not save: `roots` here is the
|
|
29
|
+
* full result of `FileService.list()`, which has ALREADY recursed the whole
|
|
30
|
+
* subtree by the time this function ever sees it — `FileService.list(dir?:
|
|
31
|
+
* string)` (`packages/protocol/files.ts`) has no depth parameter, and none of
|
|
32
|
+
* its implementations (`packages/tools-node/fileService.ts`,
|
|
33
|
+
* `src/services/files/DirectoryHandleFileService.ts`,
|
|
34
|
+
* `src/services/files/SidecarFileService.ts`) stop early. So `maxDepth`
|
|
35
|
+
* bounds what is COLLECTED FROM that in-memory listing into `out` (and
|
|
36
|
+
* therefore what is returned to the model) — it does NOT reduce the
|
|
37
|
+
* `fs.readdir`/`fs.stat`/IPC cost of producing `roots` in the first place.
|
|
38
|
+
* That deeper fix belongs in the `FileService.list` port and its
|
|
39
|
+
* implementations, not here. Omit `maxDepth` for the unlimited,
|
|
40
|
+
* today's-behavior case. */
|
|
41
|
+
function bfsNodes(roots, maxDepth = Infinity) {
|
|
42
|
+
const out = [];
|
|
43
|
+
let level = roots;
|
|
44
|
+
let depth = 1;
|
|
45
|
+
while (level.length) {
|
|
46
|
+
const next = [];
|
|
47
|
+
for (const n of level) {
|
|
48
|
+
out.push(n);
|
|
49
|
+
if (n.kind === 'directory' && n.children?.length && depth < maxDepth)
|
|
50
|
+
next.push(...n.children);
|
|
51
|
+
}
|
|
52
|
+
level = next;
|
|
53
|
+
depth++;
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
/** Cap on entries a single `list_files` call returns. A stranger typing `ls` in
|
|
58
|
+
* a large repo (no `dir`) got the WHOLE tree back — 4,369 entries in one real
|
|
59
|
+
* run, an 87K-token prompt on the very next model call. A few hundred entries
|
|
60
|
+
* is plenty to orient in a repo (see any file's immediate siblings, spot the
|
|
61
|
+
* top-level layout) without paying for the whole thing; 300 is that number —
|
|
62
|
+
* generous enough that an ordinary project's top few levels fit whole, small
|
|
63
|
+
* enough that a monorepo's `node_modules`-scale sprawl can't leak through
|
|
64
|
+
* uncapped. Every host (browser, node CLI, sidecar) shares this file, so the
|
|
65
|
+
* cap applies uniformly rather than per-host. */
|
|
66
|
+
export const LIST_FILES_MAX_ENTRIES = 300;
|
|
67
|
+
/** WHICH nodes survive: the first `LIST_FILES_MAX_ENTRIES` in BFS order —
|
|
68
|
+
* see `bfsNodes`'s comment for why breadth-first is what makes a global count
|
|
69
|
+
* cap keep the top of the tree instead of one arbitrary deep branch. Returns
|
|
70
|
+
* the surviving set plus the true total (for the marker). */
|
|
71
|
+
function selectByBreadthFirstCap(roots, maxDepth) {
|
|
72
|
+
const bfs = bfsNodes(roots, maxDepth);
|
|
73
|
+
return { keep: new Set(bfs.slice(0, LIST_FILES_MAX_ENTRIES)), total: bfs.length };
|
|
74
|
+
}
|
|
75
|
+
/** Render the surviving nodes in ORIGINAL TREE ORDER (depth-first pre-order —
|
|
76
|
+
* the natural, readable shape: a directory immediately followed by its own
|
|
77
|
+
* contents), not the BFS order used to select them.
|
|
78
|
+
*
|
|
79
|
+
* BFS decides WHICH 300 entries survive; it must not also decide how they are
|
|
80
|
+
* DISPLAYED. In a small repo that was never truncated, every node survives
|
|
81
|
+
* (`keep` has everything), and rendering in BFS order would still separate
|
|
82
|
+
* every directory from its own contents — level by level instead of subtree
|
|
83
|
+
* by subtree — which is a strictly worse read for the overwhelmingly common
|
|
84
|
+
* case (no truncation at all) to fix a problem that only exists when
|
|
85
|
+
* truncation happens. So: select breadth-first, render depth-first, over the
|
|
86
|
+
* SAME `keep` set — a directory's children only appear here if the directory
|
|
87
|
+
* itself survived (BFS always keeps a parent before any of its children, so
|
|
88
|
+
* that's automatic, not a race), and only the children that themselves
|
|
89
|
+
* survived. */
|
|
90
|
+
function describeInTreeOrder(roots, keep, maxDepth = Infinity, depth = 1, out = []) {
|
|
91
|
+
for (const n of roots) {
|
|
92
|
+
if (!keep.has(n))
|
|
93
|
+
continue;
|
|
94
|
+
out.push(describe(n));
|
|
95
|
+
if (n.kind === 'directory' && n.children?.length && depth < maxDepth) {
|
|
96
|
+
describeInTreeOrder(n.children, keep, maxDepth, depth + 1, out);
|
|
97
|
+
}
|
|
23
98
|
}
|
|
24
99
|
return out;
|
|
25
100
|
}
|
|
101
|
+
/** The unmistakable trailing marker — never let the model believe a
|
|
102
|
+
* truncated listing is the whole tree.
|
|
103
|
+
*
|
|
104
|
+
* `total` (and therefore `omitted`) is always the count of entries within the
|
|
105
|
+
* scope this call actually collected FROM — i.e. `bfsNodes`'s output length,
|
|
106
|
+
* which a depth limit already shrank before this is ever called (see
|
|
107
|
+
* `bfsNodes`'s doc comment — the underlying `FileService.list` still walked
|
|
108
|
+
* the full subtree; `maxDepth` only bounds what was collected from that
|
|
109
|
+
* result). So when `depth` is given, `total` here is the count within that
|
|
110
|
+
* depth, not the size of the whole tree, and the two truncation reasons — a
|
|
111
|
+
* depth limit excluding lower levels, vs. the entry cap additionally cutting
|
|
112
|
+
* within the collected scope — are DIFFERENT signals the model needs to tell
|
|
113
|
+
* apart to decide what to do next.
|
|
114
|
+
*
|
|
115
|
+
* Written as plain consecutive sentences, not a parenthetical nested inside
|
|
116
|
+
* the count — a model parses "340 total (not the whole tree (because...))"
|
|
117
|
+
* less reliably than separate sentences saying the same things in order. And
|
|
118
|
+
* when `depth` is in force, the right remedy is a LARGER `depth` (to see
|
|
119
|
+
* deeper), never "limit how many levels" (it's already limited) — telling the
|
|
120
|
+
* model to narrow further when it already narrowed is the wrong direction. */
|
|
121
|
+
function truncationMarker(total, maxDepth) {
|
|
122
|
+
const omitted = total - LIST_FILES_MAX_ENTRIES;
|
|
123
|
+
const omittedEntries = `${omitted} more entr${omitted === 1 ? 'y' : 'ies'} omitted`;
|
|
124
|
+
if (maxDepth != null && Number.isFinite(maxDepth)) {
|
|
125
|
+
return `… truncated: ${omittedEntries}. ${total} entries were collected within depth ${maxDepth}; ` +
|
|
126
|
+
'deeper levels were not counted, so this is not the size of the whole tree. ' +
|
|
127
|
+
'Pass `dir` to narrow by subdirectory, or a larger `depth` to go deeper.';
|
|
128
|
+
}
|
|
129
|
+
return `… truncated: ${omittedEntries} (${total} total). ` +
|
|
130
|
+
'Pass `dir` to list a specific subdirectory (narrower breadth), or `depth` to limit how many levels deep the listing goes (narrower depth), instead of the whole tree.';
|
|
131
|
+
}
|
|
132
|
+
/** Normalizes model-supplied `depth` into a safe, meaningful bound, or
|
|
133
|
+
* `undefined` for "unlimited" (today's behavior — full recursive listing,
|
|
134
|
+
* still subject to the entry cap). Never throws: `depth` is model output and
|
|
135
|
+
* may be anything.
|
|
136
|
+
*
|
|
137
|
+
* Rules:
|
|
138
|
+
* - missing / null / not coercible to a finite number -> `undefined`
|
|
139
|
+
* (unlimited) — the safest fallback, since it reproduces the behavior
|
|
140
|
+
* every existing caller already relies on.
|
|
141
|
+
* - a numeric string ("2") is accepted the same as a number.
|
|
142
|
+
* - non-finite (`NaN`, `Infinity`) -> `undefined` (unlimited).
|
|
143
|
+
* - fractional values are floored (2.7 -> 2): depth is a count of whole
|
|
144
|
+
* levels, there is no such thing as "2.7 levels deep".
|
|
145
|
+
* - anything below 1 (0, negative) is clamped up to 1 — the shallowest
|
|
146
|
+
* depth that still means something ("immediate children only"), rather
|
|
147
|
+
* than being rejected or treated as unlimited.
|
|
148
|
+
* - very large values (1e9) are accepted as-is; they behave as
|
|
149
|
+
* "effectively unlimited" and are still bounded by `LIST_FILES_MAX_ENTRIES`
|
|
150
|
+
* like the unlimited case, so there's no separate ceiling to enforce. */
|
|
151
|
+
function normalizeDepth(args) {
|
|
152
|
+
const v = args['depth'];
|
|
153
|
+
if (v == null)
|
|
154
|
+
return undefined;
|
|
155
|
+
const n = typeof v === 'number' ? v : typeof v === 'string' ? Number(v) : NaN;
|
|
156
|
+
if (!Number.isFinite(n))
|
|
157
|
+
return undefined;
|
|
158
|
+
const floored = Math.floor(n);
|
|
159
|
+
return floored < 1 ? 1 : floored;
|
|
160
|
+
}
|
|
26
161
|
export const listFilesTool = {
|
|
27
162
|
name: 'list_files',
|
|
28
163
|
description: 'List files and directories in the workspace (the open folder or the virtual workspace). ' +
|
|
29
|
-
'
|
|
164
|
+
'Start shallow and drill in: pass `depth` to limit how many levels deep the listing goes ' +
|
|
165
|
+
'(vertical narrowing — `depth: 1` returns just the immediate children of the target, a quick ' +
|
|
166
|
+
'orientation call) and/or `dir` to list a specific subdirectory instead of the whole tree ' +
|
|
167
|
+
'(horizontal narrowing). Omit `depth` for a full recursive listing. Returns paths relative to ' +
|
|
168
|
+
'the workspace root.',
|
|
30
169
|
parameters: {
|
|
31
170
|
type: 'object',
|
|
32
|
-
properties: {
|
|
171
|
+
properties: {
|
|
172
|
+
dir: { type: 'string', description: 'Subdirectory to list (optional; omit for the root).' },
|
|
173
|
+
depth: {
|
|
174
|
+
type: 'number',
|
|
175
|
+
description: 'How many levels deep to list (optional; omit for the full recursive tree). ' +
|
|
176
|
+
'1 = immediate children of `dir` (or the root) only, 2 = two levels, and so on. ' +
|
|
177
|
+
'Values below 1 (0, negative) are treated as 1, not rejected.',
|
|
178
|
+
},
|
|
179
|
+
},
|
|
33
180
|
},
|
|
34
181
|
async run(args, ctx) {
|
|
35
182
|
const files = requireFiles(ctx);
|
|
36
183
|
const nodes = await files.list(str(args, 'dir') || undefined);
|
|
37
|
-
const
|
|
184
|
+
const maxDepth = normalizeDepth(args);
|
|
185
|
+
const { keep, total } = selectByBreadthFirstCap(nodes, maxDepth);
|
|
186
|
+
const lines = describeInTreeOrder(nodes, keep, maxDepth);
|
|
187
|
+
if (total > LIST_FILES_MAX_ENTRIES)
|
|
188
|
+
lines.push(truncationMarker(total, maxDepth));
|
|
38
189
|
return lines.length ? lines.join('\n') : '(empty)';
|
|
39
190
|
},
|
|
40
191
|
};
|
package/dist/tools/files.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../tools/files.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAExE,SAAS,GAAG,CAAC,IAA6B,EAAE,GAAW;IACrD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACpB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,YAAY,CAAC,GAAgB;IACpC,IAAI,CAAC,GAAG,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACnE,OAAO,GAAG,CAAC,KAAK,CAAC;AACnB,CAAC;AAED;sFACsF;AACtF,SAAS,cAAc,CAAC,IAAY;IAClC,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,GAAG,kBAAkB,kFAAkF,IAAI,iEAAiE,CAAC,CAAC;IAChM,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,KAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../tools/files.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/http.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ToolNamespace = 'fs' | 'prompd' | 'web' | 'memory' | 'agent' | 'shell' | 'system' | 'mcp' | 'skill' | 'other';
|
|
1
|
+
export type ToolNamespace = 'fs' | 'sidecar' | 'prompd' | 'web' | 'memory' | 'agent' | 'shell' | 'system' | 'mcp' | 'skill' | 'other';
|
|
2
2
|
/** Display order + labels for the namespaces (capabilities panel grouping). */
|
|
3
3
|
export declare const NAMESPACE_LABELS: {
|
|
4
4
|
ns: ToolNamespace;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"namespaces.d.ts","sourceRoot":"","sources":["../../tools/namespaces.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,aAAa,GACrB,IAAI,
|
|
1
|
+
{"version":3,"file":"namespaces.d.ts","sourceRoot":"","sources":["../../tools/namespaces.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,aAAa,GACrB,IAAI,GASJ,SAAS,GACT,QAAQ,GACR,KAAK,GACL,QAAQ,GACR,OAAO,GACP,OAAO,GACP,QAAQ,GACR,KAAK,GACL,OAAO,GACP,OAAO,CAAC;AAEZ,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,EAAE;IAAE,EAAE,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAYlE,CAAC;AAiCF,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,aAAa,CAUpE;AAED;;;4CAG4C;AAC5C,wBAAgB,WAAW,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAsBxD;AAED;6EAC6E;AAC7E,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,EAAE,CAE9D;AAED,iEAAiE;AACjE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAI1F;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,EAAE,EAAE,aAAa,GAAG,MAAM,CAEvD"}
|
package/dist/tools/namespaces.js
CHANGED
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Policy globs may target a whole namespace (fs:*) or one tool (fs:write_file),
|
|
12
12
|
* and legacy bare-name globs (write_file) still match for back-compat. */
|
|
13
|
-
import { matchesAnyGlob } from '../guardrail/glob';
|
|
13
|
+
import { matchesAnyGlob } from '../guardrail/glob.js';
|
|
14
14
|
/** Display order + labels for the namespaces (capabilities panel grouping). */
|
|
15
15
|
export const NAMESPACE_LABELS = [
|
|
16
16
|
{ ns: 'fs', label: 'Files' },
|
|
17
|
+
{ ns: 'sidecar', label: 'This machine' },
|
|
17
18
|
{ ns: 'prompd', label: 'Prompd' },
|
|
18
19
|
{ ns: 'web', label: 'Web' },
|
|
19
20
|
{ ns: 'memory', label: 'Memory' },
|
|
@@ -33,7 +34,26 @@ const BUILTIN_NAMESPACES = {
|
|
|
33
34
|
web_search: 'web',
|
|
34
35
|
save_memory: 'memory', recall_memory: 'memory', recall_result: 'memory',
|
|
35
36
|
kv_get: 'memory', kv_set: 'memory', search_sessions: 'memory',
|
|
36
|
-
ask_user: 'agent', spawn_agent: 'agent', spawn_agents: 'agent', todo_write: 'agent',
|
|
37
|
+
ask_user: 'agent', spawn_agent: 'agent', spawn_agents: 'agent', call_agent: 'agent', todo_write: 'agent',
|
|
38
|
+
// Named here as a backstop; the sidecar's own decls also carry `namespace`,
|
|
39
|
+
// and an explicit field always wins (resolveNamespace). Both say the same
|
|
40
|
+
// thing so a sidecar that predates this still lands in the right namespace.
|
|
41
|
+
sidecar_fs_read_file: 'sidecar', sidecar_fs_write_file: 'sidecar',
|
|
42
|
+
sidecar_fs_read_bytes: 'sidecar', sidecar_fs_list_dir: 'sidecar',
|
|
43
|
+
sidecar_fs_delete: 'sidecar', sidecar_shell_exec: 'sidecar',
|
|
44
|
+
// Host-side orchestration tools. They are not in allTools() - they reach the
|
|
45
|
+
// agent as remote decls (workerFactory) - but they are still governed by the
|
|
46
|
+
// policy, so they need a canonical address like everything else.
|
|
47
|
+
create_strategy: 'agent', edit_strategy: 'agent', view_strategy: 'agent', run_strategy: 'agent',
|
|
48
|
+
list_strategies: 'agent', list_saved_strategies: 'agent',
|
|
49
|
+
// Long-lived process control (proc_start/proc_stop/proc_list, see tools/procs.ts).
|
|
50
|
+
// `shell` is its own subject, deliberately distinct from the one-shot exec's
|
|
51
|
+
// `sidecar:shell_exec`: a process that stays running is a different risk from
|
|
52
|
+
// one that returns, and one address lets an operator ban (or allow) both
|
|
53
|
+
// start and stop together. proc_list is a read - it namespaces as `sidecar`
|
|
54
|
+
// (like the other machine-state reads) so it is NOT swept up by a `shell:*`
|
|
55
|
+
// deny; listing what is running carries none of spawn/kill's risk.
|
|
56
|
+
proc_start: 'shell', proc_stop: 'shell', proc_list: 'sidecar',
|
|
37
57
|
};
|
|
38
58
|
/** Resolve a tool's namespace: explicit field > built-in table > wire prefix > 'other'. */
|
|
39
59
|
export function resolveNamespace(tool) {
|
|
@@ -62,6 +82,24 @@ export function toolAddress(tool) {
|
|
|
62
82
|
if (m)
|
|
63
83
|
leaf = leaf.slice(m[0].length);
|
|
64
84
|
}
|
|
85
|
+
// `sidecar_fs_write_file` -> `sidecar:write_file`. The wire name carries the
|
|
86
|
+
// prefix because the MODEL sees a flat list and needs to tell the two apart;
|
|
87
|
+
// the address carries it in the namespace instead, so it is not said twice.
|
|
88
|
+
// `sidecar_fs_` before `sidecar_` — the longer prefix has to win.
|
|
89
|
+
if (ns === 'sidecar') {
|
|
90
|
+
for (const p of ['sidecar_fs_', 'sidecar_']) {
|
|
91
|
+
if (leaf.startsWith(p)) {
|
|
92
|
+
leaf = leaf.slice(p.length);
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// proc_start and proc_stop are two ends of the SAME governed capability
|
|
98
|
+
// (starting a long-lived process, and ending one) — they share the one
|
|
99
|
+
// address `shell:spawn` on purpose, so a policy rule can only ever gate both
|
|
100
|
+
// together, never start-without-stop or the reverse.
|
|
101
|
+
if (ns === 'shell' && (leaf === 'proc_start' || leaf === 'proc_stop'))
|
|
102
|
+
leaf = 'spawn';
|
|
65
103
|
return `${ns}:${leaf}`;
|
|
66
104
|
}
|
|
67
105
|
/** Candidate strings a policy glob may target for this tool: its address and its
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"namespaces.js","sourceRoot":"","sources":["../../tools/namespaces.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;0EAW0E;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"namespaces.js","sourceRoot":"","sources":["../../tools/namespaces.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AgentTool, SidecarProcs } from '@corenel/protocol';
|
|
2
|
+
export interface ProcToolsOptions {
|
|
3
|
+
/** Identifies the run/session starting processes through these tools. Stamped
|
|
4
|
+
* onto every ProcInfo.label this factory produces (agentLabel()) so a dock
|
|
5
|
+
* listing can show provenance even after a reload. Optional — omitting it
|
|
6
|
+
* still marks the process as agent-started, just without a session name. */
|
|
7
|
+
session?: string;
|
|
8
|
+
/** Cap on concurrent agent-started RUNNING processes (see AGENT_TAG /
|
|
9
|
+
* isAgentStarted) — independent of, and smaller than, the daemon's own
|
|
10
|
+
* MAX_RUNNING. Default DEFAULT_AGENT_BUDGET. */
|
|
11
|
+
agentBudget?: number;
|
|
12
|
+
}
|
|
13
|
+
/** Build the proc_start / proc_stop / proc_list tools over a live SidecarProcs.
|
|
14
|
+
* `procs` is expected to be a real, already-constructed process table (node
|
|
15
|
+
* child_process-backed in production, a fake in tests) — this file never
|
|
16
|
+
* constructs one itself. */
|
|
17
|
+
export declare function procTools(procs: SidecarProcs, opts?: ProcToolsOptions): AgentTool[];
|
|
18
|
+
//# sourceMappingURL=procs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"procs.d.ts","sourceRoot":"","sources":["../../tools/procs.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,SAAS,EAAoC,YAAY,EAAE,MAAM,mBAAmB,CAAC;AA0JnG,MAAM,WAAW,gBAAgB;IAC/B;;;gFAG4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;oDAEgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;4BAG4B;AAC5B,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,GAAE,gBAAqB,GAAG,SAAS,EAAE,CA2JvF"}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
const DEFAULT_SETTLE_MS = 10000;
|
|
2
|
+
const MIN_SETTLE_MS = 100;
|
|
3
|
+
const MAX_SETTLE_MS = 120000;
|
|
4
|
+
/** How many processes THIS factory will let the agent have running at once,
|
|
5
|
+
* counted within the daemon's own MAX_RUNNING=8. Deliberately smaller than the
|
|
6
|
+
* daemon's cap: the operator may want to run their own dev server, build watch,
|
|
7
|
+
* and log tail alongside whatever the agent starts, and an agent that can eat
|
|
8
|
+
* every slot locks them out of their own dock. This protects the OPERATOR, not
|
|
9
|
+
* the agent — it is not a courtesy limit the agent could reasonably ask to
|
|
10
|
+
* raise. */
|
|
11
|
+
const DEFAULT_AGENT_BUDGET = 3;
|
|
12
|
+
/** Every process this file starts is labelled with this marker (plus the
|
|
13
|
+
* session, when known) so a listing can tell "the agent started this" from "a
|
|
14
|
+
* human started this" from ProcInfo.label alone — durable across reloads and
|
|
15
|
+
* reconnects, because the label lives on the daemon-owned ProcInfo, not in this
|
|
16
|
+
* factory's own memory. */
|
|
17
|
+
const AGENT_TAG = 'agent';
|
|
18
|
+
function agentLabel(session, userLabel) {
|
|
19
|
+
const tag = session ? `${AGENT_TAG}:${session}` : AGENT_TAG;
|
|
20
|
+
return userLabel ? `${userLabel} [${tag}]` : `[${tag}]`;
|
|
21
|
+
}
|
|
22
|
+
/** True if a ProcInfo's label carries this file's agent marker — used to count
|
|
23
|
+
* agent-started processes from the daemon's OWN table (procs.list()), not from
|
|
24
|
+
* a Set this factory keeps in memory, so the budget holds even across a reload
|
|
25
|
+
* that drops this factory and rebuilds it. */
|
|
26
|
+
function isAgentStarted(info) {
|
|
27
|
+
return /\[agent(:[^\]]*)?\]/.test(info.label ?? '');
|
|
28
|
+
}
|
|
29
|
+
function str(args, key) {
|
|
30
|
+
const v = args[key];
|
|
31
|
+
return typeof v === 'string' && v.length ? v : undefined;
|
|
32
|
+
}
|
|
33
|
+
function clamp(n, min, max) {
|
|
34
|
+
if (!Number.isFinite(n))
|
|
35
|
+
return min;
|
|
36
|
+
return Math.min(Math.max(n, min), max);
|
|
37
|
+
}
|
|
38
|
+
/** Beyond this many characters, `renderTail`'s output is truncated -- same
|
|
39
|
+
* budget and reasoning as shellTool's MAX_OUTPUT (packages/cli/src/shellTool.ts):
|
|
40
|
+
* the retention ring this reads from is bounded at up to 200_000 chars
|
|
41
|
+
* (packages/sidecar/src/procs.ts / packages/cli/src/sidecarProcs.ts), which is
|
|
42
|
+
* still large enough for one `proc_start` result to blow the model's context
|
|
43
|
+
* window on its own. `corenel run`'s tool context wires no `recall`, so
|
|
44
|
+
* offload cannot rescue this the way it can a `tool-result` that goes through
|
|
45
|
+
* compression -- the cap has to be applied here. */
|
|
46
|
+
const RENDER_TAIL_MAX = 30000;
|
|
47
|
+
/** Render the buffered tail for a process. `truncated` must show up as WORDS —
|
|
48
|
+
* a tail that looks complete when it is not is the failure that matters, so
|
|
49
|
+
* this is never left to a caller to notice on its own. Keeps the LAST
|
|
50
|
+
* RENDER_TAIL_MAX characters (not the first): for a process still starting up,
|
|
51
|
+
* the most recent output is the one that says whether it's ready. */
|
|
52
|
+
function renderTail(procs, procId) {
|
|
53
|
+
const { chunks, truncated } = procs.backlog(procId, 0);
|
|
54
|
+
const body = chunks.map((c) => (c.stream === 'err' ? `[stderr] ${c.text}` : c.text)).join('');
|
|
55
|
+
const capped = body.length > RENDER_TAIL_MAX;
|
|
56
|
+
const shown = capped ? body.slice(body.length - RENDER_TAIL_MAX) : body;
|
|
57
|
+
const notes = [];
|
|
58
|
+
if (truncated)
|
|
59
|
+
notes.push('[some earlier output was dropped from the buffer and is not shown here]');
|
|
60
|
+
if (capped) {
|
|
61
|
+
notes.push(`[showing only the last ${RENDER_TAIL_MAX} of ${body.length} characters -- earlier output in ` +
|
|
62
|
+
'this result was cut to avoid blowing the context window]');
|
|
63
|
+
}
|
|
64
|
+
const note = notes.length ? `\n${notes.join('\n')}` : '';
|
|
65
|
+
return (shown ? `Output so far:\n${shown}` : 'No output yet.') + note;
|
|
66
|
+
}
|
|
67
|
+
function describeInfo(info) {
|
|
68
|
+
return `${info.procId} (pid ${info.pid ?? 'unknown'}): ${info.command}${info.label ? ` [${info.label}]` : ''}`;
|
|
69
|
+
}
|
|
70
|
+
/** Race the three ways `proc_start` can resolve. Whichever happens first wins;
|
|
71
|
+
* the other two paths are torn down (unsubscribed / timer cleared) so only one
|
|
72
|
+
* result is ever produced. */
|
|
73
|
+
function watchStart(procs, procId, waitFor, settleMs, onChunk) {
|
|
74
|
+
return new Promise((resolve) => {
|
|
75
|
+
let settled = false;
|
|
76
|
+
let lastSeenSeq = 0;
|
|
77
|
+
let buffer = '';
|
|
78
|
+
const finish = (outcome) => {
|
|
79
|
+
if (settled)
|
|
80
|
+
return;
|
|
81
|
+
settled = true;
|
|
82
|
+
clearTimeout(timer);
|
|
83
|
+
unsub();
|
|
84
|
+
resolve(outcome);
|
|
85
|
+
};
|
|
86
|
+
const handleChunk = (c) => {
|
|
87
|
+
if (c.seq <= lastSeenSeq)
|
|
88
|
+
return; // already seen (backlog catch-up vs. live)
|
|
89
|
+
lastSeenSeq = c.seq;
|
|
90
|
+
// Check settled BEFORE streaming: once this call has resolved, nothing
|
|
91
|
+
// reads ctx.stream for it anymore, so a chunk delivered afterwards
|
|
92
|
+
// (synchronous backlog catch-up can call finish() partway through, per
|
|
93
|
+
// the caller's own comment above) must not be pushed at all, not pushed
|
|
94
|
+
// and then ignored for wait_for matching.
|
|
95
|
+
if (settled)
|
|
96
|
+
return;
|
|
97
|
+
onChunk(c);
|
|
98
|
+
if (!waitFor)
|
|
99
|
+
return;
|
|
100
|
+
buffer += c.text;
|
|
101
|
+
if (buffer.includes(waitFor)) {
|
|
102
|
+
const info = procs.get(procId);
|
|
103
|
+
if (info)
|
|
104
|
+
finish({ kind: 'matched', info });
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
// `timer` and `unsub` must both be assigned BEFORE anything that can call
|
|
108
|
+
// `finish` synchronously (the backlog catch-up below can: a command that
|
|
109
|
+
// fails instantly, or prints its wait_for text, before this promise's
|
|
110
|
+
// caller ever gets control back) — finish() reads both.
|
|
111
|
+
const timer = setTimeout(() => {
|
|
112
|
+
const info = procs.get(procId);
|
|
113
|
+
if (info)
|
|
114
|
+
finish({ kind: 'settled', info });
|
|
115
|
+
}, settleMs);
|
|
116
|
+
const unsub = procs.subscribe((ev) => {
|
|
117
|
+
if (ev.procId !== procId)
|
|
118
|
+
return;
|
|
119
|
+
if (ev.kind === 'out')
|
|
120
|
+
handleChunk(ev.chunk);
|
|
121
|
+
else
|
|
122
|
+
finish({ kind: 'exited', info: ev.info });
|
|
123
|
+
});
|
|
124
|
+
// Catch up on anything already buffered/settled BEFORE we subscribed — the
|
|
125
|
+
// daemon's spawn() has an await in it (root confinement), so output (or
|
|
126
|
+
// even exit, for a command that fails instantly) can land before this
|
|
127
|
+
// function's caller ever gets control back.
|
|
128
|
+
for (const c of procs.backlog(procId, 0).chunks)
|
|
129
|
+
handleChunk(c);
|
|
130
|
+
if (!settled) {
|
|
131
|
+
const cur = procs.get(procId);
|
|
132
|
+
if (cur && !cur.running)
|
|
133
|
+
finish({ kind: 'exited', info: cur });
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/** Build the proc_start / proc_stop / proc_list tools over a live SidecarProcs.
|
|
138
|
+
* `procs` is expected to be a real, already-constructed process table (node
|
|
139
|
+
* child_process-backed in production, a fake in tests) — this file never
|
|
140
|
+
* constructs one itself. */
|
|
141
|
+
export function procTools(procs, opts = {}) {
|
|
142
|
+
const budget = opts.agentBudget ?? DEFAULT_AGENT_BUDGET;
|
|
143
|
+
const agentRunningCount = () => procs.list().filter((p) => p.running && isAgentStarted(p)).length;
|
|
144
|
+
const procStart = {
|
|
145
|
+
name: 'proc_start',
|
|
146
|
+
means: 'start a long-running command (a dev server, a watcher, a build) and watch its output',
|
|
147
|
+
description: 'Start a long-lived command (e.g. "npm run start") and watch it come up. Unlike a one-shot ' +
|
|
148
|
+
'shell exec, this does not wait for the command to finish — it resolves once EITHER wait_for ' +
|
|
149
|
+
'matches a substring of the output, OR settle_ms elapses with the process still running, OR the ' +
|
|
150
|
+
'process exits early. The result text always says explicitly which of those happened and whether ' +
|
|
151
|
+
'the process is still running. The process keeps running (and its output keeps being pushed live) ' +
|
|
152
|
+
'after this call resolves; use proc_list to see it again and proc_stop to end it.',
|
|
153
|
+
parameters: {
|
|
154
|
+
type: 'object',
|
|
155
|
+
properties: {
|
|
156
|
+
command: { type: 'string', description: 'the shell command line to run' },
|
|
157
|
+
cwd: { type: 'string', description: 'working directory relative to the chosen root (default ".")' },
|
|
158
|
+
root: { type: 'string', description: 'which pre-approved root to resolve cwd against' },
|
|
159
|
+
label: { type: 'string', description: 'a short human-readable label for this process' },
|
|
160
|
+
wait_for: {
|
|
161
|
+
type: 'string',
|
|
162
|
+
description: 'a plain SUBSTRING (never a regex) to watch for in the combined output, e.g. "Local: http://". ' +
|
|
163
|
+
'When it appears, the call resolves immediately instead of waiting out settle_ms.',
|
|
164
|
+
},
|
|
165
|
+
settle_ms: {
|
|
166
|
+
type: 'number',
|
|
167
|
+
description: `how long to wait, in ms, before resolving anyway if wait_for never matches and the process hasn't exited (default ${DEFAULT_SETTLE_MS}, max ${MAX_SETTLE_MS})`,
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
required: ['command'],
|
|
171
|
+
},
|
|
172
|
+
namespace: 'shell',
|
|
173
|
+
mutates: true,
|
|
174
|
+
permission: 'ask',
|
|
175
|
+
async run(args, ctx) {
|
|
176
|
+
const command = str(args, 'command')?.trim();
|
|
177
|
+
if (!command)
|
|
178
|
+
return 'Error: no command given';
|
|
179
|
+
const waitFor = str(args, 'wait_for');
|
|
180
|
+
const settleMs = clamp(Number(args.settle_ms) || DEFAULT_SETTLE_MS, MIN_SETTLE_MS, MAX_SETTLE_MS);
|
|
181
|
+
const running = agentRunningCount();
|
|
182
|
+
if (running >= budget) {
|
|
183
|
+
return (`Error: refusing to start another process — this agent already has ${running} of its ` +
|
|
184
|
+
`${budget} allowed concurrent processes running. Stop one with proc_stop first, or ask the ` +
|
|
185
|
+
'operator to start it themselves.');
|
|
186
|
+
}
|
|
187
|
+
const cwd = str(args, 'cwd');
|
|
188
|
+
const root = str(args, 'root');
|
|
189
|
+
let info;
|
|
190
|
+
try {
|
|
191
|
+
info = await procs.spawn({
|
|
192
|
+
command,
|
|
193
|
+
...(cwd ? { cwd } : {}),
|
|
194
|
+
...(root ? { root } : {}),
|
|
195
|
+
label: agentLabel(opts.session, str(args, 'label')),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
return `Error: could not start the process: ${e instanceof Error ? e.message : String(e)}`;
|
|
200
|
+
}
|
|
201
|
+
const outcome = await watchStart(procs, info.procId, waitFor, settleMs, (c) => ctx.stream?.(c.text));
|
|
202
|
+
const tail = renderTail(procs, info.procId);
|
|
203
|
+
if (outcome.kind === 'matched') {
|
|
204
|
+
return (`Started ${describeInfo(outcome.info)}\n` +
|
|
205
|
+
`STILL RUNNING — matched wait_for ${JSON.stringify(waitFor)} in its output.\n\n${tail}`);
|
|
206
|
+
}
|
|
207
|
+
if (outcome.kind === 'settled') {
|
|
208
|
+
const waitNote = waitFor ? ` (wait_for ${JSON.stringify(waitFor)} has NOT appeared yet)` : '';
|
|
209
|
+
return (`Started ${describeInfo(outcome.info)}\n` +
|
|
210
|
+
`STILL RUNNING after ${settleMs}ms with no exit${waitNote}.\n\n${tail}`);
|
|
211
|
+
}
|
|
212
|
+
// outcome.kind === 'exited'
|
|
213
|
+
const { info: endInfo } = outcome;
|
|
214
|
+
const status = `exit code ${endInfo.exitCode ?? 'unknown'}${endInfo.signal ? ` (signal ${endInfo.signal})` : ''}`;
|
|
215
|
+
return (`Started ${describeInfo(endInfo)}\n` +
|
|
216
|
+
`ALREADY EXITED before it finished starting — it is NOT running. ${status}.\n\n${tail}`);
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
const procStop = {
|
|
220
|
+
name: 'proc_stop',
|
|
221
|
+
means: 'stop a process this agent (or the operator) started',
|
|
222
|
+
description: 'Stop a running process by its proc_id (from proc_start or proc_list). Idempotent — stopping an ' +
|
|
223
|
+
'already-stopped or unknown process is reported, not treated as an error.',
|
|
224
|
+
parameters: {
|
|
225
|
+
type: 'object',
|
|
226
|
+
properties: { proc_id: { type: 'string', description: 'the procId to stop' } },
|
|
227
|
+
required: ['proc_id'],
|
|
228
|
+
},
|
|
229
|
+
namespace: 'shell',
|
|
230
|
+
mutates: true,
|
|
231
|
+
permission: 'ask',
|
|
232
|
+
async run(args) {
|
|
233
|
+
const procId = str(args, 'proc_id');
|
|
234
|
+
if (!procId)
|
|
235
|
+
return 'Error: no proc_id given';
|
|
236
|
+
const before = procs.get(procId);
|
|
237
|
+
if (!before)
|
|
238
|
+
return `${procId}: no such process (it may already have been evicted after exiting).`;
|
|
239
|
+
if (!before.running) {
|
|
240
|
+
const status = `exit code ${before.exitCode ?? 'unknown'}${before.signal ? ` (signal ${before.signal})` : ''}`;
|
|
241
|
+
return `${describeInfo(before)} was already stopped (${status}).`;
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
procs.kill(procId);
|
|
245
|
+
}
|
|
246
|
+
catch (e) {
|
|
247
|
+
return `Error: could not stop ${procId}: ${e instanceof Error ? e.message : String(e)}`;
|
|
248
|
+
}
|
|
249
|
+
return `Stopping ${describeInfo(before)} (SIGTERM sent; it will be force-killed if it doesn't exit).`;
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
const procList = {
|
|
253
|
+
name: 'proc_list',
|
|
254
|
+
means: 'see every process running or recently run on this machine',
|
|
255
|
+
description: 'List the processes visible through this connection, running or recently exited — including ones ' +
|
|
256
|
+
'started before this conversation, or in an earlier turn whose proc_id has since fallen out of ' +
|
|
257
|
+
'context. A process started elsewhere (by the operator, or another client) AFTER this connection ' +
|
|
258
|
+
'was established may not appear here until it reconnects — if an expected process (e.g. a dev ' +
|
|
259
|
+
'server you did not start) is missing, that does not mean it is not running; ask before starting ' +
|
|
260
|
+
'a second one on the same port. Each entry says whether it was started by an agent or by the ' +
|
|
261
|
+
'operator directly.',
|
|
262
|
+
parameters: { type: 'object', properties: {} },
|
|
263
|
+
namespace: 'sidecar',
|
|
264
|
+
async run() {
|
|
265
|
+
const all = procs.list();
|
|
266
|
+
if (!all.length)
|
|
267
|
+
return 'No processes.';
|
|
268
|
+
return all
|
|
269
|
+
.map((p) => {
|
|
270
|
+
const who = isAgentStarted(p) ? 'agent-started' : 'operator-started';
|
|
271
|
+
const state = p.running
|
|
272
|
+
? 'running'
|
|
273
|
+
: `exited (code ${p.exitCode ?? 'unknown'}${p.signal ? `, signal ${p.signal}` : ''})`;
|
|
274
|
+
return `${describeInfo(p)} — ${who}, ${state}`;
|
|
275
|
+
})
|
|
276
|
+
.join('\n');
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
return [procStart, procStop, procList];
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=procs.js.map
|