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,106 @@
|
|
|
1
|
+
// `koppler do`: a command an app declares in the stack (Seed, Migrate), run in its clone with its secrets, once the
|
|
2
|
+
// user has allowed the stack's commands. From the canvas, its end is said in the inbox.
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { confirm, flagValue, positional } from "../cli/output.js";
|
|
5
|
+
import { appOn, storeOf } from "../core/stack.js";
|
|
6
|
+
import { readClones, readStack } from "../data.js";
|
|
7
|
+
import { fail, Failure } from "../failure.js";
|
|
8
|
+
import { BIN } from "../paths.js";
|
|
9
|
+
import { loadsCode } from "../safe-env.js";
|
|
10
|
+
import { APPROVE, approved } from "./checks.js";
|
|
11
|
+
import { live } from "./history.js";
|
|
12
|
+
import { appendMessage } from "./messages.js";
|
|
13
|
+
import { startProcess } from "./processes.js";
|
|
14
|
+
const USAGE = 'usage: koppler do <app> <command> [--arg <name>=<value>]... [--env <env>] [--yes]';
|
|
15
|
+
function argsFor(asked, args) {
|
|
16
|
+
const given = {};
|
|
17
|
+
args.forEach((arg, at) => {
|
|
18
|
+
if (args[at - 1] !== '--arg')
|
|
19
|
+
return;
|
|
20
|
+
const cut = arg.indexOf('=');
|
|
21
|
+
if (cut < 1)
|
|
22
|
+
fail(`--arg takes <name>=<value> (got ${arg})`);
|
|
23
|
+
given[arg.slice(0, cut)] = arg.slice(cut + 1);
|
|
24
|
+
});
|
|
25
|
+
for (const name of Object.keys(given))
|
|
26
|
+
if (!asked.some(one => one.name === name))
|
|
27
|
+
fail(`it takes no ${name}; it takes ${asked.map(one => one.name).join(', ') || 'nothing'}`);
|
|
28
|
+
const kept = {};
|
|
29
|
+
for (const one of asked) {
|
|
30
|
+
if (loadsCode(one.name))
|
|
31
|
+
fail(`${one.name} cannot be given: it would make the runtime load other code`);
|
|
32
|
+
const value = given[one.name] ?? '';
|
|
33
|
+
if (!value) {
|
|
34
|
+
if (one.required)
|
|
35
|
+
fail(`it needs ${one.name}: --arg ${one.name}=<value>`);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (one.type === 'number' && !/^-?\d+(\.\d+)?$/.test(value))
|
|
39
|
+
fail(`${one.name} is a number (got ${value})`);
|
|
40
|
+
if (one.type === 'choice' && !(one.choices ?? []).includes(value))
|
|
41
|
+
fail(`${one.name} is one of ${(one.choices ?? []).join(', ')} (got ${value})`);
|
|
42
|
+
kept[one.name] = value;
|
|
43
|
+
}
|
|
44
|
+
return kept;
|
|
45
|
+
}
|
|
46
|
+
async function doIt(args, canvas) {
|
|
47
|
+
const [id = '', key = ''] = positional(args, ['--env', '--arg']);
|
|
48
|
+
if (!id || !key)
|
|
49
|
+
fail(USAGE);
|
|
50
|
+
const stack = readStack() ?? fail('no stack loaded (koppler init)');
|
|
51
|
+
const app = Object.hasOwn(stack.apps, id) ? stack.apps[id] : undefined;
|
|
52
|
+
if (!app)
|
|
53
|
+
fail(`${id} is not an app in the stack`);
|
|
54
|
+
const commands = app.commands ?? {};
|
|
55
|
+
const command = Object.hasOwn(commands, key) ? commands[key] : undefined;
|
|
56
|
+
if (!command)
|
|
57
|
+
fail(`${app.name} has no command ${key}; it has ${Object.keys(commands).join(', ') || 'none'}`);
|
|
58
|
+
const show = command.show ?? 'both';
|
|
59
|
+
if (show === (canvas ? 'cli' : 'canvas'))
|
|
60
|
+
fail(`${command.label} is offered ${show === 'canvas' ? 'on the canvas' : 'with koppler do'} only`);
|
|
61
|
+
if (!approved(stack.source ?? '', stack))
|
|
62
|
+
fail(`${command.label} is a command from the stack that you have not allowed yet, or that changed since. Review it in your own terminal: ${APPROVE}`);
|
|
63
|
+
const given = argsFor(command.args ?? [], args);
|
|
64
|
+
if (command.confirm && !(await confirm(command.confirm, args)))
|
|
65
|
+
fail(`not run: ${command.confirm} Pass --yes to run it.`);
|
|
66
|
+
const env = flagValue(args, '--env') ?? live()?.env ?? stack.envs[0] ?? '';
|
|
67
|
+
if (!stack.envs.includes(env))
|
|
68
|
+
fail(`unknown env ${env}; the stack has ${stack.envs.join(', ')}`);
|
|
69
|
+
if ((appOn(stack, id, env) ?? app).outside)
|
|
70
|
+
fail(`${app.name} does not run on this Mac`);
|
|
71
|
+
const repo = readClones()[id]?.path ?? fail(`${id} is not cloned (koppler sync --rescan after cloning)`);
|
|
72
|
+
await startProcess({
|
|
73
|
+
name: `${id}-${key}`.slice(0, 64).replace(/-+$/, ''),
|
|
74
|
+
command: [path.join(BIN, 'with-secrets'), storeOf(stack, id, env), '--', 'sh', '-c', command.run],
|
|
75
|
+
cwd: repo,
|
|
76
|
+
restart: false,
|
|
77
|
+
env,
|
|
78
|
+
holdsSecrets: true,
|
|
79
|
+
setEnv: given,
|
|
80
|
+
once: { timeout: command.timeout ?? 1800 },
|
|
81
|
+
});
|
|
82
|
+
return { app: app.name, label: command.label };
|
|
83
|
+
}
|
|
84
|
+
/** `koppler do`: runs it and waits for it; from the canvas (--from-canvas), says how it ended in the inbox. */
|
|
85
|
+
export async function doCommand(args) {
|
|
86
|
+
const canvas = args.includes('--from-canvas');
|
|
87
|
+
try {
|
|
88
|
+
const { app, label } = await doIt(args, canvas);
|
|
89
|
+
if (canvas)
|
|
90
|
+
appendMessage({ kind: 'result', title: `${label} finished on ${app}` });
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
if (canvas && error instanceof Failure && error.message) {
|
|
94
|
+
const [first = '', ...rest] = error.message.split('\n');
|
|
95
|
+
appendMessage({
|
|
96
|
+
kind: 'failure',
|
|
97
|
+
title: first.slice(0, 120),
|
|
98
|
+
...(rest.length && {
|
|
99
|
+
sections: [{ title: 'Its last lines', items: rest.slice(-12).map(line => line.slice(0, 400)) }],
|
|
100
|
+
}),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=app-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-commands.js","sourceRoot":"","sources":["../../src/engine/app-commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// Starting a stack app by its id: the facts are gathered here (the app as the environment has it, its clone, launch
|
|
2
|
+
// profiles, the device), the command comes from core/launch, and the app's stored secrets are checked and attached.
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { APPROVE, approved, startsFromStack } from "./checks.js";
|
|
6
|
+
import { fail } from "../failure.js";
|
|
7
|
+
import { launchProfile, mockCommand, startCommand } from "../core/launch.js";
|
|
8
|
+
import { isProtected } from "../core/plan.js";
|
|
9
|
+
import { readClones, readStack } from "../data.js";
|
|
10
|
+
import { repoFiles } from "./investigate.js";
|
|
11
|
+
import { readJson } from "../json-files.js";
|
|
12
|
+
import { BIN, CODE, tempDir } from "../paths.js";
|
|
13
|
+
import { resolveDevice } from "./devices.js";
|
|
14
|
+
import { sh } from "./processes.js";
|
|
15
|
+
import { appOn, storeOf } from "../core/stack.js";
|
|
16
|
+
/** Where a Flutter app's `flutter run` keeps its process id: hot reload signals it. */
|
|
17
|
+
export const flutterPid = (id) => path.join(tempDir(), `flutter-${id}.pid`);
|
|
18
|
+
/** The file a run writes for a Lambda: the keys of its secret that point at local apps. */
|
|
19
|
+
export const lambdaOverrides = (id) => path.join(tempDir(), `lambda-${id}.json`);
|
|
20
|
+
/** A .NET app's launch profiles, from its clone. */
|
|
21
|
+
export function profilesOf(app, repo) {
|
|
22
|
+
if (app.kind !== 'dotnet' || !app.launchSettings || !repo)
|
|
23
|
+
return {};
|
|
24
|
+
const settings = readJson(path.join(repo, app.launchSettings));
|
|
25
|
+
return settings?.profiles ?? {};
|
|
26
|
+
}
|
|
27
|
+
/** A .NET app's plain http address from its launch profile, for callers that cannot use its development certificate. */
|
|
28
|
+
export function httpUrlOf(app, repo, env) {
|
|
29
|
+
if (app.kind !== 'dotnet' || !app.launchSettings)
|
|
30
|
+
return null;
|
|
31
|
+
const profiles = profilesOf(app, repo);
|
|
32
|
+
const profile = profiles[launchProfile(app, profiles, env).name];
|
|
33
|
+
return (profile?.applicationUrl ?? '').split(';').find(url => url.startsWith('http://')) ?? null;
|
|
34
|
+
}
|
|
35
|
+
/** Tries one stored secret against the address inside it; the outcome only, never the value. */
|
|
36
|
+
export function secretTest(store, secret) {
|
|
37
|
+
const args = [store, secret.env ?? '', ...(secret.type ? ['--type', secret.type] : [])];
|
|
38
|
+
try {
|
|
39
|
+
const said = execFileSync(path.join(BIN, 'secret-test'), args, {
|
|
40
|
+
encoding: 'utf8',
|
|
41
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
42
|
+
timeout: 40000,
|
|
43
|
+
});
|
|
44
|
+
return { code: 0, message: said.trim() };
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
const failed = error;
|
|
48
|
+
return { code: failed.status ?? 1, message: (failed.stdout ?? '').trim() || 'failed: the check did not finish' };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** The facts core/launch needs for this app, read from its clone and from what was asked for. */
|
|
52
|
+
function contextFor(id, app, repo, env, options, aliases, device) {
|
|
53
|
+
// Settings given for this start (a cable's local address) come from the environment and must win over the launch
|
|
54
|
+
// profile.
|
|
55
|
+
const ctx = {
|
|
56
|
+
repo,
|
|
57
|
+
env,
|
|
58
|
+
id,
|
|
59
|
+
engine: CODE,
|
|
60
|
+
lambdaOverrides: lambdaOverrides(id),
|
|
61
|
+
flutterPid: flutterPid(id),
|
|
62
|
+
override: Object.keys(options.setEnv ?? {}),
|
|
63
|
+
envNames: [env, ...aliases],
|
|
64
|
+
};
|
|
65
|
+
if (app.kind === 'dotnet' && app.launchSettings)
|
|
66
|
+
ctx.profiles = profilesOf(app, repo);
|
|
67
|
+
if (app.kind === 'node' || app.kind === 'web') {
|
|
68
|
+
ctx.pkg = readJson(path.join(repo, 'package.json'));
|
|
69
|
+
if (ctx.pkg?.scripts)
|
|
70
|
+
ctx.scripts = ctx.pkg.scripts;
|
|
71
|
+
}
|
|
72
|
+
if (device)
|
|
73
|
+
ctx.device = device;
|
|
74
|
+
else {
|
|
75
|
+
ctx.files = repoFiles(repo);
|
|
76
|
+
if (options.device === 'ios' || options.device === 'android')
|
|
77
|
+
ctx.platform = options.device;
|
|
78
|
+
}
|
|
79
|
+
if (options.lan) {
|
|
80
|
+
ctx.lan = true;
|
|
81
|
+
ctx.httpPort = Number(new URL(httpUrlOf(app, repo, env) ?? 'http://x').port) || undefined;
|
|
82
|
+
}
|
|
83
|
+
return ctx;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Each environment after the first has its own secret store, so a value of one never replaces or leaks into another.
|
|
87
|
+
* Ends the command when a secret the app always needs is not stored there, or when a stored one does not pass its test.
|
|
88
|
+
*/
|
|
89
|
+
function checkSecrets(id, app, store, env, test) {
|
|
90
|
+
// A secret needed only in some case (`when`) is not asked for up front.
|
|
91
|
+
const always = ({ when }) => typeof when !== 'string' || !when || /^always\b/i.test(when.trim());
|
|
92
|
+
const named = (app.secrets ?? []).filter(secret => secret.env);
|
|
93
|
+
const wanted = named.filter(always).map(secret => secret.env ?? '');
|
|
94
|
+
if (store !== id && wanted.length > 0) {
|
|
95
|
+
const have = sh(path.join(BIN, 'secret-list'), [store]).split(/\s+/);
|
|
96
|
+
const missing = wanted.filter(name => !have.includes(name));
|
|
97
|
+
if (missing.length > 0)
|
|
98
|
+
fail(`${id} has no ${missing.join(', ')} stored for ${env.toUpperCase()}; see: koppler doctor ${id} --env ${env}`);
|
|
99
|
+
}
|
|
100
|
+
if (!test)
|
|
101
|
+
return;
|
|
102
|
+
for (const secret of named) {
|
|
103
|
+
const result = secretTest(store, secret);
|
|
104
|
+
const name = secret.env ?? '';
|
|
105
|
+
if (result.code === 1) {
|
|
106
|
+
const why = result.message.replace(/^failed: /, 'did not pass its test: ');
|
|
107
|
+
fail(`${id}: ${name} for ${env.toUpperCase()} ${why}. Fix it, or start anyway with --no-test.`);
|
|
108
|
+
}
|
|
109
|
+
if (result.code === 0)
|
|
110
|
+
console.log(`${name}: ${result.message}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** How to start a stack app by id, in the chosen environment; null when the stack has no such app. */
|
|
114
|
+
export function appStart(id, options) {
|
|
115
|
+
const stack = readStack();
|
|
116
|
+
const base = stack?.apps[id];
|
|
117
|
+
if (!stack || !base)
|
|
118
|
+
return null;
|
|
119
|
+
// An app the stack marks as living outside this machine (a SaaS, a managed service) is never started here.
|
|
120
|
+
if (base.outside)
|
|
121
|
+
fail(`${base.name} does not run on this Mac: ${String(base.outside)}`);
|
|
122
|
+
const first = stack.envs[0];
|
|
123
|
+
const env = options.env ?? first ?? '';
|
|
124
|
+
if (!stack.envs.includes(env))
|
|
125
|
+
fail(`unknown env ${env}; the stack has ${stack.envs.join(', ')}`);
|
|
126
|
+
const app = appOn(stack, id, env) ?? base;
|
|
127
|
+
if (options.mock) {
|
|
128
|
+
const mock = mockCommand(app, CODE);
|
|
129
|
+
if (mock.error !== undefined)
|
|
130
|
+
fail(`${id}: ${mock.error}`);
|
|
131
|
+
return { cwd: undefined, command: mock.command, port: mock.port, onStop: undefined, device: undefined, env };
|
|
132
|
+
}
|
|
133
|
+
// A start command written in the shared stack runs only once the user has seen and allowed it, and again after it
|
|
134
|
+
// changes.
|
|
135
|
+
if (startsFromStack(stack, id, env) && !approved(stack.source ?? '', stack))
|
|
136
|
+
fail(`${base.name} is started by a command from the stack that you have not allowed yet, or that changed since. Review it in your own terminal: ${APPROVE}`);
|
|
137
|
+
const repo = readClones()[id]?.path ?? fail(`${id} is not cloned (koppler sync --rescan after cloning)`);
|
|
138
|
+
const device = app.kind === 'flutter' ? resolveDevice(options.device, app) : undefined;
|
|
139
|
+
const ctx = { ...contextFor(id, app, repo, env, options, stack.envAliases?.[env] ?? [], device), stack };
|
|
140
|
+
const start = startCommand(app, ctx);
|
|
141
|
+
if (start.error !== undefined)
|
|
142
|
+
fail(`${id}: ${start.error}; or run any command: koppler run ${id} -- <command>`);
|
|
143
|
+
const store = storeOf(stack, id, env);
|
|
144
|
+
// A protected environment's store asks the user on every read, so it is only tried when asked (--test); --no-test
|
|
145
|
+
// skips the check everywhere.
|
|
146
|
+
checkSecrets(id, app, store, env, !options.dryRun && (options.test ?? !isProtected(stack, env)));
|
|
147
|
+
// Only an app started by id gets its stored secrets; an arbitrary command never does.
|
|
148
|
+
return {
|
|
149
|
+
cwd: start.cwd,
|
|
150
|
+
command: [path.join(BIN, 'with-secrets'), store, '--', ...start.command],
|
|
151
|
+
port: start.port,
|
|
152
|
+
onStop: start.onStop,
|
|
153
|
+
device,
|
|
154
|
+
env,
|
|
155
|
+
// On its own address, so an https app is asked over https.
|
|
156
|
+
...(app.once && { once: app.once }),
|
|
157
|
+
...(app.ready &&
|
|
158
|
+
app.url && {
|
|
159
|
+
ready: {
|
|
160
|
+
url: new URL(app.ready.path, app.url).toString(),
|
|
161
|
+
status: app.ready.status,
|
|
162
|
+
timeout: app.ready.timeout,
|
|
163
|
+
},
|
|
164
|
+
}),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=app-start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-start.js","sourceRoot":"","sources":["../../src/engine/app-start.ts"],"names":[],"mappings":"AAAA,oHAAoH;AACpH,oHAAoH;AACpH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAA0C,MAAM,mBAAmB,CAAC;AACrH,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,aAAa,EAAkB,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,EAAE,EAA0C,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAgBlD,uFAAuF;AACvF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;AAC5F,2FAA2F;AAC3F,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AAEjG,oDAAoD;AACpD,MAAM,UAAU,UAAU,CAAC,GAAiB,EAAE,IAAwB;IACpE,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrE,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,cAAc,CAAC,CAAyC,CAAC;IACvG,OAAO,QAAQ,EAAE,QAAQ,IAAI,EAAE,CAAC;AAClC,CAAC;AACD,wHAAwH;AACxH,MAAM,UAAU,SAAS,CAAC,GAAiB,EAAE,IAAwB,EAAE,GAAW;IAChF,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IAC9D,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IACjE,OAAO,CAAC,OAAO,EAAE,cAAc,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,IAAI,CAAC;AACnG,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,MAAc;IACtD,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,IAAI,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACxF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,IAAI,EAAE;YAC7D,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;YACnC,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QACH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,KAA6C,CAAC;QAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,kCAAkC,EAAE,CAAC;IACnH,CAAC;AACH,CAAC;AAED,iGAAiG;AACjG,SAAS,UAAU,CACjB,EAAU,EACV,GAAQ,EACR,IAAY,EACZ,GAAW,EACX,OAAmB,EACnB,OAAiB,EACjB,MAA6B;IAE7B,iHAAiH;IACjH,WAAW;IACX,MAAM,GAAG,GAAiB;QACxB,IAAI;QACJ,GAAG;QACH,EAAE;QACF,MAAM,EAAE,IAAI;QACZ,eAAe,EAAE,eAAe,CAAC,EAAE,CAAC;QACpC,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC;QAC1B,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;QAC3C,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;KAC5B,CAAC;IACF,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,cAAc;QAAE,GAAG,CAAC,QAAQ,GAAG,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACtF,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC9C,GAAG,CAAC,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAA4C,CAAC;QAC/F,IAAI,GAAG,CAAC,GAAG,EAAE,OAAO;YAAE,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;IACtD,CAAC;IACD,IAAI,MAAM;QAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC;SAC3B,CAAC;QACJ,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;YAAE,GAAG,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9F,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC;QACf,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC;IAC5F,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,SAAS,YAAY,CAAC,EAAU,EAAE,GAAQ,EAAE,KAAa,EAAE,GAAW,EAAE,IAAa;IACnF,wEAAwE;IACxE,MAAM,MAAM,GAAG,CAAC,EAAE,IAAI,EAAU,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACzG,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;IACpE,IAAI,KAAK,KAAK,EAAE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YACpB,IAAI,CACF,GAAG,EAAE,WAAW,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,WAAW,EAAE,yBAAyB,EAAE,UAAU,GAAG,EAAE,CAC7G,CAAC;IACN,CAAC;IACD,IAAI,CAAC,IAAI;QAAE,OAAO;IAClB,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;QAC9B,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACtB,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,yBAAyB,CAAC,CAAC;YAC3E,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,QAAQ,GAAG,CAAC,WAAW,EAAE,IAAI,GAAG,2CAA2C,CAAC,CAAC;QAClG,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;AACH,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,QAAQ,CAAC,EAAU,EAAE,OAAmB;IACtD,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,MAAM,IAAI,GAAG,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7B,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,2GAA2G;IAC3G,IAAI,IAAI,CAAC,OAAO;QAAE,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,8BAA8B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACzF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,KAAK,IAAI,EAAE,CAAC;IACvC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,IAAI,CAAC,eAAe,GAAG,mBAAmB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClG,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC;IAC1C,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACpC,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC3D,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;IAC/G,CAAC;IACD,kHAAkH;IAClH,WAAW;IACX,IAAI,eAAe,CAAC,KAAK,EAAE,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,EAAE,KAAK,CAAC;QACzE,IAAI,CACF,GAAG,IAAI,CAAC,IAAI,iIAAiI,OAAO,EAAE,CACvJ,CAAC;IACJ,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,sDAAsD,CAAC,CAAC;IACzG,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACvF,MAAM,GAAG,GAAG,EAAE,GAAG,UAAU,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;IACzG,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACrC,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,GAAG,EAAE,KAAK,KAAK,CAAC,KAAK,qCAAqC,EAAE,eAAe,CAAC,CAAC;IACjH,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;IACtC,kHAAkH;IAClH,8BAA8B;IAC9B,YAAY,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IACjG,sFAAsF;IACtF,OAAO;QACL,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC;QACxE,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,MAAM;QACN,GAAG;QACH,2DAA2D;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;QACnC,GAAG,CAAC,GAAG,CAAC,KAAK;YACX,GAAG,CAAC,GAAG,IAAI;YACT,KAAK,EAAE;gBACL,GAAG,EAAE,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;gBAChD,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM;gBACxB,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO;aAC3B;SACF,CAAC;KACL,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// An app's state in words the canvas, `koppler status --json` and `koppler wait` share.
|
|
2
|
+
import { readStack } from "../data.js";
|
|
3
|
+
import { alive, listener, readRecord, statusOf, tailOf } from "./processes.js";
|
|
4
|
+
/** What its process says: building until its port answers, unhealthy while its ready check fails; null when none ran. */
|
|
5
|
+
export async function processState(name) {
|
|
6
|
+
const record = readRecord(name);
|
|
7
|
+
if (!record)
|
|
8
|
+
return null;
|
|
9
|
+
if (!alive(record)) {
|
|
10
|
+
const last = tailOf(record.log, 1).trim();
|
|
11
|
+
return { state: 'exited', detail: last ? `It stopped. Its last line: ${last.slice(0, 200)}` : 'It stopped.' };
|
|
12
|
+
}
|
|
13
|
+
if (record.port && !listener(record.port, record.bind))
|
|
14
|
+
return { state: 'building', detail: `Nothing answers on port ${String(record.port)} yet.` };
|
|
15
|
+
const app = readStack()?.apps[name];
|
|
16
|
+
if (!app?.ready || !app.url)
|
|
17
|
+
return { state: 'running', detail: '' };
|
|
18
|
+
const url = new URL(app.ready.path, app.url);
|
|
19
|
+
const status = await statusOf(url);
|
|
20
|
+
const ok = status !== null && (app.ready.status === undefined ? status < 400 : status === app.ready.status);
|
|
21
|
+
if (ok)
|
|
22
|
+
return { state: 'running', detail: '' };
|
|
23
|
+
return {
|
|
24
|
+
state: 'unhealthy',
|
|
25
|
+
detail: status === null ? `Nothing answers at ${url.pathname}.` : `${url.pathname} answers ${String(status)}.`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** The state to show: a live process first, then what the run says of its start, then a secret it lacks. */
|
|
29
|
+
export function stateOf(process, steps = [], missing = []) {
|
|
30
|
+
const start = steps.find(step => step.label === 'Start');
|
|
31
|
+
if (process && process.state !== 'exited')
|
|
32
|
+
return process;
|
|
33
|
+
if (start?.state === 'failed')
|
|
34
|
+
return { state: 'failed-to-start', detail: start.detail ?? '' };
|
|
35
|
+
if (process)
|
|
36
|
+
return process;
|
|
37
|
+
if (start?.state === 'todo')
|
|
38
|
+
return { state: 'waiting', detail: start.detail ?? '' };
|
|
39
|
+
if (missing.length)
|
|
40
|
+
return { state: 'secret-missing', detail: missing.join(', ') };
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=app-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-state.js","sourceRoot":"","sources":["../../src/engine/app-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
// Changing a board from the terminal. The change goes into state.json at once, and waits in board-edits.json for an
|
|
2
|
+
// open canvas to make it on its own copy too, so the canvas shows it and never saves its older copy over it.
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { describeEdit, editPreset, migrate, VERSION } from "../core/presets.js";
|
|
5
|
+
import { canvas } from "../cli/running.js";
|
|
6
|
+
import { fetchPresets } from "../server/sanitize.js";
|
|
7
|
+
import { readClones, readData, readStack, writeData } from "../data.js";
|
|
8
|
+
import { fail } from "../failure.js";
|
|
9
|
+
import { appendMessage } from "./messages.js";
|
|
10
|
+
import { alive, readRecord } from "./processes.js";
|
|
11
|
+
import { shareBoard } from "./share.js";
|
|
12
|
+
import { currentStack } from "./stacks.js";
|
|
13
|
+
const queued = () => (readData('board-edits')?.['edits'] ?? []);
|
|
14
|
+
const DAY = 86_400_000;
|
|
15
|
+
/** The edits an open canvas of the stack in use has not made yet. */
|
|
16
|
+
export const boardEdits = () => queued().filter(one => one.stack === currentStack());
|
|
17
|
+
/** The canvas made it (or had it already): it waits no longer. */
|
|
18
|
+
export function editDone(id) {
|
|
19
|
+
writeData('board-edits', { edits: queued().filter(one => one.id !== id) });
|
|
20
|
+
}
|
|
21
|
+
const CHANGES = '[--propose] [--add <app,...>] [--remove <app,...>] [--cable <caller>:<callee>]... [--uncable <caller>:<callee>]... [--branch <app>=<branch>]... [--note <app>="<note>"]... [--arrange]';
|
|
22
|
+
const USAGE = `usage: koppler board new "<name>" ${CHANGES}\n koppler board edit "<name>" ${CHANGES}\n koppler board share "<name>"\n koppler board open <file or link>`;
|
|
23
|
+
/** Your own board, by name, as kept for this stack. */
|
|
24
|
+
const ownBoard = (name) => {
|
|
25
|
+
const own = (readData('state')?.['presets'] ?? []);
|
|
26
|
+
return own.find(one => one.name === name) ?? own.find(one => one.name.toLowerCase() === name.toLowerCase());
|
|
27
|
+
};
|
|
28
|
+
/** Opens the pull request that makes one of your boards a team board of the stack in use. */
|
|
29
|
+
async function share(name) {
|
|
30
|
+
const dir = currentStack() ?? fail('no stack in use (koppler use)');
|
|
31
|
+
const board = ownBoard(name) ?? fail(`${name} is not one of your boards; koppler use --boards lists them`);
|
|
32
|
+
const shared = await shareBoard(dir, board);
|
|
33
|
+
if (shared.error !== undefined)
|
|
34
|
+
fail(shared.error);
|
|
35
|
+
if (shared.local)
|
|
36
|
+
console.log(`KEPT ${board.name} among the stack's team boards in ${dir}; commit the stack there so your team gets it.`);
|
|
37
|
+
else
|
|
38
|
+
console.log(`PROPOSED ${board.name} to the team on ${shared.repo}: ${shared.url}`);
|
|
39
|
+
}
|
|
40
|
+
export function boardCommand(args) {
|
|
41
|
+
const [what, name] = args;
|
|
42
|
+
if (what === 'share' && name && !name.startsWith('-'))
|
|
43
|
+
return share(name);
|
|
44
|
+
if (what === 'open' && name && !name.startsWith('-'))
|
|
45
|
+
return openBoard(name, args.includes('--no-open'));
|
|
46
|
+
if ((what !== 'edit' && what !== 'new') || !name?.trim() || name.startsWith('-'))
|
|
47
|
+
fail(USAGE);
|
|
48
|
+
const create = what === 'new';
|
|
49
|
+
const values = (flag) => args.filter((_, at) => args[at - 1] === flag);
|
|
50
|
+
const ids = (flag) => values(flag).flatMap(value => value
|
|
51
|
+
.split(',')
|
|
52
|
+
.map(id => id.trim())
|
|
53
|
+
.filter(Boolean));
|
|
54
|
+
const pairs = (flag, by) => values(flag).map(value => {
|
|
55
|
+
const at = value.indexOf(by);
|
|
56
|
+
if (at < 1)
|
|
57
|
+
fail(`${flag} ${value}: expected <app>${by}<value>\n${USAGE}`);
|
|
58
|
+
return [value.slice(0, at), value.slice(at + 1)];
|
|
59
|
+
});
|
|
60
|
+
const cables = (flag) => pairs(flag, ':').map(([from, to]) => ({ from, to }));
|
|
61
|
+
const edit = {
|
|
62
|
+
add: ids('--add'),
|
|
63
|
+
remove: ids('--remove'),
|
|
64
|
+
cable: cables('--cable'),
|
|
65
|
+
uncable: cables('--uncable'),
|
|
66
|
+
branch: Object.fromEntries(pairs('--branch', '=')),
|
|
67
|
+
note: Object.fromEntries(pairs('--note', '=')),
|
|
68
|
+
...(args.includes('--arrange') && { arrange: true }),
|
|
69
|
+
};
|
|
70
|
+
for (const line of changeBoard(name, edit, create, args.includes('--propose')))
|
|
71
|
+
console.log(line);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* `koppler board open <file or link>`: a board from a file here or a link on GitHub joins your boards, and the canvas
|
|
75
|
+
* opens on it. It remembers where it came from, so the canvas can read it again (Reload).
|
|
76
|
+
*/
|
|
77
|
+
async function openBoard(where, quiet) {
|
|
78
|
+
const source = /^https?:\/\//.test(where) ? where : path.resolve(where);
|
|
79
|
+
if (!/^https?:/.test(source) && !source.endsWith('.json'))
|
|
80
|
+
fail(`${where}: a board file is a .json file`);
|
|
81
|
+
const read = await fetchPresets(source);
|
|
82
|
+
if (read.error !== undefined)
|
|
83
|
+
fail(read.error);
|
|
84
|
+
const [first] = read.presets;
|
|
85
|
+
const checked = first && migrate(first);
|
|
86
|
+
if (!first || !checked || checked.error !== undefined)
|
|
87
|
+
fail(checked?.error ?? 'No board found in it.');
|
|
88
|
+
// Kept as the plain board it was read as.
|
|
89
|
+
const board = JSON.parse(JSON.stringify({ ...first, name: first.name.trim().slice(0, 80), source }));
|
|
90
|
+
const state = readData('state') ?? {};
|
|
91
|
+
const own = (state['presets'] ?? []);
|
|
92
|
+
writeData('state', { ...state, presets: [...own.filter(one => one.name !== board.name), board] });
|
|
93
|
+
const now = Date.now();
|
|
94
|
+
writeData('board-edits', {
|
|
95
|
+
edits: [
|
|
96
|
+
...queued().filter(one => now - Date.parse(one.at) < DAY),
|
|
97
|
+
{
|
|
98
|
+
id: now.toString(36) + Math.random().toString(36).slice(2, 8),
|
|
99
|
+
at: new Date(now).toISOString(),
|
|
100
|
+
stack: currentStack(),
|
|
101
|
+
board: board.name,
|
|
102
|
+
edit: {},
|
|
103
|
+
preset: board,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
console.log(`OPENED ${board.name} from ${source}`);
|
|
108
|
+
if (quiet)
|
|
109
|
+
console.log(`An open canvas shows it; or: koppler canvas --board "${board.name}"`);
|
|
110
|
+
else
|
|
111
|
+
await canvas(['--board', board.name]);
|
|
112
|
+
}
|
|
113
|
+
const proposals = () => (readData('board-proposals')?.['proposals'] ?? []);
|
|
114
|
+
/**
|
|
115
|
+
* The user answered a proposal: the change is made as `koppler board edit` makes it, or left. Null when the message
|
|
116
|
+
* was no proposal.
|
|
117
|
+
*/
|
|
118
|
+
export function answerProposal(message, accepted) {
|
|
119
|
+
const proposal = proposals().find(one => one.message === message);
|
|
120
|
+
if (!proposal)
|
|
121
|
+
return null;
|
|
122
|
+
writeData('board-proposals', { proposals: proposals().filter(one => one !== proposal && one.message !== message) });
|
|
123
|
+
if (!accepted)
|
|
124
|
+
return `Left ${proposal.board} as it is.`;
|
|
125
|
+
return changeBoard(proposal.board, proposal.edit, !!proposal.create, false).join(' ');
|
|
126
|
+
}
|
|
127
|
+
/** Checks a change to a board and makes it, or, proposed, asks the user in the inbox first and changes nothing. */
|
|
128
|
+
export function changeBoard(name, edit, create, propose) {
|
|
129
|
+
const stack = readStack() ?? fail('no stack loaded (koppler init)');
|
|
130
|
+
const state = readData('state') ?? {};
|
|
131
|
+
const own = (state['presets'] ?? []);
|
|
132
|
+
const team = (stack.presets ?? []);
|
|
133
|
+
const lower = name.toLowerCase();
|
|
134
|
+
const found = [...own, ...team].find(one => one.name === name) ?? [...own, ...team].find(one => one.name.toLowerCase() === lower);
|
|
135
|
+
if (create && found)
|
|
136
|
+
fail(`a board called ${found.name} already exists; change it with koppler board edit`);
|
|
137
|
+
const board = found ??
|
|
138
|
+
(create
|
|
139
|
+
? { name: name.trim(), version: VERSION, nodes: {}, edges: [] }
|
|
140
|
+
: fail(`no board called ${name}; koppler board new makes one, koppler use --boards lists them`));
|
|
141
|
+
const app = (id) => stack.apps[id];
|
|
142
|
+
const clones = readClones();
|
|
143
|
+
for (const id of edit.add ?? []) {
|
|
144
|
+
if (!app(id))
|
|
145
|
+
fail(`${id} is not an app in the stack`);
|
|
146
|
+
if (app(id)?.outside)
|
|
147
|
+
fail(`${app(id)?.name ?? id} does not run on this Mac`);
|
|
148
|
+
if (!clones[id])
|
|
149
|
+
fail(`${app(id)?.name ?? id} is not cloned on this Mac (koppler sync prints how)`);
|
|
150
|
+
}
|
|
151
|
+
const on = new Set([...Object.keys(board.nodes).filter(id => !edit.remove?.includes(id)), ...(edit.add ?? [])]);
|
|
152
|
+
const here = (id, why) => {
|
|
153
|
+
if (!on.has(id))
|
|
154
|
+
fail(`${id} is not on ${board.name}, so it cannot ${why}`);
|
|
155
|
+
};
|
|
156
|
+
for (const id of edit.remove ?? [])
|
|
157
|
+
if (!Object.hasOwn(board.nodes, id))
|
|
158
|
+
fail(`${id} is not on ${board.name}`);
|
|
159
|
+
for (const id of Object.keys(edit.branch ?? {}))
|
|
160
|
+
here(id, 'take a branch');
|
|
161
|
+
for (const id of Object.keys(edit.note ?? {}))
|
|
162
|
+
here(id, 'take a note');
|
|
163
|
+
for (const { from, to } of edit.cable ?? []) {
|
|
164
|
+
here(from, 'call');
|
|
165
|
+
here(to, 'be called');
|
|
166
|
+
}
|
|
167
|
+
const changed = { ...editPreset(board, edit), name: board.name };
|
|
168
|
+
if (!create && JSON.stringify(changed) === JSON.stringify(board))
|
|
169
|
+
return [`Nothing to change on ${board.name}.`];
|
|
170
|
+
const named = (id) => app(id)?.name ?? id;
|
|
171
|
+
if (propose) {
|
|
172
|
+
const asked = appendMessage({
|
|
173
|
+
kind: 'question',
|
|
174
|
+
title: create ? `Make the board ${board.name}?` : `Change ${board.name}?`,
|
|
175
|
+
summary: 'The agent proposes this. Nothing changes until you say yes.',
|
|
176
|
+
sections: [{ title: 'It would', items: describeEdit(edit, named, true).split('; ').filter(Boolean) }],
|
|
177
|
+
choices: [
|
|
178
|
+
{ id: 'accept', label: create ? 'Make it' : 'Make the change' },
|
|
179
|
+
{ id: 'reject', label: 'Leave it as it is' },
|
|
180
|
+
],
|
|
181
|
+
});
|
|
182
|
+
writeData('board-proposals', {
|
|
183
|
+
proposals: [
|
|
184
|
+
...proposals(),
|
|
185
|
+
{ message: asked.id, stack: currentStack(), board: board.name, edit, ...(create && { create: true }) },
|
|
186
|
+
],
|
|
187
|
+
});
|
|
188
|
+
return [
|
|
189
|
+
`PROPOSED ${board.name}: ${describeEdit(edit, named)}`,
|
|
190
|
+
'The user answers in the canvas inbox; the answer comes back as a koppler-reply prompt.',
|
|
191
|
+
];
|
|
192
|
+
}
|
|
193
|
+
const mine = own.some(one => one.name === board.name);
|
|
194
|
+
writeData('state', {
|
|
195
|
+
...state,
|
|
196
|
+
presets: mine ? own.map(one => (one.name === board.name ? changed : one)) : [...own, changed],
|
|
197
|
+
});
|
|
198
|
+
const now = Date.now();
|
|
199
|
+
const entry = {
|
|
200
|
+
id: now.toString(36) + Math.random().toString(36).slice(2, 8),
|
|
201
|
+
at: new Date(now).toISOString(),
|
|
202
|
+
stack: currentStack(),
|
|
203
|
+
board: board.name,
|
|
204
|
+
edit,
|
|
205
|
+
...(create && { create: true }),
|
|
206
|
+
};
|
|
207
|
+
writeData('board-edits', {
|
|
208
|
+
edits: [...queued().filter(one => now - Date.parse(one.at) < DAY), entry],
|
|
209
|
+
});
|
|
210
|
+
const canvas = readRecord('canvas');
|
|
211
|
+
const said = describeEdit(edit, named);
|
|
212
|
+
return [
|
|
213
|
+
`${create ? 'MADE' : 'CHANGED'} ${board.name}${said ? `: ${said}` : ''}`,
|
|
214
|
+
canvas && alive(canvas)
|
|
215
|
+
? 'An open canvas shows the change as soon as it is in view.'
|
|
216
|
+
: 'The canvas shows the change when it is opened.',
|
|
217
|
+
];
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=boards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boards.js","sourceRoot":"","sources":["../../src/engine/boards.ts"],"names":[],"mappings":"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"}
|