@rubytech/create-realagent 1.0.852 → 1.0.854
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/__tests__/preflight-port-classifier.test.js +240 -73
- package/dist/index.js +59 -11
- package/dist/preflight-port-classifier.js +176 -41
- package/package.json +1 -1
- package/payload/platform/config/brand-registry.json +44 -0
- package/payload/platform/lib/persistent-components/dist/index.d.ts +21 -0
- package/payload/platform/lib/persistent-components/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/persistent-components/dist/index.js +32 -0
- package/payload/platform/lib/persistent-components/dist/index.js.map +1 -0
- package/payload/platform/lib/persistent-components/src/index.ts +28 -0
- package/payload/platform/lib/persistent-components/tsconfig.json +8 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/PLUGIN.md +1 -1
- package/payload/platform/plugins/admin/hooks/__tests__/playwright-file-guard.test.sh +278 -0
- package/payload/platform/plugins/admin/hooks/playwright-file-guard.sh +204 -20
- package/payload/platform/plugins/admin/mcp/dist/index.js +40 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/docs/references/deployment.md +2 -0
- package/payload/platform/plugins/docs/references/getting-started.md +2 -0
- package/payload/platform/plugins/docs/references/platform.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +10 -0
- package/payload/platform/scripts/admin-persist-audit.ts +191 -0
- package/payload/platform/scripts/component-knowledgedoc-backfill.ts +214 -0
- package/payload/platform/scripts/installer-device-verify.sh +249 -0
- package/payload/platform/templates/specialists/agents/content-producer.md +2 -2
- package/payload/server/chunk-CFNSKDGA.js +667 -0
- package/payload/server/chunk-DC6DWYZJ.js +1603 -0
- package/payload/server/chunk-LTB5SSQW.js +10889 -0
- package/payload/server/chunk-MN2LGNUB.js +2143 -0
- package/payload/server/client-pool-AMT2W3II.js +34 -0
- package/payload/server/cloudflare-task-tracker-LJ4SMK2D.js +20 -0
- package/payload/server/maxy-edge.js +3 -3
- package/payload/server/public/assets/admin-DZ8Ke7t3.js +352 -0
- package/payload/server/public/assets/public-DApUXgoq.js +5 -0
- package/payload/server/public/assets/useVoiceRecorder-CI8GpxfU.js +36 -0
- package/payload/server/public/index.html +2 -2
- package/payload/server/public/public.html +2 -2
- package/payload/server/server.js +535 -351
- package/payload/server/public/assets/admin-Dyl8uNxX.js +0 -352
- package/payload/server/public/assets/public-B_PNZUph.js +0 -5
- package/payload/server/public/assets/useVoiceRecorder-fD0IWzJj.js +0 -36
|
@@ -1,32 +1,39 @@
|
|
|
1
1
|
// Task 938 — pure classifier for the install-time port collision pre-flight.
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
2
|
+
// Task 939 — extended with Xtigervnc and websockify holder anchors, closing
|
|
3
|
+
// the laptop + Pi miss where the brand's own VNC stack was misclassified
|
|
4
|
+
// UNRELATED because Xtigervnc has no `--user-data-dir=` argv to anchor on.
|
|
5
5
|
//
|
|
6
6
|
// The wrapper in index.ts owns the side effects: ss read, /proc/<pid>/cmdline
|
|
7
7
|
// read, SIGTERM/SIGKILL escalation, and the operator-override exit. This
|
|
8
|
-
// module owns only the classification rule.
|
|
8
|
+
// module owns only the classification rule — inputs in, decision out.
|
|
9
9
|
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
10
|
+
// Holder detection (post-pid):
|
|
11
|
+
// argv[0] basename ∈ chromium-set → chromium
|
|
12
|
+
// argv[0] basename === "Xtigervnc" → xtigervnc
|
|
13
|
+
// any argv basename === "websockify" (full scan → websockify
|
|
14
|
+
// because Pi Bookworm invokes it as
|
|
15
|
+
// `python3 /usr/bin/websockify …`, so argv[0] is
|
|
16
|
+
// the interpreter, not websockify itself)
|
|
17
|
+
// else → unknown
|
|
18
18
|
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
19
|
+
// Per-holder anchor:
|
|
20
|
+
// chromium — `--user-data-dir=PATH`; PATH contains `/<configDir>/chromium-profile`
|
|
21
|
+
// → OWN_BRAND if configDir matches own; PEER_BRAND if matches peer.
|
|
22
|
+
// False-match guard: argv-anchor on the flag, never substring,
|
|
23
|
+
// so `--load-extension=…/<configDir>/…` cannot poison.
|
|
24
|
+
// xtigervnc — first non-flag argv of the form `:N` (display number);
|
|
25
|
+
// vnc.sh invokes `Xtigervnc "${VNC_DISPLAY}" -rfbport …` so
|
|
26
|
+
// argv[1] is literally `:99`, `:100`, etc. Match N against
|
|
27
|
+
// own.vncDisplay / peer.vncDisplay.
|
|
28
|
+
// websockify — collect every port number embedded in argv (covers both
|
|
29
|
+
// `[::]:6080` bind form and `localhost:5900` upstream form).
|
|
30
|
+
// Per Task 924, brand websockifyPort/rfbPort sets are
|
|
31
|
+
// disjoint, so at most one brand's websockifyPort can appear.
|
|
24
32
|
//
|
|
25
33
|
// Why "last pid=" instead of "first pid=": ss with `-tlnpH sport = :PORT`
|
|
26
|
-
// emits the LISTEN row last; if a future ss locale
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
// `users:((…))` segment.
|
|
34
|
+
// emits the LISTEN row last; if a future ss locale prepends a header line
|
|
35
|
+
// containing `pid=` text, the first-match heuristic would lift the wrong
|
|
36
|
+
// pid. The last `pid=` is always inside the LISTEN row's `users:((…))`.
|
|
30
37
|
/**
|
|
31
38
|
* `cmdline` should be the raw `/proc/<pid>/cmdline` contents — NUL-separated
|
|
32
39
|
* argv as the kernel emits it. Do NOT replace NUL with space before passing:
|
|
@@ -34,11 +41,9 @@
|
|
|
34
41
|
* different flag whose value happens to contain `--user-data-dir=`.
|
|
35
42
|
*/
|
|
36
43
|
export function classifyPortHolder(args) {
|
|
37
|
-
const { ssOutput,
|
|
44
|
+
const { ssOutput, ownBrand, peerBrands, getCmdline } = args;
|
|
38
45
|
if (ssOutput.trim() === "")
|
|
39
46
|
return { kind: "EMPTY" };
|
|
40
|
-
// Take the LAST pid= match. ss -tlnpH puts the LISTEN row (which contains
|
|
41
|
-
// `users:((…,pid=N,fd=…))`) last, so the last pid= is always the listener.
|
|
42
47
|
const pidMatches = [...ssOutput.matchAll(/pid=(\d+)/g)];
|
|
43
48
|
if (pidMatches.length === 0)
|
|
44
49
|
return { kind: "UNRELATED" };
|
|
@@ -50,38 +55,168 @@ export function classifyPortHolder(args) {
|
|
|
50
55
|
catch {
|
|
51
56
|
return { kind: "UNRELATED", pid, cmdlineReadFailed: true };
|
|
52
57
|
}
|
|
53
|
-
// Pretty cmdline (NULs → spaces) for log output. The argv-aware matching
|
|
54
|
-
// operates on the raw NUL-separated form.
|
|
55
58
|
const prettyCmdline = cmdline.replace(/\0/g, " ").trim();
|
|
56
59
|
const argv = cmdline.split("\0").filter(s => s.length > 0);
|
|
57
|
-
const
|
|
60
|
+
const holderType = detectHolderType(argv);
|
|
61
|
+
switch (holderType) {
|
|
62
|
+
case "chromium":
|
|
63
|
+
return classifyChromium(argv, prettyCmdline, pid, ownBrand, peerBrands);
|
|
64
|
+
case "xtigervnc":
|
|
65
|
+
return classifyXtigervnc(argv, prettyCmdline, pid, ownBrand, peerBrands);
|
|
66
|
+
case "websockify":
|
|
67
|
+
return classifyWebsockify(argv, prettyCmdline, pid, ownBrand, peerBrands);
|
|
68
|
+
case "unknown":
|
|
69
|
+
return { kind: "UNRELATED", pid, cmdline: prettyCmdline, holderType };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Holder detection
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
const CHROMIUM_BASENAMES = new Set([
|
|
76
|
+
"chrome",
|
|
77
|
+
"chromium",
|
|
78
|
+
"chromium-browser",
|
|
79
|
+
"google-chrome",
|
|
80
|
+
"google-chrome-stable",
|
|
81
|
+
]);
|
|
82
|
+
function basename(p) {
|
|
83
|
+
const i = p.lastIndexOf("/");
|
|
84
|
+
return i === -1 ? p : p.slice(i + 1);
|
|
85
|
+
}
|
|
86
|
+
function detectHolderType(argv) {
|
|
87
|
+
if (argv.length === 0)
|
|
88
|
+
return "unknown";
|
|
89
|
+
const head = basename(argv[0]);
|
|
90
|
+
if (CHROMIUM_BASENAMES.has(head))
|
|
91
|
+
return "chromium";
|
|
92
|
+
if (head === "Xtigervnc")
|
|
93
|
+
return "xtigervnc";
|
|
94
|
+
// websockify can be invoked directly (shebang) or via python; scan argv.
|
|
95
|
+
for (const a of argv) {
|
|
96
|
+
if (basename(a) === "websockify")
|
|
97
|
+
return "websockify";
|
|
98
|
+
}
|
|
99
|
+
return "unknown";
|
|
100
|
+
}
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// Per-holder anchors
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
function classifyChromium(argv, prettyCmdline, pid, ownBrand, peerBrands) {
|
|
105
|
+
const userDataDir = findFlagValue(argv, "--user-data-dir");
|
|
58
106
|
if (userDataDir === null) {
|
|
59
|
-
|
|
107
|
+
// Kernel threads, GPU/zygote/utility chrome processes inherit profile
|
|
108
|
+
// via fork without re-stating --user-data-dir. They wouldn't be
|
|
109
|
+
// listening anyway, but classify UNRELATED if one ever shows up here
|
|
110
|
+
// — never OWN_BRAND on a substring fluke.
|
|
111
|
+
return { kind: "UNRELATED", pid, cmdline: prettyCmdline, holderType: "chromium" };
|
|
60
112
|
}
|
|
61
|
-
const ownSuffix = `/${
|
|
113
|
+
const ownSuffix = `/${ownBrand.configDir}/chromium-profile`;
|
|
62
114
|
if (userDataDir.includes(ownSuffix)) {
|
|
63
|
-
return {
|
|
115
|
+
return {
|
|
116
|
+
kind: "OWN_BRAND", pid, cmdline: prettyCmdline,
|
|
117
|
+
profilePath: userDataDir, holderType: "chromium",
|
|
118
|
+
};
|
|
64
119
|
}
|
|
65
|
-
for (const
|
|
66
|
-
const peerSuffix = `/${
|
|
120
|
+
for (const peer of peerBrands) {
|
|
121
|
+
const peerSuffix = `/${peer.configDir}/chromium-profile`;
|
|
67
122
|
if (userDataDir.includes(peerSuffix)) {
|
|
68
|
-
return {
|
|
123
|
+
return {
|
|
124
|
+
kind: "PEER_BRAND", pid, cmdline: prettyCmdline,
|
|
125
|
+
profilePath: userDataDir, holderType: "chromium",
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { kind: "UNRELATED", pid, cmdline: prettyCmdline, holderType: "chromium" };
|
|
130
|
+
}
|
|
131
|
+
function classifyXtigervnc(argv, prettyCmdline, pid, ownBrand, peerBrands) {
|
|
132
|
+
const display = parseDisplayArg(argv);
|
|
133
|
+
if (display === null) {
|
|
134
|
+
return { kind: "UNRELATED", pid, cmdline: prettyCmdline, holderType: "xtigervnc" };
|
|
135
|
+
}
|
|
136
|
+
if (display === ownBrand.vncDisplay) {
|
|
137
|
+
return {
|
|
138
|
+
kind: "OWN_BRAND", pid, cmdline: prettyCmdline,
|
|
139
|
+
vncDisplay: display, holderType: "xtigervnc",
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
for (const peer of peerBrands) {
|
|
143
|
+
if (display === peer.vncDisplay) {
|
|
144
|
+
return {
|
|
145
|
+
kind: "PEER_BRAND", pid, cmdline: prettyCmdline,
|
|
146
|
+
vncDisplay: display, holderType: "xtigervnc",
|
|
147
|
+
};
|
|
69
148
|
}
|
|
70
149
|
}
|
|
71
|
-
return {
|
|
150
|
+
return {
|
|
151
|
+
kind: "UNRELATED", pid, cmdline: prettyCmdline,
|
|
152
|
+
vncDisplay: display, holderType: "xtigervnc",
|
|
153
|
+
};
|
|
72
154
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
155
|
+
function classifyWebsockify(argv, prettyCmdline, pid, ownBrand, peerBrands) {
|
|
156
|
+
const ports = collectPorts(argv);
|
|
157
|
+
if (ports.has(ownBrand.websockifyPort)) {
|
|
158
|
+
return {
|
|
159
|
+
kind: "OWN_BRAND", pid, cmdline: prettyCmdline,
|
|
160
|
+
websockifyPort: ownBrand.websockifyPort, holderType: "websockify",
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
for (const peer of peerBrands) {
|
|
164
|
+
if (ports.has(peer.websockifyPort)) {
|
|
165
|
+
return {
|
|
166
|
+
kind: "PEER_BRAND", pid, cmdline: prettyCmdline,
|
|
167
|
+
websockifyPort: peer.websockifyPort, holderType: "websockify",
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return { kind: "UNRELATED", pid, cmdline: prettyCmdline, holderType: "websockify" };
|
|
172
|
+
}
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// argv parsing helpers
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
// Find --flag=VALUE (single argv) or --flag VALUE (split across two argvs).
|
|
177
|
+
function findFlagValue(argv, flag) {
|
|
178
|
+
const PREFIX = `${flag}=`;
|
|
79
179
|
for (let i = 0; i < argv.length; i++) {
|
|
80
180
|
const a = argv[i];
|
|
81
181
|
if (a.startsWith(PREFIX))
|
|
82
182
|
return a.slice(PREFIX.length);
|
|
83
|
-
if (a ===
|
|
183
|
+
if (a === flag && i + 1 < argv.length)
|
|
84
184
|
return argv[i + 1];
|
|
85
185
|
}
|
|
86
186
|
return null;
|
|
87
187
|
}
|
|
188
|
+
// First non-flag argv of the form `:N` after argv[0]. vnc.sh's invocation
|
|
189
|
+
// puts the display in argv[1], but the function tolerates additional
|
|
190
|
+
// pre-positional flags by scanning past any `-`-prefixed token.
|
|
191
|
+
function parseDisplayArg(argv) {
|
|
192
|
+
for (let i = 1; i < argv.length; i++) {
|
|
193
|
+
const a = argv[i];
|
|
194
|
+
if (a.startsWith("-"))
|
|
195
|
+
continue;
|
|
196
|
+
const m = a.match(/^:(\d+)$/);
|
|
197
|
+
if (m)
|
|
198
|
+
return Number(m[1]);
|
|
199
|
+
}
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
// Collect every port number embedded in argv. Matches:
|
|
203
|
+
// "[::]:6080" → 6080 (websockify bind, IPv6 wildcard)
|
|
204
|
+
// "0.0.0.0:8080" → 8080 (bind, IPv4 wildcard)
|
|
205
|
+
// "localhost:5900" → 5900 (websockify upstream)
|
|
206
|
+
// "6080" → 6080 (bare positional)
|
|
207
|
+
// Skips flag tokens beginning with "-".
|
|
208
|
+
function collectPorts(argv) {
|
|
209
|
+
const ports = new Set();
|
|
210
|
+
const portRe = /(?::|^)(\d{1,5})$/;
|
|
211
|
+
for (const a of argv) {
|
|
212
|
+
if (a.startsWith("-"))
|
|
213
|
+
continue;
|
|
214
|
+
const m = a.match(portRe);
|
|
215
|
+
if (m === null)
|
|
216
|
+
continue;
|
|
217
|
+
const n = Number(m[1]);
|
|
218
|
+
if (n >= 1 && n <= 65535)
|
|
219
|
+
ports.add(n);
|
|
220
|
+
}
|
|
221
|
+
return ports;
|
|
222
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"brands": [
|
|
3
|
+
{
|
|
4
|
+
"hostname": "maxy",
|
|
5
|
+
"configDir": ".maxy",
|
|
6
|
+
"vncDisplay": 99,
|
|
7
|
+
"rfbPort": 5900,
|
|
8
|
+
"websockifyPort": 6080,
|
|
9
|
+
"cdpPort": 9222
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"hostname": "maxy-2",
|
|
13
|
+
"configDir": ".maxy-2",
|
|
14
|
+
"vncDisplay": 101,
|
|
15
|
+
"rfbPort": 5902,
|
|
16
|
+
"websockifyPort": 6082,
|
|
17
|
+
"cdpPort": 9224
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"hostname": "maxy-3",
|
|
21
|
+
"configDir": ".maxy-3",
|
|
22
|
+
"vncDisplay": 102,
|
|
23
|
+
"rfbPort": 5903,
|
|
24
|
+
"websockifyPort": 6083,
|
|
25
|
+
"cdpPort": 9225
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"hostname": "maxy-4",
|
|
29
|
+
"configDir": ".maxy-4",
|
|
30
|
+
"vncDisplay": 103,
|
|
31
|
+
"rfbPort": 5904,
|
|
32
|
+
"websockifyPort": 6084,
|
|
33
|
+
"cdpPort": 9226
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"hostname": "realagent",
|
|
37
|
+
"configDir": ".realagent",
|
|
38
|
+
"vncDisplay": 100,
|
|
39
|
+
"rfbPort": 5901,
|
|
40
|
+
"websockifyPort": 6081,
|
|
41
|
+
"cdpPort": 9223
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The component names that the platform UI treats as long-lived editor
|
|
3
|
+
* surfaces (not single-shot prompts). They survive multiple `onSubmit`
|
|
4
|
+
* fires because the operator may auto-save mid-edit, and they are also
|
|
5
|
+
* the **server-side commitment surface** for Task 942: when the admin
|
|
6
|
+
* agent emits one of these names via `render-component`, the live
|
|
7
|
+
* stream-parser materialises the inline content as a sibling
|
|
8
|
+
* `:KnowledgeDocument` artefact so the row appears in the artefacts
|
|
9
|
+
* panel and survives session compaction.
|
|
10
|
+
*
|
|
11
|
+
* Single source of truth — the platform UI (`app/admin-types.ts`) and
|
|
12
|
+
* the admin MCP server (`plugins/admin/mcp/src/index.ts`) both import
|
|
13
|
+
* from this module. Any drift here is an account-isolation /
|
|
14
|
+
* persistence-doctrine bug; keep the constant in one place.
|
|
15
|
+
*/
|
|
16
|
+
export declare const PERSISTENT_COMPONENTS: Set<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Cheap, allocation-free guard for hot-path checks.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isPersistentComponent(name: string | undefined | null): boolean;
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,qBAAqB,aAKhC,CAAC;AAEH;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAE9E"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PERSISTENT_COMPONENTS = void 0;
|
|
4
|
+
exports.isPersistentComponent = isPersistentComponent;
|
|
5
|
+
/**
|
|
6
|
+
* The component names that the platform UI treats as long-lived editor
|
|
7
|
+
* surfaces (not single-shot prompts). They survive multiple `onSubmit`
|
|
8
|
+
* fires because the operator may auto-save mid-edit, and they are also
|
|
9
|
+
* the **server-side commitment surface** for Task 942: when the admin
|
|
10
|
+
* agent emits one of these names via `render-component`, the live
|
|
11
|
+
* stream-parser materialises the inline content as a sibling
|
|
12
|
+
* `:KnowledgeDocument` artefact so the row appears in the artefacts
|
|
13
|
+
* panel and survives session compaction.
|
|
14
|
+
*
|
|
15
|
+
* Single source of truth — the platform UI (`app/admin-types.ts`) and
|
|
16
|
+
* the admin MCP server (`plugins/admin/mcp/src/index.ts`) both import
|
|
17
|
+
* from this module. Any drift here is an account-isolation /
|
|
18
|
+
* persistence-doctrine bug; keep the constant in one place.
|
|
19
|
+
*/
|
|
20
|
+
exports.PERSISTENT_COMPONENTS = new Set([
|
|
21
|
+
'action-list',
|
|
22
|
+
'document-editor',
|
|
23
|
+
'rich-content-editor',
|
|
24
|
+
'grid-editor',
|
|
25
|
+
]);
|
|
26
|
+
/**
|
|
27
|
+
* Cheap, allocation-free guard for hot-path checks.
|
|
28
|
+
*/
|
|
29
|
+
function isPersistentComponent(name) {
|
|
30
|
+
return typeof name === 'string' && exports.PERSISTENT_COMPONENTS.has(name);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAyBA,sDAEC;AA3BD;;;;;;;;;;;;;;GAcG;AACU,QAAA,qBAAqB,GAAG,IAAI,GAAG,CAAS;IACnD,aAAa;IACb,iBAAiB;IACjB,qBAAqB;IACrB,aAAa;CACd,CAAC,CAAC;AAEH;;GAEG;AACH,SAAgB,qBAAqB,CAAC,IAA+B;IACnE,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,6BAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The component names that the platform UI treats as long-lived editor
|
|
3
|
+
* surfaces (not single-shot prompts). They survive multiple `onSubmit`
|
|
4
|
+
* fires because the operator may auto-save mid-edit, and they are also
|
|
5
|
+
* the **server-side commitment surface** for Task 942: when the admin
|
|
6
|
+
* agent emits one of these names via `render-component`, the live
|
|
7
|
+
* stream-parser materialises the inline content as a sibling
|
|
8
|
+
* `:KnowledgeDocument` artefact so the row appears in the artefacts
|
|
9
|
+
* panel and survives session compaction.
|
|
10
|
+
*
|
|
11
|
+
* Single source of truth — the platform UI (`app/admin-types.ts`) and
|
|
12
|
+
* the admin MCP server (`plugins/admin/mcp/src/index.ts`) both import
|
|
13
|
+
* from this module. Any drift here is an account-isolation /
|
|
14
|
+
* persistence-doctrine bug; keep the constant in one place.
|
|
15
|
+
*/
|
|
16
|
+
export const PERSISTENT_COMPONENTS = new Set<string>([
|
|
17
|
+
'action-list',
|
|
18
|
+
'document-editor',
|
|
19
|
+
'rich-content-editor',
|
|
20
|
+
'grid-editor',
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Cheap, allocation-free guard for hot-path checks.
|
|
25
|
+
*/
|
|
26
|
+
export function isPersistentComponent(name: string | undefined | null): boolean {
|
|
27
|
+
return typeof name === 'string' && PERSISTENT_COMPONENTS.has(name);
|
|
28
|
+
}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
"plugins/*/mcp"
|
|
7
7
|
],
|
|
8
8
|
"scripts": {
|
|
9
|
-
"build": "tsc -p lib/models/tsconfig.json && tsc -p lib/anthropic-key/tsconfig.json && tsc -p lib/oauth-llm/tsconfig.json && tsc -p lib/mcp-stderr-tee/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/screening-patterns/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && NODE_OPTIONS='--max-old-space-size=8192' tsc -b plugins/*/mcp/tsconfig.json",
|
|
10
|
-
"build:lib": "tsc -p lib/models/tsconfig.json && tsc -p lib/anthropic-key/tsconfig.json && tsc -p lib/oauth-llm/tsconfig.json && tsc -p lib/mcp-stderr-tee/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/screening-patterns/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json",
|
|
9
|
+
"build": "tsc -p lib/models/tsconfig.json && tsc -p lib/anthropic-key/tsconfig.json && tsc -p lib/oauth-llm/tsconfig.json && tsc -p lib/mcp-stderr-tee/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/screening-patterns/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json && NODE_OPTIONS='--max-old-space-size=8192' tsc -b plugins/*/mcp/tsconfig.json",
|
|
10
|
+
"build:lib": "tsc -p lib/models/tsconfig.json && tsc -p lib/anthropic-key/tsconfig.json && tsc -p lib/oauth-llm/tsconfig.json && tsc -p lib/mcp-stderr-tee/tsconfig.json && tsc -p lib/mcp-spawn-tee/tsconfig.json && tsc -p lib/account-enumeration/tsconfig.json && tsc -p lib/graph-write/tsconfig.json && tsc -p lib/graph-mcp/tsconfig.json && tsc -p lib/graph-trash/tsconfig.json && tsc -p lib/graph-search/tsconfig.json && tsc -p lib/screening-patterns/tsconfig.json && tsc -p lib/device-url/tsconfig.json && tsc -p lib/brand-templating/tsconfig.json && tsc -p lib/entitlement/tsconfig.json && tsc -p lib/task-secrets/tsconfig.json && tsc -p lib/admins-write/tsconfig.json && tsc -p lib/persistent-components/tsconfig.json",
|
|
11
11
|
"build:memory": "tsc -p plugins/memory/mcp/tsconfig.json",
|
|
12
12
|
"build:contacts": "tsc -p plugins/contacts/mcp/tsconfig.json",
|
|
13
13
|
"build:telegram": "tsc -p plugins/telegram/mcp/tsconfig.json",
|
|
@@ -71,5 +71,5 @@ Tools are available via the `admin` MCP server.
|
|
|
71
71
|
## Hooks
|
|
72
72
|
|
|
73
73
|
- `hooks/pre-tool-use.sh` — enforces admin agent write boundaries
|
|
74
|
-
- `hooks/playwright-file-guard.sh` —
|
|
74
|
+
- `hooks/playwright-file-guard.sh` — rewrites file:// URLs to a backgrounded loopback http.server before Playwright sees them
|
|
75
75
|
- `hooks/webfetch-preflight.mjs` — short-circuits WebFetch on JS-SPA shells with a structured `WEBFETCH_CANNOT_READ_JS_SPA` error so the agent surfaces a loud failure to the owner instead of paying the 60s extraction timeout. Fail-open on any internal error.
|