@bevel-software/platform-core-backend 0.8.0 → 0.9.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 (84) hide show
  1. package/dist/core/core-ports.d.ts +7 -0
  2. package/dist/core/core-ports.d.ts.map +1 -1
  3. package/dist/core/core-ports.js.map +1 -1
  4. package/dist/core/create-core-server.d.ts.map +1 -1
  5. package/dist/core/create-core-server.js +24 -11
  6. package/dist/core/create-core-server.js.map +1 -1
  7. package/dist/core/create-core-services.d.ts +7 -2
  8. package/dist/core/create-core-services.d.ts.map +1 -1
  9. package/dist/core/create-core-services.js +39 -18
  10. package/dist/core/create-core-services.js.map +1 -1
  11. package/dist/modules/access/access.routes.d.ts +3 -1
  12. package/dist/modules/access/access.routes.d.ts.map +1 -1
  13. package/dist/modules/access/access.routes.js +4 -2
  14. package/dist/modules/access/access.routes.js.map +1 -1
  15. package/dist/modules/access/render-roles-yaml.d.ts +22 -0
  16. package/dist/modules/access/render-roles-yaml.d.ts.map +1 -0
  17. package/dist/modules/access/render-roles-yaml.js +56 -0
  18. package/dist/modules/access/render-roles-yaml.js.map +1 -0
  19. package/dist/modules/access/roles-admin.service.d.ts +15 -1
  20. package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
  21. package/dist/modules/access/roles-admin.service.js +30 -15
  22. package/dist/modules/access/roles-admin.service.js.map +1 -1
  23. package/dist/modules/settings/setup.routes.d.ts +10 -1
  24. package/dist/modules/settings/setup.routes.d.ts.map +1 -1
  25. package/dist/modules/settings/setup.routes.js +111 -6
  26. package/dist/modules/settings/setup.routes.js.map +1 -1
  27. package/dist/modules/workspace/startup/kb-git.d.ts +23 -0
  28. package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -0
  29. package/dist/modules/workspace/startup/kb-git.js +86 -0
  30. package/dist/modules/workspace/startup/kb-git.js.map +1 -0
  31. package/dist/modules/workspace/startup/kb-startup-runner.d.ts +74 -0
  32. package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -0
  33. package/dist/modules/workspace/startup/kb-startup-runner.js +528 -0
  34. package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -0
  35. package/dist/modules/workspace/startup/on-server-start.d.ts +105 -0
  36. package/dist/modules/workspace/startup/on-server-start.d.ts.map +1 -0
  37. package/dist/modules/workspace/startup/on-server-start.js +21 -0
  38. package/dist/modules/workspace/startup/on-server-start.js.map +1 -0
  39. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +46 -0
  40. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -0
  41. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +492 -0
  42. package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -0
  43. package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts +23 -0
  44. package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts.map +1 -0
  45. package/dist/modules/workspace/startup/steps/roles-yaml.step.js +69 -0
  46. package/dist/modules/workspace/startup/steps/roles-yaml.step.js.map +1 -0
  47. package/dist/modules/workspace/startup/steps/seed-tree.d.ts +17 -0
  48. package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -0
  49. package/dist/modules/workspace/startup/steps/seed-tree.js +109 -0
  50. package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -0
  51. package/dist/modules/workspace/startup/steps/template-files.step.d.ts +103 -0
  52. package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -0
  53. package/dist/modules/workspace/startup/steps/template-files.step.js +337 -0
  54. package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -0
  55. package/dist/modules/workspace/workspace.service.d.ts +0 -35
  56. package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
  57. package/dist/modules/workspace/workspace.service.js +2 -101
  58. package/dist/modules/workspace/workspace.service.js.map +1 -1
  59. package/kb-template/gitignore.template +16 -0
  60. package/package.json +3 -3
  61. package/src/core/core-ports.ts +7 -0
  62. package/src/core/create-core-server.ts +30 -11
  63. package/src/core/create-core-services.ts +43 -22
  64. package/src/modules/access/__tests__/roles-admin.service.test.ts +24 -2
  65. package/src/modules/access/access.routes.ts +3 -0
  66. package/src/modules/access/render-roles-yaml.ts +65 -0
  67. package/src/modules/access/roles-admin.service.ts +32 -14
  68. package/src/modules/settings/__tests__/setup.routes.test.ts +124 -3
  69. package/src/modules/settings/setup.routes.ts +112 -5
  70. package/src/modules/workspace/__tests__/workspace.service.test.ts +5 -94
  71. package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +495 -0
  72. package/src/modules/workspace/startup/kb-git.ts +94 -0
  73. package/src/modules/workspace/startup/kb-startup-runner.ts +597 -0
  74. package/src/modules/workspace/startup/on-server-start.ts +97 -0
  75. package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +636 -0
  76. package/src/modules/workspace/{plugins-migration.ts → startup/steps/groups-to-plugins.step.ts} +342 -260
  77. package/src/modules/workspace/startup/steps/roles-yaml.step.ts +71 -0
  78. package/src/modules/workspace/startup/steps/seed-tree.ts +115 -0
  79. package/src/modules/workspace/startup/steps/template-files.step.ts +360 -0
  80. package/src/modules/workspace/workspace.service.ts +2 -106
  81. package/src/modules/workspace/__tests__/kb-seed.service.test.ts +0 -512
  82. package/src/modules/workspace/__tests__/plugins-migration.test.ts +0 -427
  83. package/src/modules/workspace/kb-seed.interface.ts +0 -36
  84. package/src/modules/workspace/kb-seed.service.ts +0 -584
@@ -0,0 +1,528 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { isBranchModelConfigured } from '@bevel-software/platform-shared';
4
+ import { workspaceIdForBranch } from '../workspace.service.js';
5
+ import { git, lsRemoteHeads, redactSecret, stampIdentity, withTempDir } from './kb-git.js';
6
+ export class KbStartupRunner {
7
+ opts;
8
+ constructor(opts) {
9
+ this.opts = opts;
10
+ }
11
+ /**
12
+ * Run the whole phase. Throws to stop the boot; returns normally when the
13
+ * KB is fully maintained (or safe boot abandoned the phase, loudly).
14
+ */
15
+ async runAll() {
16
+ if (!isBranchModelConfigured()) {
17
+ console.log('[kb-startup] branch model not configured yet — phase skipped until setup completes.');
18
+ return;
19
+ }
20
+ // A branch model without a repository URL is a PARTIALLY set-up deployment
21
+ // (the two can arrive on different saves, and a restart can land between
22
+ // them). There is nothing to maintain yet, and running anyway would
23
+ // `ls-remote ''` — a boot that fails forever while the setup screen it
24
+ // needs stays unreachable. The setup-completion invocation catches up the
25
+ // moment the URL exists.
26
+ if (this.opts.kbRepoUrl().trim() === '') {
27
+ console.log('[kb-startup] KB repository URL not configured yet — phase skipped until setup completes.');
28
+ return;
29
+ }
30
+ const safeBoot = process.env.KB_SAFE_BOOT === '1';
31
+ if (safeBoot) {
32
+ console.warn('[kb-startup] KB_SAFE_BOOT=1 — failures will abandon maintenance instead of stopping the boot. ' +
33
+ 'Remove the variable once the rescue is done.');
34
+ }
35
+ const phaseStart = Date.now();
36
+ const handles = new Map();
37
+ // ONE safe-boot boundary around the whole phase — remote preparation, the
38
+ // step loop, AND the finalize commits. Rescue mode must be able to reset
39
+ // and boot whichever of them fails; a boundary around the step loop alone
40
+ // would let an ensureRemote or finalize failure stop the very boot
41
+ // KB_SAFE_BOOT exists to allow.
42
+ try {
43
+ // A URL carrying userinfo (`https://user:token@host/…`) is operator
44
+ // error, and fail-closed means THROWING, not skipping: the embedded
45
+ // credential would ride into argv on every git invocation and be
46
+ // visible in process listings. Checked INSIDE the boundary so
47
+ // KB_SAFE_BOOT can still bring the server up over a persisted bad URL
48
+ // — the rescue never invokes git. (The message never quotes the URL.)
49
+ if (/\/\/[^/]*@/.test(this.opts.kbRepoUrl())) {
50
+ throw new Error('The KB repository URL embeds credentials (user:token@host), which would be visible in ' +
51
+ 'process listings. Remove them from the URL and configure the token via the setup ' +
52
+ 'screen or GITHUB_TOKEN instead.');
53
+ }
54
+ const heads = await this.ensureRemote();
55
+ const ctx = this.buildContext(heads, handles);
56
+ for (const step of this.opts.steps) {
57
+ const started = Date.now();
58
+ const result = await step.run(ctx).catch((err) => {
59
+ const msg = err instanceof Error ? err.message : String(err);
60
+ throw new Error(redactSecret(`KB startup step "${step.name}" failed: ${msg}`));
61
+ });
62
+ const took = `${((Date.now() - started) / 1000).toFixed(1)}s`;
63
+ if (result.outcome === 'stopBoot') {
64
+ // Redacted like every other exit: the message travels beyond logs
65
+ // (the setup status endpoint surfaces it to admins).
66
+ throw new Error(redactSecret(`KB startup step "${step.name}" stopped the boot: ${result.message}`));
67
+ }
68
+ if (result.outcome === 'skipped') {
69
+ console.warn(`[kb-startup] ${step.name}: skipped — ${result.reason} (${took})`);
70
+ for (const h of handles.values())
71
+ h.discardBuffer();
72
+ continue;
73
+ }
74
+ // Counted before applying — applyBuffer drains the buffers.
75
+ let changes = 0;
76
+ let branches = 0;
77
+ for (const h of handles.values()) {
78
+ const n = h.pendingOpCount();
79
+ if (n > 0) {
80
+ changes += n;
81
+ branches++;
82
+ }
83
+ }
84
+ const scope = changes === 0
85
+ ? 'no changes'
86
+ : `${changes} change${changes === 1 ? '' : 's'} on ${branches} branch${branches === 1 ? '' : 'es'}`;
87
+ if (result.outcome === 'partial') {
88
+ console.warn(`[kb-startup] ${step.name}: partial — ${result.reason} (${scope}, ${took})`);
89
+ }
90
+ else {
91
+ // One line per step even when nothing happened: a silent phase and a
92
+ // step that never ran look identical from the boot log otherwise.
93
+ console.log(`[kb-startup] ${step.name}: ok — ${scope} (${took})`);
94
+ }
95
+ for (const h of handles.values())
96
+ await h.applyBuffer();
97
+ }
98
+ for (const h of handles.values()) {
99
+ await this.finalize(h);
100
+ }
101
+ }
102
+ catch (err) {
103
+ if (!safeBoot)
104
+ throw err;
105
+ console.error('[kb-startup] SAFE BOOT: abandoning the phase after a failure — the KB is UNMAINTAINED this run.', redactSecret(err instanceof Error ? err.message : String(err)));
106
+ // Reset only DIRTY handles — ones an apply at least began on (the mark
107
+ // is set before the first op, so a mid-apply failure is covered). A
108
+ // clone a step merely read must NOT be swept: sweeping it would disturb
109
+ // pre-existing state in a surviving working clone that no op ever
110
+ // touched. Each reset targets the handle's recorded pre-phase sha, so
111
+ // even a created-but-unpushed finalize commit is rolled back.
112
+ for (const h of handles.values())
113
+ await h.resetUncommitted().catch(() => { });
114
+ return;
115
+ }
116
+ console.log(`[kb-startup] phase complete (${((Date.now() - phaseStart) / 1000).toFixed(1)}s).`);
117
+ }
118
+ /**
119
+ * Remote preparation — runner machinery, not a step, because every remote
120
+ * failure mode here is the runner's to own: an EMPTY remote gets the full
121
+ * seed commit pushed to every protected branch; missing protected refs are
122
+ * created from the best base. Returns the remote's head names (post-seed).
123
+ */
124
+ async ensureRemote() {
125
+ const url = this.opts.kbRepoUrl();
126
+ const user = this.opts.gitUsername();
127
+ const heads = await lsRemoteHeads(url, user);
128
+ const protectedBranches = this.opts.protectedBranches();
129
+ const defaultBranch = this.opts.defaultBranch();
130
+ if (heads.size === 0) {
131
+ if (this.opts.seedAdminEmails.length === 0) {
132
+ throw new Error('KB remote is empty and cannot be seeded: no initial Admin was supplied (ADMIN_EMAIL).');
133
+ }
134
+ const seededByOther = await withTempDir(async (dir) => {
135
+ await git(dir, user, ['init', '-b', defaultBranch]);
136
+ await stampIdentity(dir, user);
137
+ const generated = await this.opts.buildSeedTree(dir);
138
+ await git(dir, user, ['add', '-A']);
139
+ // The template may ship a `.gitignore` whose rules happen to match a
140
+ // GENERATED seed file (roles.yaml, a reserved root's .gitkeep) —
141
+ // `add -A` would silently drop it from the seed commit. Force-add
142
+ // exactly what the builder generated; `-f` on an already-staged path
143
+ // is a no-op.
144
+ if (generated.length > 0)
145
+ await git(dir, user, ['add', '-f', '--', ...generated]);
146
+ await git(dir, user, ['commit', '-m', 'Seed knowledge base from Bevel template']);
147
+ for (const b of protectedBranches) {
148
+ if (b !== defaultBranch)
149
+ await git(dir, user, ['branch', b]);
150
+ }
151
+ await git(dir, user, ['remote', 'add', 'origin', url]);
152
+ try {
153
+ await git(dir, user, ['push', '-u', 'origin', ...protectedBranches]);
154
+ return null;
155
+ }
156
+ catch (err) {
157
+ // Two replicas racing to seed the same empty remote: both saw it
158
+ // empty, one push landed first, the loser's is rejected. ONE re-read
159
+ // decides — if every protected branch now exists, the loser accepts
160
+ // the winner's work; anything less is a real push failure and
161
+ // rethrows. Ref EXISTENCE is deliberately the whole test — content
162
+ // identity is not required, because the steps that follow enforce
163
+ // the required scaffolding on every protected branch regardless of
164
+ // who seeded. A foreign seed is just an "existing remote"
165
+ // discovered late, the same contract as a repo populated before
166
+ // boot.
167
+ const reread = await lsRemoteHeads(url, user);
168
+ if (protectedBranches.every((b) => reread.has(b)))
169
+ return reread;
170
+ throw err;
171
+ }
172
+ });
173
+ if (seededByOther) {
174
+ console.log('[kb-startup] seed push rejected — another replica seeded the remote first; continuing with its branches.');
175
+ return seededByOther;
176
+ }
177
+ console.log(`[kb-startup] seeded empty KB remote with branches: ${protectedBranches.join(', ')}`);
178
+ return new Set(protectedBranches);
179
+ }
180
+ const base = heads.has(defaultBranch)
181
+ ? defaultBranch
182
+ : (protectedBranches.find((b) => heads.has(b)) ?? [...heads].sort()[0]);
183
+ for (const b of protectedBranches) {
184
+ if (heads.has(b))
185
+ continue;
186
+ await withTempDir(async (dir) => {
187
+ await git(dir, user, ['clone', '--depth', '1', '-b', base, url, 'seed']);
188
+ await git(path.join(dir, 'seed'), user, ['push', 'origin', `HEAD:refs/heads/${b}`]);
189
+ });
190
+ heads.add(b);
191
+ console.log(`[kb-startup] created missing protected branch "${b}" from "${base}"`);
192
+ }
193
+ return heads;
194
+ }
195
+ buildContext(heads, handles) {
196
+ const protectedSet = new Set(this.opts.protectedBranches());
197
+ const handleFor = (branch) => {
198
+ let h = handles.get(branch);
199
+ if (!h) {
200
+ h = new BranchHandle(branch, protectedSet.has(branch), () => this.ensureClone(branch));
201
+ handles.set(branch, h);
202
+ }
203
+ return h;
204
+ };
205
+ return {
206
+ templateDir: this.opts.templateDir,
207
+ defaultBranch: async () => handleFor(this.opts.defaultBranch()),
208
+ protectedBranches: async () => this.opts.protectedBranches().map(handleFor),
209
+ allBranches: async () => [...heads].sort().map(handleFor),
210
+ };
211
+ }
212
+ /**
213
+ * The branch's working copy at the runtime layout
214
+ * (`<workspacesRoot>/<id>/<kbDirName>`), so the workspace service finds it
215
+ * on disk afterwards. A surviving clone is fast-forwarded to origin when
216
+ * that is a pure fast-forward; a clone that is AHEAD (a crash before push
217
+ * left committed work) is left alone — maintenance lands on top and the
218
+ * push either carries both or rejects and rolls back, and the pending-
219
+ * commit recovery owns that work, not this phase.
220
+ */
221
+ async ensureClone(branch) {
222
+ const user = this.opts.gitUsername();
223
+ const workspaceDir = path.join(this.opts.workspacesRoot, workspaceIdForBranch(branch));
224
+ const repoDir = path.join(workspaceDir, this.opts.kbDirName);
225
+ const hasGit = await fs.access(path.join(repoDir, '.git')).then(() => true, () => false);
226
+ if (!hasGit) {
227
+ await fs.mkdir(workspaceDir, { recursive: true });
228
+ await fs.rm(repoDir, { recursive: true, force: true });
229
+ await git(workspaceDir, user, ['clone', '-b', branch, this.opts.kbRepoUrl(), repoDir]);
230
+ await git(repoDir, user, ['config', 'core.longpaths', 'true']);
231
+ await stampIdentity(repoDir, user);
232
+ return repoDir;
233
+ }
234
+ await git(repoDir, user, ['fetch', 'origin', branch]);
235
+ const local = (await git(repoDir, user, ['rev-parse', 'HEAD'])).trim();
236
+ const remote = (await git(repoDir, user, ['rev-parse', `origin/${branch}`])).trim();
237
+ if (local !== remote) {
238
+ const mergeBase = (await git(repoDir, user, ['merge-base', 'HEAD', `origin/${branch}`])).trim();
239
+ if (mergeBase === local) {
240
+ await git(repoDir, user, ['reset', '--hard', `origin/${branch}`]);
241
+ }
242
+ // Ahead or diverged: committed-but-unpushed work lives here; not ours to discard.
243
+ }
244
+ return repoDir;
245
+ }
246
+ /** One commit per dirty branch; push; the replica carve-out on rejection. */
247
+ async finalize(h) {
248
+ if (!h.dirty)
249
+ return;
250
+ const repoDir = await h.repoDir();
251
+ const user = this.opts.gitUsername();
252
+ await stampIdentity(repoDir, user);
253
+ // Drop any PRE-EXISTING index state first (a crashed tool may have left
254
+ // edits staged): `git commit` publishes the whole index, and the phase
255
+ // must commit exactly its own staged set. The edits stay in the working
256
+ // tree, unstaged and unpublished — preserved, not adopted.
257
+ await git(repoDir, user, ['reset', '-q']);
258
+ // Stage ONLY the paths the phase's ops touched — sources and targets both
259
+ // (a move's `from` and a remove's path stage as deletions; `add -A -- <path>`
260
+ // handles a deleted path, `-f` handles one a branch `.gitignore` matches).
261
+ // Deliberately NOT `add -A` on the whole tree: pre-existing uncommitted
262
+ // dirt in a reused clone is not this phase's work — it stays out of the
263
+ // phase's commit and remains in the tree, untouched.
264
+ //
265
+ // A pathspec matching nothing is an error, so a path is included only when
266
+ // it exists on disk OR git knows it (`ls-files` non-empty — a tracked path
267
+ // whose deletion must be staged). A path failing both was never tracked
268
+ // and no longer exists: nothing to stage.
269
+ const touched = [];
270
+ for (const rel of h.appliedPaths()) {
271
+ const onDisk = await fs.access(path.join(repoDir, rel)).then(() => true, () => false);
272
+ if (!onDisk) {
273
+ const known = (await git(repoDir, user, ['ls-files', '--', `:(literal)${rel}`])).trim();
274
+ if (known === '')
275
+ continue;
276
+ }
277
+ touched.push(rel);
278
+ }
279
+ // `:(literal)` — these are file paths, not pathspecs; chunked so a large
280
+ // migration cannot overflow the platform's argv limit.
281
+ for (let i = 0; i < touched.length; i += 100) {
282
+ await git(repoDir, user, [
283
+ 'add',
284
+ '-A',
285
+ '-f',
286
+ '--',
287
+ ...touched.slice(i, i + 100).map((rel) => `:(literal)${rel}`),
288
+ ]);
289
+ }
290
+ // Exit 0 = nothing staged: the ops converged to no byte changes. (An
291
+ // errored diff reads as "something staged"; a genuinely broken repo then
292
+ // fails loudly at commit rather than being silently skipped here.)
293
+ const nothingStaged = await git(repoDir, user, ['diff', '--cached', '--quiet']).then(() => true, () => false);
294
+ if (nothingStaged)
295
+ return;
296
+ // The commit this phase is about to add, remembered so the rollback below
297
+ // can undo exactly it — and ONLY it. Resetting to origin/<name> instead
298
+ // would also nuke a pre-existing committed-but-unpushed (AHEAD) commit
299
+ // that ensureClone deliberately preserved.
300
+ const preCommit = (await git(repoDir, user, ['rev-parse', 'HEAD'])).trim();
301
+ await git(repoDir, user, ['commit', '-m', h.commitMessage()]);
302
+ try {
303
+ await git(repoDir, user, ['push', 'origin', `HEAD:refs/heads/${h.name}`]);
304
+ console.log(`[kb-startup] ${h.name}: ${h.commitSubject()}`);
305
+ // Committed AND pushed: nothing of the phase remains uncommitted here,
306
+ // so a LATER branch's failure under KB_SAFE_BOOT must not rewind this
307
+ // clone to its pre-phase sha — that would leave it behind what origin
308
+ // already holds.
309
+ h.dirty = false;
310
+ }
311
+ catch (err) {
312
+ const msg = err instanceof Error ? err.message : String(err);
313
+ // The carve-out is ONLY for a push the remote refused as stale — a
314
+ // concurrent replica won the race, and its pass made the same idempotent
315
+ // changes. Git spells that refusal `! [rejected] … (non-fast-forward)`
316
+ // or `… (fetch first)`; the regex matches exactly those two markers.
317
+ // Deliberately NOT the generic `failed to push some refs` / `[rejected]`
318
+ // trailers: a pre-receive hook decline (branch protection on the KB
319
+ // repo, say) prints those too, and that is a policy refusal every boot
320
+ // would hit — it re-throws like auth or network failures (stopping the
321
+ // boot, or demoted to abandon under KB_SAFE_BOOT like every failure).
322
+ if (!/non-fast-forward|fetch first/i.test(msg)) {
323
+ throw err;
324
+ }
325
+ console.warn(`[kb-startup] ${h.name}: push rejected (concurrent replica?) — rolling back local commit.`, redactSecret(msg));
326
+ await git(repoDir, user, ['reset', '--hard', preCommit]).catch(() => { });
327
+ }
328
+ }
329
+ }
330
+ /**
331
+ * The {@link KbBranch} implementation: a lazy clone plus an op buffer. Ops AND
332
+ * notes accumulate while a step runs; the RUNNER applies both (`applyBuffer`)
333
+ * on `ok`/`partial` and drops both (`discardBuffer`) on `skipped` — a skipped
334
+ * step's notes must never decorate a commit made of other steps' changes.
335
+ * Applied ops mark the handle dirty; kept notes accumulate across steps into
336
+ * one commit.
337
+ */
338
+ class BranchHandle {
339
+ name;
340
+ isProtected;
341
+ constructor(name, isProtected, cloneOnce) {
342
+ this.name = name;
343
+ this.isProtected = isProtected;
344
+ this.clone = lazyOnce(async () => {
345
+ const dir = await cloneOnce();
346
+ // The rollback anchor, recorded ONCE as the clone materializes: a fresh
347
+ // clone's HEAD, or a surviving clone's pre-phase state (post the
348
+ // fast-forward ensureClone may have applied). For the empty-remote seed
349
+ // the handle clones AFTER seeding, so HEAD is the seed commit — correct.
350
+ // resetUncommitted resets to THIS sha rather than HEAD, so a finalize
351
+ // commit that was created but failed to push rolls back too instead of
352
+ // surviving as a stranded local commit no later boot would ever push.
353
+ this.prePhaseSha = (await git(dir, 'x-access-token', ['rev-parse', 'HEAD'])).trim();
354
+ return dir;
355
+ });
356
+ }
357
+ clone;
358
+ /** HEAD as of clone time — the safe-boot rollback's anchor (see the constructor). */
359
+ prePhaseSha = null;
360
+ buffer = [];
361
+ /** The CURRENT step's notes — kept or discarded with its ops. */
362
+ noteBuffer = [];
363
+ /** Notes of applied steps, in order — the commit message's material. */
364
+ notes = [];
365
+ /**
366
+ * Repo-relative paths the ops touched — SOURCES and TARGETS both: writes
367
+ * recorded BEFORE executing (a failed write can leave a partial file the
368
+ * rollback must clean), move destinations AFTER (a failed rename leaves its
369
+ * target untouched — see the note at the rename), and a move's `from` and a
370
+ * remove's path unconditionally at apply time — finalize stages exactly
371
+ * this set, and staging a deletion is what `add -A -- <path>` does.
372
+ */
373
+ applied = new Set();
374
+ dirty = false;
375
+ repoDir() {
376
+ return this.clone();
377
+ }
378
+ write(p, content) {
379
+ this.buffer.push({ kind: 'write', path: p, content });
380
+ }
381
+ move(from, to) {
382
+ this.buffer.push({ kind: 'move', from, to });
383
+ }
384
+ remove(p) {
385
+ this.buffer.push({ kind: 'remove', path: p });
386
+ }
387
+ note(line) {
388
+ this.noteBuffer.push(line);
389
+ }
390
+ discardBuffer() {
391
+ this.buffer = [];
392
+ this.noteBuffer = [];
393
+ }
394
+ /** Apply buffered ops in declaration order, each path contained to the clone. */
395
+ async applyBuffer() {
396
+ // The step's notes are kept even when it declared no ops — an advisory
397
+ // note (e.g. "both roots exist, merge by hand") surfaces in a commit only
398
+ // if a later step dirties the branch, exactly as before.
399
+ if (this.noteBuffer.length > 0) {
400
+ this.notes.push(...this.noteBuffer);
401
+ this.noteBuffer = [];
402
+ }
403
+ if (this.buffer.length === 0)
404
+ return;
405
+ const repoDir = await this.repoDir();
406
+ // Dirty from the FIRST op, not the last: a mid-apply failure must leave
407
+ // the handle marked so the safe-boot rollback sweeps its partial writes.
408
+ this.dirty = true;
409
+ const ops = this.buffer;
410
+ this.buffer = [];
411
+ for (const op of ops) {
412
+ if (op.kind === 'write') {
413
+ this.applied.add(op.path);
414
+ const abs = await containedPath(repoDir, op.path);
415
+ await fs.mkdir(path.dirname(abs), { recursive: true });
416
+ await fs.writeFile(abs, op.content);
417
+ }
418
+ else if (op.kind === 'move') {
419
+ // The SOURCE is recorded unconditionally: finalize must stage its
420
+ // disappearance. (Harmless to the rollback — a tracked source is
421
+ // restored by the reset, and `clean` never touches tracked paths.)
422
+ this.applied.add(op.from);
423
+ const from = await containedPath(repoDir, op.from);
424
+ const to = await containedPath(repoDir, op.to);
425
+ await fs.mkdir(path.dirname(to), { recursive: true });
426
+ await fs.rename(from, to);
427
+ // Recorded AFTER the rename, unlike a write's pre-record: rename
428
+ // cannot leave a partial destination (it either happened or errored
429
+ // with the target untouched), and pre-recording would let the
430
+ // rollback delete a pre-existing ignored file at an untouched target.
431
+ this.applied.add(op.to);
432
+ }
433
+ else {
434
+ // Recorded unconditionally, like a move's source: finalize must stage
435
+ // the deletion of a removed tracked file.
436
+ this.applied.add(op.path);
437
+ const abs = await containedPath(repoDir, op.path);
438
+ await fs.rm(abs, { force: true });
439
+ }
440
+ }
441
+ }
442
+ /** Ops declared by the current step and not yet applied — log material. */
443
+ pendingOpCount() {
444
+ return this.buffer.length;
445
+ }
446
+ /**
447
+ * Every path the applied ops touched — sources and targets. Finalize stages
448
+ * exactly this set (force-added past any branch `.gitignore`); the safe-boot
449
+ * rollback scopes its `clean` to it.
450
+ */
451
+ appliedPaths() {
452
+ return [...this.applied];
453
+ }
454
+ /**
455
+ * Discard everything the phase did (safe boot's abandonment). Keyed on
456
+ * `dirty`, which is set BEFORE the first op applies, so a mid-apply failure
457
+ * is covered — while a clone a step only read is never swept.
458
+ *
459
+ * `reset --hard` targets the PRE-PHASE sha recorded at clone time, not
460
+ * HEAD: a finalize commit that was created but failed to push must roll
461
+ * back too, or it survives as a stranded local commit no later boot would
462
+ * ever push. The reset restores everything tracked; the SCOPED
463
+ * `clean -fdx -- <op paths>` then removes files the ops created (including
464
+ * a partial write whose path a branch `.gitignore` happens to match). No
465
+ * global `clean`: it would delete pre-existing untracked files in a
466
+ * surviving working clone that the phase never touched.
467
+ */
468
+ async resetUncommitted() {
469
+ if (!this.dirty)
470
+ return;
471
+ const repoDir = await this.repoDir();
472
+ await git(repoDir, 'x-access-token', ['reset', '--hard', this.prePhaseSha ?? 'HEAD']).catch(() => { });
473
+ if (this.applied.size > 0) {
474
+ // `:(literal)` — these are file paths, not pathspecs: a name that
475
+ // happens to contain glob or magic characters must match itself only,
476
+ // never broaden the cleanup.
477
+ await git(repoDir, 'x-access-token', [
478
+ 'clean',
479
+ '-fdx',
480
+ '--',
481
+ ...[...this.applied].map((rel) => `:(literal)${rel}`),
482
+ ]).catch(() => { });
483
+ }
484
+ }
485
+ commitSubject() {
486
+ return this.notes[0] ?? "Bring the knowledge base up to this build's expectations";
487
+ }
488
+ commitMessage() {
489
+ if (this.notes.length <= 1)
490
+ return this.commitSubject();
491
+ return `${this.commitSubject()}\n\n${this.notes.slice(1).map((n) => `- ${n}`).join('\n')}`;
492
+ }
493
+ }
494
+ function lazyOnce(fn) {
495
+ let p;
496
+ return () => (p ??= fn());
497
+ }
498
+ /**
499
+ * Resolve a repo-relative op path and refuse everything the write layer
500
+ * refuses: absolute paths, `..` escapes, and any SYMLINK among the existing
501
+ * components (a link is a second path to other content — the two can
502
+ * disagree about what a write actually touched).
503
+ */
504
+ async function containedPath(repoDir, rel) {
505
+ if (!rel || path.isAbsolute(rel)) {
506
+ throw new Error(`op path "${rel}" must be a non-empty repo-relative path`);
507
+ }
508
+ const abs = path.resolve(repoDir, rel);
509
+ const rootRel = path.relative(repoDir, abs);
510
+ if (rootRel.startsWith('..') || path.isAbsolute(rootRel)) {
511
+ throw new Error(`op path "${rel}" escapes the repository`);
512
+ }
513
+ // Walk the EXISTING ancestry; every present component must be a real
514
+ // file/dir. (`.git` is off-limits outright.)
515
+ if (rootRel === '.git' || rootRel.startsWith(`.git${path.sep}`)) {
516
+ throw new Error(`op path "${rel}" targets .git`);
517
+ }
518
+ let probe = abs;
519
+ while (probe !== repoDir) {
520
+ const stat = await fs.lstat(probe).catch(() => null);
521
+ if (stat?.isSymbolicLink()) {
522
+ throw new Error(`op path "${rel}" traverses a symlink at "${path.relative(repoDir, probe)}"`);
523
+ }
524
+ probe = path.dirname(probe);
525
+ }
526
+ return abs;
527
+ }
528
+ //# sourceMappingURL=kb-startup-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kb-startup-runner.js","sourceRoot":"","sources":["../../../../src/modules/workspace/startup/kb-startup-runner.ts"],"names":[],"mappings":"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"}