koppler 0.0.0-stage → 0.0.2
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/LICENSE +21 -0
- package/README.md +101 -2
- package/bin/run-logged +16 -0
- package/bin/secret-list +7 -0
- package/bin/secret-psql +41 -0
- package/bin/secret-set +17 -0
- package/bin/secret-store +82 -0
- package/bin/secret-test +10 -0
- package/bin/with-secrets +25 -0
- package/dist/.built +1 -0
- package/dist/cli/agent.js +144 -0
- package/dist/cli/agent.js.map +1 -0
- package/dist/cli/doctor.js +173 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/mcp.js +204 -0
- package/dist/cli/mcp.js.map +1 -0
- package/dist/cli/output.js +37 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/records.js +121 -0
- package/dist/cli/records.js.map +1 -0
- package/dist/cli/running.js +270 -0
- package/dist/cli/running.js.map +1 -0
- package/dist/cli/shell.js +43 -0
- package/dist/cli/shell.js.map +1 -0
- package/dist/cli/wait.js +59 -0
- package/dist/cli/wait.js.map +1 -0
- package/dist/core/addresses.js +55 -0
- package/dist/core/addresses.js.map +1 -0
- package/dist/core/arrange.js +329 -0
- package/dist/core/arrange.js.map +1 -0
- package/dist/core/cables.js +158 -0
- package/dist/core/cables.js.map +1 -0
- package/dist/core/expressions.js +72 -0
- package/dist/core/expressions.js.map +1 -0
- package/dist/core/frameworks.js +13 -0
- package/dist/core/frameworks.js.map +1 -0
- package/dist/core/kinds.js +244 -0
- package/dist/core/kinds.js.map +1 -0
- package/dist/core/launch.js +181 -0
- package/dist/core/launch.js.map +1 -0
- package/dist/core/logfmt.js +144 -0
- package/dist/core/logfmt.js.map +1 -0
- package/dist/core/mock.js +27 -0
- package/dist/core/mock.js.map +1 -0
- package/dist/core/plan.js +147 -0
- package/dist/core/plan.js.map +1 -0
- package/dist/core/ports.js +155 -0
- package/dist/core/ports.js.map +1 -0
- package/dist/core/presets.js +186 -0
- package/dist/core/presets.js.map +1 -0
- package/dist/core/secret-types.js +3 -0
- package/dist/core/secret-types.js.map +1 -0
- package/dist/core/sign-in.js +30 -0
- package/dist/core/sign-in.js.map +1 -0
- package/dist/core/stack-path.js +64 -0
- package/dist/core/stack-path.js.map +1 -0
- package/dist/core/stack.js +509 -0
- package/dist/core/stack.js.map +1 -0
- package/dist/core/terraform.js +393 -0
- package/dist/core/terraform.js.map +1 -0
- package/dist/data.js +37 -0
- package/dist/data.js.map +1 -0
- package/dist/engine/actions.js +99 -0
- package/dist/engine/actions.js.map +1 -0
- package/dist/engine/app-commands.js +106 -0
- package/dist/engine/app-commands.js.map +1 -0
- package/dist/engine/app-start.js +167 -0
- package/dist/engine/app-start.js.map +1 -0
- package/dist/engine/app-state.js +43 -0
- package/dist/engine/app-state.js.map +1 -0
- package/dist/engine/boards.js +219 -0
- package/dist/engine/boards.js.map +1 -0
- package/dist/engine/branch.js +194 -0
- package/dist/engine/branch.js.map +1 -0
- package/dist/engine/browser-console.js +45 -0
- package/dist/engine/browser-console.js.map +1 -0
- package/dist/engine/calls.js +97 -0
- package/dist/engine/calls.js.map +1 -0
- package/dist/engine/checks.js +270 -0
- package/dist/engine/checks.js.map +1 -0
- package/dist/engine/clones.js +67 -0
- package/dist/engine/clones.js.map +1 -0
- package/dist/engine/config.js +26 -0
- package/dist/engine/config.js.map +1 -0
- package/dist/engine/deployed.js +488 -0
- package/dist/engine/deployed.js.map +1 -0
- package/dist/engine/devices.js +81 -0
- package/dist/engine/devices.js.map +1 -0
- package/dist/engine/discover.js +236 -0
- package/dist/engine/discover.js.map +1 -0
- package/dist/engine/down.js +253 -0
- package/dist/engine/down.js.map +1 -0
- package/dist/engine/history.js +215 -0
- package/dist/engine/history.js.map +1 -0
- package/dist/engine/investigate.js +278 -0
- package/dist/engine/investigate.js.map +1 -0
- package/dist/engine/libraries.js +129 -0
- package/dist/engine/libraries.js.map +1 -0
- package/dist/engine/linked.js +146 -0
- package/dist/engine/linked.js.map +1 -0
- package/dist/engine/listen.js +223 -0
- package/dist/engine/listen.js.map +1 -0
- package/dist/engine/locks.js +38 -0
- package/dist/engine/locks.js.map +1 -0
- package/dist/engine/messages.js +177 -0
- package/dist/engine/messages.js.map +1 -0
- package/dist/engine/needs.js +363 -0
- package/dist/engine/needs.js.map +1 -0
- package/dist/engine/processes.js +350 -0
- package/dist/engine/processes.js.map +1 -0
- package/dist/engine/query.js +241 -0
- package/dist/engine/query.js.map +1 -0
- package/dist/engine/queues.js +100 -0
- package/dist/engine/queues.js.map +1 -0
- package/dist/engine/recipes.js +248 -0
- package/dist/engine/recipes.js.map +1 -0
- package/dist/engine/reload.js +32 -0
- package/dist/engine/reload.js.map +1 -0
- package/dist/engine/repos.js +214 -0
- package/dist/engine/repos.js.map +1 -0
- package/dist/engine/research.js +134 -0
- package/dist/engine/research.js.map +1 -0
- package/dist/engine/run-logs.js +79 -0
- package/dist/engine/run-logs.js.map +1 -0
- package/dist/engine/run.js +54 -0
- package/dist/engine/run.js.map +1 -0
- package/dist/engine/runs.js +223 -0
- package/dist/engine/runs.js.map +1 -0
- package/dist/engine/session.js +130 -0
- package/dist/engine/session.js.map +1 -0
- package/dist/engine/share.js +124 -0
- package/dist/engine/share.js.map +1 -0
- package/dist/engine/stack-file.js +206 -0
- package/dist/engine/stack-file.js.map +1 -0
- package/dist/engine/stack-share.js +86 -0
- package/dist/engine/stack-share.js.map +1 -0
- package/dist/engine/stacks.js +143 -0
- package/dist/engine/stacks.js.map +1 -0
- package/dist/engine/sync.js +214 -0
- package/dist/engine/sync.js.map +1 -0
- package/dist/engine/traces.js +65 -0
- package/dist/engine/traces.js.map +1 -0
- package/dist/engine/up.js +621 -0
- package/dist/engine/up.js.map +1 -0
- package/dist/engine/watch.js +71 -0
- package/dist/engine/watch.js.map +1 -0
- package/dist/engine/wire.js +120 -0
- package/dist/engine/wire.js.map +1 -0
- package/dist/failure.js +16 -0
- package/dist/failure.js.map +1 -0
- package/dist/github.js +95 -0
- package/dist/github.js.map +1 -0
- package/dist/ids.js +6 -0
- package/dist/ids.js.map +1 -0
- package/dist/json-files.js +36 -0
- package/dist/json-files.js.map +1 -0
- package/dist/koppler.mjs +840 -0
- package/dist/koppler.mjs.map +1 -0
- package/dist/lambda-local.mjs +250 -0
- package/dist/lambda-local.mjs.map +1 -0
- package/dist/lambda-secrets-proxy.go +31 -0
- package/dist/mock-server.mjs +23 -0
- package/dist/mock-server.mjs.map +1 -0
- package/dist/page/assets/JetBrainsMono-cyrillic-D2jMJ_bk.woff2 +0 -0
- package/dist/page/assets/JetBrainsMono-greek-D2nYnAec.woff2 +0 -0
- package/dist/page/assets/JetBrainsMono-latin-Db4Uuiha.woff2 +0 -0
- package/dist/page/assets/JetBrainsMono-latin-ext-Bnd2h4Br.woff2 +0 -0
- package/dist/page/assets/JetBrainsMono-vietnamese-CNlsqbWb.woff2 +0 -0
- package/dist/page/assets/SchibstedGrotesk-latin-DxefFeRw.woff2 +0 -0
- package/dist/page/assets/SchibstedGrotesk-latin-ext-CnpJE18X.woff2 +0 -0
- package/dist/page/assets/index-Bkj_pX35.js +42 -0
- package/dist/page/assets/index-Dq45jswH.css +1 -0
- package/dist/page/index.html +14 -0
- package/dist/page/theme.js +8 -0
- package/dist/paths.js +19 -0
- package/dist/paths.js.map +1 -0
- package/dist/safe-env.js +73 -0
- package/dist/safe-env.js.map +1 -0
- package/dist/sam-local.mjs +135 -0
- package/dist/sam-local.mjs.map +1 -0
- package/dist/scrub.js +87 -0
- package/dist/scrub.js.map +1 -0
- package/dist/secret-check.mjs +262 -0
- package/dist/secret-check.mjs.map +1 -0
- package/dist/server/browser-console.js +117 -0
- package/dist/server/browser-console.js.map +1 -0
- package/dist/server/cable-test.js +365 -0
- package/dist/server/cable-test.js.map +1 -0
- package/dist/server/choices.js +51 -0
- package/dist/server/choices.js.map +1 -0
- package/dist/server/files.js +107 -0
- package/dist/server/files.js.map +1 -0
- package/dist/server/gate.js +128 -0
- package/dist/server/gate.js.map +1 -0
- package/dist/server/logs.js +76 -0
- package/dist/server/logs.js.map +1 -0
- package/dist/server/mobile.js +113 -0
- package/dist/server/mobile.js.map +1 -0
- package/dist/server/routes.js +326 -0
- package/dist/server/routes.js.map +1 -0
- package/dist/server/runs.js +111 -0
- package/dist/server/runs.js.map +1 -0
- package/dist/server/sanitize.js +242 -0
- package/dist/server/sanitize.js.map +1 -0
- package/dist/server/secrets.js +111 -0
- package/dist/server/secrets.js.map +1 -0
- package/dist/server/status.js +321 -0
- package/dist/server/status.js.map +1 -0
- package/dist/server/token.js +38 -0
- package/dist/server/token.js.map +1 -0
- package/dist/server/waiting.js +79 -0
- package/dist/server/waiting.js.map +1 -0
- package/dist/status-watch.mjs +63 -0
- package/dist/status-watch.mjs.map +1 -0
- package/package.json +74 -4
- package/skills/koppler-run/SKILL.md +169 -0
- package/skills/koppler-run/VERSION +1 -0
- package/skills/koppler-run/references/action-log.md +50 -0
- package/skills/koppler-run/references/permissions.md +25 -0
- package/skills/koppler-run/references/preparing-nodes.md +62 -0
- package/skills/koppler-run/references/reporting-bugs.md +76 -0
- package/skills/koppler-run/references/research.md +40 -0
- package/skills/koppler-run/references/secrets.md +56 -0
- package/skills/koppler-run/references/stack.md +197 -0
- package/skills/koppler-run/references/status.md +92 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// The commands that say whether something can run here, and what it needs: doctor (tools, what the user still has to
|
|
2
|
+
// do, secrets, connections), the tunnels of a plan, and the secrets themselves.
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { isProtected } from "../core/plan.js";
|
|
6
|
+
import { describePlan, planSteps, planTunnels } from "../core/ports.js";
|
|
7
|
+
import { readData, readStack } from "../data.js";
|
|
8
|
+
import { secretTest } from "../engine/app-start.js";
|
|
9
|
+
import { checkTools, missingTunnels, report } from "../engine/checks.js";
|
|
10
|
+
import { needs } from "../engine/needs.js";
|
|
11
|
+
import { live } from "../engine/history.js";
|
|
12
|
+
import { tunnelsOf } from "../engine/up.js";
|
|
13
|
+
import { cableTest } from "../server/cable-test.js";
|
|
14
|
+
import { APP, BIN } from "../paths.js";
|
|
15
|
+
import { confirm, envOf, positional } from "./output.js";
|
|
16
|
+
import { fail } from "../failure.js";
|
|
17
|
+
import { appOn, storeOf } from "../core/stack.js";
|
|
18
|
+
const loaded = () => readStack() ?? fail('no stack loaded (koppler init)');
|
|
19
|
+
const portOf = (stack, id) => Number(new URL(stack.apps[id]?.url ?? 'http://x').port);
|
|
20
|
+
/** The tunnels a set of apps needs, with shared, moved and loopback-aliased ones worked out (default: the apps on the canvas). */
|
|
21
|
+
export function ports(args) {
|
|
22
|
+
const stack = loaded();
|
|
23
|
+
const envAt = args.indexOf('--env');
|
|
24
|
+
const env = (envAt >= 0 ? args[envAt + 1] : stack.envs[0]) ?? '';
|
|
25
|
+
const ENV = env.toUpperCase();
|
|
26
|
+
if (!stack.envs.includes(env))
|
|
27
|
+
fail(`unknown env ${String(args[envAt + 1])}; the stack has ${stack.envs.join(', ')}`);
|
|
28
|
+
const given = args.filter((arg, at) => !arg.startsWith('--') && (envAt < 0 || at !== envAt + 1));
|
|
29
|
+
const ids = given.length ? given : Object.keys(readData('state')?.['nodes'] ?? {});
|
|
30
|
+
const name = (id) => stack.apps[id]?.name ?? id;
|
|
31
|
+
for (const id of ids)
|
|
32
|
+
if (!stack.apps[id])
|
|
33
|
+
fail(`${id} is not an app in the stack`);
|
|
34
|
+
for (const id of ids) {
|
|
35
|
+
const outside = stack.apps[id]?.outside;
|
|
36
|
+
if (outside)
|
|
37
|
+
fail(`${name(id)} does not run on this Mac: ${String(outside)}`);
|
|
38
|
+
}
|
|
39
|
+
// An app with no tunnels for this environment never gets the first environment's: that would reach the wrong database.
|
|
40
|
+
const noTunnel = missingTunnels(stack, env).filter(id => ids.includes(id));
|
|
41
|
+
if (noTunnel.length)
|
|
42
|
+
fail(`${noTunnel.map(name).join(', ')}: the stack has no ${ENV} tunnel, and another environment's is never used. Set it with koppler stack set apps.<id>.envs.${env}.prereqs before running on ${ENV}.`);
|
|
43
|
+
const needed = ids.flatMap(id => tunnelsOf(stack, id, env));
|
|
44
|
+
const taken = ids.map(id => portOf(stack, id)).filter(Boolean);
|
|
45
|
+
const plan = planTunnels(needed, taken).map(tunnel => ({ ...tunnel, steps: planSteps(tunnel) }));
|
|
46
|
+
if (args.includes('--json')) {
|
|
47
|
+
console.log(JSON.stringify(plan, null, 2));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (!plan.length) {
|
|
51
|
+
console.log(`no tunnels needed for ${ids.join(', ') || 'these apps'}`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
for (const line of describePlan(plan, name))
|
|
55
|
+
console.log(line);
|
|
56
|
+
for (const tunnel of plan) {
|
|
57
|
+
const { steps } = tunnel;
|
|
58
|
+
const port = String(tunnel.port);
|
|
59
|
+
const bind = tunnel.needsAlias ? ` --bind ${tunnel.bind}` : '';
|
|
60
|
+
console.log(`\n${tunnel.host} -> ${tunnel.bind}:${port} (for ${tunnel.apps.map(name).join(', ')})`);
|
|
61
|
+
for (const command of steps.sudo)
|
|
62
|
+
console.log(` you run: ${command}`);
|
|
63
|
+
for (const command of steps.undo)
|
|
64
|
+
console.log(` undo: ${command}`);
|
|
65
|
+
console.log(` tunnel: koppler run ${steps.name} --port ${port}${bind} --restart -- ${steps.tunnel}`);
|
|
66
|
+
for (const { app, env: setting, value } of steps.settings)
|
|
67
|
+
console.log(` setting: ${setting}=${value} in ${name(app)}'s -LOCAL profile`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Tries each stored secret the apps declare and says only whether it works; the values stay in their store. */
|
|
71
|
+
function secretTests(stack, ids, env) {
|
|
72
|
+
return ids.flatMap(id => {
|
|
73
|
+
const app = appOn(stack, id, env) ?? fail(`${id} is not an app in the stack`);
|
|
74
|
+
const store = storeOf(stack, id, env);
|
|
75
|
+
return (app.secrets ?? []).flatMap(secret => secret.env ? [{ app: id, name: secret.env, env, ...secretTest(store, secret) }] : []);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Every connection of what runs now, tested the way the canvas's Flow check does: each app answers, each cable reaches
|
|
80
|
+
* its local app, each tunnel reaches its database or cache.
|
|
81
|
+
*/
|
|
82
|
+
async function flowCheck(args) {
|
|
83
|
+
const stack = loaded();
|
|
84
|
+
const board = live();
|
|
85
|
+
if (!board || !Object.keys(board.nodes).length) {
|
|
86
|
+
console.log('Nothing is running, so there is nothing to test.');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const env = board.env ?? stack.envs[0] ?? '';
|
|
90
|
+
const name = (id) => stack.apps[id]?.name ?? id;
|
|
91
|
+
const ids = Object.keys(board.nodes).filter(id => stack.apps[id]);
|
|
92
|
+
const tunnels = planTunnels(ids.filter(id => board.nodes[id]?.tunnels !== false).flatMap(id => tunnelsOf(stack, id, env)));
|
|
93
|
+
const jobs = [
|
|
94
|
+
...ids.filter(id => stack.apps[id]?.url).map(id => ({ label: name(id), body: { env, node: id } })),
|
|
95
|
+
...board.edges.map(({ from, to }) => ({ label: `${name(from)} to local ${name(to)}`, body: { env, from, to } })),
|
|
96
|
+
...tunnels.flatMap(tunnel => tunnel.apps.map(id => ({
|
|
97
|
+
label: `${name(id)} to ${tunnel.what}`,
|
|
98
|
+
body: { env, app: id, host: tunnel.bind, port: tunnel.port, original: tunnel.original },
|
|
99
|
+
}))),
|
|
100
|
+
];
|
|
101
|
+
const results = [];
|
|
102
|
+
for (const { label, body } of jobs)
|
|
103
|
+
results.push({ label, result: await cableTest(stack, body) });
|
|
104
|
+
if (args.includes('--json')) {
|
|
105
|
+
const shown = results.map(({ label, result }) => ({
|
|
106
|
+
connection: label,
|
|
107
|
+
ok: result.ok,
|
|
108
|
+
text: result.text,
|
|
109
|
+
detail: result.detail,
|
|
110
|
+
}));
|
|
111
|
+
console.log(JSON.stringify(shown, null, 2));
|
|
112
|
+
}
|
|
113
|
+
else
|
|
114
|
+
for (const { label, result } of results) {
|
|
115
|
+
const state = result.ok ? 'ok ' : result.unsure ? 'unsure ' : 'FAILED ';
|
|
116
|
+
console.log(`${state} ${label}: ${result.text}${result.ok ? '' : ` (${result.detail})`}`);
|
|
117
|
+
}
|
|
118
|
+
if (results.some(({ result }) => !result.ok && !result.unsure))
|
|
119
|
+
process.exitCode = 1;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Can these apps run here? The tools this stack needs, then what the user still has to do for the apps, then (asked
|
|
123
|
+
* for) whether each stored secret works, or whether every connection of what runs now answers.
|
|
124
|
+
*/
|
|
125
|
+
export async function doctor(args) {
|
|
126
|
+
if (args.includes('--flow')) {
|
|
127
|
+
await flowCheck(args);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const json = args.includes('--json');
|
|
131
|
+
const stack = loaded();
|
|
132
|
+
const env = envOf(stack, args);
|
|
133
|
+
const ids = positional(args, ['--env', '--no-tunnels']);
|
|
134
|
+
// Approving runs commands from a shared file on this Mac: only a person at the terminal can say yes, never --yes.
|
|
135
|
+
const tools = await checkTools({ approve: args.includes('--approve'), confirm: question => confirm(question) });
|
|
136
|
+
if (tools.error !== undefined)
|
|
137
|
+
fail(tools.error);
|
|
138
|
+
const forNeeds = args.filter(arg => arg !== '--secrets' && arg !== '--approve');
|
|
139
|
+
const todo = ids.length ? needs(forNeeds, { skill: APP, collect: json }) : undefined;
|
|
140
|
+
const wanted = args.includes('--secrets');
|
|
141
|
+
const secrets = wanted ? secretTests(stack, ids.length ? ids : Object.keys(stack.apps), env) : [];
|
|
142
|
+
if (json) {
|
|
143
|
+
console.log(JSON.stringify({ tools: tools.results, ...todo, ...(wanted && { secrets }) }, null, 2));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (!ids.length)
|
|
147
|
+
report(tools.results);
|
|
148
|
+
for (const secret of secrets)
|
|
149
|
+
console.log(`${secret.app} ${secret.name} (${env.toUpperCase()}): ${secret.message}`);
|
|
150
|
+
if (tools.results.some(result => result.state === 'missing') || secrets.some(secret => secret.code === 1))
|
|
151
|
+
process.exitCode = 1;
|
|
152
|
+
}
|
|
153
|
+
const SCRIPTS = { set: 'secret-set', list: 'secret-list', psql: 'secret-psql' };
|
|
154
|
+
/** Secrets, in the user's own terminal: the values never pass through Koppler's output. */
|
|
155
|
+
export function secret(args) {
|
|
156
|
+
const [action = '', ...rest] = args;
|
|
157
|
+
if (action === 'remove') {
|
|
158
|
+
const [store, name] = rest;
|
|
159
|
+
if (!store || !name)
|
|
160
|
+
fail('usage: koppler secret remove <app>[@<env>] <NAME>');
|
|
161
|
+
process.exit(spawnSync(path.join(BIN, 'secret-store'), ['remove', store, name], { stdio: 'inherit' }).status ?? 1);
|
|
162
|
+
}
|
|
163
|
+
const script = (Object.hasOwn(SCRIPTS, action) ? SCRIPTS[action] : undefined) ??
|
|
164
|
+
fail('usage: koppler secret set|list|remove|psql <app>[@<env>] [<NAME>]');
|
|
165
|
+
// A protected environment's value is stored so that every read asks the user (the stack says which; else all but
|
|
166
|
+
// the first).
|
|
167
|
+
const stack = readStack();
|
|
168
|
+
const env = (rest[0] ?? '').split('@')[1] ?? stack?.envs[0] ?? '';
|
|
169
|
+
const mark = stack ? { KOPPLER_SECRET_PROTECTED: isProtected(stack, env) ? '1' : '0' } : {};
|
|
170
|
+
const ran = spawnSync(path.join(BIN, script), rest, { stdio: 'inherit', env: { ...process.env, ...mark } });
|
|
171
|
+
process.exit(ran.status ?? 1);
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/mcp.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
// `koppler mcp`: an MCP server on stdio, so an agent reads and waits on Koppler without the listen loop.
|
|
2
|
+
// Each tool runs the koppler command itself with fixed flags; nothing that needs the user's approval is offered.
|
|
3
|
+
import { execFile } from 'node:child_process';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import readline from 'node:readline';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { APP_ID, RUN_ID } from "../ids.js";
|
|
8
|
+
import { CODE } from "../paths.js";
|
|
9
|
+
const app = z.string().regex(APP_ID).describe('An app id from the stack, such as orders-api');
|
|
10
|
+
const env = z.string().regex(APP_ID).describe('An environment of the stack, such as qa; the first one when left out');
|
|
11
|
+
const JSON_OUT = { type: 'object' };
|
|
12
|
+
const tool = (one) => one;
|
|
13
|
+
const TOOLS = {
|
|
14
|
+
status: tool({
|
|
15
|
+
description: 'What Koppler runs now (apps, tunnels, the canvas), each with its state, port and uptime.',
|
|
16
|
+
input: z.strictObject({
|
|
17
|
+
apps: z.boolean().optional().describe("Add every app in the stack with its clone's branch"),
|
|
18
|
+
}),
|
|
19
|
+
readOnly: true,
|
|
20
|
+
json: true,
|
|
21
|
+
command: ({ apps }) => ({ args: ['status', '--json', ...(apps ? ['--apps'] : [])] }),
|
|
22
|
+
}),
|
|
23
|
+
logs: tool({
|
|
24
|
+
description: "The last lines of an app's or tunnel's log, secrets masked.",
|
|
25
|
+
input: z.strictObject({
|
|
26
|
+
name: app,
|
|
27
|
+
lines: z.number().int().min(1).max(2000).optional().describe('How many, 100 when left out'),
|
|
28
|
+
}),
|
|
29
|
+
readOnly: true,
|
|
30
|
+
json: false,
|
|
31
|
+
command: ({ name, lines }) => ({ args: ['logs', name, '-n', String(lines ?? 100)] }),
|
|
32
|
+
}),
|
|
33
|
+
doctor: tool({
|
|
34
|
+
description: 'Whether apps can run on this Mac: tools, sign-ins, tunnels, hosts entries, secrets, and what the user still has to do.',
|
|
35
|
+
input: z.strictObject({
|
|
36
|
+
apps: z.array(app).max(50).optional().describe('The apps to check; every app on the board when left out'),
|
|
37
|
+
env: env.optional(),
|
|
38
|
+
secrets: z.boolean().optional().describe('Also check that each stored secret is there'),
|
|
39
|
+
flow: z.boolean().optional().describe('Also test every connection between the apps that run'),
|
|
40
|
+
}),
|
|
41
|
+
readOnly: true,
|
|
42
|
+
json: true,
|
|
43
|
+
command: ({ apps, env: on, secrets, flow }) => ({
|
|
44
|
+
args: [
|
|
45
|
+
'doctor',
|
|
46
|
+
...(apps ?? []),
|
|
47
|
+
...(on ? ['--env', on] : []),
|
|
48
|
+
...(secrets ? ['--secrets'] : []),
|
|
49
|
+
...(flow ? ['--flow'] : []),
|
|
50
|
+
'--json',
|
|
51
|
+
],
|
|
52
|
+
}),
|
|
53
|
+
}),
|
|
54
|
+
plan: tool({
|
|
55
|
+
description: 'What the newest run does compared with what runs now: what starts, restarts, stops and keeps running.',
|
|
56
|
+
input: z.strictObject({ apps: z.array(app).max(50).optional(), env: env.optional() }),
|
|
57
|
+
readOnly: true,
|
|
58
|
+
json: true,
|
|
59
|
+
command: ({ apps, env: on }) => ({ args: ['plan', ...(apps ?? []), ...(on ? ['--env', on] : []), '--json'] }),
|
|
60
|
+
}),
|
|
61
|
+
history: tool({
|
|
62
|
+
description: 'Recent runs and Stops, and how each ended.',
|
|
63
|
+
input: z.strictObject({}),
|
|
64
|
+
readOnly: true,
|
|
65
|
+
json: true,
|
|
66
|
+
command: () => ({ args: ['history', '--json'] }),
|
|
67
|
+
}),
|
|
68
|
+
wait: tool({
|
|
69
|
+
description: 'Waits until apps are healthy (answering, and passing their ready check), up or down. Fails on a timeout or an app that exits, naming each state.',
|
|
70
|
+
input: z.strictObject({
|
|
71
|
+
apps: z.array(app).min(1).max(50),
|
|
72
|
+
until: z.enum(['healthy', 'up', 'down']),
|
|
73
|
+
timeoutSeconds: z.number().int().min(1).max(1800).optional().describe('120 when left out'),
|
|
74
|
+
}),
|
|
75
|
+
readOnly: true,
|
|
76
|
+
json: true,
|
|
77
|
+
command: ({ apps, until, timeoutSeconds }) => ({
|
|
78
|
+
args: ['wait', ...apps, `--${until}`, '--timeout', String(timeoutSeconds ?? 120), '--json'],
|
|
79
|
+
}),
|
|
80
|
+
}),
|
|
81
|
+
say: tool({
|
|
82
|
+
description: "Shows a question, a result or a failure in the canvas's inbox. Commands for the user go in a section's commands.",
|
|
83
|
+
input: z.strictObject({
|
|
84
|
+
kind: z.enum(['question', 'result', 'failure', 'info']),
|
|
85
|
+
title: z.string().min(1).max(120),
|
|
86
|
+
summary: z.string().max(800).optional(),
|
|
87
|
+
run: z.string().regex(RUN_ID).optional().describe('The run it is about'),
|
|
88
|
+
sections: z
|
|
89
|
+
.array(z.strictObject({
|
|
90
|
+
title: z.string().max(80),
|
|
91
|
+
items: z.array(z.string().max(400)).max(12),
|
|
92
|
+
commands: z.array(z.string().max(1000)).max(6).optional(),
|
|
93
|
+
}))
|
|
94
|
+
.max(8)
|
|
95
|
+
.optional(),
|
|
96
|
+
choices: z
|
|
97
|
+
.array(z.strictObject({
|
|
98
|
+
id: z.string().regex(/^[a-z0-9-]{1,32}$/),
|
|
99
|
+
label: z.string().min(1).max(80),
|
|
100
|
+
detail: z.string().max(300).optional(),
|
|
101
|
+
}))
|
|
102
|
+
.max(6)
|
|
103
|
+
.optional(),
|
|
104
|
+
}),
|
|
105
|
+
readOnly: false,
|
|
106
|
+
json: false,
|
|
107
|
+
command: message => ({ args: ['say'], stdin: JSON.stringify(message) }),
|
|
108
|
+
}),
|
|
109
|
+
};
|
|
110
|
+
const ENTRY = path.join(CODE, 'koppler.mjs');
|
|
111
|
+
/** Runs koppler with the given arguments: what it printed, and whether it failed. */
|
|
112
|
+
const koppler = (args, stdin) => new Promise(resolve => {
|
|
113
|
+
const child = execFile(process.execPath, [ENTRY, ...args], { maxBuffer: 8 << 20, timeout: 31 * 60_000 }, (error, out, err) => {
|
|
114
|
+
resolve({ out, err, failed: !!error });
|
|
115
|
+
});
|
|
116
|
+
child.stdin?.end(stdin ?? '');
|
|
117
|
+
});
|
|
118
|
+
async function call(name, given) {
|
|
119
|
+
if (!Object.hasOwn(TOOLS, name))
|
|
120
|
+
return { content: [{ type: 'text', text: `No tool called ${name}` }], isError: true };
|
|
121
|
+
const one = TOOLS[name];
|
|
122
|
+
const parsed = one.input.safeParse(given ?? {});
|
|
123
|
+
if (!parsed.success)
|
|
124
|
+
return { content: [{ type: 'text', text: z.prettifyError(parsed.error) }], isError: true };
|
|
125
|
+
const { args, stdin } = one.command(parsed.data);
|
|
126
|
+
const { out, err, failed } = await koppler(args, stdin);
|
|
127
|
+
const text = [out.trim(), err.trim()].filter(Boolean).join('\n') || (failed ? 'failed' : 'done');
|
|
128
|
+
let structured;
|
|
129
|
+
if (one.json)
|
|
130
|
+
try {
|
|
131
|
+
structured = JSON.parse(out);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// Not JSON (a failure said in words): the text says it.
|
|
135
|
+
}
|
|
136
|
+
const object = structured && typeof structured === 'object' && !Array.isArray(structured);
|
|
137
|
+
return {
|
|
138
|
+
content: [{ type: 'text', text }],
|
|
139
|
+
...(object
|
|
140
|
+
? { structuredContent: structured }
|
|
141
|
+
: structured !== undefined && { structuredContent: { result: structured } }),
|
|
142
|
+
isError: failed,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const PROTOCOLS = ['2025-06-18', '2025-03-26', '2024-11-05'];
|
|
146
|
+
async function answer(request, version) {
|
|
147
|
+
const { method, params = {} } = request;
|
|
148
|
+
if (method === 'initialize') {
|
|
149
|
+
const asked = typeof params['protocolVersion'] === 'string' ? params['protocolVersion'] : '';
|
|
150
|
+
return {
|
|
151
|
+
protocolVersion: PROTOCOLS.includes(asked) ? asked : PROTOCOLS[0],
|
|
152
|
+
capabilities: { tools: {} },
|
|
153
|
+
serverInfo: { name: 'koppler', version },
|
|
154
|
+
instructions: 'Koppler runs part of a stack locally. Read with status, plan, history, logs and doctor; wait for apps with wait; talk to the user on the canvas with say. Starting, stopping and approving stay with the koppler command and the user.',
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (method === 'ping')
|
|
158
|
+
return {};
|
|
159
|
+
if (method === 'tools/list')
|
|
160
|
+
return {
|
|
161
|
+
tools: Object.entries(TOOLS).map(([name, one]) => ({
|
|
162
|
+
name,
|
|
163
|
+
description: one.description,
|
|
164
|
+
inputSchema: z.toJSONSchema(one.input),
|
|
165
|
+
...(one.json && { outputSchema: JSON_OUT }),
|
|
166
|
+
annotations: { readOnlyHint: one.readOnly },
|
|
167
|
+
})),
|
|
168
|
+
};
|
|
169
|
+
if (method === 'tools/call')
|
|
170
|
+
return call(typeof params['name'] === 'string' ? params['name'] : '', params['arguments']);
|
|
171
|
+
throw Object.assign(new Error(`Method not found: ${String(method)}`), { code: -32601 });
|
|
172
|
+
}
|
|
173
|
+
/** Serves MCP over stdin and stdout, one JSON message a line, until stdin closes. */
|
|
174
|
+
export async function mcp(version) {
|
|
175
|
+
const send = (message) => process.stdout.write(`${JSON.stringify(message)}\n`);
|
|
176
|
+
const lines = readline.createInterface({ input: process.stdin });
|
|
177
|
+
const pending = new Set();
|
|
178
|
+
for await (const line of lines) {
|
|
179
|
+
if (!line.trim())
|
|
180
|
+
continue;
|
|
181
|
+
let request;
|
|
182
|
+
try {
|
|
183
|
+
request = JSON.parse(line);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
send({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error' } });
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
// A notification gets no answer.
|
|
190
|
+
if (request.id === undefined)
|
|
191
|
+
continue;
|
|
192
|
+
const id = request.id;
|
|
193
|
+
const done = answer(request, version).then(result => {
|
|
194
|
+
send({ jsonrpc: '2.0', id, result });
|
|
195
|
+
}, (error) => {
|
|
196
|
+
const { code = -32603, message = String(error) } = error;
|
|
197
|
+
send({ jsonrpc: '2.0', id, error: { code, message } });
|
|
198
|
+
});
|
|
199
|
+
pending.add(done);
|
|
200
|
+
void done.finally(() => pending.delete(done));
|
|
201
|
+
}
|
|
202
|
+
await Promise.all(pending);
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/cli/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// What every command shares when it talks to the person at the terminal: asking, tables, and reading its arguments.
|
|
2
|
+
import { fail } from "../failure.js";
|
|
3
|
+
/** A y/N question in a terminal; without one (a script, an agent), only --yes says yes. */
|
|
4
|
+
export async function confirm(question, args = []) {
|
|
5
|
+
if (args.includes('--yes') || args.includes('-y'))
|
|
6
|
+
return true;
|
|
7
|
+
if (!process.stdin.isTTY)
|
|
8
|
+
return false;
|
|
9
|
+
const { createInterface } = await import('node:readline/promises');
|
|
10
|
+
const terminal = createInterface({ input: process.stdin, output: process.stderr });
|
|
11
|
+
const answer = (await terminal.question(`${question} [y/N] `)).trim().toLowerCase();
|
|
12
|
+
terminal.close();
|
|
13
|
+
return answer === 'y' || answer === 'yes';
|
|
14
|
+
}
|
|
15
|
+
/** Rows as columns, each as wide as its longest cell. */
|
|
16
|
+
export function table(rows) {
|
|
17
|
+
const widths = (rows[0] ?? []).map((_, column) => Math.max(...rows.map(row => String(row[column] ?? '').length)));
|
|
18
|
+
for (const row of rows)
|
|
19
|
+
console.log(row
|
|
20
|
+
.map((cell, column) => String(cell).padEnd(widths[column] ?? 0))
|
|
21
|
+
.join(' ')
|
|
22
|
+
.trimEnd());
|
|
23
|
+
}
|
|
24
|
+
/** The arguments that are not options, nor the value of one of the `valued` options. */
|
|
25
|
+
export const positional = (args, valued = []) => args.filter((arg, at) => !arg.startsWith('-') && !valued.includes(args[at - 1] ?? ''));
|
|
26
|
+
export const flagValue = (args, name) => {
|
|
27
|
+
const at = args.indexOf(name);
|
|
28
|
+
return at >= 0 ? args[at + 1] : undefined;
|
|
29
|
+
};
|
|
30
|
+
/** The environment a command was asked for, the stack's first when none was; an unknown one ends the command. */
|
|
31
|
+
export function envOf(stack, args) {
|
|
32
|
+
const env = flagValue(args, '--env') ?? stack.envs[0] ?? '';
|
|
33
|
+
if (!stack.envs.includes(env))
|
|
34
|
+
fail(`unknown env ${env}; the stack has ${stack.envs.join(', ')}`);
|
|
35
|
+
return env;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// What an agent records while it helps with a run, through commands: the changes Stop must undo, and the steps a card
|
|
2
|
+
// shows. Nobody writes these files by hand, so each entry is checked and each file is written whole.
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fail } from "../failure.js";
|
|
6
|
+
import { readActions, updateActions } from "../engine/actions.js";
|
|
7
|
+
import { APP_ID } from "../ids.js";
|
|
8
|
+
import { readJson, writeJson } from "../json-files.js";
|
|
9
|
+
import { tempDir } from "../paths.js";
|
|
10
|
+
import { redact } from "../scrub.js";
|
|
11
|
+
import { flagValue, positional } from "./output.js";
|
|
12
|
+
const LOG = () => path.join(tempDir(), 'actions.json');
|
|
13
|
+
/** What each kind of entry cannot do without. `checkout` is written by `koppler switch` only. */
|
|
14
|
+
const NEEDS = {
|
|
15
|
+
edit: ['file', 'before', 'after'],
|
|
16
|
+
profile: ['file', 'name'],
|
|
17
|
+
'env-file': ['file', 'lines'],
|
|
18
|
+
file: ['file'],
|
|
19
|
+
'npm-local': ['repo', 'packages'],
|
|
20
|
+
process: ['command'],
|
|
21
|
+
secret: ['app', 'env'],
|
|
22
|
+
};
|
|
23
|
+
const ACTIONS = "usage: koppler actions [--json] | add '<json>' | add --file <json file> | clear [--app <app>]";
|
|
24
|
+
function checked(entry) {
|
|
25
|
+
if (typeof entry !== 'object' || entry === null || Array.isArray(entry))
|
|
26
|
+
fail('an entry is an object with a kind');
|
|
27
|
+
const fields = entry;
|
|
28
|
+
const kind = typeof fields['kind'] === 'string' ? fields['kind'] : '';
|
|
29
|
+
const needs = Object.hasOwn(NEEDS, kind) ? NEEDS[kind] : undefined;
|
|
30
|
+
if (!needs)
|
|
31
|
+
fail(`kind "${kind}" is not one an entry can have: ${Object.keys(NEEDS).join(', ')}`);
|
|
32
|
+
const missing = needs.filter(name => fields[name] === undefined);
|
|
33
|
+
if (missing.length)
|
|
34
|
+
fail(`a ${kind} entry needs ${missing.join(', ')}`);
|
|
35
|
+
if (fields['app'] !== undefined && !(typeof fields['app'] === 'string' && APP_ID.test(fields['app'])))
|
|
36
|
+
fail('app is an app id of the stack');
|
|
37
|
+
// Stop looks a file up by its full path; one written from another folder would be found in the wrong place.
|
|
38
|
+
if (typeof fields['file'] === 'string' && !path.isAbsolute(fields['file']))
|
|
39
|
+
fail(`file is a full path, not ${fields['file']}`);
|
|
40
|
+
const text = JSON.stringify(entry);
|
|
41
|
+
if (redact(text) !== text)
|
|
42
|
+
fail('the entry holds what looks like a secret value; the log never keeps one');
|
|
43
|
+
return entry;
|
|
44
|
+
}
|
|
45
|
+
/** `koppler actions`: the changes Stop undoes; `add` logs one before it is made, `clear` empties the log after a revert. */
|
|
46
|
+
export function actionsCommand(args) {
|
|
47
|
+
const [verb] = positional(args, ['--file', '--app']);
|
|
48
|
+
if (verb === 'add') {
|
|
49
|
+
const file = flagValue(args, '--file');
|
|
50
|
+
const given = file ? fs.readFileSync(file, 'utf8') : (positional(args, ['--file'])[1] ?? fail(ACTIONS));
|
|
51
|
+
let parsed;
|
|
52
|
+
try {
|
|
53
|
+
parsed = JSON.parse(given);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
fail('that is not JSON: an entry such as {"kind":"env-file","app":"orders","file":"/full/path/.env.local","lines":["A=1"]}');
|
|
57
|
+
}
|
|
58
|
+
const entries = [parsed].flat().map(checked);
|
|
59
|
+
const total = updateActions(LOG(), list => list.push(...entries));
|
|
60
|
+
console.log(`Logged ${String(entries.length)} ${entries.length === 1 ? 'change' : 'changes'}; ${String(total)} for Stop to undo.`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (verb === 'clear') {
|
|
64
|
+
const app = flagValue(args, '--app');
|
|
65
|
+
const left = updateActions(LOG(), list => {
|
|
66
|
+
const keep = app ? list.filter(action => action.app !== app) : [];
|
|
67
|
+
list.splice(0, list.length, ...keep);
|
|
68
|
+
return keep.length;
|
|
69
|
+
});
|
|
70
|
+
console.log(app ? `Cleared ${app}'s entries; ${String(left)} left.` : 'The action log is empty.');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (verb)
|
|
74
|
+
fail(ACTIONS);
|
|
75
|
+
const list = readActions(LOG());
|
|
76
|
+
if (args.includes('--json'))
|
|
77
|
+
console.log(JSON.stringify(list, null, 2));
|
|
78
|
+
else if (!list.length)
|
|
79
|
+
console.log('Nothing logged: Stop has no change to undo.');
|
|
80
|
+
else
|
|
81
|
+
for (const action of list)
|
|
82
|
+
console.log(`${action.app ?? '-'} ${action.kind} ${'file' in action ? action.file : ''}`);
|
|
83
|
+
}
|
|
84
|
+
const STATES = ['done', 'todo', 'user', 'failed'];
|
|
85
|
+
const STEP = 'usage: koppler status step <app> "<label>" done|todo|user|failed [--detail "<what>"] [--copy "<command>"] [--port <n>] [--log <file>] | step <app> --clear';
|
|
86
|
+
/** `koppler status step`: one step of an app's checklist on its card, set or replaced by its label. */
|
|
87
|
+
export function stepCommand(args) {
|
|
88
|
+
const [app, label, state] = positional(args, ['--detail', '--copy', '--port', '--log']);
|
|
89
|
+
if (!app || !APP_ID.test(app))
|
|
90
|
+
fail(STEP);
|
|
91
|
+
const file = path.join(tempDir(), 'status.json');
|
|
92
|
+
const read = readJson(file);
|
|
93
|
+
const shown = typeof read === 'object' && read !== null && !Array.isArray(read) ? read : {};
|
|
94
|
+
const apps = { ...shown.apps };
|
|
95
|
+
if (args.includes('--clear')) {
|
|
96
|
+
delete apps[app]; // eslint-disable-line @typescript-eslint/no-dynamic-delete -- checked to be an app id
|
|
97
|
+
writeJson(file, { ...shown, apps });
|
|
98
|
+
console.log(`${app}: no steps of yours on its card.`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (!label || !state || !STATES.includes(state))
|
|
102
|
+
fail(STEP);
|
|
103
|
+
const cut = (text, most) => (text ? redact(text).slice(0, most) : undefined);
|
|
104
|
+
const detail = cut(flagValue(args, '--detail'), 400);
|
|
105
|
+
const copy = cut(flagValue(args, '--copy'), 2000);
|
|
106
|
+
const port = Number(flagValue(args, '--port'));
|
|
107
|
+
const log = flagValue(args, '--log');
|
|
108
|
+
const step = { label: label.slice(0, 60), state, ...(detail && { detail }), ...(copy && { copy }) };
|
|
109
|
+
const now = apps[app] ?? {};
|
|
110
|
+
const steps = now.steps ?? [];
|
|
111
|
+
const at = steps.findIndex(one => one.label === step.label);
|
|
112
|
+
apps[app] = {
|
|
113
|
+
...now,
|
|
114
|
+
...(Number.isInteger(port) && port > 0 && port < 65536 && { port }),
|
|
115
|
+
...(log && { log: path.resolve(log) }),
|
|
116
|
+
steps: at >= 0 ? steps.with(at, step) : [...steps, step],
|
|
117
|
+
};
|
|
118
|
+
writeJson(file, { ...shown, apps });
|
|
119
|
+
console.log(`${app}: ${step.label} ${state}`);
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=records.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"records.js","sourceRoot":"","sources":["../../src/cli/records.ts"],"names":[],"mappings":"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"}
|