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.
Files changed (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +101 -2
  3. package/bin/run-logged +16 -0
  4. package/bin/secret-list +7 -0
  5. package/bin/secret-psql +41 -0
  6. package/bin/secret-set +17 -0
  7. package/bin/secret-store +82 -0
  8. package/bin/secret-test +10 -0
  9. package/bin/with-secrets +25 -0
  10. package/dist/.built +1 -0
  11. package/dist/cli/agent.js +144 -0
  12. package/dist/cli/agent.js.map +1 -0
  13. package/dist/cli/doctor.js +173 -0
  14. package/dist/cli/doctor.js.map +1 -0
  15. package/dist/cli/mcp.js +204 -0
  16. package/dist/cli/mcp.js.map +1 -0
  17. package/dist/cli/output.js +37 -0
  18. package/dist/cli/output.js.map +1 -0
  19. package/dist/cli/records.js +121 -0
  20. package/dist/cli/records.js.map +1 -0
  21. package/dist/cli/running.js +270 -0
  22. package/dist/cli/running.js.map +1 -0
  23. package/dist/cli/shell.js +43 -0
  24. package/dist/cli/shell.js.map +1 -0
  25. package/dist/cli/wait.js +59 -0
  26. package/dist/cli/wait.js.map +1 -0
  27. package/dist/core/addresses.js +55 -0
  28. package/dist/core/addresses.js.map +1 -0
  29. package/dist/core/arrange.js +329 -0
  30. package/dist/core/arrange.js.map +1 -0
  31. package/dist/core/cables.js +158 -0
  32. package/dist/core/cables.js.map +1 -0
  33. package/dist/core/expressions.js +72 -0
  34. package/dist/core/expressions.js.map +1 -0
  35. package/dist/core/frameworks.js +13 -0
  36. package/dist/core/frameworks.js.map +1 -0
  37. package/dist/core/kinds.js +244 -0
  38. package/dist/core/kinds.js.map +1 -0
  39. package/dist/core/launch.js +181 -0
  40. package/dist/core/launch.js.map +1 -0
  41. package/dist/core/logfmt.js +144 -0
  42. package/dist/core/logfmt.js.map +1 -0
  43. package/dist/core/mock.js +27 -0
  44. package/dist/core/mock.js.map +1 -0
  45. package/dist/core/plan.js +147 -0
  46. package/dist/core/plan.js.map +1 -0
  47. package/dist/core/ports.js +155 -0
  48. package/dist/core/ports.js.map +1 -0
  49. package/dist/core/presets.js +186 -0
  50. package/dist/core/presets.js.map +1 -0
  51. package/dist/core/secret-types.js +3 -0
  52. package/dist/core/secret-types.js.map +1 -0
  53. package/dist/core/sign-in.js +30 -0
  54. package/dist/core/sign-in.js.map +1 -0
  55. package/dist/core/stack-path.js +64 -0
  56. package/dist/core/stack-path.js.map +1 -0
  57. package/dist/core/stack.js +509 -0
  58. package/dist/core/stack.js.map +1 -0
  59. package/dist/core/terraform.js +393 -0
  60. package/dist/core/terraform.js.map +1 -0
  61. package/dist/data.js +37 -0
  62. package/dist/data.js.map +1 -0
  63. package/dist/engine/actions.js +99 -0
  64. package/dist/engine/actions.js.map +1 -0
  65. package/dist/engine/app-commands.js +106 -0
  66. package/dist/engine/app-commands.js.map +1 -0
  67. package/dist/engine/app-start.js +167 -0
  68. package/dist/engine/app-start.js.map +1 -0
  69. package/dist/engine/app-state.js +43 -0
  70. package/dist/engine/app-state.js.map +1 -0
  71. package/dist/engine/boards.js +219 -0
  72. package/dist/engine/boards.js.map +1 -0
  73. package/dist/engine/branch.js +194 -0
  74. package/dist/engine/branch.js.map +1 -0
  75. package/dist/engine/browser-console.js +45 -0
  76. package/dist/engine/browser-console.js.map +1 -0
  77. package/dist/engine/calls.js +97 -0
  78. package/dist/engine/calls.js.map +1 -0
  79. package/dist/engine/checks.js +270 -0
  80. package/dist/engine/checks.js.map +1 -0
  81. package/dist/engine/clones.js +67 -0
  82. package/dist/engine/clones.js.map +1 -0
  83. package/dist/engine/config.js +26 -0
  84. package/dist/engine/config.js.map +1 -0
  85. package/dist/engine/deployed.js +488 -0
  86. package/dist/engine/deployed.js.map +1 -0
  87. package/dist/engine/devices.js +81 -0
  88. package/dist/engine/devices.js.map +1 -0
  89. package/dist/engine/discover.js +236 -0
  90. package/dist/engine/discover.js.map +1 -0
  91. package/dist/engine/down.js +253 -0
  92. package/dist/engine/down.js.map +1 -0
  93. package/dist/engine/history.js +215 -0
  94. package/dist/engine/history.js.map +1 -0
  95. package/dist/engine/investigate.js +278 -0
  96. package/dist/engine/investigate.js.map +1 -0
  97. package/dist/engine/libraries.js +129 -0
  98. package/dist/engine/libraries.js.map +1 -0
  99. package/dist/engine/linked.js +146 -0
  100. package/dist/engine/linked.js.map +1 -0
  101. package/dist/engine/listen.js +223 -0
  102. package/dist/engine/listen.js.map +1 -0
  103. package/dist/engine/locks.js +38 -0
  104. package/dist/engine/locks.js.map +1 -0
  105. package/dist/engine/messages.js +177 -0
  106. package/dist/engine/messages.js.map +1 -0
  107. package/dist/engine/needs.js +363 -0
  108. package/dist/engine/needs.js.map +1 -0
  109. package/dist/engine/processes.js +350 -0
  110. package/dist/engine/processes.js.map +1 -0
  111. package/dist/engine/query.js +241 -0
  112. package/dist/engine/query.js.map +1 -0
  113. package/dist/engine/queues.js +100 -0
  114. package/dist/engine/queues.js.map +1 -0
  115. package/dist/engine/recipes.js +248 -0
  116. package/dist/engine/recipes.js.map +1 -0
  117. package/dist/engine/reload.js +32 -0
  118. package/dist/engine/reload.js.map +1 -0
  119. package/dist/engine/repos.js +214 -0
  120. package/dist/engine/repos.js.map +1 -0
  121. package/dist/engine/research.js +134 -0
  122. package/dist/engine/research.js.map +1 -0
  123. package/dist/engine/run-logs.js +79 -0
  124. package/dist/engine/run-logs.js.map +1 -0
  125. package/dist/engine/run.js +54 -0
  126. package/dist/engine/run.js.map +1 -0
  127. package/dist/engine/runs.js +223 -0
  128. package/dist/engine/runs.js.map +1 -0
  129. package/dist/engine/session.js +130 -0
  130. package/dist/engine/session.js.map +1 -0
  131. package/dist/engine/share.js +124 -0
  132. package/dist/engine/share.js.map +1 -0
  133. package/dist/engine/stack-file.js +206 -0
  134. package/dist/engine/stack-file.js.map +1 -0
  135. package/dist/engine/stack-share.js +86 -0
  136. package/dist/engine/stack-share.js.map +1 -0
  137. package/dist/engine/stacks.js +143 -0
  138. package/dist/engine/stacks.js.map +1 -0
  139. package/dist/engine/sync.js +214 -0
  140. package/dist/engine/sync.js.map +1 -0
  141. package/dist/engine/traces.js +65 -0
  142. package/dist/engine/traces.js.map +1 -0
  143. package/dist/engine/up.js +621 -0
  144. package/dist/engine/up.js.map +1 -0
  145. package/dist/engine/watch.js +71 -0
  146. package/dist/engine/watch.js.map +1 -0
  147. package/dist/engine/wire.js +120 -0
  148. package/dist/engine/wire.js.map +1 -0
  149. package/dist/failure.js +16 -0
  150. package/dist/failure.js.map +1 -0
  151. package/dist/github.js +95 -0
  152. package/dist/github.js.map +1 -0
  153. package/dist/ids.js +6 -0
  154. package/dist/ids.js.map +1 -0
  155. package/dist/json-files.js +36 -0
  156. package/dist/json-files.js.map +1 -0
  157. package/dist/koppler.mjs +840 -0
  158. package/dist/koppler.mjs.map +1 -0
  159. package/dist/lambda-local.mjs +250 -0
  160. package/dist/lambda-local.mjs.map +1 -0
  161. package/dist/lambda-secrets-proxy.go +31 -0
  162. package/dist/mock-server.mjs +23 -0
  163. package/dist/mock-server.mjs.map +1 -0
  164. package/dist/page/assets/JetBrainsMono-cyrillic-D2jMJ_bk.woff2 +0 -0
  165. package/dist/page/assets/JetBrainsMono-greek-D2nYnAec.woff2 +0 -0
  166. package/dist/page/assets/JetBrainsMono-latin-Db4Uuiha.woff2 +0 -0
  167. package/dist/page/assets/JetBrainsMono-latin-ext-Bnd2h4Br.woff2 +0 -0
  168. package/dist/page/assets/JetBrainsMono-vietnamese-CNlsqbWb.woff2 +0 -0
  169. package/dist/page/assets/SchibstedGrotesk-latin-DxefFeRw.woff2 +0 -0
  170. package/dist/page/assets/SchibstedGrotesk-latin-ext-CnpJE18X.woff2 +0 -0
  171. package/dist/page/assets/index-Bkj_pX35.js +42 -0
  172. package/dist/page/assets/index-Dq45jswH.css +1 -0
  173. package/dist/page/index.html +14 -0
  174. package/dist/page/theme.js +8 -0
  175. package/dist/paths.js +19 -0
  176. package/dist/paths.js.map +1 -0
  177. package/dist/safe-env.js +73 -0
  178. package/dist/safe-env.js.map +1 -0
  179. package/dist/sam-local.mjs +135 -0
  180. package/dist/sam-local.mjs.map +1 -0
  181. package/dist/scrub.js +87 -0
  182. package/dist/scrub.js.map +1 -0
  183. package/dist/secret-check.mjs +262 -0
  184. package/dist/secret-check.mjs.map +1 -0
  185. package/dist/server/browser-console.js +117 -0
  186. package/dist/server/browser-console.js.map +1 -0
  187. package/dist/server/cable-test.js +365 -0
  188. package/dist/server/cable-test.js.map +1 -0
  189. package/dist/server/choices.js +51 -0
  190. package/dist/server/choices.js.map +1 -0
  191. package/dist/server/files.js +107 -0
  192. package/dist/server/files.js.map +1 -0
  193. package/dist/server/gate.js +128 -0
  194. package/dist/server/gate.js.map +1 -0
  195. package/dist/server/logs.js +76 -0
  196. package/dist/server/logs.js.map +1 -0
  197. package/dist/server/mobile.js +113 -0
  198. package/dist/server/mobile.js.map +1 -0
  199. package/dist/server/routes.js +326 -0
  200. package/dist/server/routes.js.map +1 -0
  201. package/dist/server/runs.js +111 -0
  202. package/dist/server/runs.js.map +1 -0
  203. package/dist/server/sanitize.js +242 -0
  204. package/dist/server/sanitize.js.map +1 -0
  205. package/dist/server/secrets.js +111 -0
  206. package/dist/server/secrets.js.map +1 -0
  207. package/dist/server/status.js +321 -0
  208. package/dist/server/status.js.map +1 -0
  209. package/dist/server/token.js +38 -0
  210. package/dist/server/token.js.map +1 -0
  211. package/dist/server/waiting.js +79 -0
  212. package/dist/server/waiting.js.map +1 -0
  213. package/dist/status-watch.mjs +63 -0
  214. package/dist/status-watch.mjs.map +1 -0
  215. package/package.json +74 -4
  216. package/skills/koppler-run/SKILL.md +169 -0
  217. package/skills/koppler-run/VERSION +1 -0
  218. package/skills/koppler-run/references/action-log.md +50 -0
  219. package/skills/koppler-run/references/permissions.md +25 -0
  220. package/skills/koppler-run/references/preparing-nodes.md +62 -0
  221. package/skills/koppler-run/references/reporting-bugs.md +76 -0
  222. package/skills/koppler-run/references/research.md +40 -0
  223. package/skills/koppler-run/references/secrets.md +56 -0
  224. package/skills/koppler-run/references/stack.md +197 -0
  225. package/skills/koppler-run/references/status.md +92 -0
@@ -0,0 +1,143 @@
1
+ // The stacks on this Mac, and switching between them: each keeps its own boards, history and live state.
2
+ import crypto from 'node:crypto';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { readJson, writeJson } from "../json-files.js";
6
+ import { validateStack } from "../core/stack.js";
7
+ import { writeData } from "../data.js";
8
+ import { Failure } from "../failure.js";
9
+ import { configDir, tempDir } from "../paths.js";
10
+ import { loadConfig, readIndex, saveConfig, tilde, } from "./config.js";
11
+ import { candidateRepos, findStacks } from "./repos.js";
12
+ // Each stack keeps its own board, history, live state, action log and notes; switching puts them away and brings the other's back.
13
+ // The board in both its forms: one saved before boards were JSON moves along until it is saved again.
14
+ const PER_STACK = [
15
+ 'state.json',
16
+ 'state.js',
17
+ 'history.jsonl',
18
+ 'live.json',
19
+ 'actions.json',
20
+ 'status.json',
21
+ 'NOTES.md',
22
+ 'stack.suggestions.json',
23
+ 'stack.deployed.json',
24
+ ];
25
+ /** Says which stack a `koppler sync` is loading, for as long as it runs. */
26
+ export const LOADING = path.join(tempDir(), 'loading.json');
27
+ export const stackKey = (dir) => crypto.createHash('sha1').update(path.resolve(dir)).digest('hex').slice(0, 12);
28
+ /** Moves each per-stack file that is in `from` to `to`. */
29
+ const moveFiles = (from, to, make = true) => {
30
+ const there = PER_STACK.filter(file => fs.existsSync(path.join(from, file)));
31
+ if (make && there.length)
32
+ fs.mkdirSync(to, { recursive: true });
33
+ for (const file of there)
34
+ fs.renameSync(path.join(from, file), path.join(to, file));
35
+ };
36
+ export function setStack(config, dir, save = saveConfig) {
37
+ const from = config.stack;
38
+ if (from && path.resolve(from) === path.resolve(dir))
39
+ return;
40
+ // The undo log goes with its stack: switched away mid-run, a Stop would find nothing to revert.
41
+ const logged = readJson(path.join(tempDir(), 'actions.json'), []);
42
+ if (Array.isArray(logged) && logged.length)
43
+ throw new Failure('the run on this stack still has changes to undo; stop and revert it first (canvas, or koppler down), then switch');
44
+ const shelf = (stack) => path.join(tempDir(), 'stacks', stackKey(stack));
45
+ if (from) {
46
+ fs.mkdirSync(shelf(from), { recursive: true });
47
+ moveFiles(tempDir(), shelf(from), false);
48
+ }
49
+ // With no stack in use before, what lies there is put aside too, never deleted: it may be a run's action log.
50
+ else
51
+ moveFiles(tempDir(), path.join(tempDir(), 'stacks', `unassigned-${String(Date.now())}`));
52
+ moveFiles(shelf(dir), tempDir(), false);
53
+ config.stack = dir;
54
+ save(config);
55
+ }
56
+ export const currentStack = () => loadConfig().stack ?? null;
57
+ /** The stacks on this Mac for the switcher, looked up again at most every 10 seconds. */
58
+ export function stacksHere() {
59
+ if (Date.now() - stacksCache.at > 10000)
60
+ stacksCache = { at: Date.now(), list: knownStacks(readIndex()) };
61
+ return stacksCache.list;
62
+ }
63
+ export function forgetStacks() {
64
+ stacksCache.at = 0;
65
+ }
66
+ // Stacks the user created here live with their private config until they move one to a shared repo.
67
+ const PRIVATE_STACKS = path.join(configDir(), 'stacks');
68
+ let stacksCache = { at: 0, list: [] };
69
+ export const privateStacks = () => {
70
+ try {
71
+ return fs
72
+ .readdirSync(PRIVATE_STACKS, { withFileTypes: true })
73
+ .filter(dir => dir.isDirectory() && fs.existsSync(path.join(PRIVATE_STACKS, dir.name, 'stack.json')))
74
+ .map(dir => path.join(PRIVATE_STACKS, dir.name));
75
+ }
76
+ catch {
77
+ return [];
78
+ }
79
+ };
80
+ /** A new, empty stack: a name and its deployed environments (first one is the default). It becomes the stack in use. */
81
+ export function createStack(input, { config = loadConfig(), dir = PRIVATE_STACKS, save = saveConfig, } = {}) {
82
+ const given = (input ?? {});
83
+ const name = typeof given.name === 'string' ? given.name.trim().slice(0, 60) : '';
84
+ if (!name)
85
+ return { error: 'Give the stack a name.' };
86
+ const typed = typeof given.envs === 'string' ? given.envs.split(/[\s,]+/) : [];
87
+ const listed = Array.isArray(given.envs) ? given.envs : typed;
88
+ const envs = [...new Set(listed.map(env => String(env).trim().toLowerCase()).filter(Boolean))];
89
+ if (!envs.length)
90
+ return { error: 'Name at least one environment, e.g. qa.' };
91
+ if (envs.length > 8 || !envs.every(env => /^[a-z0-9-]{1,16}$/.test(env)))
92
+ return { error: 'Environment names are short and use lowercase letters, digits and dashes, e.g. qa, prod.' };
93
+ const slug = name
94
+ .toLowerCase()
95
+ .replace(/[^a-z0-9]+/g, '-')
96
+ .replace(/^-+|-+$/g, '') || 'stack';
97
+ const folder = path.join(dir, slug);
98
+ if (fs.existsSync(path.join(folder, 'stack.json')))
99
+ return { error: `You already have a stack called ${name}.` };
100
+ writeJson(path.join(folder, 'stack.json'), { name, envs, apps: {} });
101
+ setStack(config, folder, save);
102
+ return { stack: folder };
103
+ }
104
+ /** Every stack on this Mac: in a cloned repo (shared) or in the private config, with enough to tell them apart. */
105
+ export function knownStacks(index) {
106
+ const dirs = [
107
+ ...findStacks(index?.repos ?? []).map((dir) => [dir, true]),
108
+ ...privateStacks().map((dir) => [dir, false]),
109
+ ];
110
+ return dirs.flatMap(([dir, inRepo]) => {
111
+ const stack = readJson(path.join(dir, 'stack.json'));
112
+ const linked = readJson(path.join(dir, '.source.json'))?.url;
113
+ if (!stack || validateStack(stack).length)
114
+ return [];
115
+ return [
116
+ {
117
+ dir,
118
+ path: linked ?? tilde(dir),
119
+ name: stack.name ?? path.basename(dir),
120
+ apps: Object.keys(stack.apps).length,
121
+ envs: stack.envs ?? [],
122
+ shared: inRepo || !!linked,
123
+ ...(linked && { linked }),
124
+ },
125
+ ];
126
+ });
127
+ }
128
+ /** Switches to one of those stacks; any other folder is refused. */
129
+ export function useStack(dir, { config = loadConfig(), index = readIndex(), save = saveConfig, } = {}) {
130
+ const found = knownStacks(index).find(stack => stack.dir === dir);
131
+ if (!found)
132
+ return { error: 'That is not a stack Koppler found on this Mac. Clone its repo, then run koppler init again.' };
133
+ setStack(config, found.dir, save);
134
+ return { stack: found.dir };
135
+ }
136
+ /** With no stack yet, the canvas still opens: it asks for a name and environments, then for the apps. */
137
+ export function writeSetup(index) {
138
+ fs.mkdirSync(tempDir(), { recursive: true });
139
+ writeData('registry', { name: '', envs: ['dev'], apps: {}, setup: true, stacks: knownStacks(index) });
140
+ writeData('local', { roots: index.roots, at: new Date().toISOString(), apps: {} });
141
+ writeData('repos', { roots: index.roots.map(tilde), stack: null, repos: candidateRepos(index, { apps: {} }, null) });
142
+ }
143
+ //# sourceMappingURL=stacks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stacks.js","sourceRoot":"","sources":["../../src/engine/stacks.ts"],"names":[],"mappings":"AAAA,yGAAyG;AACzG,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAGL,UAAU,EACV,SAAS,EAET,UAAU,EAEV,KAAK,GACN,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAcxD,mIAAmI;AACnI,sGAAsG;AACtG,MAAM,SAAS,GAAG;IAChB,YAAY;IACZ,UAAU;IACV,eAAe;IACf,WAAW;IACX,cAAc;IACd,aAAa;IACb,UAAU;IACV,wBAAwB;IACxB,qBAAqB;CACtB,CAAC;AAEF,4EAA4E;AAC5E,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AAE5D,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAU,EAAE,CAC9C,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAEjF,2DAA2D;AAC3D,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAU,EAAE,IAAI,GAAG,IAAI,EAAE,EAAE;IAC1D,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7E,IAAI,IAAI,IAAI,KAAK,CAAC,MAAM;QAAE,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;AACtF,CAAC,CAAC;AAEF,MAAM,UAAU,QAAQ,CAAC,MAAc,EAAE,GAAW,EAAE,OAAa,UAAU;IAC3E,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;IAC1B,IAAI,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO;IAC7D,gGAAgG;IAChG,MAAM,MAAM,GAAG,QAAQ,CAAY,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7E,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM;QACxC,MAAM,IAAI,OAAO,CACf,kHAAkH,CACnH,CAAC;IACJ,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IACjF,IAAI,IAAI,EAAE,CAAC;QACT,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,SAAS,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,8GAA8G;;QACzG,SAAS,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,cAAc,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9F,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;IACxC,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC;IACnB,IAAI,CAAC,MAAM,CAAC,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,GAAkB,EAAE,CAAC,UAAU,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC;AAE5E,yFAAyF;AACzF,MAAM,UAAU,UAAU;IACxB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,CAAC,EAAE,GAAG,KAAK;QAAE,WAAW,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC;IAC1G,OAAO,WAAW,CAAC,IAAI,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,WAAW,CAAC,EAAE,GAAG,CAAC,CAAC;AACrB,CAAC;AAED,oGAAoG;AACpG,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,QAAQ,CAAC,CAAC;AAExD,IAAI,WAAW,GAAuC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AAC1E,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,EAAE;IAChC,IAAI,CAAC;QACH,OAAO,EAAE;aACN,WAAW,CAAC,cAAc,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;aACpD,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC;aACpG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC,CAAC;AAEF,wHAAwH;AACxH,MAAM,UAAU,WAAW,CACzB,KAAc,EACd,EACE,MAAM,GAAG,UAAU,EAAE,EACrB,GAAG,GAAG,cAAc,EACpB,IAAI,GAAG,UAAU,MACiC,EAAE;IAEtD,MAAM,KAAK,GAAG,CAAC,KAAK,IAAI,EAAE,CAAuC,CAAC;IAClE,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAClF,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,wBAAwB,EAAE,CAAC;IACtD,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/E,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,KAAK,CAAC,IAAkB,CAAC,CAAC,CAAC,KAAK,CAAC;IAC7E,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/F,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,KAAK,EAAE,yCAAyC,EAAE,CAAC;IAC9E,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtE,OAAO,EAAE,KAAK,EAAE,0FAA0F,EAAE,CAAC;IAC/G,MAAM,IAAI,GACR,IAAI;SACD,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC;IACxC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACpC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,mCAAmC,IAAI,GAAG,EAAE,CAAC;IACjH,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IACrE,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAC/B,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC;AAED,mHAAmH;AACnH,MAAM,UAAU,WAAW,CAAC,KAA8C;IACxE,MAAM,IAAI,GAAwB;QAChC,GAAG,UAAU,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAqB,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC9E,GAAG,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,EAAqB,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;KACjE,CAAC;IACF,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAgB,EAAE;QAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAqB,CAAC;QACzE,MAAM,MAAM,GAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAA6B,EAAE,GAAG,CAAC;QAC1F,IAAI,CAAC,KAAK,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QACrD,OAAO;YACL;gBACE,GAAG;gBACH,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC;gBAC1B,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;gBACtC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM;gBACpC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;gBACtB,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC,MAAM;gBAC1B,GAAG,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC;aAC1B;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,QAAQ,CACtB,GAAW,EACX,EACE,MAAM,GAAG,UAAU,EAAE,EACrB,KAAK,GAAG,SAAS,EAAE,EACnB,IAAI,GAAG,UAAU,MACyC,EAAE;IAE9D,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IAClE,IAAI,CAAC,KAAK;QACR,OAAO,EAAE,KAAK,EAAE,6FAA6F,EAAE,CAAC;IAClH,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAClC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;AAC9B,CAAC;AAED,yGAAyG;AACzG,MAAM,UAAU,UAAU,CAAC,KAAY;IACrC,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,SAAS,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACtG,SAAS,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IACnF,SAAS,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;AACvH,CAAC"}
@@ -0,0 +1,214 @@
1
+ // Finds your local repos (any git host) and the shared stack config, then copies the stack into the run folder as registry.json and
2
+ // each app's clone into local.json, for the canvas and the commands.
3
+ // Usage: koppler init [--root <dir>]... [--depth <n>] [--stack <dir>] first-time scan of every repo, remembered
4
+ // koppler sync [--stack <dir>] [--rescan] before each run
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import { readJson, writeJson } from "../json-files.js";
8
+ import { of as kindOf } from "../core/kinds.js";
9
+ import { validateStack } from "../core/stack.js";
10
+ import { writeData } from "../data.js";
11
+ import { tempDir } from "../paths.js";
12
+ import { checkStack as checkLoadedStack } from "./checks.js";
13
+ import { librariesFor, packageOf } from "./libraries.js";
14
+ import { grepClone, hostOwners, hostsByApp, lines, missingCalls } from "./calls.js";
15
+ import { CONFIG, expand, fail, loadConfig, readIndex, tilde } from "./config.js";
16
+ import { branchesOf, candidateRepos, DEFAULT_DEPTH, DEFAULT_ROOTS, git, scan, slugMatches, findStacks, } from "./repos.js";
17
+ import { currentStack, knownStacks, LOADING, setStack, useStack, writeSetup, privateStacks } from "./stacks.js";
18
+ function parseFlags(args) {
19
+ const flags = { roots: [] };
20
+ for (let at = 0; at < args.length; at++) {
21
+ const arg = args[at];
22
+ if (arg === '--root')
23
+ flags.roots.push(expand(args[++at] ?? fail('--root needs a folder')));
24
+ else if (arg === '--stack')
25
+ flags.stack = expand(args[++at] ?? fail('--stack needs a folder'));
26
+ else if (arg === '--depth')
27
+ flags.depth = Number(args[++at]);
28
+ else if (arg === '--rescan')
29
+ flags.rescan = true;
30
+ else
31
+ fail(`unknown option ${String(arg)}`);
32
+ }
33
+ if (flags.depth !== undefined && !(flags.depth >= 1 && flags.depth <= 8))
34
+ fail('--depth must be 1 to 8');
35
+ return flags;
36
+ }
37
+ /** Copies the stack and resolves each app to a clone from the index; branch and changes are read fresh every time. */
38
+ function syncStack(stackDir, index) {
39
+ const source = path.join(stackDir, 'stack.json');
40
+ const stack = readJson(source) ?? fail(`cannot read ${source}`);
41
+ const errors = validateStack(stack);
42
+ if (errors.length)
43
+ fail(`${source} is invalid:\n ${errors.join('\n ')}`);
44
+ fs.mkdirSync(tempDir(), { recursive: true });
45
+ // A copy of the stack file; `source` says which, and that is the one to edit.
46
+ writeData('registry', { ...stack, source });
47
+ const count = String(Object.keys(stack.apps).length);
48
+ console.log(`STACK ${stack.name ?? tilde(stackDir)}: ${count} apps from ${tilde(source)}`);
49
+ const local = {};
50
+ const here = index.repos.filter(repo => fs.existsSync(repo.path));
51
+ // Every clone that publishes a package (Dart or npm), so an app can use the local copy of a library it depends on.
52
+ const packages = here.flatMap((repo) => {
53
+ const published = packageOf(repo.path);
54
+ return published ? [{ path: repo.path, ...published }] : [];
55
+ });
56
+ for (const [id, app] of Object.entries(stack.apps)) {
57
+ local[id] = null;
58
+ // An outside system has nothing to clone.
59
+ if (app.outside)
60
+ continue;
61
+ const slug = app.slug ?? '';
62
+ const paths = here.filter(repo => repo.keys.some(key => slugMatches(slug, key))).map(repo => repo.path);
63
+ const [clone, ...others] = paths.sort((a, b) => a.length - b.length);
64
+ if (!clone) {
65
+ const host = slug.split('/')[0]?.includes('.') ? '' : 'github.com/';
66
+ console.log(`MISSING ${id}: git clone https://${host}${slug}.git (then koppler sync --rescan)`);
67
+ continue;
68
+ }
69
+ const dirty = lines(git(clone, 'status', '--porcelain')).length;
70
+ const libraries = librariesFor(clone, packages);
71
+ const branch = git(clone, 'branch', '--show-current') || null;
72
+ local[id] = { path: clone, branch, dirty, branches: branchesOf(clone), ...(libraries.length && { libraries }) };
73
+ const also = others.length ? ` (also: ${others.map(tilde).join(', ')})` : '';
74
+ console.log(`OK ${id}: ${tilde(clone)} [${branch ?? 'detached'}]${dirty ? ` dirty=${String(dirty)}` : ''}${also}`);
75
+ }
76
+ writeData('repos', {
77
+ roots: index.roots.map(tilde),
78
+ stack: tilde(stackDir),
79
+ repos: candidateRepos(index, stack, stackDir),
80
+ });
81
+ writeData('local', { roots: index.roots, at: new Date().toISOString(), apps: local });
82
+ // An empty `consumes` means nobody has mapped that app yet, not that it calls nothing: look in every clone.
83
+ const found = missingCalls(stack, (id, hosts) => {
84
+ const clone = local[id];
85
+ return clone ? grepClone(clone.path, hosts) : [];
86
+ });
87
+ for (const [caller, calls] of Object.entries(found))
88
+ for (const [callee, where] of Object.entries(calls))
89
+ console.log(`FOUND ${caller} -> ${callee}, not in stack.json: ${where}`);
90
+ const known = hostsByApp(stack);
91
+ for (const [id, app] of Object.entries(stack.apps))
92
+ if (!app.outside && !known[id]?.size && kindOf(app, stack).serves)
93
+ console.log(`UNKNOWN ${id}: no deployed address in stack.json, so calls to it cannot be found`);
94
+ for (const [host, ids] of hostOwners(stack).shared)
95
+ console.log(`SHARED ${host} is used by ${ids.join(' and ')}, so calls to it are not attributed`);
96
+ writeData('registry', { ...stack, source, found });
97
+ }
98
+ const checkStack = (dir) => {
99
+ if (!fs.existsSync(path.join(dir, 'stack.json')))
100
+ fail(`no stack.json in ${tilde(dir)}`);
101
+ };
102
+ const keepConfig = () => undefined;
103
+ const SEVERAL = 'Several stacks found. Pick one on the canvas (koppler init --pick), or: koppler init --stack <one of the folders above>';
104
+ const NONE = [
105
+ 'No stack yet. Start one:',
106
+ ' koppler init --new "<name>" --envs qa,prod then pick its apps on the canvas',
107
+ ' koppler link <GitHub link to a stack.json> use one your team shares',
108
+ ' koppler init --stack <folder> use one in a folder on this Mac',
109
+ ].join('\n');
110
+ export function init(args) {
111
+ const flags = parseFlags(args);
112
+ if (flags.stack)
113
+ checkStack(flags.stack);
114
+ const config = loadConfig();
115
+ const usual = () => DEFAULT_ROOTS.map(expand).filter(dir => fs.existsSync(dir));
116
+ const roots = flags.roots.length ? flags.roots : config.roots?.length ? config.roots : usual();
117
+ if (!roots.length)
118
+ fail('no folder to scan: koppler init --root <folder with your repos>');
119
+ const depth = flags.depth ?? config.depth ?? DEFAULT_DEPTH;
120
+ Object.assign(config, { roots, depth });
121
+ const index = scan(roots, depth);
122
+ const stacks = [...findStacks(index.repos), ...privateStacks()];
123
+ for (const stack of stacks)
124
+ console.log(`FOUND stack ${tilde(stack)}`);
125
+ const [only] = stacks;
126
+ if (flags.stack)
127
+ setStack(config, flags.stack, keepConfig);
128
+ else if (!config.stack && stacks.length === 1 && only)
129
+ setStack(config, only, keepConfig);
130
+ writeJson(CONFIG, config);
131
+ if (!config.stack) {
132
+ console.log(stacks.length ? SEVERAL : NONE);
133
+ writeSetup(index);
134
+ return;
135
+ }
136
+ checkStack(config.stack);
137
+ console.log(`USING stack ${tilde(config.stack)} (change with --stack)`);
138
+ syncStack(config.stack, index);
139
+ }
140
+ export function sync(args) {
141
+ const flags = parseFlags(args);
142
+ const config = loadConfig();
143
+ if (flags.stack) {
144
+ checkStack(flags.stack);
145
+ setStack(config, flags.stack, keepConfig);
146
+ }
147
+ if (flags.roots.length)
148
+ config.roots = flags.roots;
149
+ if (!config.stack)
150
+ fail('no stack set yet: koppler init');
151
+ fs.mkdirSync(tempDir(), { recursive: true });
152
+ writeJson(LOADING, { stack: config.stack, pid: process.pid });
153
+ try {
154
+ let index = readIndex();
155
+ if (!index || flags.rescan || flags.roots.length) {
156
+ if (!config.roots?.length)
157
+ fail('no repos scanned yet: koppler init');
158
+ index = scan(config.roots, config.depth ?? DEFAULT_DEPTH);
159
+ }
160
+ writeJson(CONFIG, config);
161
+ syncStack(config.stack, index);
162
+ }
163
+ finally {
164
+ fs.rmSync(LOADING, { force: true });
165
+ }
166
+ // A stack says what it needs when it loads: missing programs, and its own checks once they were approved.
167
+ console.log('');
168
+ checkLoadedStack();
169
+ }
170
+ /** `koppler use`: every stack on this Mac. */
171
+ export function stacksCommand(args = []) {
172
+ const here = currentStack();
173
+ const list = knownStacks(readIndex());
174
+ if (args.includes('--json')) {
175
+ const shown = list.map(stack => ({
176
+ name: stack.name,
177
+ inUse: stack.dir === here,
178
+ path: stack.path,
179
+ apps: stack.apps,
180
+ envs: stack.envs,
181
+ shared: stack.shared,
182
+ linked: !!stack.linked,
183
+ }));
184
+ console.log(JSON.stringify(shown, null, 2));
185
+ return;
186
+ }
187
+ if (!list.length)
188
+ console.log('No stack found on this Mac. Create one: koppler init --new "<name>" --envs qa,prod');
189
+ for (const stack of list) {
190
+ const kind = stack.linked ? 'linked from GitHub' : stack.shared ? 'shared' : 'private';
191
+ const about = `${kind}, ${String(stack.apps)} apps, ${stack.envs.join('/')}`;
192
+ console.log(`${stack.dir === here ? '*' : ' '} ${stack.name} (${about}) ${stack.path}`);
193
+ }
194
+ }
195
+ /** `koppler use <name or folder>`: switch to one (it must not have anything running). */
196
+ export function useCommand(args) {
197
+ const want = args.join(' ').trim();
198
+ const list = knownStacks(readIndex());
199
+ if (!want)
200
+ fail('usage: koppler use <stack name or folder>');
201
+ const folder = path.resolve(expand(want));
202
+ const matches = list.filter(stack => stack.dir === folder || stack.name.toLowerCase() === want.toLowerCase());
203
+ const [match] = matches;
204
+ if (!match || matches.length !== 1)
205
+ fail(matches.length
206
+ ? `several stacks are called ${want}; use its folder: koppler use`
207
+ : `no stack called ${want}; see: koppler use`);
208
+ const result = useStack(match.dir);
209
+ if (result.error !== undefined)
210
+ fail(result.error);
211
+ console.log(`USING ${match.name} (${match.path})`);
212
+ sync([]);
213
+ }
214
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/engine/sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ // Traces across local apps: one Jaeger in Docker takes OpenTelemetry from every app Koppler starts while it runs, and
2
+ // its trace view follows one request across the apps on the board, to where it failed.
3
+ import { spawn } from 'node:child_process';
4
+ import { positional } from "../cli/output.js";
5
+ import { fail } from "../failure.js";
6
+ import { alive, listener, readRecord, startProcess, stopOne } from "./processes.js";
7
+ export const TRACES = 'koppler-traces';
8
+ export const VIEW_PORT = 16686;
9
+ const OTLP_PORT = 4318;
10
+ // To update: the digest of the new version's tag on Docker Hub (jaegertracing/jaeger), once it is two weeks old.
11
+ const IMAGE = 'jaegertracing/jaeger:2.21.0@sha256:3d0ac795ff98aa04d1be04311d2dac6c25b4bfc8322dc02e53bc5b170c5018c3';
12
+ // Stopping the Docker client does not stop its container: it is removed on stop, and a leftover one before starting.
13
+ const RM = `docker rm -f ${TRACES} >/dev/null 2>&1`;
14
+ const COLLECTOR = [
15
+ 'sh',
16
+ '-c',
17
+ `${RM}; trap '${RM}; exit 0' TERM INT HUP; docker run --rm --name ${TRACES} -p 127.0.0.1:${String(VIEW_PORT)}:16686 -p 127.0.0.1:${String(OTLP_PORT)}:4318 ${IMAGE} & wait`,
18
+ ];
19
+ /** Whether the collector runs, so apps started now send it their traces. */
20
+ export const tracing = () => {
21
+ const record = readRecord(TRACES);
22
+ return !!record && alive(record);
23
+ };
24
+ /** The settings an OpenTelemetry SDK (.NET, Node, Java, Python, Go) reads to send its traces here. */
25
+ export const traceEnv = (app) => ({
26
+ OTEL_EXPORTER_OTLP_ENDPOINT: `http://localhost:${String(OTLP_PORT)}`,
27
+ OTEL_EXPORTER_OTLP_PROTOCOL: 'http/protobuf',
28
+ OTEL_SERVICE_NAME: app,
29
+ OTEL_TRACES_EXPORTER: 'otlp',
30
+ });
31
+ /** Where one app's traces are, or every app's. */
32
+ export const traceView = (app) => `http://localhost:${String(VIEW_PORT)}/search${app ? `?service=${encodeURIComponent(app)}` : ''}`;
33
+ /** `koppler traces start|stop|open [<app>]`. */
34
+ export async function tracesCommand(args) {
35
+ const [what = 'open', app] = positional(args);
36
+ const record = readRecord(TRACES);
37
+ if (what === 'stop') {
38
+ console.log(record ? await stopOne(record) : 'traces are not being collected');
39
+ return;
40
+ }
41
+ if (what === 'start') {
42
+ if (record && alive(record))
43
+ console.log(`traces are collected already: ${traceView()}`);
44
+ else {
45
+ await startProcess({
46
+ name: TRACES,
47
+ command: COLLECTOR,
48
+ restart: false,
49
+ port: VIEW_PORT,
50
+ onStop: [['docker', 'rm', '-f', TRACES]],
51
+ });
52
+ console.log(`Collecting traces: ${traceView()}`);
53
+ }
54
+ console.log('Apps Koppler starts from now on send theirs; restart the ones already running to include them.');
55
+ return;
56
+ }
57
+ if (what !== 'open')
58
+ fail('usage: koppler traces start|stop|open [<app>]');
59
+ if (!tracing() || !listener(VIEW_PORT))
60
+ fail('traces are not being collected: koppler traces start');
61
+ const url = traceView(app);
62
+ spawn(process.platform === 'darwin' ? 'open' : 'xdg-open', [url], { detached: true, stdio: 'ignore' }).unref();
63
+ console.log(url);
64
+ }
65
+ //# sourceMappingURL=traces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traces.js","sourceRoot":"","sources":["../../src/engine/traces.ts"],"names":[],"mappings":"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"}