koppler 0.0.0-stage → 0.0.1
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 +73 -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,321 @@
|
|
|
1
|
+
// What the canvas shows about each app, put together every second and a half: temp/status.json as the agent wrote it,
|
|
2
|
+
// plus live port state, log tails, credentials, the run history and everything else the page re-loads on a timer.
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import net from 'node:net';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { of as kindOf } from "../core/kinds.js";
|
|
7
|
+
import { dataFile, readStack } from "../data.js";
|
|
8
|
+
import { readJson as readJsonOr, whenChanged } from "../json-files.js";
|
|
9
|
+
import { linkedStatus } from "../engine/linked.js";
|
|
10
|
+
import { listenerPid } from "../engine/listen.js";
|
|
11
|
+
import { boardEdits } from "../engine/boards.js";
|
|
12
|
+
import { lockedPaths } from "../engine/locks.js";
|
|
13
|
+
import { stackSource } from "../engine/stack-file.js";
|
|
14
|
+
import { readMessages } from "../engine/messages.js";
|
|
15
|
+
import { recipesFor } from "../engine/recipes.js";
|
|
16
|
+
import { runningEnvs, runningNames } from "../engine/runs.js";
|
|
17
|
+
import { live, notes, runs } from "../engine/history.js";
|
|
18
|
+
import { currentStack, LOADING, stacksHere } from "../engine/stacks.js";
|
|
19
|
+
import { CODE, logsDir, stateDir, tempDir } from "../paths.js";
|
|
20
|
+
import { redact } from "../scrub.js";
|
|
21
|
+
import { tail } from "./logs.js";
|
|
22
|
+
import { mobileState, refreshMobile } from "./mobile.js";
|
|
23
|
+
import { secretsStatus } from "./secrets.js";
|
|
24
|
+
import { waiting } from "./waiting.js";
|
|
25
|
+
import { APP_ID, RUN_ID } from "../ids.js";
|
|
26
|
+
import { processState, stateOf } from "../engine/app-state.js";
|
|
27
|
+
import { pinned, runLogs } from "../engine/run-logs.js";
|
|
28
|
+
import { traceView, tracing, VIEW_PORT } from "../engine/traces.js";
|
|
29
|
+
import { listener as answering } from "../engine/processes.js";
|
|
30
|
+
export const SOURCE = path.join(tempDir(), 'status.json');
|
|
31
|
+
const OUT = path.join(tempDir(), 'status.js');
|
|
32
|
+
const STEP_STATES = ['done', 'failed', 'user', 'todo'];
|
|
33
|
+
/** A value from a file as text, cut to size. */
|
|
34
|
+
const cut = (value, most) => String(value).slice(0, most);
|
|
35
|
+
const readJson = (file) => JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
36
|
+
const procFile = (name) => path.join(stateDir(), 'procs', name);
|
|
37
|
+
// The status is put together every 1.5 seconds; the stack is parsed again only when a sync wrote it anew.
|
|
38
|
+
const stackOnce = whenChanged(() => readStack());
|
|
39
|
+
const stackNow = () => stackOnce(dataFile('registry'));
|
|
40
|
+
/** The newest of the server's own files: the page reloads itself, but the server's code only takes effect after a restart. */
|
|
41
|
+
const codeVersion = () => {
|
|
42
|
+
try {
|
|
43
|
+
const own = fs.readdirSync(CODE).filter(file => /\.m?js$/.test(file) && !file.includes('.test.'));
|
|
44
|
+
return Math.max(...own.map(file => fs.statSync(path.join(CODE, file)).mtimeMs));
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const STARTED_CODE = codeVersion();
|
|
51
|
+
const STARTED_AT = new Date().toISOString();
|
|
52
|
+
// Run from its source folder rather than an installed plugin: Koppler itself is being worked on, so the debug log stays on.
|
|
53
|
+
const DEV = !fs.realpathSync(CODE).split(path.sep).join('/').includes('/plugins/cache/');
|
|
54
|
+
const portOpen = (port) => new Promise(resolve => {
|
|
55
|
+
const socket = net.connect({ host: '127.0.0.1', port, timeout: 400 });
|
|
56
|
+
const done = (open) => {
|
|
57
|
+
socket.destroy();
|
|
58
|
+
resolve(open);
|
|
59
|
+
};
|
|
60
|
+
socket.once('connect', () => {
|
|
61
|
+
done(true);
|
|
62
|
+
});
|
|
63
|
+
socket.once('timeout', () => {
|
|
64
|
+
done(false);
|
|
65
|
+
});
|
|
66
|
+
socket.once('error', () => {
|
|
67
|
+
done(false);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
/** Every tunnel port in the stack, so cards can show whether their database or cache is reachable. */
|
|
71
|
+
function tunnelPorts() {
|
|
72
|
+
const stack = stackNow();
|
|
73
|
+
if (!stack)
|
|
74
|
+
return [];
|
|
75
|
+
const needs = Object.values(stack.apps).flatMap(app => [
|
|
76
|
+
...(app.prereqs ?? []),
|
|
77
|
+
...Object.values(app.envs ?? {}).flatMap(env => env.prereqs ?? []),
|
|
78
|
+
]);
|
|
79
|
+
const declared = needs.flatMap(({ tunnel, port }) => tunnel && port !== undefined && Number.isInteger(port) && port > 0 && port < 65536 ? [port] : []);
|
|
80
|
+
// Tunnels koppler moved to another port are checked there too.
|
|
81
|
+
let running = [];
|
|
82
|
+
try {
|
|
83
|
+
running = fs.readdirSync(procFile('')).flatMap(file => {
|
|
84
|
+
try {
|
|
85
|
+
return readJson(procFile(file)).port || [];
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Nothing was started yet.
|
|
94
|
+
}
|
|
95
|
+
return [...new Set([...declared, ...running])];
|
|
96
|
+
}
|
|
97
|
+
/** The steps of the run Koppler applies itself (koppler up), for cards the agent wrote no checklist for. */
|
|
98
|
+
function addProgress(status) {
|
|
99
|
+
try {
|
|
100
|
+
const progress = readJson(path.join(tempDir(), 'progress.json'));
|
|
101
|
+
if (!RUN_ID.test(progress.run ?? ''))
|
|
102
|
+
return;
|
|
103
|
+
const apps = Object.entries(progress.apps ?? {}).filter(([id]) => APP_ID.test(id));
|
|
104
|
+
status['progress'] = { run: progress.run, env: cut(progress.env ?? '', 16), apps: apps.map(([id]) => id) };
|
|
105
|
+
for (const [id, steps] of apps) {
|
|
106
|
+
if (!Array.isArray(steps))
|
|
107
|
+
continue;
|
|
108
|
+
const app = (status.apps[id] ??= {});
|
|
109
|
+
if (app.steps?.length)
|
|
110
|
+
continue;
|
|
111
|
+
app.steps = steps.slice(0, 12).map(step => ({
|
|
112
|
+
label: cut(step['label'], 60),
|
|
113
|
+
state: STEP_STATES.includes(step.state) ? step.state : 'todo',
|
|
114
|
+
...(!!step['detail'] && { detail: cut(step['detail'], 300) }),
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// No run of Koppler's own in progress.
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** What the stack needs on this Mac, as `koppler doctor` last found it. */
|
|
123
|
+
function lastChecks() {
|
|
124
|
+
try {
|
|
125
|
+
const { results } = readJson(path.join(tempDir(), 'checks.json'));
|
|
126
|
+
return results.slice(0, 80).map(result => ({
|
|
127
|
+
name: cut(result['name'], 80),
|
|
128
|
+
state: cut(result.state, 16),
|
|
129
|
+
detail: redact(cut(result['detail'] ?? '', Infinity)).slice(0, 400),
|
|
130
|
+
...(Array.isArray(result['for']) && { for: result['for'].slice(0, 10).map(who => cut(who, 80)) }),
|
|
131
|
+
...(result.state === 'gap' && {
|
|
132
|
+
app: cut(result['app'], 64),
|
|
133
|
+
env: cut(result['env'], 16),
|
|
134
|
+
kind: cut(result['kind'], 16),
|
|
135
|
+
}),
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** Remembered code changes per app, with how each did on this Mac; the review lists the ones a Send applies. */
|
|
143
|
+
function recipesByApp() {
|
|
144
|
+
try {
|
|
145
|
+
const stack = stackNow();
|
|
146
|
+
const byApp = Object.keys(stack?.apps ?? {}).map((id) => [
|
|
147
|
+
id,
|
|
148
|
+
recipesFor(stack, id)
|
|
149
|
+
.filter(recipe => !recipe.os || recipe.os === 'any' || recipe.os === process.platform)
|
|
150
|
+
.map(({ id: recipe, why, file, when, scope, here }) => ({
|
|
151
|
+
id: recipe,
|
|
152
|
+
why: cut(why, 200),
|
|
153
|
+
file: cut(file, 200),
|
|
154
|
+
when,
|
|
155
|
+
scope,
|
|
156
|
+
...(here && { here: { ok: here.ok, at: cut(here.at, 10) } }),
|
|
157
|
+
})),
|
|
158
|
+
]);
|
|
159
|
+
return Object.fromEntries(byApp.filter(([, list]) => list.length));
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return {};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/** Whether an agent session takes Sends: listening now, working on one it took (for up to two hours), or none. */
|
|
166
|
+
function agentState() {
|
|
167
|
+
let listener;
|
|
168
|
+
try {
|
|
169
|
+
listener = readJson(path.join(tempDir(), 'listener.json'));
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return { state: 'none' };
|
|
173
|
+
}
|
|
174
|
+
if (typeof listener !== 'object' || listener === null)
|
|
175
|
+
return { state: 'none' };
|
|
176
|
+
if (listener.pid)
|
|
177
|
+
return listenerPid(listener) ? { state: 'listening', since: listener.since } : { state: 'none' };
|
|
178
|
+
// Working on what it took, until it marks a run done or failed after that: then it has finished and is not listening.
|
|
179
|
+
const ended = Math.max(0, ...runs().map(run => Date.parse(run.endedAt ?? '') || 0));
|
|
180
|
+
const took = Date.parse(listener.busy ?? '');
|
|
181
|
+
return listener.busy && took > ended && Date.now() - took < 2 * 3600 * 1000
|
|
182
|
+
? { state: 'busy', since: listener.since, busy: listener.busy }
|
|
183
|
+
: { state: 'none' };
|
|
184
|
+
}
|
|
185
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
186
|
+
/** Where an app's log is read from: the file it names when that is a log, else where Koppler keeps its own. */
|
|
187
|
+
export const logFile = (id, named) => typeof named === 'string' && path.isAbsolute(named) && /\.(log|out|txt)$/i.test(named)
|
|
188
|
+
? named
|
|
189
|
+
: path.join(logsDir(), `${id}.log`);
|
|
190
|
+
async function snapshot(serving) {
|
|
191
|
+
let written = {};
|
|
192
|
+
try {
|
|
193
|
+
written = readJson(SOURCE);
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// No agent wrote a status yet.
|
|
197
|
+
}
|
|
198
|
+
// An app Koppler started itself (koppler up) has a card too, even when no agent wrote a status for it.
|
|
199
|
+
// Anyone can have written that file: only what is shaped like an app's status is kept.
|
|
200
|
+
const given = isRecord(written) ? written : {};
|
|
201
|
+
const apps = Object.entries(isRecord(given.apps) ? given.apps : {}).filter(([id, app]) => APP_ID.test(id) && isRecord(app));
|
|
202
|
+
const status = { ...given, apps: Object.fromEntries(apps) };
|
|
203
|
+
for (const name of runningNames()) {
|
|
204
|
+
if (status.apps[name] || name === 'canvas' || name.startsWith('tunnel-'))
|
|
205
|
+
continue;
|
|
206
|
+
try {
|
|
207
|
+
const record = readJson(procFile(`${name}.json`));
|
|
208
|
+
status.apps[name] = { ...(record.port && { port: record.port }), log: record.log };
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// Its record went away between the two looks.
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
addProgress(status);
|
|
215
|
+
// A mobile app on the applied board is looked for on the simulators and devices too, even when started from the IDE.
|
|
216
|
+
const stack = stackNow();
|
|
217
|
+
for (const id of Object.keys(live()?.nodes ?? {}))
|
|
218
|
+
if (!status.apps[id] && stack?.apps[id] && kindOf(stack.apps[id]).platforms)
|
|
219
|
+
status.apps[id] = {};
|
|
220
|
+
await refreshMobile(Object.keys(status.apps));
|
|
221
|
+
for (const [id, app] of Object.entries(status.apps)) {
|
|
222
|
+
if (app.port)
|
|
223
|
+
app.listening = await portOpen(app.port);
|
|
224
|
+
if (mobileState[id])
|
|
225
|
+
app.running = mobileState[id];
|
|
226
|
+
app.logTail = tail(logFile(id, app.log));
|
|
227
|
+
delete app.log;
|
|
228
|
+
}
|
|
229
|
+
// Each app's state in words, checked side by side: a ready check can take a few seconds to answer. One started
|
|
230
|
+
// outside Koppler (by the agent, in the IDE, on a simulator) runs while it answers.
|
|
231
|
+
await Promise.all(Object.entries(status.apps).map(async ([id, app]) => {
|
|
232
|
+
const outside = app.listening || app.running?.length ? { state: 'running', detail: '' } : null;
|
|
233
|
+
const state = stateOf((await processState(id)) ?? outside, app.steps);
|
|
234
|
+
if (state)
|
|
235
|
+
app.state = state;
|
|
236
|
+
}));
|
|
237
|
+
const ports = await Promise.all(tunnelPorts().map(async (port) => [port, await portOpen(port)]));
|
|
238
|
+
status['ports'] = Object.fromEntries(ports);
|
|
239
|
+
status['secrets'] = await secretsStatus().catch(() => ({}));
|
|
240
|
+
status['recipes'] = recipesByApp();
|
|
241
|
+
const inUse = currentStack();
|
|
242
|
+
status['stack'] = loadedStack(inUse);
|
|
243
|
+
status['loading'] = loadingStack();
|
|
244
|
+
status['checks'] = lastChecks();
|
|
245
|
+
status['stacks'] = stacksHere();
|
|
246
|
+
status['linked'] = inUse ? linkedStatus(inUse) : null;
|
|
247
|
+
status['live'] = live();
|
|
248
|
+
status['messages'] = readMessages();
|
|
249
|
+
status['boardEdits'] = boardEdits();
|
|
250
|
+
// `koppler refresh`: when it last asked an open canvas to read the stack and its board again.
|
|
251
|
+
status['traces'] = tracing()
|
|
252
|
+
? { state: answering(VIEW_PORT) ? 'on' : 'starting', view: traceView() }
|
|
253
|
+
: { state: 'off' };
|
|
254
|
+
status['refresh'] = readJsonOr(path.join(tempDir(), 'refresh.json'))?.at ?? null;
|
|
255
|
+
const source = stackSource();
|
|
256
|
+
status['locks'] = source ? lockedPaths(source) : [];
|
|
257
|
+
status['agent'] = agentState();
|
|
258
|
+
// Sends, Stops and answers no session has taken yet.
|
|
259
|
+
status['waiting'] = waiting();
|
|
260
|
+
status['queued'] = status['waiting'].length;
|
|
261
|
+
status['running'] = runningNames();
|
|
262
|
+
status['runningEnvs'] = runningEnvs();
|
|
263
|
+
const pins = pinned();
|
|
264
|
+
status['runs'] = runs()
|
|
265
|
+
.slice(-20)
|
|
266
|
+
.map(({ nodes, edges, ...run }) => ({
|
|
267
|
+
...run,
|
|
268
|
+
nodes,
|
|
269
|
+
edges,
|
|
270
|
+
logs: runLogs(run.id),
|
|
271
|
+
pinned: pins.includes(run.id),
|
|
272
|
+
}));
|
|
273
|
+
status['notes'] = notes().slice(-20);
|
|
274
|
+
status['at'] = new Date().toISOString();
|
|
275
|
+
// The page works out the server's addresses from its own, so the token is in no file but its own.
|
|
276
|
+
if (serving)
|
|
277
|
+
status['server'] = true;
|
|
278
|
+
try {
|
|
279
|
+
status['pageVersion'] = fs.statSync(path.join(CODE, 'page', 'index.html')).mtimeMs;
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
// The page is gone: nothing to reload.
|
|
283
|
+
}
|
|
284
|
+
status['startedAt'] = STARTED_AT;
|
|
285
|
+
if (DEV)
|
|
286
|
+
status['dev'] = true;
|
|
287
|
+
status['start'] = 'koppler canvas';
|
|
288
|
+
if (codeVersion() > STARTED_CODE)
|
|
289
|
+
status['restart'] = 'koppler canvas stop && koppler canvas start';
|
|
290
|
+
return status;
|
|
291
|
+
}
|
|
292
|
+
let shown = null;
|
|
293
|
+
/** The stack the page is told about: one just switched to is named once its data is loaded, never half way. */
|
|
294
|
+
function loadedStack(inUse) {
|
|
295
|
+
const registry = stackNow();
|
|
296
|
+
if (!inUse || (registry?.source === path.join(inUse, 'stack.json') && registry.found))
|
|
297
|
+
shown = inUse;
|
|
298
|
+
return shown;
|
|
299
|
+
}
|
|
300
|
+
/** The stack a running `koppler sync` is loading, when it is not the one the page shows already. */
|
|
301
|
+
function loadingStack() {
|
|
302
|
+
try {
|
|
303
|
+
const { stack, pid } = readJson(LOADING);
|
|
304
|
+
process.kill(pid, 0);
|
|
305
|
+
return typeof stack === 'string' && stack !== shown ? stack : null;
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
let latest = null;
|
|
312
|
+
/** The status as last put together, as JSON, for the page that asks for it instead of loading it as a script. */
|
|
313
|
+
export const statusJson = () => latest;
|
|
314
|
+
/** Writes the status where the page loads it from, whole or not at all. */
|
|
315
|
+
export async function publish(serving) {
|
|
316
|
+
latest = JSON.stringify(await snapshot(serving));
|
|
317
|
+
const body = `window.__kopplerStatus && window.__kopplerStatus(${latest});\n`;
|
|
318
|
+
fs.writeFileSync(OUT + '.tmp', body, { mode: 0o600 });
|
|
319
|
+
fs.renameSync(OUT + '.tmp', OUT);
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/server/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// The canvas page's access token: in its address, kept across restarts so an open tab keeps working, and replaced on
|
|
2
|
+
// request so every address given out before stops working.
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { stateDir, tempDir } from "../paths.js";
|
|
7
|
+
const file = () => path.join(stateDir(), 'canvas-token');
|
|
8
|
+
let current = null;
|
|
9
|
+
const keep = (token) => {
|
|
10
|
+
fs.mkdirSync(stateDir(), { recursive: true, mode: 0o700 });
|
|
11
|
+
fs.writeFileSync(file(), token + '\n', { mode: 0o600 });
|
|
12
|
+
return token;
|
|
13
|
+
};
|
|
14
|
+
/** The token in use: the one kept, else a new one. */
|
|
15
|
+
export function pageToken() {
|
|
16
|
+
if (current)
|
|
17
|
+
return current;
|
|
18
|
+
try {
|
|
19
|
+
const kept = fs.readFileSync(file(), 'utf8').trim();
|
|
20
|
+
if (/^[0-9a-f]{48}$/.test(kept))
|
|
21
|
+
return (current = kept);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// The first start on this Mac.
|
|
25
|
+
}
|
|
26
|
+
return (current = keep(crypto.randomBytes(24).toString('hex')));
|
|
27
|
+
}
|
|
28
|
+
/** A new token: the page's old address stops working at once. */
|
|
29
|
+
export function newToken() {
|
|
30
|
+
return (current = keep(crypto.randomBytes(24).toString('hex')));
|
|
31
|
+
}
|
|
32
|
+
/** The page's address with the token in use, kept where `koppler canvas` finds it. */
|
|
33
|
+
export function writePageUrl(port) {
|
|
34
|
+
const page = `http://127.0.0.1:${port}/s/${pageToken()}/`;
|
|
35
|
+
fs.writeFileSync(path.join(tempDir(), 'canvas-url'), page + '\n', { mode: 0o600 });
|
|
36
|
+
return page;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/server/token.ts"],"names":[],"mappings":"AAAA,qHAAqH;AACrH,2DAA2D;AAC3D,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,cAAc,CAAC,CAAC;AACzD,IAAI,OAAO,GAAkB,IAAI,CAAC;AAElC,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,EAAE;IAC7B,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3D,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,KAAK,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,sDAAsD;AACtD,MAAM,UAAU,SAAS;IACvB,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAC5B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QACpD,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,+BAA+B;IACjC,CAAC;IACD,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,QAAQ;IACtB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,IAAI,GAAG,oBAAoB,IAAI,MAAM,SAAS,EAAE,GAAG,CAAC;IAC1D,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnF,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// The requests no agent session has taken yet, as the canvas lists them, and dropping one of them.
|
|
2
|
+
import crypto from 'node:crypto';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { readStack } from "../data.js";
|
|
6
|
+
import { appendEvent, runs } from "../engine/history.js";
|
|
7
|
+
import { tempDir } from "../paths.js";
|
|
8
|
+
const PROMPTS = path.join(tempDir(), 'prompts.jsonl');
|
|
9
|
+
/** A value from the queue as text, when it is text. */
|
|
10
|
+
const text = (value) => (typeof value === 'string' ? value : '');
|
|
11
|
+
const keyOf = (line) => crypto.createHash('sha1').update(line).digest('hex').slice(0, 12);
|
|
12
|
+
const lines = () => {
|
|
13
|
+
try {
|
|
14
|
+
return fs.readFileSync(PROMPTS, 'utf8').split('\n').filter(Boolean);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const parsed = (line) => {
|
|
21
|
+
try {
|
|
22
|
+
const { tag, at, data } = JSON.parse(line);
|
|
23
|
+
return { tag: text(tag), at: text(at) || text(data?.['at']), data: data ?? {} };
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
/** What a request asks for, in the words the canvas uses for it. */
|
|
30
|
+
function describe(tag, data) {
|
|
31
|
+
const apps = readStack()?.apps ?? {};
|
|
32
|
+
const name = (id) => apps[text(id)]?.name ?? text(id);
|
|
33
|
+
const env = text(data['env']).toUpperCase();
|
|
34
|
+
const nodes = Array.isArray(data['nodes']) ? data['nodes'] : [];
|
|
35
|
+
const on = nodes.map(node => name(node.id)).join(', ');
|
|
36
|
+
const failures = Array.isArray(data['failures']) ? data['failures'] : [];
|
|
37
|
+
switch (tag) {
|
|
38
|
+
case 'koppler':
|
|
39
|
+
return `${data['mode'] === 'manual' ? 'Checklist for' : 'Run on'} ${env}${on ? `: ${on}` : ''}`;
|
|
40
|
+
case 'koppler-stop':
|
|
41
|
+
return data['switchTo'] ? 'Stop and revert, then switch stacks' : 'Stop and revert';
|
|
42
|
+
case 'koppler-fix':
|
|
43
|
+
return `Fix ${failures.map(one => text(one.connection)).join(', ') || 'what the Flow check found'}`;
|
|
44
|
+
case 'koppler-facts':
|
|
45
|
+
return data['app'] ? `Fill in ${name(data['app'])}'s settings` : `Find the ${env} facts the stack misses`;
|
|
46
|
+
case 'koppler-reply':
|
|
47
|
+
return 'Your answer to a question';
|
|
48
|
+
case 'koppler-review':
|
|
49
|
+
return 'Review of the last session';
|
|
50
|
+
default:
|
|
51
|
+
return 'A request for the agent';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export const waiting = () => lines().flatMap(line => {
|
|
55
|
+
const prompt = parsed(line);
|
|
56
|
+
return prompt
|
|
57
|
+
? [{ key: keyOf(line), tag: prompt.tag, at: prompt.at, what: describe(prompt.tag, prompt.data).slice(0, 200) }]
|
|
58
|
+
: [];
|
|
59
|
+
});
|
|
60
|
+
/**
|
|
61
|
+
* Takes one request out of the queue. A run or Stop that still waited for it is closed in the history, with the reason.
|
|
62
|
+
* ponytail: the queue is rewritten without the listener's lock; a session taking it in the same instant could still
|
|
63
|
+
* get the dropped request. Share the lock if that is ever seen.
|
|
64
|
+
*/
|
|
65
|
+
export function drop(key) {
|
|
66
|
+
const all = lines();
|
|
67
|
+
const gone = all.find(line => keyOf(line) === key);
|
|
68
|
+
if (!gone)
|
|
69
|
+
return false;
|
|
70
|
+
const rest = all.filter(line => line !== gone);
|
|
71
|
+
fs.writeFileSync(PROMPTS + '.tmp', rest.map(line => line + '\n').join(''), { mode: 0o600 });
|
|
72
|
+
fs.renameSync(PROMPTS + '.tmp', PROMPTS);
|
|
73
|
+
const id = parsed(gone)?.data['id'];
|
|
74
|
+
if (typeof id === 'string' &&
|
|
75
|
+
runs().some(run => run.id === id && (run.state === 'waiting' || run.state === 'applying')))
|
|
76
|
+
appendEvent(id, 'failed', 'Dropped from the canvas before an agent took it');
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=waiting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waiting.js","sourceRoot":"","sources":["../../src/server/waiting.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// The canvas server. Publishes temp/status.json plus live port state and log tails as temp/status.js, which the canvas
|
|
2
|
+
// re-loads on a timer, and runs a loopback-only, token-protected HTTP server: the standalone canvas page, layout
|
|
3
|
+
// autosaves (the board, state.json) and Send/Stop prompts (temp/prompts.jsonl).
|
|
4
|
+
// Usage: node status-watch.mjs [--once] (port 4747 or KOPPLER_PORT, token kept across restarts so the page URL in temp/canvas-url stays the same)
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import http from 'node:http';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { tempDir } from "./paths.js";
|
|
9
|
+
import { failRequest, gate, logged } from "./server/gate.js";
|
|
10
|
+
import { pageToken, writePageUrl } from "./server/token.js";
|
|
11
|
+
import { publish } from "./server/status.js";
|
|
12
|
+
const PORT = Number(process.env['KOPPLER_PORT']) || 4747;
|
|
13
|
+
const INTERVAL_MS = 1500;
|
|
14
|
+
/** Loopback only, token-protected. Serves the canvas standalone, takes layout autosaves and Send/Stop prompts. */
|
|
15
|
+
function startServer() {
|
|
16
|
+
const server = http.createServer((req, res) => {
|
|
17
|
+
try {
|
|
18
|
+
gate(req, res, pageToken(), String(server.address().port));
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
failRequest(res, error);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
server.on('error', (error) => {
|
|
25
|
+
const said = error.code === 'EADDRINUSE' ? `port ${String(PORT)} is in use (another watcher? koppler status)` : error.message;
|
|
26
|
+
console.error(`status-watch: ${said}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
});
|
|
29
|
+
server.listen(PORT, '127.0.0.1', () => {
|
|
30
|
+
console.log(`canvas: ${writePageUrl(String(server.address().port))}`);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (process.argv[1] && fs.realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
34
|
+
// With --once the status is published a single time and nothing is served.
|
|
35
|
+
const serving = !process.argv.includes('--once');
|
|
36
|
+
// On a machine where Koppler never ran, nothing has made its folder yet.
|
|
37
|
+
fs.mkdirSync(tempDir(), { recursive: true, mode: 0o700 });
|
|
38
|
+
// Said from the very first status on: a page that loaded can only have come from this server.
|
|
39
|
+
if (serving)
|
|
40
|
+
startServer();
|
|
41
|
+
// A status that cannot be put together is said, not the end of the canvas.
|
|
42
|
+
await publish(serving).catch(logged);
|
|
43
|
+
if (serving) {
|
|
44
|
+
// A slow publish is not started again on top of itself.
|
|
45
|
+
let publishing = false;
|
|
46
|
+
setInterval(() => {
|
|
47
|
+
if (publishing)
|
|
48
|
+
return;
|
|
49
|
+
publishing = true;
|
|
50
|
+
publish(serving)
|
|
51
|
+
.catch((error) => {
|
|
52
|
+
console.error(`status-watch: ${error?.message ?? String(error)}`);
|
|
53
|
+
})
|
|
54
|
+
.finally(() => {
|
|
55
|
+
publishing = false;
|
|
56
|
+
});
|
|
57
|
+
}, INTERVAL_MS);
|
|
58
|
+
// Whatever still slips through (a callback of a finished request) is logged; the canvas stays up.
|
|
59
|
+
process.on('uncaughtException', logged);
|
|
60
|
+
process.on('unhandledRejection', logged);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=status-watch.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-watch.mjs","sourceRoot":"","sources":["../src/status-watch.mts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,75 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koppler",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Run the part of your stack you need locally, wired together, while the rest keeps calling a deployed environment.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Ivan Yanowsky",
|
|
7
|
+
"homepage": "https://github.com/evan-mcgeek/koppler",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/evan-mcgeek/koppler.git",
|
|
11
|
+
"directory": "app"
|
|
12
|
+
},
|
|
13
|
+
"bugs": "https://github.com/evan-mcgeek/koppler/issues",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"local-development",
|
|
16
|
+
"microservices",
|
|
17
|
+
"dev-environment",
|
|
18
|
+
"canvas",
|
|
19
|
+
"dotnet",
|
|
20
|
+
"flutter",
|
|
21
|
+
"aws"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=22"
|
|
25
|
+
},
|
|
26
|
+
"os": [
|
|
27
|
+
"darwin",
|
|
28
|
+
"linux"
|
|
29
|
+
],
|
|
30
|
+
"bin": {
|
|
31
|
+
"koppler": "dist/koppler.mjs"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"bin",
|
|
36
|
+
"skills"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"test": "npm run build && vitest run && node --test --test-concurrency=1 test/*.test.mjs",
|
|
40
|
+
"test:canvas": "npm run build && playwright test",
|
|
41
|
+
"start": "node scripts/koppler-dev.mjs canvas",
|
|
42
|
+
"play": "npm run build && node scripts/play.mjs",
|
|
43
|
+
"lint": "eslint .",
|
|
44
|
+
"format": "prettier --write .",
|
|
45
|
+
"format:check": "prettier --check .",
|
|
46
|
+
"types": "tsc --noEmit && svelte-check --workspace canvas --tsconfig ./tsconfig.json --fail-on-warnings",
|
|
47
|
+
"build": "node scripts/build.mjs",
|
|
48
|
+
"prepack": "npm run build && node scripts/pack-skill.mjs",
|
|
49
|
+
"postpack": "node scripts/pack-skill.mjs --clean"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@eslint/js": "^10.0.1",
|
|
53
|
+
"@lucide/svelte": "^1.56.0",
|
|
54
|
+
"@playwright/test": "^1.64.0",
|
|
55
|
+
"@sveltejs/vite-plugin-svelte": "^7.3.1",
|
|
56
|
+
"@types/node": "^22.20.5",
|
|
57
|
+
"@xyflow/svelte": "^1.7.0",
|
|
58
|
+
"eslint": "^10.12.0",
|
|
59
|
+
"eslint-plugin-svelte": "^3.23.1",
|
|
60
|
+
"globals": "^17.13.0",
|
|
61
|
+
"prettier": "^3.9.10",
|
|
62
|
+
"prettier-plugin-svelte": "^3.5.2",
|
|
63
|
+
"simple-icons": "^16.35.0",
|
|
64
|
+
"svelte": "^5.57.2",
|
|
65
|
+
"svelte-check": "^4.7.6",
|
|
66
|
+
"typescript": "^6.0.3",
|
|
67
|
+
"typescript-eslint": "^8.71.1",
|
|
68
|
+
"vite": "^8.3.4",
|
|
69
|
+
"vitest": "^4.1.11"
|
|
70
|
+
},
|
|
71
|
+
"type": "module",
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"zod": "^4.6.5"
|
|
74
|
+
}
|
|
75
|
+
}
|