@enderfga/claw-orchestrator 3.7.1 → 4.0.3
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/README.md +45 -3
- package/configs/autoloop-coder-prompt.md +65 -28
- package/configs/autoloop-planner-prompt.md +103 -42
- package/configs/autoloop-reviewer-prompt.md +58 -30
- package/dist/bin/cli.js +30 -7
- package/dist/bin/cli.js.map +1 -1
- package/dist/src/autoloop/dispatcher.js +16 -2
- package/dist/src/autoloop/dispatcher.js.map +1 -1
- package/dist/src/autoloop/messages.d.ts +0 -2
- package/dist/src/autoloop/messages.js +0 -2
- package/dist/src/autoloop/messages.js.map +1 -1
- package/dist/src/autoloop/planner-tools.d.ts +11 -6
- package/dist/src/autoloop/planner-tools.js +24 -7
- package/dist/src/autoloop/planner-tools.js.map +1 -1
- package/dist/src/autoloop/runner.d.ts +1 -2
- package/dist/src/autoloop/runner.js +1 -2
- package/dist/src/autoloop/runner.js.map +1 -1
- package/dist/src/autoloop/types.d.ts +0 -2
- package/dist/src/autoloop/types.js +0 -2
- package/dist/src/autoloop/types.js.map +1 -1
- package/dist/src/council.js +1 -0
- package/dist/src/council.js.map +1 -1
- package/dist/src/dashboard/index.html +1066 -12
- package/dist/src/embedded-server.d.ts +7 -0
- package/dist/src/embedded-server.js +359 -17
- package/dist/src/embedded-server.js.map +1 -1
- package/dist/src/index.js +222 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/session-manager.d.ts +98 -1
- package/dist/src/session-manager.js +340 -5
- package/dist/src/session-manager.js.map +1 -1
- package/dist/src/ultraapp/build-events.d.ts +46 -0
- package/dist/src/ultraapp/build-events.js +6 -0
- package/dist/src/ultraapp/build-events.js.map +1 -0
- package/dist/src/ultraapp/build.d.ts +39 -0
- package/dist/src/ultraapp/build.js +111 -0
- package/dist/src/ultraapp/build.js.map +1 -0
- package/dist/src/ultraapp/conventions.d.ts +8 -0
- package/dist/src/ultraapp/conventions.js +248 -0
- package/dist/src/ultraapp/conventions.js.map +1 -0
- package/dist/src/ultraapp/council-adapter.d.ts +49 -0
- package/dist/src/ultraapp/council-adapter.js +152 -0
- package/dist/src/ultraapp/council-adapter.js.map +1 -0
- package/dist/src/ultraapp/deploy.d.ts +45 -0
- package/dist/src/ultraapp/deploy.js +82 -0
- package/dist/src/ultraapp/deploy.js.map +1 -0
- package/dist/src/ultraapp/diff-apply.d.ts +15 -0
- package/dist/src/ultraapp/diff-apply.js +48 -0
- package/dist/src/ultraapp/diff-apply.js.map +1 -0
- package/dist/src/ultraapp/docker.d.ts +57 -0
- package/dist/src/ultraapp/docker.js +83 -0
- package/dist/src/ultraapp/docker.js.map +1 -0
- package/dist/src/ultraapp/feedback-classifier.d.ts +24 -0
- package/dist/src/ultraapp/feedback-classifier.js +85 -0
- package/dist/src/ultraapp/feedback-classifier.js.map +1 -0
- package/dist/src/ultraapp/files.d.ts +24 -0
- package/dist/src/ultraapp/files.js +79 -0
- package/dist/src/ultraapp/files.js.map +1 -0
- package/dist/src/ultraapp/fix-on-failure-session.d.ts +23 -0
- package/dist/src/ultraapp/fix-on-failure-session.js +48 -0
- package/dist/src/ultraapp/fix-on-failure-session.js.map +1 -0
- package/dist/src/ultraapp/fix-on-failure.d.ts +39 -0
- package/dist/src/ultraapp/fix-on-failure.js +69 -0
- package/dist/src/ultraapp/fix-on-failure.js.map +1 -0
- package/dist/src/ultraapp/host-strategy.d.ts +57 -0
- package/dist/src/ultraapp/host-strategy.js +205 -0
- package/dist/src/ultraapp/host-strategy.js.map +1 -0
- package/dist/src/ultraapp/interview-parser.d.ts +41 -0
- package/dist/src/ultraapp/interview-parser.js +83 -0
- package/dist/src/ultraapp/interview-parser.js.map +1 -0
- package/dist/src/ultraapp/interview-tools.d.ts +16 -0
- package/dist/src/ultraapp/interview-tools.js +36 -0
- package/dist/src/ultraapp/interview-tools.js.map +1 -0
- package/dist/src/ultraapp/json-patch.d.ts +6 -0
- package/dist/src/ultraapp/json-patch.js +78 -0
- package/dist/src/ultraapp/json-patch.js.map +1 -0
- package/dist/src/ultraapp/lifecycle.d.ts +38 -0
- package/dist/src/ultraapp/lifecycle.js +31 -0
- package/dist/src/ultraapp/lifecycle.js.map +1 -0
- package/dist/src/ultraapp/manager.d.ts +150 -0
- package/dist/src/ultraapp/manager.js +684 -0
- package/dist/src/ultraapp/manager.js.map +1 -0
- package/dist/src/ultraapp/narrator-prompt.d.ts +10 -0
- package/dist/src/ultraapp/narrator-prompt.js +54 -0
- package/dist/src/ultraapp/narrator-prompt.js.map +1 -0
- package/dist/src/ultraapp/narrator.d.ts +49 -0
- package/dist/src/ultraapp/narrator.js +83 -0
- package/dist/src/ultraapp/narrator.js.map +1 -0
- package/dist/src/ultraapp/patcher.d.ts +35 -0
- package/dist/src/ultraapp/patcher.js +159 -0
- package/dist/src/ultraapp/patcher.js.map +1 -0
- package/dist/src/ultraapp/router.d.ts +39 -0
- package/dist/src/ultraapp/router.js +139 -0
- package/dist/src/ultraapp/router.js.map +1 -0
- package/dist/src/ultraapp/spec-delta.d.ts +18 -0
- package/dist/src/ultraapp/spec-delta.js +35 -0
- package/dist/src/ultraapp/spec-delta.js.map +1 -0
- package/dist/src/ultraapp/spec.d.ts +82 -0
- package/dist/src/ultraapp/spec.js +125 -0
- package/dist/src/ultraapp/spec.js.map +1 -0
- package/dist/src/ultraapp/store.d.ts +67 -0
- package/dist/src/ultraapp/store.js +177 -0
- package/dist/src/ultraapp/store.js.map +1 -0
- package/dist/src/ultraapp/versions.d.ts +50 -0
- package/dist/src/ultraapp/versions.js +65 -0
- package/dist/src/ultraapp/versions.js.map +1 -0
- package/openclaw.plugin.json +15 -1
- package/package.json +3 -1
- package/skills/SKILL.md +2 -2
- package/skills/references/autoloop.md +7 -4
- package/skills/references/dashboard.md +153 -0
- package/skills/references/mcp.md +2 -2
- package/skills/references/tools.md +183 -0
- package/skills/references/ultraapp.md +203 -0
- package/skills/ultraapp/SKILL.md +112 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-spawn runtime strategy — runs the generated app as a regular Node
|
|
3
|
+
* process on the host, no Docker. The natural default for personal /
|
|
4
|
+
* internal-tool use; Docker is the opt-in mode for shared production
|
|
5
|
+
* hosts where isolation matters.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors the docker.ts shape (`build / run / stop / start / rm`) so the
|
|
8
|
+
* deploy orchestrator and lifecycle helpers stay the same.
|
|
9
|
+
*
|
|
10
|
+
* State persistence:
|
|
11
|
+
* ~/.claw-orchestrator/host-procs.json keyed by container-name (we keep
|
|
12
|
+
* the term to match the rest of the API) → { pid, port, cwd, env, since }.
|
|
13
|
+
* Survives orchestrator restarts: hostStart re-spawns from the saved
|
|
14
|
+
* metadata, hostStop kills the recorded pid + child group.
|
|
15
|
+
*/
|
|
16
|
+
import { spawn } from 'node:child_process';
|
|
17
|
+
import * as fs from 'node:fs';
|
|
18
|
+
import * as os from 'node:os';
|
|
19
|
+
import * as path from 'node:path';
|
|
20
|
+
const STATE_FILE = path.join(os.homedir(), '.claw-orchestrator', 'host-procs.json');
|
|
21
|
+
function readState() {
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(fs.readFileSync(STATE_FILE, 'utf8'));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function writeState(state) {
|
|
30
|
+
fs.mkdirSync(path.dirname(STATE_FILE), { recursive: true });
|
|
31
|
+
fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
32
|
+
}
|
|
33
|
+
function isAlive(pid) {
|
|
34
|
+
try {
|
|
35
|
+
process.kill(pid, 0);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Host build = `npm install` + `npm run build` (if a build script exists).
|
|
44
|
+
* No isolation; we mutate the worktree directly. The "tag" is metadata only
|
|
45
|
+
* — host-mode doesn't have container images.
|
|
46
|
+
*/
|
|
47
|
+
export async function hostBuild(args) {
|
|
48
|
+
if (!fs.existsSync(path.join(args.cwd, 'package.json'))) {
|
|
49
|
+
return { ok: false, error: `no package.json at ${args.cwd}` };
|
|
50
|
+
}
|
|
51
|
+
const install = await runCmd('npm', ['install'], { cwd: args.cwd, env: args.buildArgs });
|
|
52
|
+
if (!install.ok)
|
|
53
|
+
return { ok: false, error: `npm install failed: ${install.stderr.slice(0, 500)}` };
|
|
54
|
+
// Only run build if the script exists.
|
|
55
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(args.cwd, 'package.json'), 'utf8'));
|
|
56
|
+
if (pkg.scripts?.build) {
|
|
57
|
+
const build = await runCmd('npm', ['run', 'build'], { cwd: args.cwd, env: args.buildArgs });
|
|
58
|
+
if (!build.ok)
|
|
59
|
+
return { ok: false, error: `npm run build failed: ${build.stderr.slice(0, 500)}` };
|
|
60
|
+
}
|
|
61
|
+
return { ok: true, imageId: `host:${args.tag}` };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Host run = spawn `npm start` (or `node server.js` fallback) detached, with
|
|
65
|
+
* PORT + caller env. Records pid in host-procs.json keyed by name.
|
|
66
|
+
*/
|
|
67
|
+
export async function hostRun(args) {
|
|
68
|
+
// image arg is repurposed to mean "cwd of the codebase" in host mode. The
|
|
69
|
+
// caller (deploy orchestrator) passes `tag` as image; we accept either
|
|
70
|
+
// a tag (which we look up — but we don't have a registry, so we expect
|
|
71
|
+
// the caller passes the cwd directly via image).
|
|
72
|
+
// NOTE: deploy.ts currently passes `tag` not `cwd`. We need the cwd
|
|
73
|
+
// separately — passed via env.HOST_CWD as a contract for host mode.
|
|
74
|
+
const cwd = args.env.HOST_CWD || args.image;
|
|
75
|
+
if (!fs.existsSync(path.join(cwd, 'package.json'))) {
|
|
76
|
+
return { ok: false, error: `no package.json at ${cwd}` };
|
|
77
|
+
}
|
|
78
|
+
// Strip the contract env keys from what gets exported to the child
|
|
79
|
+
const childEnv = { ...process.env, ...args.env };
|
|
80
|
+
delete childEnv.HOST_CWD;
|
|
81
|
+
childEnv.PORT = String(args.hostPort);
|
|
82
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));
|
|
83
|
+
let cmd;
|
|
84
|
+
let cmdArgs;
|
|
85
|
+
if (pkg.scripts?.start) {
|
|
86
|
+
cmd = 'npm';
|
|
87
|
+
cmdArgs = ['start'];
|
|
88
|
+
}
|
|
89
|
+
else if (pkg.main) {
|
|
90
|
+
cmd = 'node';
|
|
91
|
+
cmdArgs = [pkg.main];
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
return { ok: false, error: 'no scripts.start and no main entry in package.json' };
|
|
95
|
+
}
|
|
96
|
+
const child = spawn(cmd, cmdArgs, {
|
|
97
|
+
cwd,
|
|
98
|
+
env: childEnv,
|
|
99
|
+
detached: true,
|
|
100
|
+
stdio: 'ignore',
|
|
101
|
+
});
|
|
102
|
+
child.unref();
|
|
103
|
+
const pid = child.pid;
|
|
104
|
+
if (typeof pid !== 'number') {
|
|
105
|
+
return { ok: false, error: 'spawn returned no pid' };
|
|
106
|
+
}
|
|
107
|
+
const state = readState();
|
|
108
|
+
state[args.name] = {
|
|
109
|
+
pid,
|
|
110
|
+
port: args.hostPort,
|
|
111
|
+
cwd,
|
|
112
|
+
env: args.env,
|
|
113
|
+
since: new Date().toISOString(),
|
|
114
|
+
};
|
|
115
|
+
writeState(state);
|
|
116
|
+
return { ok: true, containerName: args.name };
|
|
117
|
+
}
|
|
118
|
+
export async function hostStop(name) {
|
|
119
|
+
const state = readState();
|
|
120
|
+
const entry = state[name];
|
|
121
|
+
if (!entry)
|
|
122
|
+
return { ok: false, error: `no host proc named ${name}` };
|
|
123
|
+
if (isAlive(entry.pid)) {
|
|
124
|
+
try {
|
|
125
|
+
// Kill the process group (child + grandchildren via npm)
|
|
126
|
+
process.kill(-entry.pid, 'SIGTERM');
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
try {
|
|
130
|
+
process.kill(entry.pid, 'SIGTERM');
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
/* already dead */
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Give it a beat then SIGKILL if still alive
|
|
137
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
138
|
+
if (isAlive(entry.pid)) {
|
|
139
|
+
try {
|
|
140
|
+
process.kill(-entry.pid, 'SIGKILL');
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
try {
|
|
144
|
+
process.kill(entry.pid, 'SIGKILL');
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
/* already dead */
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return { ok: true };
|
|
153
|
+
}
|
|
154
|
+
export async function hostStart(name) {
|
|
155
|
+
const state = readState();
|
|
156
|
+
const entry = state[name];
|
|
157
|
+
if (!entry)
|
|
158
|
+
return { ok: false, error: `no host proc named ${name}` };
|
|
159
|
+
if (isAlive(entry.pid))
|
|
160
|
+
return { ok: true }; // already running
|
|
161
|
+
// Re-spawn using saved metadata
|
|
162
|
+
const r = await hostRun({
|
|
163
|
+
image: entry.cwd,
|
|
164
|
+
name,
|
|
165
|
+
hostPort: entry.port,
|
|
166
|
+
env: { ...entry.env, HOST_CWD: entry.cwd },
|
|
167
|
+
});
|
|
168
|
+
return r.ok ? { ok: true } : { ok: false, error: r.error };
|
|
169
|
+
}
|
|
170
|
+
export async function hostRm(name) {
|
|
171
|
+
await hostStop(name).catch(() => ({ ok: true }));
|
|
172
|
+
const state = readState();
|
|
173
|
+
delete state[name];
|
|
174
|
+
writeState(state);
|
|
175
|
+
return { ok: true };
|
|
176
|
+
}
|
|
177
|
+
/** Stub matching dockerRmi — host mode has no images, so this is a no-op. */
|
|
178
|
+
export async function hostRmi(_tag) {
|
|
179
|
+
return { ok: true };
|
|
180
|
+
}
|
|
181
|
+
export async function hostPs() {
|
|
182
|
+
const state = readState();
|
|
183
|
+
const containers = Object.entries(state).map(([name, entry]) => ({
|
|
184
|
+
name,
|
|
185
|
+
state: isAlive(entry.pid) ? 'running' : 'exited',
|
|
186
|
+
ports: `${entry.port}->${entry.port}`,
|
|
187
|
+
}));
|
|
188
|
+
return { containers };
|
|
189
|
+
}
|
|
190
|
+
function runCmd(cmd, args, opts) {
|
|
191
|
+
return new Promise((resolve) => {
|
|
192
|
+
const child = spawn(cmd, args, {
|
|
193
|
+
cwd: opts.cwd,
|
|
194
|
+
env: { ...process.env, ...(opts.env ?? {}) },
|
|
195
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
196
|
+
});
|
|
197
|
+
let stdout = '';
|
|
198
|
+
let stderr = '';
|
|
199
|
+
child.stdout?.on('data', (d) => (stdout += d.toString()));
|
|
200
|
+
child.stderr?.on('data', (d) => (stderr += d.toString()));
|
|
201
|
+
child.on('close', (code) => resolve({ ok: code === 0, stdout, stderr }));
|
|
202
|
+
child.on('error', (e) => resolve({ ok: false, stdout, stderr: stderr + e.message }));
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=host-strategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-strategy.js","sourceRoot":"","sources":["../../../src/ultraapp/host-strategy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface QuestionEnvelope {
|
|
2
|
+
question: string;
|
|
3
|
+
options: Array<{
|
|
4
|
+
label: string;
|
|
5
|
+
value: string;
|
|
6
|
+
}>;
|
|
7
|
+
recommended: string;
|
|
8
|
+
freeformAccepted: boolean;
|
|
9
|
+
context?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ToolCall {
|
|
12
|
+
name: string;
|
|
13
|
+
argsRaw: string;
|
|
14
|
+
}
|
|
15
|
+
export type ParsedReply = {
|
|
16
|
+
kind: 'question';
|
|
17
|
+
question: QuestionEnvelope;
|
|
18
|
+
rawText: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'complete';
|
|
21
|
+
summary: string;
|
|
22
|
+
} | {
|
|
23
|
+
/** Tool calls AND a question in the same reply. The manager runs the
|
|
24
|
+
tools, sends the tool_result followup (background), and emits the
|
|
25
|
+
question to the user without waiting for another LLM round-trip. */
|
|
26
|
+
kind: 'tools-and-question';
|
|
27
|
+
toolCalls: ToolCall[];
|
|
28
|
+
question: QuestionEnvelope;
|
|
29
|
+
rawText: string;
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'tools';
|
|
32
|
+
toolCalls: ToolCall[];
|
|
33
|
+
rawText: string;
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'text';
|
|
36
|
+
text: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'error';
|
|
39
|
+
reason: string;
|
|
40
|
+
};
|
|
41
|
+
export declare function parseInterviewReply(reply: string): ParsedReply;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const FENCE_RE = /```question\s*\n([\s\S]*?)\n```/;
|
|
2
|
+
const COMPLETE_RE = /^\[INTERVIEW:\s*COMPLETE\]\s*$/m;
|
|
3
|
+
const TOOL_RE = /<tool\s+name="([a-z_]+)"\s*>([\s\S]*?)<\/tool>/g;
|
|
4
|
+
export function parseInterviewReply(reply) {
|
|
5
|
+
const tools = [];
|
|
6
|
+
let m;
|
|
7
|
+
TOOL_RE.lastIndex = 0;
|
|
8
|
+
while ((m = TOOL_RE.exec(reply)) !== null) {
|
|
9
|
+
tools.push({ name: m[1], argsRaw: m[2].trim() });
|
|
10
|
+
}
|
|
11
|
+
// Try to also parse a fenced question — it's common (and previously
|
|
12
|
+
// dropped silently) for Claude to emit tool calls AND the next question
|
|
13
|
+
// in a single reply.
|
|
14
|
+
const parsedQuestion = (() => {
|
|
15
|
+
const fence = FENCE_RE.exec(reply);
|
|
16
|
+
if (!fence)
|
|
17
|
+
return null;
|
|
18
|
+
let parsed;
|
|
19
|
+
try {
|
|
20
|
+
parsed = JSON.parse(fence[1]);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const v = validateQuestion(parsed);
|
|
26
|
+
return v.ok ? v.value : null;
|
|
27
|
+
})();
|
|
28
|
+
if (tools.length > 0 && parsedQuestion) {
|
|
29
|
+
return { kind: 'tools-and-question', toolCalls: tools, question: parsedQuestion, rawText: reply };
|
|
30
|
+
}
|
|
31
|
+
if (tools.length > 0) {
|
|
32
|
+
return { kind: 'tools', toolCalls: tools, rawText: reply };
|
|
33
|
+
}
|
|
34
|
+
if (COMPLETE_RE.test(reply)) {
|
|
35
|
+
return { kind: 'complete', summary: reply.replace(COMPLETE_RE, '').trim() };
|
|
36
|
+
}
|
|
37
|
+
if (parsedQuestion) {
|
|
38
|
+
return { kind: 'question', question: parsedQuestion, rawText: reply };
|
|
39
|
+
}
|
|
40
|
+
// Re-run the parse to surface a malformed-fence error if a fence was present
|
|
41
|
+
// but its JSON was bad.
|
|
42
|
+
const fence = FENCE_RE.exec(reply);
|
|
43
|
+
if (fence) {
|
|
44
|
+
try {
|
|
45
|
+
JSON.parse(fence[1]);
|
|
46
|
+
return { kind: 'error', reason: 'invalid question envelope' };
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
return { kind: 'error', reason: `malformed JSON in question fence: ${e.message}` };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { kind: 'text', text: reply.trim() };
|
|
53
|
+
}
|
|
54
|
+
function validateQuestion(x) {
|
|
55
|
+
if (!x || typeof x !== 'object')
|
|
56
|
+
return { ok: false, reason: 'envelope is not an object' };
|
|
57
|
+
const o = x;
|
|
58
|
+
if (typeof o.question !== 'string' || o.question.length === 0)
|
|
59
|
+
return { ok: false, reason: 'missing .question' };
|
|
60
|
+
if (!Array.isArray(o.options) || o.options.length < 1)
|
|
61
|
+
return { ok: false, reason: 'missing .options' };
|
|
62
|
+
for (const opt of o.options) {
|
|
63
|
+
if (!opt || typeof opt !== 'object')
|
|
64
|
+
return { ok: false, reason: 'option is not an object' };
|
|
65
|
+
const oo = opt;
|
|
66
|
+
if (typeof oo.label !== 'string' || typeof oo.value !== 'string') {
|
|
67
|
+
return { ok: false, reason: 'option missing label/value' };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (typeof o.recommended !== 'string')
|
|
71
|
+
return { ok: false, reason: 'missing .recommended' };
|
|
72
|
+
return {
|
|
73
|
+
ok: true,
|
|
74
|
+
value: {
|
|
75
|
+
question: o.question,
|
|
76
|
+
options: o.options,
|
|
77
|
+
recommended: o.recommended,
|
|
78
|
+
freeformAccepted: o.freeformAccepted === true,
|
|
79
|
+
context: typeof o.context === 'string' ? o.context : undefined,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=interview-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interview-parser.js","sourceRoot":"","sources":["../../../src/ultraapp/interview-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { UltraappStore } from './store.js';
|
|
2
|
+
import type { ToolCall } from './interview-parser.js';
|
|
3
|
+
import type { FileMetadata } from './files.js';
|
|
4
|
+
export interface ToolResult {
|
|
5
|
+
name: string;
|
|
6
|
+
ok: boolean;
|
|
7
|
+
result?: unknown;
|
|
8
|
+
error?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface RunToolsArgs {
|
|
11
|
+
runId: string;
|
|
12
|
+
store: UltraappStore;
|
|
13
|
+
extractMetadata: (ref: string) => Promise<FileMetadata>;
|
|
14
|
+
calls: ToolCall[];
|
|
15
|
+
}
|
|
16
|
+
export declare function runToolCalls(args: RunToolsArgs): Promise<ToolResult[]>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { applyPatch } from './json-patch.js';
|
|
2
|
+
import { isComplete } from './spec.js';
|
|
3
|
+
export async function runToolCalls(args) {
|
|
4
|
+
const out = [];
|
|
5
|
+
for (const call of args.calls) {
|
|
6
|
+
out.push(await dispatch(call, args));
|
|
7
|
+
}
|
|
8
|
+
return out;
|
|
9
|
+
}
|
|
10
|
+
async function dispatch(call, args) {
|
|
11
|
+
try {
|
|
12
|
+
if (call.name === 'update_spec') {
|
|
13
|
+
const patch = JSON.parse(call.argsRaw);
|
|
14
|
+
const spec = await args.store.readSpec(args.runId);
|
|
15
|
+
const next = applyPatch(spec, patch);
|
|
16
|
+
await args.store.writeSpec(args.runId, next);
|
|
17
|
+
return { name: call.name, ok: true, result: { applied: patch.length } };
|
|
18
|
+
}
|
|
19
|
+
if (call.name === 'extract_metadata') {
|
|
20
|
+
const a = JSON.parse(call.argsRaw);
|
|
21
|
+
if (typeof a.ref !== 'string')
|
|
22
|
+
throw new Error('extract_metadata requires .ref');
|
|
23
|
+
const meta = await args.extractMetadata(a.ref);
|
|
24
|
+
return { name: call.name, ok: true, result: meta };
|
|
25
|
+
}
|
|
26
|
+
if (call.name === 'check_completeness') {
|
|
27
|
+
const spec = await args.store.readSpec(args.runId);
|
|
28
|
+
return { name: call.name, ok: true, result: isComplete(spec) };
|
|
29
|
+
}
|
|
30
|
+
return { name: call.name, ok: false, error: `unknown tool: ${call.name}` };
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
return { name: call.name, ok: false, error: e.message };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=interview-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interview-tools.js","sourceRoot":"","sources":["../../../src/ultraapp/interview-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAmBvC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAkB;IACnD,MAAM,GAAG,GAAiB,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,GAAG,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,IAAc,EAAE,IAAkB;IACxD,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAInC,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnD,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACrC,MAAM,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAmB,CAAC,CAAC;YAC5D,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QAC1E,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YACrC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAoB,CAAC;YACtD,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;YACjF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAC/C,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACrD,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,oBAAoB,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACjE,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;IAC7E,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAG,CAAW,CAAC,OAAO,EAAE,CAAC;IACrE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export function applyPatch(doc, ops) {
|
|
2
|
+
let next = deepClone(doc);
|
|
3
|
+
for (const op of ops) {
|
|
4
|
+
next = applyOne(next, op);
|
|
5
|
+
}
|
|
6
|
+
return next;
|
|
7
|
+
}
|
|
8
|
+
function applyOne(doc, op) {
|
|
9
|
+
const tokens = parsePath(op.path);
|
|
10
|
+
if (tokens.length === 0) {
|
|
11
|
+
if (op.op === 'replace' || op.op === 'add')
|
|
12
|
+
return op.value;
|
|
13
|
+
throw new Error(`unsupported root op ${op.op}`);
|
|
14
|
+
}
|
|
15
|
+
const last = tokens[tokens.length - 1];
|
|
16
|
+
const parent = walk(doc, tokens.slice(0, -1));
|
|
17
|
+
if (op.op === 'add' || op.op === 'replace') {
|
|
18
|
+
setIn(parent, last, op.value);
|
|
19
|
+
return doc;
|
|
20
|
+
}
|
|
21
|
+
if (op.op === 'remove') {
|
|
22
|
+
removeIn(parent, last);
|
|
23
|
+
return doc;
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`unsupported op ${op.op}`);
|
|
26
|
+
}
|
|
27
|
+
function parsePath(path) {
|
|
28
|
+
if (path === '')
|
|
29
|
+
return [];
|
|
30
|
+
if (!path.startsWith('/'))
|
|
31
|
+
throw new Error(`bad path ${path}`);
|
|
32
|
+
return path
|
|
33
|
+
.slice(1)
|
|
34
|
+
.split('/')
|
|
35
|
+
.map((t) => t.replace(/~1/g, '/').replace(/~0/g, '~'));
|
|
36
|
+
}
|
|
37
|
+
function walk(doc, tokens) {
|
|
38
|
+
let cur = doc;
|
|
39
|
+
for (const t of tokens) {
|
|
40
|
+
if (Array.isArray(cur)) {
|
|
41
|
+
const i = t === '-' ? cur.length : Number(t);
|
|
42
|
+
cur = cur[i];
|
|
43
|
+
}
|
|
44
|
+
else if (cur && typeof cur === 'object') {
|
|
45
|
+
cur = cur[t];
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
throw new Error(`cannot walk into ${typeof cur} at ${t}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return cur;
|
|
52
|
+
}
|
|
53
|
+
function setIn(parent, key, value) {
|
|
54
|
+
if (Array.isArray(parent)) {
|
|
55
|
+
if (key === '-')
|
|
56
|
+
parent.push(value);
|
|
57
|
+
else
|
|
58
|
+
parent.splice(Number(key), 0, value);
|
|
59
|
+
}
|
|
60
|
+
else if (parent && typeof parent === 'object') {
|
|
61
|
+
parent[key] = value;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
throw new Error(`cannot set into ${typeof parent}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function removeIn(parent, key) {
|
|
68
|
+
if (Array.isArray(parent)) {
|
|
69
|
+
parent.splice(Number(key), 1);
|
|
70
|
+
}
|
|
71
|
+
else if (parent && typeof parent === 'object') {
|
|
72
|
+
delete parent[key];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function deepClone(x) {
|
|
76
|
+
return JSON.parse(JSON.stringify(x));
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=json-patch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-patch.js","sourceRoot":"","sources":["../../../src/ultraapp/json-patch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Container lifecycle helpers — start / stop / delete with router (de)registration,
|
|
3
|
+
* plus cold-eligibility logic for the periodic GC sweeper.
|
|
4
|
+
*
|
|
5
|
+
* The actual GC sweeper itself is wired in v0.4+ (it needs lastAccess
|
|
6
|
+
* accounting from the router, which is not present in v0.3). This module
|
|
7
|
+
* only exposes the pure predicate findColdContainers.
|
|
8
|
+
*/
|
|
9
|
+
import { dockerStart, dockerStop, dockerRm } from './docker.js';
|
|
10
|
+
import type { UltraappRouter } from './router.js';
|
|
11
|
+
export interface ContainerLastAccess {
|
|
12
|
+
containerName: string;
|
|
13
|
+
lastAccess: number;
|
|
14
|
+
slug?: string;
|
|
15
|
+
port?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function findColdContainers(items: ContainerLastAccess[], now: number, days: number): ContainerLastAccess[];
|
|
18
|
+
export interface StartOpts {
|
|
19
|
+
dockerStartFn?: typeof dockerStart;
|
|
20
|
+
}
|
|
21
|
+
export declare function startContainerAndRegister(containerName: string, slug: string, port: number, router: UltraappRouter, opts?: StartOpts): Promise<{
|
|
22
|
+
ok: boolean;
|
|
23
|
+
error?: string;
|
|
24
|
+
}>;
|
|
25
|
+
export interface StopOpts {
|
|
26
|
+
dockerStopFn?: typeof dockerStop;
|
|
27
|
+
}
|
|
28
|
+
export declare function stopContainerAndDeregister(containerName: string, slug: string, router: UltraappRouter, opts?: StopOpts): Promise<{
|
|
29
|
+
ok: boolean;
|
|
30
|
+
error?: string;
|
|
31
|
+
}>;
|
|
32
|
+
export interface DeleteOpts {
|
|
33
|
+
dockerRmFn?: typeof dockerRm;
|
|
34
|
+
}
|
|
35
|
+
export declare function deleteContainerAndDeregister(containerName: string, slug: string, router: UltraappRouter, opts?: DeleteOpts): Promise<{
|
|
36
|
+
ok: boolean;
|
|
37
|
+
error?: string;
|
|
38
|
+
}>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Container lifecycle helpers — start / stop / delete with router (de)registration,
|
|
3
|
+
* plus cold-eligibility logic for the periodic GC sweeper.
|
|
4
|
+
*
|
|
5
|
+
* The actual GC sweeper itself is wired in v0.4+ (it needs lastAccess
|
|
6
|
+
* accounting from the router, which is not present in v0.3). This module
|
|
7
|
+
* only exposes the pure predicate findColdContainers.
|
|
8
|
+
*/
|
|
9
|
+
import { dockerStart, dockerStop, dockerRm } from './docker.js';
|
|
10
|
+
export function findColdContainers(items, now, days) {
|
|
11
|
+
const cutoff = now - days * 86400000;
|
|
12
|
+
return items.filter((i) => i.lastAccess < cutoff);
|
|
13
|
+
}
|
|
14
|
+
export async function startContainerAndRegister(containerName, slug, port, router, opts = {}) {
|
|
15
|
+
const fn = opts.dockerStartFn ?? dockerStart;
|
|
16
|
+
const r = await fn(containerName);
|
|
17
|
+
if (r.ok)
|
|
18
|
+
router.register(slug, port);
|
|
19
|
+
return r;
|
|
20
|
+
}
|
|
21
|
+
export async function stopContainerAndDeregister(containerName, slug, router, opts = {}) {
|
|
22
|
+
const fn = opts.dockerStopFn ?? dockerStop;
|
|
23
|
+
router.deregister(slug);
|
|
24
|
+
return fn(containerName);
|
|
25
|
+
}
|
|
26
|
+
export async function deleteContainerAndDeregister(containerName, slug, router, opts = {}) {
|
|
27
|
+
const fn = opts.dockerRmFn ?? dockerRm;
|
|
28
|
+
router.deregister(slug);
|
|
29
|
+
return fn(containerName);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../src/ultraapp/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAUhE,MAAM,UAAU,kBAAkB,CAAC,KAA4B,EAAE,GAAW,EAAE,IAAY;IACxF,MAAM,MAAM,GAAG,GAAG,GAAG,IAAI,GAAG,QAAQ,CAAC;IACrC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;AACpD,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,aAAqB,EACrB,IAAY,EACZ,IAAY,EACZ,MAAsB,EACtB,OAAkB,EAAE;IAEpB,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,IAAI,WAAW,CAAC;IAC7C,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,aAAa,CAAC,CAAC;IAClC,IAAI,CAAC,CAAC,EAAE;QAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACtC,OAAO,CAAC,CAAC;AACX,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,aAAqB,EACrB,IAAY,EACZ,MAAsB,EACtB,OAAiB,EAAE;IAEnB,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,IAAI,UAAU,CAAC;IAC3C,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACxB,OAAO,EAAE,CAAC,aAAa,CAAC,CAAC;AAC3B,CAAC;AAMD,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,aAAqB,EACrB,IAAY,EACZ,MAAsB,EACtB,OAAmB,EAAE;IAErB,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,IAAI,QAAQ,CAAC;IACvC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACxB,OAAO,EAAE,CAAC,aAAa,CAAC,CAAC;AAC3B,CAAC"}
|