@obh/forge 0.2.0

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 (215) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/dist/capabilities/analytics.d.ts +3 -0
  4. package/dist/capabilities/analytics.d.ts.map +1 -0
  5. package/dist/capabilities/analytics.js +91 -0
  6. package/dist/capabilities/analytics.js.map +1 -0
  7. package/dist/capabilities/api-keys.d.ts +3 -0
  8. package/dist/capabilities/api-keys.d.ts.map +1 -0
  9. package/dist/capabilities/api-keys.js +90 -0
  10. package/dist/capabilities/api-keys.js.map +1 -0
  11. package/dist/capabilities/audit.d.ts +3 -0
  12. package/dist/capabilities/audit.d.ts.map +1 -0
  13. package/dist/capabilities/audit.js +74 -0
  14. package/dist/capabilities/audit.js.map +1 -0
  15. package/dist/capabilities/entitlements.d.ts +3 -0
  16. package/dist/capabilities/entitlements.d.ts.map +1 -0
  17. package/dist/capabilities/entitlements.js +94 -0
  18. package/dist/capabilities/entitlements.js.map +1 -0
  19. package/dist/capabilities/events.d.ts +3 -0
  20. package/dist/capabilities/events.d.ts.map +1 -0
  21. package/dist/capabilities/events.js +107 -0
  22. package/dist/capabilities/events.js.map +1 -0
  23. package/dist/capabilities/files.d.ts +3 -0
  24. package/dist/capabilities/files.d.ts.map +1 -0
  25. package/dist/capabilities/files.js +100 -0
  26. package/dist/capabilities/files.js.map +1 -0
  27. package/dist/capabilities/helpers.d.ts +27 -0
  28. package/dist/capabilities/helpers.d.ts.map +1 -0
  29. package/dist/capabilities/helpers.js +63 -0
  30. package/dist/capabilities/helpers.js.map +1 -0
  31. package/dist/capabilities/import-export.d.ts +3 -0
  32. package/dist/capabilities/import-export.d.ts.map +1 -0
  33. package/dist/capabilities/import-export.js +267 -0
  34. package/dist/capabilities/import-export.js.map +1 -0
  35. package/dist/capabilities/index.d.ts +16 -0
  36. package/dist/capabilities/index.d.ts.map +1 -0
  37. package/dist/capabilities/index.js +71 -0
  38. package/dist/capabilities/index.js.map +1 -0
  39. package/dist/capabilities/jobs.d.ts +3 -0
  40. package/dist/capabilities/jobs.d.ts.map +1 -0
  41. package/dist/capabilities/jobs.js +117 -0
  42. package/dist/capabilities/jobs.js.map +1 -0
  43. package/dist/capabilities/notifications.d.ts +3 -0
  44. package/dist/capabilities/notifications.d.ts.map +1 -0
  45. package/dist/capabilities/notifications.js +113 -0
  46. package/dist/capabilities/notifications.js.map +1 -0
  47. package/dist/capabilities/search.d.ts +3 -0
  48. package/dist/capabilities/search.d.ts.map +1 -0
  49. package/dist/capabilities/search.js +121 -0
  50. package/dist/capabilities/search.js.map +1 -0
  51. package/dist/capabilities/settings.d.ts +3 -0
  52. package/dist/capabilities/settings.d.ts.map +1 -0
  53. package/dist/capabilities/settings.js +75 -0
  54. package/dist/capabilities/settings.js.map +1 -0
  55. package/dist/capabilities/types.d.ts +16 -0
  56. package/dist/capabilities/types.d.ts.map +1 -0
  57. package/dist/capabilities/types.js +3 -0
  58. package/dist/capabilities/types.js.map +1 -0
  59. package/dist/capabilities/webhooks.d.ts +3 -0
  60. package/dist/capabilities/webhooks.d.ts.map +1 -0
  61. package/dist/capabilities/webhooks.js +117 -0
  62. package/dist/capabilities/webhooks.js.map +1 -0
  63. package/dist/cli.d.ts +3 -0
  64. package/dist/cli.d.ts.map +1 -0
  65. package/dist/cli.js +60 -0
  66. package/dist/cli.js.map +1 -0
  67. package/dist/commands/add.d.ts +3 -0
  68. package/dist/commands/add.d.ts.map +1 -0
  69. package/dist/commands/add.js +88 -0
  70. package/dist/commands/add.js.map +1 -0
  71. package/dist/commands/doctor.d.ts +3 -0
  72. package/dist/commands/doctor.d.ts.map +1 -0
  73. package/dist/commands/doctor.js +94 -0
  74. package/dist/commands/doctor.js.map +1 -0
  75. package/dist/commands/generate.d.ts +3 -0
  76. package/dist/commands/generate.d.ts.map +1 -0
  77. package/dist/commands/generate.js +41 -0
  78. package/dist/commands/generate.js.map +1 -0
  79. package/dist/commands/inspect.d.ts +3 -0
  80. package/dist/commands/inspect.d.ts.map +1 -0
  81. package/dist/commands/inspect.js +64 -0
  82. package/dist/commands/inspect.js.map +1 -0
  83. package/dist/commands/new.d.ts +18 -0
  84. package/dist/commands/new.d.ts.map +1 -0
  85. package/dist/commands/new.js +149 -0
  86. package/dist/commands/new.js.map +1 -0
  87. package/dist/commands/shared.d.ts +14 -0
  88. package/dist/commands/shared.d.ts.map +1 -0
  89. package/dist/commands/shared.js +36 -0
  90. package/dist/commands/shared.js.map +1 -0
  91. package/dist/commands/skill.d.ts +3 -0
  92. package/dist/commands/skill.d.ts.map +1 -0
  93. package/dist/commands/skill.js +59 -0
  94. package/dist/commands/skill.js.map +1 -0
  95. package/dist/commands/stack.d.ts +13 -0
  96. package/dist/commands/stack.d.ts.map +1 -0
  97. package/dist/commands/stack.js +192 -0
  98. package/dist/commands/stack.js.map +1 -0
  99. package/dist/generators/api.d.ts +16 -0
  100. package/dist/generators/api.d.ts.map +1 -0
  101. package/dist/generators/api.js +375 -0
  102. package/dist/generators/api.js.map +1 -0
  103. package/dist/generators/lwd.d.ts +12 -0
  104. package/dist/generators/lwd.d.ts.map +1 -0
  105. package/dist/generators/lwd.js +143 -0
  106. package/dist/generators/lwd.js.map +1 -0
  107. package/dist/generators/mobile.d.ts +16 -0
  108. package/dist/generators/mobile.d.ts.map +1 -0
  109. package/dist/generators/mobile.js +180 -0
  110. package/dist/generators/mobile.js.map +1 -0
  111. package/dist/generators/platform-package.d.ts +18 -0
  112. package/dist/generators/platform-package.d.ts.map +1 -0
  113. package/dist/generators/platform-package.js +568 -0
  114. package/dist/generators/platform-package.js.map +1 -0
  115. package/dist/generators/root.d.ts +15 -0
  116. package/dist/generators/root.d.ts.map +1 -0
  117. package/dist/generators/root.js +249 -0
  118. package/dist/generators/root.js.map +1 -0
  119. package/dist/generators/sdk.d.ts +14 -0
  120. package/dist/generators/sdk.d.ts.map +1 -0
  121. package/dist/generators/sdk.js +137 -0
  122. package/dist/generators/sdk.js.map +1 -0
  123. package/dist/generators/web.d.ts +15 -0
  124. package/dist/generators/web.d.ts.map +1 -0
  125. package/dist/generators/web.js +203 -0
  126. package/dist/generators/web.js.map +1 -0
  127. package/dist/generators/worker.d.ts +13 -0
  128. package/dist/generators/worker.d.ts.map +1 -0
  129. package/dist/generators/worker.js +148 -0
  130. package/dist/generators/worker.js.map +1 -0
  131. package/dist/index.d.ts +10 -0
  132. package/dist/index.d.ts.map +1 -0
  133. package/dist/index.js +44 -0
  134. package/dist/index.js.map +1 -0
  135. package/dist/project/context.d.ts +24 -0
  136. package/dist/project/context.d.ts.map +1 -0
  137. package/dist/project/context.js +63 -0
  138. package/dist/project/context.js.map +1 -0
  139. package/dist/project/manifest.d.ts +26 -0
  140. package/dist/project/manifest.d.ts.map +1 -0
  141. package/dist/project/manifest.js +73 -0
  142. package/dist/project/manifest.js.map +1 -0
  143. package/dist/project/paths.d.ts +25 -0
  144. package/dist/project/paths.d.ts.map +1 -0
  145. package/dist/project/paths.js +51 -0
  146. package/dist/project/paths.js.map +1 -0
  147. package/dist/project/plan.d.ts +42 -0
  148. package/dist/project/plan.d.ts.map +1 -0
  149. package/dist/project/plan.js +251 -0
  150. package/dist/project/plan.js.map +1 -0
  151. package/dist/prompts/index.d.ts +24 -0
  152. package/dist/prompts/index.d.ts.map +1 -0
  153. package/dist/prompts/index.js +111 -0
  154. package/dist/prompts/index.js.map +1 -0
  155. package/dist/recipes/index.d.ts +25 -0
  156. package/dist/recipes/index.d.ts.map +1 -0
  157. package/dist/recipes/index.js +77 -0
  158. package/dist/recipes/index.js.map +1 -0
  159. package/dist/stack/infer.d.ts +4 -0
  160. package/dist/stack/infer.d.ts.map +1 -0
  161. package/dist/stack/infer.js +165 -0
  162. package/dist/stack/infer.js.map +1 -0
  163. package/dist/stack/lwd.d.ts +24 -0
  164. package/dist/stack/lwd.d.ts.map +1 -0
  165. package/dist/stack/lwd.js +62 -0
  166. package/dist/stack/lwd.js.map +1 -0
  167. package/dist/stack/lwdtoml.d.ts +38 -0
  168. package/dist/stack/lwdtoml.d.ts.map +1 -0
  169. package/dist/stack/lwdtoml.js +57 -0
  170. package/dist/stack/lwdtoml.js.map +1 -0
  171. package/dist/stack/manifest.d.ts +15 -0
  172. package/dist/stack/manifest.d.ts.map +1 -0
  173. package/dist/stack/manifest.js +86 -0
  174. package/dist/stack/manifest.js.map +1 -0
  175. package/dist/stack/types.d.ts +48 -0
  176. package/dist/stack/types.d.ts.map +1 -0
  177. package/dist/stack/types.js +5 -0
  178. package/dist/stack/types.js.map +1 -0
  179. package/dist/stack/wire.d.ts +40 -0
  180. package/dist/stack/wire.d.ts.map +1 -0
  181. package/dist/stack/wire.js +192 -0
  182. package/dist/stack/wire.js.map +1 -0
  183. package/dist/types.d.ts +114 -0
  184. package/dist/types.d.ts.map +1 -0
  185. package/dist/types.js +5 -0
  186. package/dist/types.js.map +1 -0
  187. package/dist/utils/fs.d.ts +13 -0
  188. package/dist/utils/fs.d.ts.map +1 -0
  189. package/dist/utils/fs.js +64 -0
  190. package/dist/utils/fs.js.map +1 -0
  191. package/dist/utils/git.d.ts +17 -0
  192. package/dist/utils/git.d.ts.map +1 -0
  193. package/dist/utils/git.js +49 -0
  194. package/dist/utils/git.js.map +1 -0
  195. package/dist/utils/logger.d.ts +16 -0
  196. package/dist/utils/logger.d.ts.map +1 -0
  197. package/dist/utils/logger.js +21 -0
  198. package/dist/utils/logger.js.map +1 -0
  199. package/dist/utils/shell.d.ts +21 -0
  200. package/dist/utils/shell.d.ts.map +1 -0
  201. package/dist/utils/shell.js +40 -0
  202. package/dist/utils/shell.js.map +1 -0
  203. package/dist/version.d.ts +2 -0
  204. package/dist/version.d.ts.map +1 -0
  205. package/dist/version.js +6 -0
  206. package/dist/version.js.map +1 -0
  207. package/package.json +40 -0
  208. package/skills/obh-add-events/SKILL.md +26 -0
  209. package/skills/obh-generate-audit-rules/SKILL.md +26 -0
  210. package/skills/obh-inspect-project/SKILL.md +26 -0
  211. package/skills/obh-lwd-manifest/SKILL.md +26 -0
  212. package/skills/obh-retrofit-files/SKILL.md +24 -0
  213. package/skills/obh-retrofit-jobs/SKILL.md +26 -0
  214. package/skills/obh-sdk-extraction/SKILL.md +24 -0
  215. package/skills/obh-settings-migration/SKILL.md +24 -0
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.inferStack = inferStack;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const manifest_1 = require("./manifest");
9
+ const lwdtoml_1 = require("./lwdtoml");
10
+ const manifest_2 = require("../project/manifest");
11
+ const node_fs_1 = require("node:fs");
12
+ const RANDOM_SECRET_RE = /(^JWT_SECRET$|_SECRET$|_PEPPER$|_KEY$|_TOKEN$)/;
13
+ const RESOURCE_IMAGE_RE = /^(postgres|redis|valkey|mysql|mariadb|mongo|minio)/;
14
+ const ROLE_ORDER = { resource: 0, api: 1, worker: 2, web: 3, app: 4 };
15
+ /** Inspect deploy/*.lwd.toml (+ forge.json) and propose a stack manifest. */
16
+ async function inferStack(root) {
17
+ const deployDir = node_path_1.default.join(root, "deploy");
18
+ let files = [];
19
+ try {
20
+ files = (await node_fs_1.promises.readdir(deployDir)).filter((f) => f.endsWith(".lwd.toml"));
21
+ }
22
+ catch {
23
+ files = [];
24
+ }
25
+ if (files.length === 0)
26
+ throw new Error("no deploy/*.lwd.toml files found — nothing to assemble into a stack");
27
+ const forge = await (0, manifest_2.loadManifest)(root);
28
+ const forgeRoles = {};
29
+ for (const [name, app] of Object.entries(forge?.apps ?? {}))
30
+ forgeRoles[name] = app.role;
31
+ const infos = [];
32
+ for (const file of files.sort()) {
33
+ const toml = await (0, lwdtoml_1.readLwdToml)(node_path_1.default.join(deployDir, file));
34
+ if (!toml || !toml.name)
35
+ continue;
36
+ infos.push({ base: file.replace(/\.lwd\.toml$/, ""), manifestRel: `deploy/${file}`, toml });
37
+ }
38
+ const apps = infos.map((i) => ({
39
+ name: i.toml.name,
40
+ manifest: i.manifestRel,
41
+ role: inferRole(i, forgeRoles),
42
+ }));
43
+ const roleOf = new Map(apps.map((a, i) => [infos[i].toml.name, a.role]));
44
+ // Which apps need each secret (app top-level secrets + backing-service secrets).
45
+ const needers = new Map();
46
+ const need = (secret, app) => {
47
+ const s = needers.get(secret) ?? new Set();
48
+ s.add(app);
49
+ needers.set(secret, s);
50
+ };
51
+ for (const i of infos) {
52
+ for (const s of i.toml.secrets)
53
+ need(s, i.toml.name);
54
+ for (const svc of i.toml.services)
55
+ for (const s of svc.secrets)
56
+ need(s, i.toml.name);
57
+ }
58
+ // Postgres sources: co-located [[services]] blocks + dedicated resource apps.
59
+ const pgSources = [];
60
+ for (const i of infos) {
61
+ for (const svc of i.toml.services) {
62
+ if (/^postgres/.test(svc.image))
63
+ pgSources.push(pgFromService(i.toml.name, svc));
64
+ }
65
+ if (roleOf.get(i.toml.name) === "resource" && /^postgres/.test(i.toml.image ?? "")) {
66
+ pgSources.push({
67
+ ownerApp: i.toml.name,
68
+ host: i.toml.name,
69
+ user: i.toml.env.POSTGRES_USER ?? "app",
70
+ db: i.toml.env.POSTGRES_DB ?? "app",
71
+ coLocated: false,
72
+ passwordSecret: i.toml.secrets.find((s) => /PASSWORD/.test(s)) ?? "POSTGRES_PASSWORD",
73
+ });
74
+ }
75
+ }
76
+ const generate = {};
77
+ const connections = {};
78
+ const manual = [];
79
+ const classified = new Set();
80
+ // 1. Postgres password → generated on the owning app; DATABASE_URL → connection.
81
+ for (const pg of pgSources) {
82
+ generate[pg.passwordSecret] = { type: "password", bytes: 24, apps: [pg.ownerApp] };
83
+ classified.add(pg.passwordSecret);
84
+ if (needers.has("DATABASE_URL") && !connections.DATABASE_URL) {
85
+ const consumers = [...(needers.get("DATABASE_URL") ?? [])];
86
+ const template = `postgres://${pg.user}:\${${pg.passwordSecret}}@${pg.host}:5432/${pg.db}`;
87
+ if (pg.coLocated) {
88
+ const owner = consumers.includes(pg.ownerApp) ? pg.ownerApp : consumers[0];
89
+ connections.DATABASE_URL = {
90
+ template,
91
+ service: { app: pg.ownerApp, name: serviceNameOf(infos, pg.ownerApp) ?? "db" },
92
+ apps: [owner],
93
+ sharedWith: consumers.filter((a) => a !== owner),
94
+ };
95
+ }
96
+ else {
97
+ connections.DATABASE_URL = {
98
+ template,
99
+ service: { app: pg.ownerApp, name: pg.ownerApp },
100
+ apps: consumers,
101
+ };
102
+ }
103
+ classified.add("DATABASE_URL");
104
+ }
105
+ }
106
+ // 2. Remaining secrets: random-looking → generate hex; else → manual.
107
+ for (const [name, appsSet] of needers) {
108
+ if (classified.has(name))
109
+ continue;
110
+ if (RANDOM_SECRET_RE.test(name)) {
111
+ generate[name] = { type: "hex", bytes: 32, apps: [...appsSet] };
112
+ }
113
+ else {
114
+ manual.push(name);
115
+ }
116
+ }
117
+ manual.sort();
118
+ const name = forge?.name ?? commonPrefix(apps.map((a) => a.name)) ?? node_path_1.default.basename(root);
119
+ const order = [...apps].sort((a, b) => ROLE_ORDER[a.role] - ROLE_ORDER[b.role]).map((a) => a.name);
120
+ return { name, stackVersion: manifest_1.STACK_VERSION, apps, order, secrets: { generate, connections, manual } };
121
+ }
122
+ function pgFromService(ownerApp, svc) {
123
+ return {
124
+ ownerApp,
125
+ host: svc.name,
126
+ user: svc.env.POSTGRES_USER ?? "app",
127
+ db: svc.env.POSTGRES_DB ?? "app",
128
+ coLocated: true,
129
+ passwordSecret: svc.secrets.find((s) => /PASSWORD/.test(s)) ?? "POSTGRES_PASSWORD",
130
+ };
131
+ }
132
+ function serviceNameOf(infos, app) {
133
+ const info = infos.find((i) => i.toml.name === app);
134
+ const pg = info?.toml.services.find((s) => /^postgres/.test(s.image));
135
+ return pg?.name;
136
+ }
137
+ function inferRole(info, forgeRoles) {
138
+ const fr = forgeRoles[info.base];
139
+ if (fr === "api" || fr === "web" || fr === "worker")
140
+ return fr;
141
+ const t = info.toml;
142
+ const isResource = (t.services.length > 0 && !t.git && !t.image) || (RESOURCE_IMAGE_RE.test(t.image ?? "") && !t.git);
143
+ if (isResource)
144
+ return "resource";
145
+ if (/worker/i.test(t.name) || info.base === "worker")
146
+ return "worker";
147
+ if (t.port === 80 || info.base === "admin" || info.base === "web")
148
+ return "web";
149
+ return "api";
150
+ }
151
+ function commonPrefix(names) {
152
+ if (names.length === 0)
153
+ return undefined;
154
+ const first = names[0];
155
+ let prefix = "";
156
+ for (let i = 0; i < first.length; i++) {
157
+ const ch = first[i];
158
+ if (names.every((n) => n[i] === ch))
159
+ prefix += ch;
160
+ else
161
+ break;
162
+ }
163
+ return prefix.replace(/[-_]$/, "") || undefined;
164
+ }
165
+ //# sourceMappingURL=infer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infer.js","sourceRoot":"","sources":["../../src/stack/infer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { type CaptureOptions, type CaptureResult } from "../utils/shell";
2
+ import type { AppStatus } from "./types";
3
+ export type Runner = (cmd: string, args: string[], opts?: CaptureOptions) => Promise<CaptureResult>;
4
+ export interface LwdAdapter {
5
+ secretLs(app: string): Promise<string[]>;
6
+ secretSet(app: string, key: string, value: string): Promise<void>;
7
+ apply(manifestPath: string): Promise<void>;
8
+ status(app: string): Promise<AppStatus>;
9
+ rm(app: string): Promise<void>;
10
+ }
11
+ export interface LwdAdapterOptions {
12
+ /** lwd binary name/path (default "lwd"). */
13
+ bin?: string;
14
+ cwd?: string;
15
+ /** Injectable runner for tests; defaults to the real capturing shell. */
16
+ run?: Runner;
17
+ }
18
+ /**
19
+ * Thin wrapper over the `lwd` CLI. Inherits ambient LWD_DAEMON/LWD_API_TOKEN
20
+ * (so it targets local or remote daemons unchanged). Secret values go in on
21
+ * stdin, never argv. No lwd changes — a pure client of its stable CLI.
22
+ */
23
+ export declare function createLwdAdapter(opts?: LwdAdapterOptions): LwdAdapter;
24
+ //# sourceMappingURL=lwd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lwd.d.ts","sourceRoot":"","sources":["../../src/stack/lwd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACjF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,aAAa,CAAC,CAAA;AAEnG,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACxC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjE,KAAK,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;IACvC,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,iBAAsB,GAAG,UAAU,CAkDzE"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLwdAdapter = createLwdAdapter;
4
+ const shell_1 = require("../utils/shell");
5
+ const SECRET_NAME_LINE = /^[A-Za-z_][A-Za-z0-9_]*$/;
6
+ /**
7
+ * Thin wrapper over the `lwd` CLI. Inherits ambient LWD_DAEMON/LWD_API_TOKEN
8
+ * (so it targets local or remote daemons unchanged). Secret values go in on
9
+ * stdin, never argv. No lwd changes — a pure client of its stable CLI.
10
+ */
11
+ function createLwdAdapter(opts = {}) {
12
+ const bin = opts.bin ?? "lwd";
13
+ const run = opts.run ?? ((cmd, args, o) => (0, shell_1.capture)(cmd, args, { cwd: opts.cwd, ...o }));
14
+ async function invoke(args, o) {
15
+ try {
16
+ return await run(bin, args, o);
17
+ }
18
+ catch (err) {
19
+ const e = err;
20
+ if (e.code === "ENOENT") {
21
+ throw new Error(`\`${bin}\` not found on PATH. Install lwd or set the binary path.`);
22
+ }
23
+ throw err;
24
+ }
25
+ }
26
+ const ensureOk = (r, what) => {
27
+ if (r.code !== 0)
28
+ throw new Error(`${what} failed: ${(r.stderr || r.stdout).trim() || `exit ${r.code}`}`);
29
+ };
30
+ return {
31
+ async secretLs(app) {
32
+ const r = await invoke(["secret", "ls", app]);
33
+ // A not-yet-deployed app has no secrets — treat any error as empty.
34
+ if (r.code !== 0)
35
+ return [];
36
+ return r.stdout
37
+ .split(/\r?\n/)
38
+ .map((l) => l.trim())
39
+ .filter((l) => SECRET_NAME_LINE.test(l));
40
+ },
41
+ async secretSet(app, key, value) {
42
+ const r = await invoke(["secret", "set", app, key], { stdin: value });
43
+ ensureOk(r, `lwd secret set ${app} ${key}`);
44
+ },
45
+ async apply(manifestPath) {
46
+ const r = await invoke(["apply", manifestPath]);
47
+ ensureOk(r, `lwd apply ${manifestPath}`);
48
+ },
49
+ async status(app) {
50
+ const r = await invoke(["status", app]);
51
+ const text = (r.stdout + " " + r.stderr).toLowerCase();
52
+ const healthy = /\b(running|healthy)\b/.test(text) && !/\b(stopped|failed|error|unhealthy|crash)\b/.test(text);
53
+ const state = (text.match(/\b(running|healthy|stopped|failed|pending|starting|unhealthy)\b/) ?? ["unknown"])[0];
54
+ return { app, healthy, state };
55
+ },
56
+ async rm(app) {
57
+ const r = await invoke(["rm", app]);
58
+ ensureOk(r, `lwd rm ${app}`);
59
+ },
60
+ };
61
+ }
62
+ //# sourceMappingURL=lwd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lwd.js","sourceRoot":"","sources":["../../src/stack/lwd.ts"],"names":[],"mappings":";;AA4BA,4CAkDC;AA9ED,0CAAiF;AAqBjF,MAAM,gBAAgB,GAAG,0BAA0B,CAAA;AAEnD;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,OAA0B,EAAE;IAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,KAAK,CAAA;IAC7B,MAAM,GAAG,GAAW,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAA,eAAO,EAAC,GAAG,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;IAE/F,KAAK,UAAU,MAAM,CAAC,IAAc,EAAE,CAAkB;QACtD,IAAI,CAAC;YACH,OAAO,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,GAA4B,CAAA;YACtC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,KAAK,GAAG,2DAA2D,CAAC,CAAA;YACtF,CAAC;YACD,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,CAAgB,EAAE,IAAY,EAAQ,EAAE;QACxD,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IAC3G,CAAC,CAAA;IAED,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,GAAG;YAChB,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;YAC7C,oEAAoE;YACpE,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAA;YAC3B,OAAO,CAAC,CAAC,MAAM;iBACZ,KAAK,CAAC,OAAO,CAAC;iBACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;QAC5C,CAAC;QACD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK;YAC7B,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;YACrE,QAAQ,CAAC,CAAC,EAAE,kBAAkB,GAAG,IAAI,GAAG,EAAE,CAAC,CAAA;QAC7C,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,YAAY;YACtB,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAA;YAC/C,QAAQ,CAAC,CAAC,EAAE,aAAa,YAAY,EAAE,CAAC,CAAA;QAC1C,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,GAAG;YACd,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAA;YACvC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAA;YACtD,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,4CAA4C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC9G,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,iEAAiE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC/G,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;QAChC,CAAC;QACD,KAAK,CAAC,EAAE,CAAC,GAAG;YACV,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;YACnC,QAAQ,CAAC,CAAC,EAAE,UAAU,GAAG,EAAE,CAAC,CAAA;QAC9B,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,38 @@
1
+ export interface LwdService {
2
+ name: string;
3
+ image: string;
4
+ command?: string;
5
+ env: Record<string, string>;
6
+ secrets: string[];
7
+ volume?: string;
8
+ }
9
+ export interface LwdToml {
10
+ name: string;
11
+ domain?: string;
12
+ port?: number;
13
+ image?: string;
14
+ env: Record<string, string>;
15
+ secrets: string[];
16
+ replicas?: number;
17
+ compose?: string;
18
+ service?: string;
19
+ git?: {
20
+ url: string;
21
+ ref?: string;
22
+ path?: string;
23
+ };
24
+ build?: {
25
+ dockerfile?: string;
26
+ context?: string;
27
+ };
28
+ health?: {
29
+ path?: string;
30
+ timeout?: string;
31
+ };
32
+ services: LwdService[];
33
+ }
34
+ /** Parse an lwd.toml string into a typed, normalised shape. */
35
+ export declare function parseLwdToml(content: string): LwdToml;
36
+ /** Read + parse an lwd.toml file, or undefined if it does not exist. */
37
+ export declare function readLwdToml(absPath: string): Promise<LwdToml | undefined>;
38
+ //# sourceMappingURL=lwdtoml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lwdtoml.d.ts","sourceRoot":"","sources":["../../src/stack/lwdtoml.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,GAAG,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAClD,KAAK,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACjD,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5C,QAAQ,EAAE,UAAU,EAAE,CAAA;CACvB;AAcD,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CA4BrD;AAED,wEAAwE;AACxE,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAI/E"}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseLwdToml = parseLwdToml;
4
+ exports.readLwdToml = readLwdToml;
5
+ const fs_1 = require("../utils/fs");
6
+ // @iarna/toml is CommonJS; require sidesteps its empty `types` field. It parses
7
+ // the subset lwd uses (inline tables, arrays-of-tables, comments).
8
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
9
+ const TOML = require("@iarna/toml");
10
+ function strMap(v) {
11
+ const out = {};
12
+ if (v && typeof v === "object") {
13
+ for (const [k, val] of Object.entries(v))
14
+ out[k] = String(val);
15
+ }
16
+ return out;
17
+ }
18
+ function strList(v) {
19
+ return Array.isArray(v) ? v.map((x) => String(x)) : [];
20
+ }
21
+ /** Parse an lwd.toml string into a typed, normalised shape. */
22
+ function parseLwdToml(content) {
23
+ const raw = TOML.parse(content);
24
+ const services = Array.isArray(raw.services)
25
+ ? raw.services.map((s) => ({
26
+ name: String(s.name),
27
+ image: String(s.image),
28
+ command: s.command !== undefined ? String(s.command) : undefined,
29
+ env: strMap(s.env),
30
+ secrets: strList(s.secrets),
31
+ volume: s.volume !== undefined ? String(s.volume) : undefined,
32
+ }))
33
+ : [];
34
+ return {
35
+ name: String(raw.name ?? ""),
36
+ domain: raw.domain !== undefined ? String(raw.domain) : undefined,
37
+ port: typeof raw.port === "number" ? raw.port : undefined,
38
+ image: raw.image !== undefined ? String(raw.image) : undefined,
39
+ env: strMap(raw.env),
40
+ secrets: strList(raw.secrets),
41
+ replicas: typeof raw.replicas === "number" ? raw.replicas : undefined,
42
+ compose: raw.compose !== undefined ? String(raw.compose) : undefined,
43
+ service: raw.service !== undefined ? String(raw.service) : undefined,
44
+ git: raw.git ? { url: String(raw.git.url), ref: raw.git.ref, path: raw.git.path } : undefined,
45
+ build: raw.build ? { dockerfile: raw.build.dockerfile, context: raw.build.context } : undefined,
46
+ health: raw.health ? { path: raw.health.path, timeout: raw.health.timeout } : undefined,
47
+ services,
48
+ };
49
+ }
50
+ /** Read + parse an lwd.toml file, or undefined if it does not exist. */
51
+ async function readLwdToml(absPath) {
52
+ const content = await (0, fs_1.readFileSafe)(absPath);
53
+ if (content === undefined)
54
+ return undefined;
55
+ return parseLwdToml(content);
56
+ }
57
+ //# sourceMappingURL=lwdtoml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lwdtoml.js","sourceRoot":"","sources":["../../src/stack/lwdtoml.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { StackManifest } from "./types";
2
+ export declare const STACK_VERSION = "0.1.0";
3
+ export declare function loadStackManifest(root: string): Promise<StackManifest | undefined>;
4
+ export declare function saveStackManifest(root: string, manifest: StackManifest): Promise<void>;
5
+ /**
6
+ * Validate a stack manifest. Returns a list of human-readable problems (empty =
7
+ * valid): unique app names; every order/apps/sharedWith/service ref resolves;
8
+ * every connection ${NAME} resolves to a generate key; secret names well-formed.
9
+ */
10
+ export declare function validateStackManifest(m: StackManifest): string[];
11
+ /** All ${NAME} references in a connection template. */
12
+ export declare function templateRefs(template: string): string[];
13
+ /** Substitute ${NAME} refs in a template from a values map. */
14
+ export declare function resolveTemplate(template: string, values: Record<string, string>): string;
15
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/stack/manifest.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAI5C,eAAO,MAAM,aAAa,UAAU,CAAA;AAGpC,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAExF;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5F;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,EAAE,CAqChE;AAED,uDAAuD;AACvD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAMvD;AAED,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAExF"}
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.STACK_VERSION = void 0;
7
+ exports.loadStackManifest = loadStackManifest;
8
+ exports.saveStackManifest = saveStackManifest;
9
+ exports.validateStackManifest = validateStackManifest;
10
+ exports.templateRefs = templateRefs;
11
+ exports.resolveTemplate = resolveTemplate;
12
+ const node_path_1 = __importDefault(require("node:path"));
13
+ const fs_1 = require("../utils/fs");
14
+ const paths_1 = require("../project/paths");
15
+ exports.STACK_VERSION = "0.1.0";
16
+ const SECRET_NAME_RE = /^[A-Z][A-Z0-9_]*$/;
17
+ async function loadStackManifest(root) {
18
+ return (0, fs_1.readJson)(node_path_1.default.join(root, paths_1.paths.stackManifest));
19
+ }
20
+ async function saveStackManifest(root, manifest) {
21
+ await (0, fs_1.writeJson)(node_path_1.default.join(root, paths_1.paths.stackManifest), manifest);
22
+ }
23
+ /**
24
+ * Validate a stack manifest. Returns a list of human-readable problems (empty =
25
+ * valid): unique app names; every order/apps/sharedWith/service ref resolves;
26
+ * every connection ${NAME} resolves to a generate key; secret names well-formed.
27
+ */
28
+ function validateStackManifest(m) {
29
+ const errors = [];
30
+ const appNames = new Set(m.apps.map((a) => a.name));
31
+ if (m.apps.length !== appNames.size)
32
+ errors.push("duplicate app names");
33
+ for (const name of m.order) {
34
+ if (!appNames.has(name))
35
+ errors.push(`order references unknown app "${name}"`);
36
+ }
37
+ if (m.order.length !== m.apps.length) {
38
+ errors.push(`order lists ${m.order.length} apps but ${m.apps.length} are declared`);
39
+ }
40
+ const checkSecretName = (name) => {
41
+ if (!SECRET_NAME_RE.test(name))
42
+ errors.push(`invalid secret name "${name}" (want ^[A-Z][A-Z0-9_]*$)`);
43
+ };
44
+ const generateKeys = new Set(Object.keys(m.secrets.generate));
45
+ for (const [name, g] of Object.entries(m.secrets.generate)) {
46
+ checkSecretName(name);
47
+ for (const app of g.apps)
48
+ if (!appNames.has(app))
49
+ errors.push(`generate.${name} targets unknown app "${app}"`);
50
+ if (g.bytes <= 0)
51
+ errors.push(`generate.${name} needs bytes > 0`);
52
+ }
53
+ for (const [name, c] of Object.entries(m.secrets.connections)) {
54
+ checkSecretName(name);
55
+ if (!appNames.has(c.service.app))
56
+ errors.push(`connections.${name}.service.app unknown app "${c.service.app}"`);
57
+ for (const app of c.apps)
58
+ if (!appNames.has(app))
59
+ errors.push(`connections.${name} targets unknown app "${app}"`);
60
+ for (const app of c.sharedWith ?? []) {
61
+ if (!appNames.has(app))
62
+ errors.push(`connections.${name}.sharedWith unknown app "${app}"`);
63
+ }
64
+ for (const ref of templateRefs(c.template)) {
65
+ if (!generateKeys.has(ref))
66
+ errors.push(`connections.${name} references \${${ref}} which is not a generate secret`);
67
+ }
68
+ }
69
+ for (const name of m.secrets.manual)
70
+ checkSecretName(name);
71
+ return errors;
72
+ }
73
+ /** All ${NAME} references in a connection template. */
74
+ function templateRefs(template) {
75
+ const out = [];
76
+ const re = /\$\{([A-Z][A-Z0-9_]*)\}/g;
77
+ let match;
78
+ while ((match = re.exec(template)) !== null)
79
+ out.push(match[1]);
80
+ return out;
81
+ }
82
+ /** Substitute ${NAME} refs in a template from a values map. */
83
+ function resolveTemplate(template, values) {
84
+ return template.replace(/\$\{([A-Z][A-Z0-9_]*)\}/g, (_, name) => values[name] ?? `\${${name}}`);
85
+ }
86
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/stack/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ export type AppRole = "api" | "web" | "worker" | "resource" | "app";
2
+ export interface StackApp {
3
+ name: string;
4
+ /** Repo-relative path to the app's lwd.toml. */
5
+ manifest: string;
6
+ role: AppRole;
7
+ }
8
+ /** A secret whose value the tool generates and sets on `apps`. */
9
+ export interface GenerateSecret {
10
+ type: "password" | "hex";
11
+ bytes: number;
12
+ apps: string[];
13
+ }
14
+ /** A secret DERIVED from generated components via `template`. */
15
+ export interface ConnectionSecret {
16
+ /** Shell-free string with ${NAME} refs into `generate` keys. */
17
+ template: string;
18
+ /** The backing service this connection reaches (for reachability checks). */
19
+ service: {
20
+ app: string;
21
+ name: string;
22
+ };
23
+ /** Consumers KNOWN to reach the service (validated). */
24
+ apps: string[];
25
+ /** Requested cross-app consumers (validated → may be flagged). */
26
+ sharedWith?: string[];
27
+ }
28
+ export interface StackSecrets {
29
+ generate: Record<string, GenerateSecret>;
30
+ connections: Record<string, ConnectionSecret>;
31
+ /** Names the tool won't invent; the operator sets them. */
32
+ manual: string[];
33
+ }
34
+ export interface StackManifest {
35
+ name: string;
36
+ stackVersion: string;
37
+ apps: StackApp[];
38
+ /** App names in dependency order for apply. */
39
+ order: string[];
40
+ secrets: StackSecrets;
41
+ }
42
+ /** Health/state parsed from `lwd status <app>`. */
43
+ export interface AppStatus {
44
+ app: string;
45
+ healthy: boolean;
46
+ state: string;
47
+ }
48
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/stack/types.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,KAAK,CAAA;AAEnE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,OAAO,CAAA;CACd;AAED,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,GAAG,KAAK,CAAA;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,EAAE,CAAA;CACf;AAED,iEAAiE;AACjE,MAAM,WAAW,gBAAgB;IAC/B,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACtC,wDAAwD;IACxD,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IACxC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;IAC7C,2DAA2D;IAC3D,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,QAAQ,EAAE,CAAA;IAChB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,OAAO,EAAE,YAAY,CAAA;CACtB;AAED,mDAAmD;AACnD,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ // The stack delivery contract: deploy/stack.json. Distinct from forge.json
3
+ // (a receipt) — this is the reviewable repo→lwd wiring plan.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/stack/types.ts"],"names":[],"mappings":";AAAA,2EAA2E;AAC3E,6DAA6D"}
@@ -0,0 +1,40 @@
1
+ import type { StackManifest } from "./types";
2
+ import { type LwdToml } from "./lwdtoml";
3
+ import type { LwdAdapter } from "./lwd";
4
+ export type SecretAction = "skip" | "generate" | "derive" | "blocked" | "manual-missing";
5
+ export interface SecretPlanItem {
6
+ app: string;
7
+ key: string;
8
+ action: SecretAction;
9
+ /** Resolved value for generate/derive — NEVER logged. */
10
+ value?: string;
11
+ reason?: string;
12
+ }
13
+ export interface StackPlan {
14
+ order: string[];
15
+ items: SecretPlanItem[];
16
+ /** Connectivity / derivation problems that block a clean deploy. */
17
+ flags: string[];
18
+ }
19
+ export interface PlanOptions {
20
+ rotate?: string[];
21
+ onlyApp?: string;
22
+ }
23
+ /**
24
+ * Pure planning: given the manifest, each app's lwd.toml, and the secret names
25
+ * lwd already holds per app, decide what to skip / generate / derive / block.
26
+ * No IO, no execution — this is what the tests exercise.
27
+ */
28
+ export declare function planSecrets(manifest: StackManifest, tomlByApp: Record<string, LwdToml>, existingByApp: Record<string, string[]>, opts?: PlanOptions): StackPlan;
29
+ /** Read each app's lwd.toml and the secret names lwd already holds, then plan. */
30
+ export declare function computeStackDeploy(root: string, manifest: StackManifest, adapter: LwdAdapter, opts?: PlanOptions): Promise<{
31
+ plan: StackPlan;
32
+ tomlByApp: Record<string, LwdToml>;
33
+ }>;
34
+ /** Log the plan, masking every value (a generated value never appears in output). */
35
+ export declare function printStackPlan(manifest: StackManifest, plan: StackPlan): void;
36
+ /** Execute the plan: set missing secrets per app in order, apply, gate on health. */
37
+ export declare function executeStackDeploy(root: string, manifest: StackManifest, adapter: LwdAdapter, plan: StackPlan, opts?: {
38
+ noWait?: boolean;
39
+ }): Promise<void>;
40
+ //# sourceMappingURL=wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../../src/stack/wire.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE5C,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,WAAW,CAAA;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAGvC,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,gBAAgB,CAAA;AAExF,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,YAAY,CAAA;IACpB,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,KAAK,EAAE,cAAc,EAAE,CAAA;IACvB,oEAAoE;IACpE,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAaD;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,aAAa,EACvB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACvC,IAAI,GAAE,WAAgB,GACrB,SAAS,CAuEX;AAED,kFAAkF;AAClF,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,UAAU,EACnB,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CAUlE;AAED,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CAyB7E;AAED,qFAAqF;AACrF,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,UAAU,EACnB,IAAI,EAAE,SAAS,EACf,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9B,OAAO,CAAC,IAAI,CAAC,CA4Bf"}