teapot-coding-agent 0.28.0 → 0.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +33 -7
- package/dist/master.js +41 -17
- package/package.json +1 -1
- package/public/assets/{index-DWsd_EOl.js → index-DTHHmNVF.js} +19 -19
- package/public/assets/index-DTHHmNVF.js.map +1 -0
- package/public/assets/{shiki-D0LgHyHH.js → shiki-B3arOyuY.js} +2 -2
- package/public/assets/{shiki-D0LgHyHH.js.map → shiki-B3arOyuY.js.map} +1 -1
- package/public/index.html +1 -1
- package/public/assets/index-DWsd_EOl.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* Config may also come from TEAPOT_* env vars (see src/master.ts).
|
|
6
6
|
* First run (no config file): boot anyway and finish setup in the web UI.
|
|
7
7
|
*/
|
|
8
|
-
import { existsSync } from "node:fs";
|
|
8
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
9
9
|
import { createServer } from "node:net";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
10
11
|
import { loadConfig, resolveConfigPath, Master } from "./master.js";
|
|
11
12
|
import { buildApp, serveApp } from "./server/api.js";
|
|
12
13
|
/**
|
|
@@ -259,10 +260,35 @@ async function main() {
|
|
|
259
260
|
// test importing it and sat at 48% branch coverage. The check is the standard
|
|
260
261
|
// ESM "am I the entry point" test, and `node --experimental-strip-types src/index.ts`
|
|
261
262
|
// and `node dist/index.js` both still take this branch.
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
263
|
+
function isEntryPoint() {
|
|
264
|
+
const arg = process.argv[1];
|
|
265
|
+
if (!arg)
|
|
266
|
+
return false;
|
|
267
|
+
// `npm i -g teapot-coding-agent` puts a SYMLINK at node_modules/.bin/teapot, and
|
|
268
|
+
// npm invokes the target THROUGH it. So `process.argv[1]` is the symlink path
|
|
269
|
+
// (…/node_modules/.bin/teapot), NOT the file it points at — which matched none
|
|
270
|
+
// of the checks below, `main()` never ran, and the installed command exited 0
|
|
271
|
+
// in silence. Reporting `teapot` did nothing and needing `node dist/index.js`
|
|
272
|
+
// was the only symptom. `realpathSync` is what resolves it.
|
|
273
|
+
try {
|
|
274
|
+
const self = realpathSync(fileURLToPath(import.meta.url));
|
|
275
|
+
const entry = realpathSync(arg);
|
|
276
|
+
if (self === entry)
|
|
277
|
+
return true;
|
|
278
|
+
// `self === entry` is the ONLY correct test: it is the definition of being the
|
|
279
|
+
// entry point. The suffix checks that used to follow were a fallback for the
|
|
280
|
+
// symlink case, and they were far too loose — `endsWith("/index.ts")` is true
|
|
281
|
+
// for EVERY test file that imports this module, so importing it booted a real
|
|
282
|
+
// server on port 7788 and `cli-args.test.ts` failed with EADDRINUSE.
|
|
283
|
+
//
|
|
284
|
+
// Keep a basename check as a safety net for a bundler that rewrites paths, but
|
|
285
|
+
// require BOTH that we are the module AND that nothing else is: an argv[1] that
|
|
286
|
+
// resolves to a DIFFERENT file is by definition not this module's entry.
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (isEntryPoint())
|
|
268
294
|
void main();
|
package/dist/master.js
CHANGED
|
@@ -109,7 +109,18 @@ const DATA_DIR = process.env.TEAPOT_DATA_DIR ??
|
|
|
109
109
|
path.join(os.homedir(), ".local", "share", "teapot-coding-agent");
|
|
110
110
|
const DEFAULT_CONFIG = {
|
|
111
111
|
port: Number(process.env.TEAPOT_PORT ?? 7788),
|
|
112
|
-
|
|
112
|
+
// #140: this was `process.env.TEAPOT_HOST`, i.e. UNDEFINED when unset — and an
|
|
113
|
+
// undefined hostname makes `@hono/node-server` bind every interface. So the
|
|
114
|
+
// default was the opposite of the documented one: `--help` says
|
|
115
|
+
// "127.0.0.1 (default) · 0.0.0.0 exposes the UI to your network", and yet the
|
|
116
|
+
// default WAS "expose to your network".
|
|
117
|
+
//
|
|
118
|
+
// Measured: with no --host the server answered on the machine's LAN address as
|
|
119
|
+
// well as loopback.
|
|
120
|
+
//
|
|
121
|
+
// Loopback is the right default for something holding API tokens and agent
|
|
122
|
+
// workspaces; exposing it has to be a deliberate act.
|
|
123
|
+
host: process.env.TEAPOT_HOST ?? "127.0.0.1",
|
|
113
124
|
dataDir: DATA_DIR,
|
|
114
125
|
llm: {
|
|
115
126
|
baseUrl: process.env.TEAPOT_BASE_URL ?? "https://openrouter.ai/api/v1",
|
|
@@ -764,29 +775,42 @@ When this task is done (or truly blocked), call finish() with a summary for @${p
|
|
|
764
775
|
/** Stop direct children (and their descendants by default) of an agent. */
|
|
765
776
|
async stopChildrenFor(parentId, ids) {
|
|
766
777
|
const stopped = [];
|
|
767
|
-
|
|
778
|
+
// `inScope` is true once we are INSIDE a subtree we were asked to stop, and
|
|
779
|
+
// stays true all the way down.
|
|
780
|
+
//
|
|
781
|
+
// #142: the old walk passed `ids` down unchanged, so after matching an
|
|
782
|
+
// explicit id every DESCENDANT failed `ids.includes(id)` and was skipped —
|
|
783
|
+
// which is why the explicit branch hand-rolled its own one-level loop, and
|
|
784
|
+
// why that loop could not reach a great-grandchild.
|
|
785
|
+
const walk = (pid, inScope) => {
|
|
768
786
|
for (const { id, agent } of this.childrenOf(pid)) {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
787
|
+
const take = inScope || !ids || ids.includes(id);
|
|
788
|
+
if (!take) {
|
|
789
|
+
// out of scope, but its own subtree may hold something in scope
|
|
790
|
+
walk(id, false);
|
|
772
791
|
continue;
|
|
773
792
|
}
|
|
774
793
|
agent.stop("stopped by parent agent");
|
|
775
794
|
stopped.push(id);
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
795
|
+
// #142: RECURSE for both modes.
|
|
796
|
+
//
|
|
797
|
+
// The explicit-id branch used to iterate `childrenOf(id)` exactly once, so
|
|
798
|
+
// a great-grandchild was never reached — stopping a child left its
|
|
799
|
+
// grandchild's child running, indefinitely, still holding a model
|
|
800
|
+
// connection and billing tokens:
|
|
801
|
+
//
|
|
802
|
+
// root-sub stopped
|
|
803
|
+
// root-sub-sub stopped
|
|
804
|
+
// root-sub-sub-sub running <-- orphaned
|
|
805
|
+
//
|
|
806
|
+
// `walk` already means "this subtree", and it stops every node it visits,
|
|
807
|
+
// so one code path serves both cases. The only difference between the two
|
|
808
|
+
// modes is the `ids && !ids.includes(id)` test at the top, which decides
|
|
809
|
+
// whether a node is in scope — not how deep the walk goes.
|
|
810
|
+
walk(id, true);
|
|
787
811
|
}
|
|
788
812
|
};
|
|
789
|
-
walk(parentId);
|
|
813
|
+
walk(parentId, false);
|
|
790
814
|
return { stopped };
|
|
791
815
|
}
|
|
792
816
|
/** Deliver a parent's message into a child's mailbox (and wake it). */
|