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,278 @@
|
|
|
1
|
+
// Goes through every stack app's clone and reports the ports it listens on locally, its calls, port conflicts and gaps
|
|
2
|
+
// against stack.json. Suggestions go to temp/stack.suggestions.json; the shared stack is never changed.
|
|
3
|
+
// Usage: koppler discover
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { table } from "../cli/output.js";
|
|
7
|
+
import { fail } from "../failure.js";
|
|
8
|
+
import { frameworkOf } from "../core/frameworks.js";
|
|
9
|
+
import { defaultPort, detect, of as kindOf } from "../core/kinds.js";
|
|
10
|
+
import { describePlan, planTunnels } from "../core/ports.js";
|
|
11
|
+
import { readClones, readStack } from "../data.js";
|
|
12
|
+
import { tempDir } from "../paths.js";
|
|
13
|
+
import { hostsByApp } from "./calls.js";
|
|
14
|
+
import { writeJson } from "../json-files.js";
|
|
15
|
+
const SKIP = new Set([
|
|
16
|
+
'node_modules',
|
|
17
|
+
'.git',
|
|
18
|
+
'bin',
|
|
19
|
+
'obj',
|
|
20
|
+
'build',
|
|
21
|
+
'dist',
|
|
22
|
+
'.dart_tool',
|
|
23
|
+
'Pods',
|
|
24
|
+
'coverage',
|
|
25
|
+
'.next',
|
|
26
|
+
'vendor',
|
|
27
|
+
'target',
|
|
28
|
+
]);
|
|
29
|
+
const read = (file) => {
|
|
30
|
+
try {
|
|
31
|
+
return fs.readFileSync(file, 'utf8');
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/** Files up to a few levels deep whose name matches, skipping build output and dependencies. */
|
|
38
|
+
export function findFiles(dir, test, depth = 5, found = []) {
|
|
39
|
+
let entries;
|
|
40
|
+
try {
|
|
41
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return found;
|
|
45
|
+
}
|
|
46
|
+
for (const entry of entries) {
|
|
47
|
+
const file = path.join(dir, entry.name);
|
|
48
|
+
if (entry.isDirectory()) {
|
|
49
|
+
if (depth > 0 && !SKIP.has(entry.name) && !entry.name.startsWith('.'))
|
|
50
|
+
findFiles(file, test, depth - 1, found);
|
|
51
|
+
}
|
|
52
|
+
else if (test(entry.name, file))
|
|
53
|
+
found.push(file);
|
|
54
|
+
}
|
|
55
|
+
return found;
|
|
56
|
+
}
|
|
57
|
+
const LISTENS = String.raw `(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\*|\+):(\d{2,5})`;
|
|
58
|
+
export const urlsIn = (text) => [...text.matchAll(new RegExp(`(https?)://${LISTENS}`, 'g'))].map(match => ({
|
|
59
|
+
scheme: match[1] ?? '',
|
|
60
|
+
port: Number(match[2]),
|
|
61
|
+
}));
|
|
62
|
+
export const portsIn = (text) => [
|
|
63
|
+
...new Set([...text.matchAll(new RegExp(LISTENS, 'g'))].map(match => Number(match[1]))),
|
|
64
|
+
];
|
|
65
|
+
/** .NET: every launch profile's applicationUrl. */
|
|
66
|
+
export function dotnetPorts(launchSettingsText) {
|
|
67
|
+
let profiles;
|
|
68
|
+
try {
|
|
69
|
+
const settings = JSON.parse(launchSettingsText.replace(/^\uFEFF/, ''));
|
|
70
|
+
profiles = settings.profiles ?? {};
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return portsIn(launchSettingsText).map(port => ({ port, where: 'launchSettings.json' }));
|
|
74
|
+
}
|
|
75
|
+
return Object.entries(profiles).flatMap(([name, profile]) => urlsIn(profile?.applicationUrl ?? '').map(url => ({ ...url, where: `profile ${name}` })));
|
|
76
|
+
}
|
|
77
|
+
/** Node: PORT in .env files, a dev server port in vite/serverless config, --port in package.json scripts. */
|
|
78
|
+
export function nodePorts(files) {
|
|
79
|
+
const out = [];
|
|
80
|
+
const add = (text, pattern, where) => {
|
|
81
|
+
for (const match of text.matchAll(pattern))
|
|
82
|
+
out.push({ port: Number(match[1]), where });
|
|
83
|
+
};
|
|
84
|
+
for (const [name, text] of Object.entries(files)) {
|
|
85
|
+
if (!text)
|
|
86
|
+
continue;
|
|
87
|
+
if (name.startsWith('.env'))
|
|
88
|
+
add(text, /^\s*PORT\s*=\s*(\d{2,5})/gm, `${name} PORT`);
|
|
89
|
+
if (/^vite\.config|^serverless\./.test(name))
|
|
90
|
+
add(text, /\b(?:port|httpPort)\s*[:=]\s*(\d{2,5})/g, name);
|
|
91
|
+
if (name !== 'package.json')
|
|
92
|
+
continue;
|
|
93
|
+
let scripts = {};
|
|
94
|
+
try {
|
|
95
|
+
scripts = JSON.parse(text).scripts ?? {};
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Not JSON: no scripts to read.
|
|
99
|
+
}
|
|
100
|
+
for (const [script, command] of Object.entries(scripts))
|
|
101
|
+
add(String(command), /(?:--port|-p|--httpPort)[ =](\d{2,5})/g, `npm run ${script}`);
|
|
102
|
+
}
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
/** A clone as the kind recipes see it (core/kinds): which files it has, their text, what a folder holds. */
|
|
106
|
+
export const repoFiles = (repo) => ({
|
|
107
|
+
has: file => fs.existsSync(path.join(repo, file)),
|
|
108
|
+
read: file => {
|
|
109
|
+
try {
|
|
110
|
+
const full = path.join(repo, file);
|
|
111
|
+
return fs.statSync(full).size < 512 * 1024 ? fs.readFileSync(full, 'utf8') : null;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
list: dir => {
|
|
118
|
+
try {
|
|
119
|
+
const entries = fs.readdirSync(path.join(repo, dir), { withFileTypes: true });
|
|
120
|
+
return entries.filter(entry => entry.isDirectory()).map(entry => entry.name);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
find: suffix => findFiles(repo, name => name.endsWith(suffix), 4).length > 0,
|
|
127
|
+
});
|
|
128
|
+
export const detectKind = (repo, stack) => detect(repoFiles(repo), stack);
|
|
129
|
+
const inProperties = (name, file) => name === 'launchSettings.json' && file.includes(`${path.sep}Properties${path.sep}`);
|
|
130
|
+
const NODE_FILE = /^package\.json$|^\.env|^vite\.config\.|^serverless\./;
|
|
131
|
+
const ENTRY_FILES = ['server', 'index', 'app', 'main'].flatMap(name => ['js', 'mjs', 'cjs', 'ts'].flatMap(ext => [`${name}.${ext}`, `src/${name}.${ext}`]));
|
|
132
|
+
/**
|
|
133
|
+
* The port a Node app's entry file falls back to, `process.env.PORT || 3000` or `.listen(3000)`: the file its start
|
|
134
|
+
* script runs, else its `main`, else the usual names.
|
|
135
|
+
*/
|
|
136
|
+
function entryPorts(repo, pkg) {
|
|
137
|
+
const run = Object.values(pkg?.scripts ?? {}).flatMap(command => [...command.matchAll(/\b(?:node|nodemon|tsx|ts-node)\s+(?:-\S+\s+)*([\w./-]+\.[cm]?[jt]s)\b/g)].map(found => found[1] ?? ''));
|
|
138
|
+
const main = typeof pkg?.main === 'string' ? [pkg.main] : [];
|
|
139
|
+
for (const name of new Set([...run, ...main, ...ENTRY_FILES])) {
|
|
140
|
+
if (!name || name.startsWith('/') || name.split('/').includes('..'))
|
|
141
|
+
continue;
|
|
142
|
+
const text = read(path.join(repo, name)) ?? '';
|
|
143
|
+
const port = /process\.env\.PORT\)?\s*(?:\|\||\?\?)\s*['"]?(\d{2,5})/.exec(text)?.[1] ??
|
|
144
|
+
/\.listen\(\s*(\d{2,5})\b/.exec(text)?.[1];
|
|
145
|
+
if (port)
|
|
146
|
+
return [{ port: Number(port), where: name }];
|
|
147
|
+
}
|
|
148
|
+
return [];
|
|
149
|
+
}
|
|
150
|
+
export function localPorts(repo, kind, stack) {
|
|
151
|
+
if (kind === 'dotnet')
|
|
152
|
+
return findFiles(repo, inProperties).flatMap(file => dotnetPorts(read(file) ?? '').map(found => ({ ...found, where: `${path.relative(repo, file)} ${found.where}` })));
|
|
153
|
+
if (kind === 'node' || kind === 'web') {
|
|
154
|
+
const names = fs.readdirSync(repo).filter(name => NODE_FILE.test(name));
|
|
155
|
+
const found = nodePorts(Object.fromEntries(names.map(name => [name, read(path.join(repo, name))])));
|
|
156
|
+
// A front end with no port set uses its framework's default.
|
|
157
|
+
let pkg = null;
|
|
158
|
+
try {
|
|
159
|
+
pkg = JSON.parse(read(path.join(repo, 'package.json')) ?? 'null');
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Not JSON: no framework to tell.
|
|
163
|
+
}
|
|
164
|
+
if (found.length)
|
|
165
|
+
return found;
|
|
166
|
+
const framework = kind === 'web' ? frameworkOf(pkg) : null;
|
|
167
|
+
if (framework)
|
|
168
|
+
return [{ port: framework.port, scheme: 'http', where: `${framework.name} default` }];
|
|
169
|
+
return entryPorts(repo, pkg);
|
|
170
|
+
}
|
|
171
|
+
const usual = kind ? defaultPort(kind, repoFiles(repo), stack) : null;
|
|
172
|
+
return usual
|
|
173
|
+
? [{ port: usual, scheme: 'http', where: `${kindOf({ kind: kind ?? undefined }, stack).label} default` }]
|
|
174
|
+
: [];
|
|
175
|
+
}
|
|
176
|
+
const portOf = (url) => {
|
|
177
|
+
try {
|
|
178
|
+
return Number(new URL(url ?? '').port) || null;
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
/** Ports that two different things want at once. A tunnel to one host is one thing, even when several apps need it. */
|
|
185
|
+
export function conflicts(apps) {
|
|
186
|
+
const owners = new Map();
|
|
187
|
+
const claim = (port, owner, label) => {
|
|
188
|
+
const claims = owners.get(port) ?? new Map();
|
|
189
|
+
claims.set(owner, [...(claims.get(owner) ?? []), label]);
|
|
190
|
+
owners.set(port, claims);
|
|
191
|
+
};
|
|
192
|
+
for (const app of apps) {
|
|
193
|
+
const own = app.stackPort ?? app.ports[0]?.port;
|
|
194
|
+
if (own)
|
|
195
|
+
claim(own, `app:${app.id}`, app.id);
|
|
196
|
+
for (const { tunnel, port } of app.tunnels)
|
|
197
|
+
if (port)
|
|
198
|
+
claim(port, `tunnel:${String(tunnel)}`, `tunnel to ${String(tunnel)} (for ${app.id})`);
|
|
199
|
+
}
|
|
200
|
+
// Two tunnels on one port are planned by core/ports (share, move or loopback); only clashes involving an app are
|
|
201
|
+
// reported here.
|
|
202
|
+
return [...owners]
|
|
203
|
+
.filter(([, claims]) => claims.size > 1 && [...claims.keys()].some(owner => owner.startsWith('app:')))
|
|
204
|
+
.map(([port, claims]) => ({ port, who: [...claims.values()].map(labels => labels.join(', ')) }));
|
|
205
|
+
}
|
|
206
|
+
export function investigate({ afterSync = false } = {}) {
|
|
207
|
+
const stack = readStack() ?? fail('no stack loaded (koppler init)');
|
|
208
|
+
const clones = readClones();
|
|
209
|
+
const found = stack.found ?? {};
|
|
210
|
+
const known = hostsByApp(stack);
|
|
211
|
+
const apps = Object.entries(stack.apps).map(([id, app]) => {
|
|
212
|
+
const repo = clones[id]?.path;
|
|
213
|
+
const kind = app.kind ?? (repo ? (detectKind(repo, stack) ?? undefined) : undefined);
|
|
214
|
+
return {
|
|
215
|
+
id,
|
|
216
|
+
name: app.name,
|
|
217
|
+
kind,
|
|
218
|
+
repo,
|
|
219
|
+
ports: repo ? localPorts(repo, kind, stack) : [],
|
|
220
|
+
tunnels: (app.prereqs ?? []).filter(need => need.tunnel && need.port),
|
|
221
|
+
stackPort: portOf(app.url),
|
|
222
|
+
stackUrl: app.url ?? null,
|
|
223
|
+
deployed: app.deployedUrl ?? null,
|
|
224
|
+
calls: Object.keys(app.consumes ?? {}),
|
|
225
|
+
found: Object.keys(found[id] ?? {}),
|
|
226
|
+
};
|
|
227
|
+
});
|
|
228
|
+
const portsOf = (app) => [...new Set(app.ports.map(found => found.port))];
|
|
229
|
+
const rows = apps.map(app => {
|
|
230
|
+
const listens = app.kind === 'flutter'
|
|
231
|
+
? '(app, calls out only)'
|
|
232
|
+
: portsOf(app).join(', ') || (app.repo ? 'none found' : 'not cloned');
|
|
233
|
+
const counted = [
|
|
234
|
+
app.calls.length && `${String(app.calls.length)} recorded`,
|
|
235
|
+
app.found.length && `${String(app.found.length)} found`,
|
|
236
|
+
];
|
|
237
|
+
const tunnels = app.tunnels.map(tunnel => tunnel.port).join(', ') || '-';
|
|
238
|
+
return [app.id, app.kind ?? '?', listens, app.stackPort ?? '-', tunnels, counted.filter(Boolean).join(', ') || '-'];
|
|
239
|
+
});
|
|
240
|
+
table([['APP', 'KIND', 'LISTENS ON', 'STACK PORT', 'TUNNELS', 'CALLS'], ...rows]);
|
|
241
|
+
const suggestions = {};
|
|
242
|
+
console.log('');
|
|
243
|
+
for (const clash of conflicts(apps))
|
|
244
|
+
console.log(`CONFLICT port ${String(clash.port)}: ${clash.who.join(', ')}`);
|
|
245
|
+
// Tunnels that clash when the apps needing them run together, and how koppler plan resolves it.
|
|
246
|
+
const needs = apps.flatMap(app => app.tunnels.flatMap(({ tunnel, port, env, connectsAs }) => tunnel && port ? [{ app: app.id, tunnel, port, env, connectsAs }] : []));
|
|
247
|
+
const clashing = new Set(needs
|
|
248
|
+
.filter(need => needs.some(other => other.port === need.port && other.tunnel !== need.tunnel))
|
|
249
|
+
.map(need => need.port));
|
|
250
|
+
for (const port of clashing) {
|
|
251
|
+
const plan = planTunnels(needs.filter(need => need.port === port));
|
|
252
|
+
const who = plan.map(tunnel => `${tunnel.host.split('.')[0] ?? ''} (${tunnel.apps.join(', ')})`);
|
|
253
|
+
console.log(`TUNNELS port ${String(port)}: ${who.join(' and ')} clash when run together`);
|
|
254
|
+
for (const line of describePlan(plan))
|
|
255
|
+
console.log(` RESOLVE ${line}`);
|
|
256
|
+
}
|
|
257
|
+
for (const app of apps) {
|
|
258
|
+
if (!app.repo || app.kind === 'flutter')
|
|
259
|
+
continue;
|
|
260
|
+
const ports = portsOf(app);
|
|
261
|
+
const [first] = app.ports;
|
|
262
|
+
if (!app.stackUrl && first) {
|
|
263
|
+
const url = `${first.scheme ?? 'http'}://localhost:${String(first.port)}/`;
|
|
264
|
+
(suggestions[app.id] ??= {})['url'] = url;
|
|
265
|
+
console.log(`SUGGEST ${app.id}.url = ${JSON.stringify(url)} (from ${first.where})`);
|
|
266
|
+
}
|
|
267
|
+
else if (app.stackPort && ports.length && !ports.includes(app.stackPort))
|
|
268
|
+
console.log(`MISMATCH ${app.id}: stack.json says port ${String(app.stackPort)}, the repo uses ${ports.join(', ')}`);
|
|
269
|
+
if (!afterSync && !known[app.id]?.size && kindOf(app, stack).serves)
|
|
270
|
+
console.log(`UNKNOWN ${app.id}: no deployed address in stack.json, so calls to it cannot be found`);
|
|
271
|
+
for (const callee of app.found)
|
|
272
|
+
console.log(`FOUND ${app.id} -> ${callee}: not in stack.json (koppler sync shows where)`);
|
|
273
|
+
}
|
|
274
|
+
const file = path.join(tempDir(), 'stack.suggestions.json');
|
|
275
|
+
writeJson(file, { at: new Date().toISOString(), apps, suggestions });
|
|
276
|
+
console.log(`\nFull results and suggestions: ${file}`);
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=investigate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"investigate.js","sourceRoot":"","sources":["../../src/engine/investigate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// Local libraries: an app uses your clone of a library it depends on instead of the published one, without a change to
|
|
2
|
+
// any tracked file, and back again on Stop.
|
|
3
|
+
// Dart / Flutter: a pubspec_overrides.yaml in the app with a path override (Dart reads it on top of pubspec.yaml).
|
|
4
|
+
// npm: `npm install --no-save <path>` (package.json and the lockfile stay as they are; Stop reinstalls from them).
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { spawnSync } from 'node:child_process';
|
|
8
|
+
import { readJson } from "../json-files.js";
|
|
9
|
+
import { readActions, updateActions } from "./actions.js";
|
|
10
|
+
const read = (file) => {
|
|
11
|
+
try {
|
|
12
|
+
return fs.readFileSync(file, 'utf8');
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const packageJson = (dir) => readJson(path.join(dir, 'package.json'));
|
|
19
|
+
/** The package a clone publishes: its Dart package name or its npm name. */
|
|
20
|
+
export function packageOf(dir) {
|
|
21
|
+
const dart = /^name:\s*([\w]+)\s*$/m.exec(read(path.join(dir, 'pubspec.yaml')) ?? '')?.[1];
|
|
22
|
+
if (dart)
|
|
23
|
+
return { name: dart, ecosystem: 'dart' };
|
|
24
|
+
const npm = packageJson(dir)?.name;
|
|
25
|
+
return npm ? { name: npm, ecosystem: 'npm' } : null;
|
|
26
|
+
}
|
|
27
|
+
/** The packages an app depends on, by name. */
|
|
28
|
+
export function dependenciesOf(dir) {
|
|
29
|
+
const pubspec = read(path.join(dir, 'pubspec.yaml'));
|
|
30
|
+
if (pubspec) {
|
|
31
|
+
const names = new Set();
|
|
32
|
+
for (const section of ['dependencies', 'dev_dependencies', 'dependency_overrides']) {
|
|
33
|
+
const block = new RegExp(`^${section}:\\s*\\n((?:[ \\t]+.*\\n?|\\s*\\n)*)`, 'm').exec(pubspec)?.[1] ?? '';
|
|
34
|
+
for (const entry of block.matchAll(/^ {2}([\w]+):/gm))
|
|
35
|
+
if (entry[1])
|
|
36
|
+
names.add(entry[1]);
|
|
37
|
+
}
|
|
38
|
+
return { ecosystem: 'dart', names: [...names] };
|
|
39
|
+
}
|
|
40
|
+
const pkg = packageJson(dir);
|
|
41
|
+
return pkg ? { ecosystem: 'npm', names: Object.keys({ ...pkg.dependencies, ...pkg.devDependencies }) } : null;
|
|
42
|
+
}
|
|
43
|
+
/** The libraries an app can use locally: clones that publish a package it depends on (other than itself). */
|
|
44
|
+
export function librariesFor(appDir, clones) {
|
|
45
|
+
const deps = dependenciesOf(appDir);
|
|
46
|
+
if (!deps)
|
|
47
|
+
return [];
|
|
48
|
+
return clones
|
|
49
|
+
.filter(clone => clone.path !== appDir && clone.ecosystem === deps.ecosystem && deps.names.includes(clone.name))
|
|
50
|
+
.map(({ name, path: clonePath, ecosystem }) => ({ name, path: clonePath, ecosystem }));
|
|
51
|
+
}
|
|
52
|
+
const OVERRIDES = 'pubspec_overrides.yaml';
|
|
53
|
+
const MARK = '# Written by Koppler for a local run; Stop removes it.';
|
|
54
|
+
const SECTION = /^dependency_overrides:\s*$/m;
|
|
55
|
+
/** The overrides file with the local libraries in it, keeping what the user had there. */
|
|
56
|
+
function withOverrides(before, libraries) {
|
|
57
|
+
const lines = libraries.map(library => ` ${library.name}:\n path: ${library.path}`).join('\n');
|
|
58
|
+
// A file Koppler wrote on an earlier run is replaced; the user's own is added to.
|
|
59
|
+
const own = before && !before.includes(MARK) ? before : null;
|
|
60
|
+
if (!own)
|
|
61
|
+
return `${MARK}\ndependency_overrides:\n${lines}\n`;
|
|
62
|
+
return SECTION.test(own)
|
|
63
|
+
? own.replace(SECTION, () => `dependency_overrides:\n${lines}`)
|
|
64
|
+
: `${own.trimEnd()}\n\ndependency_overrides:\n${lines}\n`;
|
|
65
|
+
}
|
|
66
|
+
/** Points the app at the local libraries; returns the action-log entries that undo it. */
|
|
67
|
+
export function link(appId, appDir, libraries, logFile) {
|
|
68
|
+
const log = readActions(logFile);
|
|
69
|
+
const done = [];
|
|
70
|
+
// Each change is logged before it is made, so a crash part-way still leaves Stop an entry to undo.
|
|
71
|
+
const record = (entry) => {
|
|
72
|
+
updateActions(logFile, list => void list.push(entry));
|
|
73
|
+
done.push(entry);
|
|
74
|
+
};
|
|
75
|
+
const dart = libraries.filter(library => library.ecosystem === 'dart');
|
|
76
|
+
const npm = libraries.filter(library => library.ecosystem === 'npm');
|
|
77
|
+
if (dart.length > 0) {
|
|
78
|
+
const file = path.join(appDir, OVERRIDES);
|
|
79
|
+
const before = read(file);
|
|
80
|
+
const text = withOverrides(before, dart);
|
|
81
|
+
const logged = (action) => action.kind === 'file' && action.file === file;
|
|
82
|
+
// Stop puts back the file as it was before the first change of this run, if it still holds what Koppler wrote
|
|
83
|
+
// last.
|
|
84
|
+
if (!log.some(logged))
|
|
85
|
+
record({ kind: 'file', app: appId, file, before, after: text });
|
|
86
|
+
else
|
|
87
|
+
updateActions(logFile, list => {
|
|
88
|
+
const entry = list.find(logged);
|
|
89
|
+
if (entry)
|
|
90
|
+
entry.after = text;
|
|
91
|
+
});
|
|
92
|
+
fs.writeFileSync(file, text);
|
|
93
|
+
}
|
|
94
|
+
if (npm.length > 0) {
|
|
95
|
+
const names = npm.map(library => library.name);
|
|
96
|
+
record({ kind: 'npm-local', app: appId, repo: appDir, packages: names });
|
|
97
|
+
const installed = spawnSync('npm', ['install', '--no-save', ...npm.map(library => library.path)], {
|
|
98
|
+
cwd: appDir,
|
|
99
|
+
encoding: 'utf8',
|
|
100
|
+
});
|
|
101
|
+
if (installed.status !== 0) {
|
|
102
|
+
const why = installed.stderr.trim().split('\n').pop() ?? '';
|
|
103
|
+
throw new Error(`npm could not install the local ${names.join(', ')}: ${why}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return done;
|
|
107
|
+
}
|
|
108
|
+
/** Undoes one entry from link(); returns what happened, in words. Throws when it would overwrite the user's edits. */
|
|
109
|
+
export function unlink(entry) {
|
|
110
|
+
if (entry.kind === 'npm-local') {
|
|
111
|
+
const installed = spawnSync('npm', ['install'], { cwd: entry.repo, encoding: 'utf8' });
|
|
112
|
+
if (installed.status !== 0)
|
|
113
|
+
throw new Error(`npm install failed in ${entry.repo}`);
|
|
114
|
+
return `published ${entry.packages.join(', ')} back`;
|
|
115
|
+
}
|
|
116
|
+
const name = path.basename(entry.file);
|
|
117
|
+
const before = entry.before ?? null;
|
|
118
|
+
const now = read(entry.file);
|
|
119
|
+
if (now === before)
|
|
120
|
+
return `${name} already as before`;
|
|
121
|
+
if (entry.after !== undefined && now !== entry.after)
|
|
122
|
+
throw new Error(`${name} changed since Koppler wrote it; take Koppler's lines out by hand`);
|
|
123
|
+
if (before === null)
|
|
124
|
+
fs.rmSync(entry.file, { force: true });
|
|
125
|
+
else
|
|
126
|
+
fs.writeFileSync(entry.file, before);
|
|
127
|
+
return `${name} ${before === null ? 'removed' : 'restored'}`;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=libraries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"libraries.js","sourceRoot":"","sources":["../../src/engine/libraries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// Stacks used straight from GitHub. Koppler keeps a copy in the private config; what it learns goes into that copy,
|
|
2
|
+
// shows as changes not in the shared stack yet, and reaches the team only through a pull request the user opens.
|
|
3
|
+
// Next to the copy, .source.json holds the link and `base`: the shared file as it was when last fetched.
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { validateStack } from "../core/stack.js";
|
|
6
|
+
import { fileUrl, githubFile, proposeFile, readFile } from "../github.js";
|
|
7
|
+
import { setStack } from "./stacks.js";
|
|
8
|
+
import { configDir } from "../paths.js";
|
|
9
|
+
import { readJson, writeJson } from "../json-files.js";
|
|
10
|
+
const SOURCE = '.source.json';
|
|
11
|
+
const NOT_LINKED = { error: 'That stack is not linked to GitHub.' };
|
|
12
|
+
const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
|
|
13
|
+
const stamp = () => new Date().toISOString();
|
|
14
|
+
export const sourceOf = (dir) => readJson(path.join(dir, SOURCE));
|
|
15
|
+
const copyIn = (dir) => readJson(path.join(dir, 'stack.json'));
|
|
16
|
+
async function fetchStack(file, read = readFile) {
|
|
17
|
+
const text = await read(file);
|
|
18
|
+
if (text === null)
|
|
19
|
+
return { error: 'Could not read that file. Check the link, and that gh is signed in for a private repo.' };
|
|
20
|
+
let stack;
|
|
21
|
+
try {
|
|
22
|
+
stack = JSON.parse(text);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return { error: 'That file is not JSON.' };
|
|
26
|
+
}
|
|
27
|
+
const errors = validateStack(stack);
|
|
28
|
+
return errors.length ? { error: `That is not a stack Koppler can use: ${errors.slice(0, 3).join('; ')}` } : { stack };
|
|
29
|
+
}
|
|
30
|
+
/** Links a stack on GitHub and makes it the one in use. */
|
|
31
|
+
export async function linkStack(link, { config, save, read } = {}) {
|
|
32
|
+
const file = githubFile(link);
|
|
33
|
+
if (!file)
|
|
34
|
+
return {
|
|
35
|
+
error: 'Paste a link to a stack.json on GitHub, e.g. https://github.com/<owner>/<repo>/blob/main/stacks/<name>/stack.json',
|
|
36
|
+
};
|
|
37
|
+
const got = await fetchStack(file, read);
|
|
38
|
+
if (got.error !== undefined)
|
|
39
|
+
return got;
|
|
40
|
+
const folder = path.basename(path.dirname(file.path)) || 'stack';
|
|
41
|
+
const slug = `${file.owner}-${file.repo}-${folder}`.toLowerCase().replace(/[^a-z0-9]+/g, '-');
|
|
42
|
+
const dir = path.join(configDir(), 'stacks', slug);
|
|
43
|
+
const old = sourceOf(dir);
|
|
44
|
+
if (old && old.url !== fileUrl(file))
|
|
45
|
+
return { error: `A different linked stack already uses the name ${slug}.` };
|
|
46
|
+
if (!old) {
|
|
47
|
+
writeJson(path.join(dir, 'stack.json'), got.stack);
|
|
48
|
+
writeJson(path.join(dir, SOURCE), { url: fileUrl(file), file, base: got.stack, fetchedAt: stamp() });
|
|
49
|
+
}
|
|
50
|
+
const configFile = path.join(configDir(), 'config.json');
|
|
51
|
+
setStack(config ?? readJson(configFile) ?? {}, dir, save ??
|
|
52
|
+
(next => {
|
|
53
|
+
writeJson(configFile, next);
|
|
54
|
+
}));
|
|
55
|
+
return { stack: dir, name: got.stack.name };
|
|
56
|
+
}
|
|
57
|
+
/** What differs between the shared stack as last fetched and the copy here, in plain lines. */
|
|
58
|
+
export function changes(base, local) {
|
|
59
|
+
const out = [];
|
|
60
|
+
const name = (stack, id) => stack.apps?.[id]?.['name'] ?? id;
|
|
61
|
+
const before = base.apps ?? {};
|
|
62
|
+
const after = local.apps ?? {};
|
|
63
|
+
for (const id of Object.keys(after))
|
|
64
|
+
if (!before[id])
|
|
65
|
+
out.push(`added ${name(local, id)}`);
|
|
66
|
+
for (const id of Object.keys(before))
|
|
67
|
+
if (!after[id])
|
|
68
|
+
out.push(`removed ${name(base, id)}`);
|
|
69
|
+
for (const [id, now] of Object.entries(after)) {
|
|
70
|
+
const was = before[id];
|
|
71
|
+
if (!was || !now || same(was, now))
|
|
72
|
+
continue;
|
|
73
|
+
const keys = [...new Set([...Object.keys(was), ...Object.keys(now)])].filter(key => !same(was[key], now[key]));
|
|
74
|
+
out.push(`changed ${name(local, id)}: ${keys.join(', ')}`);
|
|
75
|
+
}
|
|
76
|
+
for (const key of new Set([...Object.keys(base), ...Object.keys(local)]))
|
|
77
|
+
if (key !== 'apps' && !same(base[key], local[key]))
|
|
78
|
+
out.push(`changed ${key}`);
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
export function linkedStatus(dir) {
|
|
82
|
+
const source = sourceOf(dir);
|
|
83
|
+
const local = copyIn(dir);
|
|
84
|
+
if (!source || !local)
|
|
85
|
+
return null;
|
|
86
|
+
return {
|
|
87
|
+
url: source.url,
|
|
88
|
+
fetchedAt: source.fetchedAt,
|
|
89
|
+
changes: changes(source.base, local),
|
|
90
|
+
...(source.pr && { pr: source.pr }),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Brings in what changed on GitHub. A copy with changes of its own is only updated when nothing would be lost. */
|
|
94
|
+
export async function updateStack(dir, { read } = {}) {
|
|
95
|
+
const source = sourceOf(dir);
|
|
96
|
+
const local = copyIn(dir);
|
|
97
|
+
if (!source)
|
|
98
|
+
return NOT_LINKED;
|
|
99
|
+
const got = await fetchStack(source.file, read);
|
|
100
|
+
if (got.error !== undefined)
|
|
101
|
+
return got;
|
|
102
|
+
const remote = got.stack;
|
|
103
|
+
const keep = (next) => {
|
|
104
|
+
writeJson(path.join(dir, SOURCE), { ...source, ...next, fetchedAt: stamp() });
|
|
105
|
+
};
|
|
106
|
+
if (same(remote, source.base)) {
|
|
107
|
+
keep({});
|
|
108
|
+
return { updated: false, message: 'Already up to date.' };
|
|
109
|
+
}
|
|
110
|
+
const merged = same(local, remote);
|
|
111
|
+
if (same(local, source.base) || merged) {
|
|
112
|
+
writeJson(path.join(dir, 'stack.json'), remote);
|
|
113
|
+
keep({ base: remote, pr: merged ? undefined : source.pr });
|
|
114
|
+
return { updated: true, message: merged ? 'Your changes are in the shared stack now.' : 'Updated from GitHub.' };
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
error: 'The shared stack changed on GitHub, and this copy has changes of its own. Open a pull request with yours first, or discard them, then check again.',
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
export function discardChanges(dir) {
|
|
121
|
+
const source = sourceOf(dir);
|
|
122
|
+
if (!source)
|
|
123
|
+
return NOT_LINKED;
|
|
124
|
+
writeJson(path.join(dir, 'stack.json'), source.base);
|
|
125
|
+
return { discarded: true };
|
|
126
|
+
}
|
|
127
|
+
/** A pull request with this copy's changes. Outward-facing: only from the user's own confirmation on the canvas or in the terminal. */
|
|
128
|
+
export async function proposeChanges(dir, { propose = proposeFile } = {}) {
|
|
129
|
+
const source = sourceOf(dir);
|
|
130
|
+
const local = copyIn(dir);
|
|
131
|
+
if (!source || !local)
|
|
132
|
+
return NOT_LINKED;
|
|
133
|
+
const list = changes(source.base, local);
|
|
134
|
+
if (!list.length)
|
|
135
|
+
return { error: 'There is nothing to share: this copy matches the shared stack.' };
|
|
136
|
+
const slug = (local.name ?? 'stack').toLowerCase().replace(/[^a-z0-9]+/g, '-');
|
|
137
|
+
const result = await propose(source.file, JSON.stringify(local, null, 2) + '\n', {
|
|
138
|
+
branch: `koppler/${slug}-${Date.now().toString(36)}`,
|
|
139
|
+
title: `${String(local.name)}: ${String(list.length)} ${list.length === 1 ? 'change' : 'changes'} from Koppler`,
|
|
140
|
+
body: `What Koppler learned while running these apps locally:\n\n${list.map(line => `- ${line}`).join('\n')}\n\nNames and addresses only; no secret values.`,
|
|
141
|
+
});
|
|
142
|
+
if (result.error === undefined)
|
|
143
|
+
writeJson(path.join(dir, SOURCE), { ...source, pr: result.url });
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=linked.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linked.js","sourceRoot":"","sources":["../../src/engine/linked.ts"],"names":[],"mappings":"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"}
|