@crouton-kit/crouter 0.3.48 → 0.3.50
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/builtin-pi-packages/pi-crtr-extensions/README.md +1 -1
- package/dist/clients/attach/attach-cmd.js +825 -863
- package/dist/clients/attach/titled-editor.js +6 -3
- package/dist/commands/human/prompts.js +1 -1
- package/dist/commands/human/shared.js +7 -3
- package/dist/commands/memory/write.js +2 -0
- package/dist/commands/node.js +96 -11
- package/dist/commands/profile/default.d.ts +2 -0
- package/dist/commands/profile/default.js +143 -0
- package/dist/commands/profile/new.js +3 -3
- package/dist/commands/profile/project.d.ts +2 -0
- package/dist/commands/profile/project.js +97 -0
- package/dist/commands/profile/show.js +1 -1
- package/dist/commands/profile.js +10 -11
- package/dist/commands/sys/__tests__/sync-import.test.js +156 -3
- package/dist/commands/sys/sync.js +82 -25
- package/dist/core/__tests__/broker-sdk-wiring.test.js +4 -7
- package/dist/core/__tests__/context-intro.test.js +15 -7
- package/dist/core/__tests__/memory-resolver-precedence.test.d.ts +1 -0
- package/dist/core/__tests__/memory-resolver-precedence.test.js +144 -0
- package/dist/core/__tests__/on-read-identity.test.d.ts +1 -0
- package/dist/core/__tests__/on-read-identity.test.js +68 -0
- package/dist/core/fs-utils.d.ts +1 -1
- package/dist/core/fs-utils.js +5 -3
- package/dist/core/memory-resolver.d.ts +27 -11
- package/dist/core/memory-resolver.js +105 -109
- package/dist/core/profiles/default-binding.d.ts +10 -0
- package/dist/core/profiles/default-binding.js +50 -0
- package/dist/core/profiles/select.d.ts +13 -1
- package/dist/core/profiles/select.js +92 -26
- package/dist/core/runtime/bearings.d.ts +4 -9
- package/dist/core/runtime/bearings.js +10 -17
- package/dist/core/runtime/front-door.js +11 -4
- package/dist/core/runtime/revive.js +2 -1
- package/dist/core/runtime/spawn.d.ts +4 -0
- package/dist/core/runtime/spawn.js +1 -1
- package/dist/core/substrate/index.d.ts +1 -1
- package/dist/core/substrate/index.js +3 -1
- package/dist/core/substrate/on-read.js +14 -9
- package/dist/core/substrate/render.js +7 -3
- package/dist/core/substrate/schema.d.ts +8 -2
- package/dist/core/substrate/schema.js +19 -2
- package/dist/daemon/crtrd.js +44 -2
- package/dist/daemon/manage.d.ts +20 -0
- package/dist/daemon/manage.js +64 -2
- package/package.json +3 -3
- package/dist/commands/profile/add-project.d.ts +0 -1
- package/dist/commands/profile/add-project.js +0 -42
- package/dist/commands/profile/remove-project.d.ts +0 -1
- package/dist/commands/profile/remove-project.js +0 -42
package/dist/daemon/manage.js
CHANGED
|
@@ -6,11 +6,61 @@
|
|
|
6
6
|
import { spawn } from 'node:child_process';
|
|
7
7
|
import { dirname, join } from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
|
-
import { mkdirSync } from 'node:fs';
|
|
9
|
+
import { mkdirSync, openSync, closeSync } from 'node:fs';
|
|
10
10
|
import { crtrHome } from '../core/canvas/paths.js';
|
|
11
11
|
import { hostExecPath } from '../core/runtime/branded-host.js';
|
|
12
12
|
import { isDaemonRunning, readPidfile, isPidAlive } from './crtrd.js';
|
|
13
13
|
// ---------------------------------------------------------------------------
|
|
14
|
+
// Daemon env sanitization
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/** Env keys that must NEVER reach the daemon process. Restarting crtrd is
|
|
17
|
+
* overwhelmingly done from inside an agent node's own bash tool (`crtr sys
|
|
18
|
+
* daemon stop && start`), which inherits that node's FULL env — its identity
|
|
19
|
+
* (`CRTR_NODE_ID`/`CRTR_KIND`/…, the `nodeEnv()` shape in `core/runtime/
|
|
20
|
+
* nodes.ts`), its front-door recursion-guard flag, and any pi-engine
|
|
21
|
+
* resolution seam a prior test/dev session left exported. The daemon is a
|
|
22
|
+
* singleton supervisor, never "a node" itself, so none of this belongs in its
|
|
23
|
+
* env regardless of whether today's code happens to read it — and at least one
|
|
24
|
+
* of these IS actively read: `host.ts`'s broker-engine resolution falls back to
|
|
25
|
+
* `process.env['CRTR_BROKER_ENGINE']` verbatim (nodeEnv() never sets that key,
|
|
26
|
+
* so nothing overrides it per child launch), so a daemon that inherits a
|
|
27
|
+
* stale/dev override throws inside `headlessBrokerHost.launch()` on EVERY
|
|
28
|
+
* relaunch it ever attempts, for its whole lifetime — the 2026-07-06 diagnosis
|
|
29
|
+
* root cause behind 19 nodes killed with "failed to relaunch and is now dead". */
|
|
30
|
+
export const DAEMON_ENV_STRIP_KEYS = [
|
|
31
|
+
// Node identity (nodeEnv() shape) — meaningless for a process supervising
|
|
32
|
+
// many nodes rather than being one.
|
|
33
|
+
'CRTR_NODE_ID',
|
|
34
|
+
'CRTR_KIND',
|
|
35
|
+
'CRTR_MODE',
|
|
36
|
+
'CRTR_LIFECYCLE',
|
|
37
|
+
'CRTR_NODE_CWD',
|
|
38
|
+
'CRTR_CONTEXT_DIR',
|
|
39
|
+
'CRTR_CYCLES',
|
|
40
|
+
'CRTR_PROFILE_ID',
|
|
41
|
+
'CRTR_PARENT_NODE_ID',
|
|
42
|
+
// Recursion-guard flag — only meaningful inside a pi engine process.
|
|
43
|
+
'CRTR_FRONT_DOOR',
|
|
44
|
+
// Engine-resolution seams NOT overridden per child launch — the proven and
|
|
45
|
+
// suspected poison vectors.
|
|
46
|
+
'CRTR_BROKER_ENGINE',
|
|
47
|
+
'CRTR_PI_BINARY',
|
|
48
|
+
'CRTR_FAULT_RETRY_PROBE',
|
|
49
|
+
// Generic Node.js env poisoning (a stray dev/debug flag from the restarting
|
|
50
|
+
// shell).
|
|
51
|
+
'NODE_OPTIONS',
|
|
52
|
+
];
|
|
53
|
+
/** A copy of `process.env` with every `DAEMON_ENV_STRIP_KEYS` entry removed.
|
|
54
|
+
* Deliberate global config the user actually wants the daemon to see —
|
|
55
|
+
* `CRTR_HOME`, `CRTR_SUBTREE`, `CRTR_LOG`, `CRTR_DEBUG`, etc. — passes through
|
|
56
|
+
* untouched; only the node-identity/engine-poisoning surface is stripped. */
|
|
57
|
+
export function sanitizedDaemonEnv() {
|
|
58
|
+
const env = { ...process.env };
|
|
59
|
+
for (const key of DAEMON_ENV_STRIP_KEYS)
|
|
60
|
+
delete env[key];
|
|
61
|
+
return env;
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
14
64
|
// Entry point resolution
|
|
15
65
|
// ---------------------------------------------------------------------------
|
|
16
66
|
/** Resolve the absolute path to the crtrd-cli entry point.
|
|
@@ -70,10 +120,22 @@ export async function spawnDaemon() {
|
|
|
70
120
|
// is launchd-owned, the plist's ProgramArguments must point at the branded
|
|
71
121
|
// binary too — this path only covers a manual `crtr sys daemon start`.
|
|
72
122
|
const entry = resolveCrtrdEntry();
|
|
123
|
+
// Route stdout+stderr to an append-mode file instead of discarding them
|
|
124
|
+
// (stdio:'ignore'). Every `[crtrd] …` diagnostic — including the one line
|
|
125
|
+
// that names WHY a relaunch failed (crtrd.ts's per-node supervise catch) —
|
|
126
|
+
// used to go to /dev/null for any manually-started daemon, the common case
|
|
127
|
+
// (only a launchd-owned daemon had a logging plist). Mirrors host.ts's
|
|
128
|
+
// broker.log pattern: one fd, both streams, append so a restart keeps history.
|
|
129
|
+
const errLogPath = join(crtrHome(), 'crtrd.err');
|
|
130
|
+
const errFd = openSync(errLogPath, 'a');
|
|
73
131
|
const child = spawn(hostExecPath(), [entry], {
|
|
74
132
|
detached: true,
|
|
75
|
-
stdio: 'ignore',
|
|
133
|
+
stdio: ['ignore', errFd, errFd],
|
|
134
|
+
env: sanitizedDaemonEnv(),
|
|
76
135
|
});
|
|
136
|
+
// The child holds its own dup of the fd; release the parent's copy so the
|
|
137
|
+
// launching process never leaks it.
|
|
138
|
+
closeSync(errFd);
|
|
77
139
|
const pid = child.pid;
|
|
78
140
|
if (pid === undefined) {
|
|
79
141
|
throw new Error('daemon spawn did not return a pid');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crouton-kit/crouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.50",
|
|
4
4
|
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"prebuild": "rm -rf node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-tui node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-ai node_modules/@earendil-works/pi-coding-agent/node_modules/@earendil-works/pi-agent-core",
|
|
34
34
|
"build": "rm -rf dist && tsc && cp -R src/builtin-views dist/builtin-views && cp -R src/builtin-memory dist/builtin-memory && cp -R src/builtin-pi-packages dist/builtin-pi-packages && npm run build:attach && vite build --config src/clients/web/web-client/vite.config.ts",
|
|
35
35
|
"lint:web-px": "node scripts/lint-web-px.mjs",
|
|
36
|
-
"build:attach": "esbuild src/clients/attach/attach-cmd.ts --bundle --minify --format=esm --platform=node --target=node22 --alias:@earendil-works/pi-tui=$PWD/node_modules/@earendil-works/pi-tui --outfile=dist/clients/attach/attach-cmd.js --log-level=warning --banner:js=\"import{createRequire as __cr}from'node:module';const require=__cr(import.meta.url);\"",
|
|
36
|
+
"build:attach": "esbuild src/clients/attach/attach-cmd.ts --bundle --minify --format=esm --platform=node --target=node22 --alias:@earendil-works/pi-tui=$PWD/node_modules/@earendil-works/pi-tui --external:@crouton-kit/humanloop --outfile=dist/clients/attach/attach-cmd.js --log-level=warning --banner:js=\"import{createRequire as __cr}from'node:module';const require=__cr(import.meta.url);\"",
|
|
37
37
|
"postinstall": "node scripts/postinstall.mjs",
|
|
38
38
|
"dev": "tsx src/cli.ts",
|
|
39
39
|
"link": "npm link",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"license": "MIT",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@crouton-kit/humanloop": "^0.3.
|
|
50
|
+
"@crouton-kit/humanloop": "^0.3.29",
|
|
51
51
|
"@earendil-works/pi-agent-core": "0.80.2",
|
|
52
52
|
"@earendil-works/pi-ai": "0.80.3",
|
|
53
53
|
"@earendil-works/pi-coding-agent": "0.80.2",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const addProjectLeaf: import("../../core/command.js").LeafDef;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { defineLeaf } from '../../core/command.js';
|
|
2
|
-
import { addProfileProject, loadProfileManifest } from '../../core/profiles/manifest.js';
|
|
3
|
-
export const addProjectLeaf = defineLeaf({
|
|
4
|
-
name: 'add-project',
|
|
5
|
-
description: "add a project directory to a profile's purview",
|
|
6
|
-
whenToUse: "a profile needs to see (memory + config from) another project directory — extend its purview after creation, including mid-session from a node already running under that profile.",
|
|
7
|
-
help: {
|
|
8
|
-
name: 'profile add-project',
|
|
9
|
-
summary: "append a project directory to a profile's manifest, deduped by real path",
|
|
10
|
-
params: [
|
|
11
|
-
{
|
|
12
|
-
kind: 'positional',
|
|
13
|
-
name: 'profile',
|
|
14
|
-
required: true,
|
|
15
|
-
constraint: 'Exact profile id, or a unique manifest name.',
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
kind: 'flag',
|
|
19
|
-
name: 'dir',
|
|
20
|
-
type: 'path',
|
|
21
|
-
required: true,
|
|
22
|
-
constraint: 'Directory to add. Must exist and be a directory; resolved to its absolute real path before storing. A path already on the manifest is a no-op, not an error.',
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
output: [
|
|
26
|
-
{ name: 'profile_id', type: 'string', required: true, constraint: 'Stable directory id.' },
|
|
27
|
-
{ name: 'projects', type: 'string[]', required: true, constraint: 'The updated, deduped project list in manifest order.' },
|
|
28
|
-
{ name: 'follow_up', type: 'string', required: true, constraint: 'Concrete next commands.' },
|
|
29
|
-
],
|
|
30
|
-
outputKind: 'object',
|
|
31
|
-
effects: ["Appends to the profile manifest's `projects` array. Invalidates the process scope cache."],
|
|
32
|
-
},
|
|
33
|
-
run: async (input) => {
|
|
34
|
-
const { profileId } = loadProfileManifest(input['profile']);
|
|
35
|
-
const { manifest } = addProfileProject(profileId, input['dir']);
|
|
36
|
-
return {
|
|
37
|
-
profile_id: profileId,
|
|
38
|
-
projects: manifest.projects,
|
|
39
|
-
follow_up: `Show the full manifest with \`crtr profile show ${profileId}\`.`,
|
|
40
|
-
};
|
|
41
|
-
},
|
|
42
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const removeProjectLeaf: import("../../core/command.js").LeafDef;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { defineLeaf } from '../../core/command.js';
|
|
2
|
-
import { loadProfileManifest, removeProfileProject } from '../../core/profiles/manifest.js';
|
|
3
|
-
export const removeProjectLeaf = defineLeaf({
|
|
4
|
-
name: 'remove-project',
|
|
5
|
-
description: "remove a project directory from a profile's purview",
|
|
6
|
-
whenToUse: "a profile no longer needs purview over one of its listed project directories — narrow it back. Works even if the directory itself was since deleted.",
|
|
7
|
-
help: {
|
|
8
|
-
name: 'profile remove-project',
|
|
9
|
-
summary: "remove a project directory from a profile's manifest",
|
|
10
|
-
params: [
|
|
11
|
-
{
|
|
12
|
-
kind: 'positional',
|
|
13
|
-
name: 'profile',
|
|
14
|
-
required: true,
|
|
15
|
-
constraint: 'Exact profile id, or a unique manifest name.',
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
kind: 'flag',
|
|
19
|
-
name: 'dir',
|
|
20
|
-
type: 'path',
|
|
21
|
-
required: true,
|
|
22
|
-
constraint: 'Directory to remove, matched by its resolved real path against the manifest. Does not require the directory to still exist on disk.',
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
output: [
|
|
26
|
-
{ name: 'profile_id', type: 'string', required: true, constraint: 'Stable directory id.' },
|
|
27
|
-
{ name: 'projects', type: 'string[]', required: true, constraint: 'The updated project list in manifest order.' },
|
|
28
|
-
{ name: 'follow_up', type: 'string', required: true, constraint: 'Concrete next commands.' },
|
|
29
|
-
],
|
|
30
|
-
outputKind: 'object',
|
|
31
|
-
effects: ["Removes an entry from the profile manifest's `projects` array. Invalidates the process scope cache."],
|
|
32
|
-
},
|
|
33
|
-
run: async (input) => {
|
|
34
|
-
const { profileId } = loadProfileManifest(input['profile']);
|
|
35
|
-
const { manifest } = removeProfileProject(profileId, input['dir']);
|
|
36
|
-
return {
|
|
37
|
-
profile_id: profileId,
|
|
38
|
-
projects: manifest.projects,
|
|
39
|
-
follow_up: `Show the full manifest with \`crtr profile show ${profileId}\`.`,
|
|
40
|
-
};
|
|
41
|
-
},
|
|
42
|
-
});
|