blun-king-cli 9.1.624 → 9.1.626

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 (142) hide show
  1. package/CHANGELOG.md +62 -213
  2. package/LIESMICH.txt +57 -74
  3. package/README.md +76 -119
  4. package/agent-spine-plugin/scripts/check-install.js +4 -4
  5. package/agent-spine-plugin/src/hook.js +0 -4
  6. package/agent-spine-plugin/src/lib/documents.js +1 -1
  7. package/agent-spine-plugin/src/lib/hook-context.js +0 -1
  8. package/agent-spine-plugin/src/lib/host-instruction-budget.js +2 -1
  9. package/agent-spine-plugin/src/lib/preflight.js +9 -38
  10. package/agent-spine-plugin/src/lib/source-roots.js +1 -1
  11. package/bin/agentspine-king-goal-inbox.mjs +127 -127
  12. package/bin/agentspine-king-goal-intake.mjs +106 -106
  13. package/bin/agentspine-king-host-runner.mjs +109 -109
  14. package/bin/agentspine-king-snapshot-policy.cjs +80 -80
  15. package/bin/agentspine-king-status-policy.mjs +226 -226
  16. package/bin/agentspine-king-worker-host.mjs +160 -160
  17. package/bin/core-bootstrap.js +83 -97
  18. package/bin/launcher-mode.js +93 -93
  19. package/bin/launcher-restart-policy.cjs +131 -131
  20. package/bin/launcher-runtime.js +91 -254
  21. package/bin/managed-node.js +186 -186
  22. package/bin/managed-plugin-selection.cjs +109 -116
  23. package/bin/native-module-repair.js +201 -201
  24. package/bin/node-runtime.js +34 -34
  25. package/bin/node-version.js +49 -49
  26. package/bin/plugin-bootstrap.js +149 -172
  27. package/bin/private-paths.js +1578 -1624
  28. package/bin/runtime-exit-ledger.cjs +144 -144
  29. package/bin/runtime-exit-ledger.d.cts +23 -23
  30. package/bin/standard-tools-bootstrap.js +277 -272
  31. package/bin/turn-thinking-policy.cjs +82 -82
  32. package/bin/update-copy.js +200 -200
  33. package/bin/update-lease.js +597 -599
  34. package/bin/update-notice.js +1568 -1568
  35. package/bin/verify-agent-behavior.cjs +122 -122
  36. package/bin/verify-agent-components.cjs +104 -104
  37. package/bin/verify-bundled-agent-sources.cjs +91 -96
  38. package/bin/windows-node-crash-dump.cjs +289 -289
  39. package/blun.mjs +187640 -180475
  40. package/bundled-agent-sources.json +26 -30
  41. package/codebase-index/codebase_index.py +462 -470
  42. package/dist-web/assets/{CodeBlockNode-TKKkJX8L.js → CodeBlockNode-BMbuG85x.js} +1 -1
  43. package/dist-web/assets/{CodeBlockShell.vue_vue_type_style_index_0_lang-CUj2Ds5x.js → CodeBlockShell.vue_vue_type_style_index_0_lang-C1fv7l_Z.js} +1 -1
  44. package/dist-web/assets/DesignSystemView-6HgAUEmC.css +1 -0
  45. package/dist-web/assets/DesignSystemView-CEEBqXSX.js +12 -0
  46. package/dist-web/assets/{Tooltip-CTWv7WCU.js → Tooltip--YoauJ24.js} +1 -1
  47. package/dist-web/assets/{abnfDiagram-N423BO3Z-DA8V8Zjh.js → abnfDiagram-N423BO3Z-DZvBWkRg.js} +1 -1
  48. package/dist-web/assets/{arc-YtddKbdY.js → arc-B04JATeX.js} +1 -1
  49. package/dist-web/assets/{architectureDiagram-T3A2C74G-CGEiObmo.js → architectureDiagram-T3A2C74G-DmYnMep2.js} +1 -1
  50. package/dist-web/assets/{blockDiagram-VBNYF7ZC-Bd5Vt50e.js → blockDiagram-VBNYF7ZC-DJ1gPS1C.js} +1 -1
  51. package/dist-web/assets/{c4Diagram-5PPSVZJV-D2ApPM54.js → c4Diagram-5PPSVZJV-DmjxvUbd.js} +1 -1
  52. package/dist-web/assets/channel-472fcEvw.js +1 -0
  53. package/dist-web/assets/{chunk-2GRJ4B5K-BDcIEZSl.js → chunk-2GRJ4B5K-AB0raj3I.js} +1 -1
  54. package/dist-web/assets/{chunk-2Q5K7J3B-6aSabCX7.js → chunk-2Q5K7J3B-Drf039vM.js} +1 -1
  55. package/dist-web/assets/{chunk-5RXB4S5H-BFRQvIJS.js → chunk-5RXB4S5H-D5ILttmz.js} +1 -1
  56. package/dist-web/assets/{chunk-5VM5RSS4-ChAa-DNY.js → chunk-5VM5RSS4-DrLSdi8y.js} +1 -1
  57. package/dist-web/assets/{chunk-6Q2QTUOP-BIfrb2Jc.js → chunk-6Q2QTUOP-LiaqdEOQ.js} +1 -1
  58. package/dist-web/assets/{chunk-GF5L2VYU-BR0gvtWI.js → chunk-GF5L2VYU-AIYkb--o.js} +1 -1
  59. package/dist-web/assets/{chunk-JWPE2WC7-BgXKsx5E.js → chunk-JWPE2WC7-CogdNl0i.js} +1 -1
  60. package/dist-web/assets/{chunk-KBJHAD2P-I8mrZhpz.js → chunk-KBJHAD2P-DHjpNtZv.js} +1 -1
  61. package/dist-web/assets/{chunk-RYQCIY6F-BMPaem92.js → chunk-RYQCIY6F-BUSOqH2X.js} +1 -1
  62. package/dist-web/assets/{chunk-XXDRQBXY-COy0J-0j.js → chunk-XXDRQBXY-BpoMV0bh.js} +1 -1
  63. package/dist-web/assets/classDiagram-JCYQIIEL-BTZeLngj.js +1 -0
  64. package/dist-web/assets/classDiagram-v2-OCEON4UE-BTZeLngj.js +1 -0
  65. package/dist-web/assets/{cose-bilkent-JH36ORCC-MosTTRdo.js → cose-bilkent-JH36ORCC-BJr2I61o.js} +1 -1
  66. package/dist-web/assets/{cynefin-VYW2F7L2-5tjPgrkP.js → cynefin-VYW2F7L2-HtysQZ4A.js} +1 -1
  67. package/dist-web/assets/{cynefinDiagram-MW4NZA55-CbDcdInR.js → cynefinDiagram-MW4NZA55-CcpC_2uv.js} +1 -1
  68. package/dist-web/assets/{dagre-VZM6K2ZE-YaBom1ZH.js → dagre-VZM6K2ZE-D8Ao0LUg.js} +1 -1
  69. package/dist-web/assets/{diagram-7IWD3JNH-Da4m-Hgz.js → diagram-7IWD3JNH-BITiLhjX.js} +1 -1
  70. package/dist-web/assets/{diagram-B4RE2ZJO-CAUUegxg.js → diagram-B4RE2ZJO-CJtwfy9f.js} +1 -1
  71. package/dist-web/assets/{diagram-LBJQPF4R-o21mWKG4.js → diagram-LBJQPF4R-BsVTh6w8.js} +1 -1
  72. package/dist-web/assets/{diagram-Q27KOJAE-BA3z3sXf.js → diagram-Q27KOJAE-pA_MUCUf.js} +1 -1
  73. package/dist-web/assets/{diagram-UB23O5K3-CGRdSSDK.js → diagram-UB23O5K3-CIY8z7vu.js} +1 -1
  74. package/dist-web/assets/{ebnfDiagram-BXEA7PRR-Bw-iU9FP.js → ebnfDiagram-BXEA7PRR-C3FMioqp.js} +1 -1
  75. package/dist-web/assets/{erDiagram-JOGREHBK-BwM1yiR0.js → erDiagram-JOGREHBK-CzoyKmKc.js} +1 -1
  76. package/dist-web/assets/{flowDiagram-UKHOOZJN-z05eOR1Q.js → flowDiagram-UKHOOZJN-DOqfushy.js} +1 -1
  77. package/dist-web/assets/{ganttDiagram-PKOTCBZU-BMUubNTl.js → ganttDiagram-PKOTCBZU-Cf9XQSWl.js} +1 -1
  78. package/dist-web/assets/{gitGraphDiagram-DS77QQ5N-Dccbi1wU.js → gitGraphDiagram-DS77QQ5N-DHUDofE5.js} +1 -1
  79. package/dist-web/assets/{index-h0KEOmkU.js → index-B6qEMQMx.js} +14 -14
  80. package/dist-web/assets/{index-C9eDH3u-.css → index-BmKj7CB1.css} +1 -1
  81. package/dist-web/assets/{index-BBbC5LRF.js → index-DokxDX1w.js} +1 -1
  82. package/dist-web/assets/{index-D48p0M2S.js → index-auojtiAA.js} +2 -2
  83. package/dist-web/assets/{index10-Qbuw1N6u.js → index10-Drb2n5e5.js} +1 -1
  84. package/dist-web/assets/{index11-g8v025wN.js → index11-Cx-aV4G2.js} +1 -1
  85. package/dist-web/assets/{index5-BYNcV8BY.js → index5-Dg3qGTyH.js} +1 -1
  86. package/dist-web/assets/{index6-BetANtnV.js → index6-BgvtIICP.js} +1 -1
  87. package/dist-web/assets/{index7-BcPbgCKN.js → index7-uEnniPQG.js} +1 -1
  88. package/dist-web/assets/{index8-B1lp-RvF.js → index8-h4IKc0ek.js} +2 -2
  89. package/dist-web/assets/{infoDiagram-6WML65LV-BF_pbUnN.js → infoDiagram-6WML65LV-D-3tvEiJ.js} +1 -1
  90. package/dist-web/assets/{ishikawaDiagram-WSZJBQD7-Dedv4urS.js → ishikawaDiagram-WSZJBQD7-DIIBNv7a.js} +1 -1
  91. package/dist-web/assets/{journeyDiagram-NVQOT4AX-B1Ex3b6o.js → journeyDiagram-NVQOT4AX-DP4r1Vlx.js} +1 -1
  92. package/dist-web/assets/{kanban-definition-27J2QSJJ-BtCGliBH.js → kanban-definition-27J2QSJJ-C3_Ztgxv.js} +1 -1
  93. package/dist-web/assets/{linear-ByItc8Qr.js → linear-DnqhIw-y.js} +1 -1
  94. package/dist-web/assets/{mermaid.core-B1M2O7nN.js → mermaid.core-xYUgBa3T.js} +4 -4
  95. package/dist-web/assets/{mindmap-definition-FAOFIHXS-D0UHKUyj.js → mindmap-definition-FAOFIHXS-l-dq-zfr.js} +1 -1
  96. package/dist-web/assets/{pegDiagram-VL7TDLO6-D7zYCVmG.js → pegDiagram-VL7TDLO6-C8vXQiaJ.js} +1 -1
  97. package/dist-web/assets/{pieDiagram-7S7Q4E2Y-Bd0i9CHa.js → pieDiagram-7S7Q4E2Y-CyNRSsI6.js} +1 -1
  98. package/dist-web/assets/{quadrantDiagram-CIZ2JOQS-MG-Ug47d.js → quadrantDiagram-CIZ2JOQS-D-w8AD_g.js} +1 -1
  99. package/dist-web/assets/{railroadDiagram-AXF67PYL-AZdl90Gj.js → railroadDiagram-AXF67PYL-BLkyQCWy.js} +1 -1
  100. package/dist-web/assets/{requirementDiagram-LRYGKXZP-DjplF9kt.js → requirementDiagram-LRYGKXZP-CEWO7XfT.js} +1 -1
  101. package/dist-web/assets/{sankeyDiagram-W5VNT64P-Bi9Zgfjs.js → sankeyDiagram-W5VNT64P-ByGoAaGj.js} +1 -1
  102. package/dist-web/assets/{sequenceDiagram-SI44F4Z6-ChEpdCvb.js → sequenceDiagram-SI44F4Z6-Bhn9GQtd.js} +1 -1
  103. package/dist-web/assets/{sizeCapture-X5ZJPWSS-B5RFUdaa.js → sizeCapture-X5ZJPWSS-jVKR9CTu.js} +1 -1
  104. package/dist-web/assets/{stateDiagram-OKZ733FA-BkRblSKp.js → stateDiagram-OKZ733FA-wW3XbegA.js} +1 -1
  105. package/dist-web/assets/stateDiagram-v2-UEYNNEHI-B8aids-Z.js +1 -0
  106. package/dist-web/assets/{swimlanes-SLNWSIFB-DLXH6Zhc.js → swimlanes-SLNWSIFB-B8QyFS7G.js} +2 -2
  107. package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-B8XAkdSm.js +8 -0
  108. package/dist-web/assets/{timeline-definition-Z64GVDOM-C_N88siO.js → timeline-definition-Z64GVDOM-DpvxS-1A.js} +1 -1
  109. package/dist-web/assets/{vennDiagram-T6HMQDX7-DMsnvDt0.js → vennDiagram-T6HMQDX7-BzGM0ihY.js} +1 -1
  110. package/dist-web/assets/{vue.runtime.esm-bundler-B-3uIy85.js → vue.runtime.esm-bundler-BOcpwIX1.js} +1 -1
  111. package/dist-web/assets/{wardleyDiagram-T6FBY63Y-C9SJIPzq.js → wardleyDiagram-T6FBY63Y-2DKAOs5e.js} +1 -1
  112. package/dist-web/assets/{xychartDiagram-ELKLHX3M-DZLWA6Go.js → xychartDiagram-ELKLHX3M-B0SP0TXd.js} +1 -1
  113. package/dist-web/index.html +32 -32
  114. package/dist-web/vis/index.html.gz +0 -0
  115. package/package.json +1 -1
  116. package/scripts/fix-node-pty-perms.js +53 -53
  117. package/standard-skills/blun-app-design-system/SKILL.md +30 -30
  118. package/standard-skills/blun-app-design-system/provenance.json +17 -17
  119. package/standard-skills/blun-app-design-system/references/tokens.md +48 -48
  120. package/standard-skills/blun-app-design-system/scripts/check-blun-design.mjs +49 -49
  121. package/standard-skills/translate-native/README.md +1 -1
  122. package/standard-skills/translate-native/scripts/blun_language_guard.py +2 -0
  123. package/standard-skills/translate-native/scripts/language_gateway.py +2 -0
  124. package/standard-skills/translate-native/scripts/pre_output_guard.py +2 -0
  125. package/standard-tools/language-guard/blun_language_guard.py +2 -0
  126. package/standard-tools/language-guard/language_gateway.py +2 -0
  127. package/standard-tools/language-guard/pre_output_guard.py +2 -0
  128. package/telegram-plugin/blun.plugin.json +20 -20
  129. package/telegram-plugin/commands/access.md +37 -37
  130. package/telegram-plugin/dist/bridge.mjs +310 -187
  131. package/telegram-plugin/dist/mcp-server.mjs +174 -261
  132. package/telegram-plugin/dist/noise.mjs +1 -19
  133. package/worker-host.mjs +13747 -16824
  134. package/bin/profile-handoff.cjs +0 -152
  135. package/bin/profile-launch.cjs +0 -120
  136. package/dist-web/assets/DesignSystemView-DwK1aQMo.js +0 -12
  137. package/dist-web/assets/DesignSystemView-szjTj7ns.css +0 -1
  138. package/dist-web/assets/channel-BnluexuN.js +0 -1
  139. package/dist-web/assets/classDiagram-JCYQIIEL-BliFdSD9.js +0 -1
  140. package/dist-web/assets/classDiagram-v2-OCEON4UE-BliFdSD9.js +0 -1
  141. package/dist-web/assets/stateDiagram-v2-UEYNNEHI-fVkQcACW.js +0 -1
  142. package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-Bg-BiZJQ.js +0 -8
@@ -1,152 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('node:fs');
4
- const path = require('node:path');
5
- const { randomUUID } = require('node:crypto');
6
- const { listExistingProfiles, resolveSelectedProfile } = require('./profile-launch.cjs');
7
-
8
- const PROFILE_HANDOFF_REQUEST = 'blun-profile-handoff-request';
9
- const PROFILE_HANDOFF_REPLY = 'blun-profile-handoff-reply';
10
- const PROFILE_HANDOFF_CANCEL = 'blun-profile-handoff-cancel';
11
- const PROFILE_HANDOFF_READY = 'blun-profile-handoff-ready';
12
- const PROFILE_HANDOFF_EXIT = 76;
13
- const REQUEST_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
14
- const SESSION_ID = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/u;
15
- const samePath = (a, b) => process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b;
16
- const unavailable = () => Object.assign(new Error('PROFILE_HANDOFF_UNAVAILABLE'), { code: 'PROFILE_HANDOFF_UNAVAILABLE' });
17
-
18
- function createProfileHandoff(env, isBusy = () => false) {
19
- let pending;
20
- const validate = (name) => {
21
- if (typeof env.BLUN_HOME !== 'string' || !path.isAbsolute(env.BLUN_HOME)
22
- || (env.BLUN_SHARED_HOME !== undefined && !path.isAbsolute(env.BLUN_SHARED_HOME))) throw unavailable();
23
- const sharedHome = path.resolve(env.BLUN_SHARED_HOME || env.BLUN_HOME);
24
- const homeDir = path.resolve(env.BLUN_HOME);
25
- const current = env.BLUN_PROFILE;
26
- if (current !== undefined) {
27
- if (!env.BLUN_SHARED_HOME || path.basename(resolveSelectedProfile(sharedHome, current)) !== current
28
- || !samePath(homeDir, resolveSelectedProfile(sharedHome, current))) throw unavailable();
29
- } else if (!samePath(homeDir, sharedHome)) throw unavailable();
30
- const names = listExistingProfiles(sharedHome);
31
- if (typeof name !== 'string' || !names.includes(name) || name === current
32
- || (current !== undefined && !names.includes(current))) throw unavailable();
33
- const target = resolveSelectedProfile(sharedHome, name);
34
- if (isBusy(target)) throw unavailable();
35
- const identities = [sharedHome, path.join(sharedHome, 'profile'), homeDir, target]
36
- .map(file => ({ file, stat: fs.lstatSync(file, { bigint: true }) }));
37
- if (identities.some(({ stat }) => !stat.isDirectory() || stat.isSymbolicLink())) throw unavailable();
38
- return { name, sharedHome, homeDir: target, identities };
39
- };
40
- return {
41
- hasPending: () => pending !== undefined,
42
- getSourceSessionId: () => pending?.sourceSessionId,
43
- prepare(message) {
44
- if (message?.type === PROFILE_HANDOFF_CANCEL && typeof message.requestId === 'string'
45
- && REQUEST_ID.test(message.requestId) && Object.keys(message).sort().join(',') === 'requestId,type') {
46
- if (pending?.requestId === message.requestId) pending = undefined;
47
- return { type: PROFILE_HANDOFF_REPLY, requestId: message.requestId, status: 'cancelled' };
48
- }
49
- if (!message || message.type !== PROFILE_HANDOFF_REQUEST || typeof message.requestId !== 'string' || !REQUEST_ID.test(message.requestId)) return undefined;
50
- const shape = Object.keys(message).sort().join(',');
51
- if (shape !== 'name,requestId,type' && shape !== 'name,requestId,sourceSessionId,type') return undefined;
52
- if (shape === 'name,requestId,sourceSessionId,type'
53
- && (typeof message.sourceSessionId !== 'string' || !SESSION_ID.test(message.sourceSessionId))) return undefined;
54
- let status = 'rejected';
55
- try {
56
- if (pending) {
57
- if (pending.requestId === message.requestId && pending.name === message.name
58
- && pending.sourceSessionId === message.sourceSessionId) status = 'prepared';
59
- } else {
60
- pending = { ...validate(message.name), requestId: message.requestId, sourceSessionId: message.sourceSessionId };
61
- status = 'prepared';
62
- }
63
- } catch {}
64
- return { type: PROFILE_HANDOFF_REPLY, requestId: message.requestId, status };
65
- },
66
- commit() {
67
- try {
68
- if (!pending) throw unavailable();
69
- const fresh = validate(pending.name);
70
- for (let index = 0; index < pending.identities.length; index++) {
71
- const before = pending.identities[index];
72
- const after = fresh.identities[index];
73
- if (before.file !== after.file || before.stat.dev !== after.stat.dev || before.stat.ino !== after.stat.ino) throw unavailable();
74
- }
75
- return Object.freeze({ name: fresh.name, sharedHome: fresh.sharedHome, homeDir: fresh.homeDir,
76
- ...(pending.sourceSessionId === undefined ? {} : { sourceSessionId: pending.sourceSessionId }) });
77
- } catch {
78
- throw unavailable();
79
- }
80
- },
81
- };
82
- }
83
-
84
- function createProfileHandoffClient(channel = process) {
85
- const enabled = channel.env?.BLUN_PROFILE_HANDOFF === '1';
86
- let pending;
87
- let disposed = false;
88
- const available = () => !disposed && enabled && channel.connected === true
89
- && typeof channel.send === 'function';
90
- const cancel = () => {
91
- const request = pending;
92
- if (!request) return;
93
- pending = undefined;
94
- request.finish(false);
95
- if (channel.connected === true) {
96
- try { channel.send({ type: PROFILE_HANDOFF_CANCEL, requestId: request.id }, () => {}); } catch {}
97
- }
98
- };
99
- return Object.freeze({
100
- isPrepared: () => available() && pending?.prepared === true,
101
- cancel,
102
- dispose() { cancel(); disposed = true; },
103
- /** @param {string} name @param {{ signal?: AbortSignal, timeoutMs?: number, sourceSessionId?: string }} [options] */
104
- prepare(name, { signal, timeoutMs = 5000, sourceSessionId } = {}) {
105
- try {
106
- if (!available() || pending || signal?.aborted || typeof name !== 'string'
107
- || path.basename(resolveSelectedProfile(path.parse(__dirname).root, name)) !== name
108
- || !Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 30000
109
- || (sourceSessionId !== undefined && (typeof sourceSessionId !== 'string' || !SESSION_ID.test(sourceSessionId)))) return Promise.resolve(false);
110
- } catch { return Promise.resolve(false); }
111
- return new Promise(resolve => {
112
- const request = { id: randomUUID(), prepared: false, finish: undefined };
113
- let settled = false;
114
- let timer;
115
- const aborted = () => cancel();
116
- const disconnected = () => cancel();
117
- const message = reply => {
118
- if (pending !== request || reply?.type !== PROFILE_HANDOFF_REPLY || reply.requestId !== request.id
119
- || Object.keys(reply).sort().join(',') !== 'requestId,status,type') return;
120
- if (reply.status === 'prepared') request.finish(true);
121
- else if (reply.status === 'rejected' || reply.status === 'cancelled') cancel();
122
- };
123
- request.finish = prepared => {
124
- if (!prepared) signal?.removeEventListener('abort', aborted);
125
- if (settled) return;
126
- settled = true;
127
- clearTimeout(timer);
128
- channel.removeListener('message', message);
129
- channel.removeListener('disconnect', disconnected);
130
- try { channel.channel?.unref(); } catch {}
131
- request.prepared = prepared;
132
- resolve(prepared);
133
- };
134
- pending = request;
135
- channel.on('message', message);
136
- channel.once('disconnect', disconnected);
137
- signal?.addEventListener('abort', aborted, { once: true });
138
- timer = setTimeout(aborted, timeoutMs);
139
- try {
140
- channel.channel?.ref();
141
- channel.send({ type: PROFILE_HANDOFF_REQUEST, requestId: request.id, name,
142
- ...(sourceSessionId === undefined ? {} : { sourceSessionId }) }, error => {
143
- if (error && pending === request) cancel();
144
- });
145
- } catch { cancel(); }
146
- });
147
- },
148
- });
149
- }
150
-
151
- module.exports = { createProfileHandoff, createProfileHandoffClient, PROFILE_HANDOFF_CANCEL, PROFILE_HANDOFF_REQUEST, PROFILE_HANDOFF_REPLY,
152
- PROFILE_HANDOFF_READY, PROFILE_HANDOFF_EXIT };
@@ -1,120 +0,0 @@
1
- 'use strict';
2
-
3
- const path = require('node:path');
4
- const fs = require('node:fs');
5
-
6
- const PROFILE_NAME = /^[a-z0-9][a-z0-9_-]{0,31}$/u;
7
- const RESERVED = new Set(['doctor', 'export', 'help', 'login', 'mcp', 'server', 'tools', 'update', 'upgrade', 'version']);
8
-
9
- function profileName(value) {
10
- const name = String(value || '').trim().toLowerCase();
11
- if (!PROFILE_NAME.test(name)) {
12
- throw new Error('Profilnamen duerfen nur Buchstaben, Zahlen, Unterstriche und Bindestriche enthalten.');
13
- }
14
- return name;
15
- }
16
-
17
- function parseProfileLaunchArgs(args, mode) {
18
- const remaining = [...args];
19
- if (mode !== 'king') return { args: remaining, name: undefined };
20
-
21
- const flag = remaining.indexOf('--profile');
22
- if (flag >= 0) {
23
- if (flag + 1 >= remaining.length) throw new Error('--profile braucht einen Profilnamen.');
24
- const name = profileName(remaining[flag + 1]);
25
- remaining.splice(flag, 2);
26
- return { args: remaining, name };
27
- }
28
-
29
- if (remaining.length === 1 && !remaining[0].startsWith('-') && !RESERVED.has(remaining[0].toLowerCase())) {
30
- return { args: [], name: profileName(remaining[0]), implicit: true };
31
- }
32
- if (remaining.length === 2 && remaining.includes('-c')) {
33
- const candidate = remaining.find(value => value !== '-c');
34
- if (candidate && !candidate.startsWith('-')) return { args: ['-c'], name: profileName(candidate), implicit: true };
35
- }
36
- return { args: remaining, name: undefined };
37
- }
38
-
39
- function resolveSelectedProfile(sharedHome, name, pathImpl = path) {
40
- return pathImpl.join(sharedHome, 'profile', profileName(name));
41
- }
42
-
43
- function catalogUnavailable() {
44
- return Object.assign(new Error('PROFILE_CATALOG_UNAVAILABLE'), { code: 'PROFILE_CATALOG_UNAVAILABLE' });
45
- }
46
-
47
- function directoryIdentity(target, fsImpl) {
48
- let stat;
49
- try { stat = fsImpl.lstatSync(target, { bigint: true }); }
50
- catch (error) {
51
- if (error.code === 'ENOENT') return undefined;
52
- throw error;
53
- }
54
- if (!stat.isDirectory() || stat.isSymbolicLink()) throw catalogUnavailable();
55
- return stat;
56
- }
57
-
58
- function homeIdentity(home, fsImpl) {
59
- const root = path.parse(home).root;
60
- let current = root;
61
- let stat = directoryIdentity(current, fsImpl);
62
- for (const part of home.slice(root.length).split(path.sep).filter(Boolean)) {
63
- if (stat === undefined) return undefined;
64
- current = path.join(current, part);
65
- stat = directoryIdentity(current, fsImpl);
66
- }
67
- return stat;
68
- }
69
-
70
- function sameDirectory(before, after) {
71
- return before !== undefined && after !== undefined && before.dev === after.dev && before.ino === after.ino;
72
- }
73
-
74
- /** Directory names only; selection must revalidate them before changing owner. */
75
- function listExistingProfiles(sharedHome, options = {}) {
76
- const fsImpl = options.fsImpl || fs;
77
- try {
78
- if (typeof sharedHome !== 'string' || !path.isAbsolute(sharedHome)) throw catalogUnavailable();
79
- const home = path.resolve(sharedHome);
80
- if (process.platform === 'win32' && home.startsWith('\\\\')) throw catalogUnavailable();
81
- const beforeHome = homeIdentity(home, fsImpl);
82
- if (beforeHome === undefined) return [];
83
- const profileRoot = path.join(home, 'profile');
84
- const beforeProfiles = directoryIdentity(profileRoot, fsImpl);
85
- if (beforeProfiles === undefined) {
86
- if (!sameDirectory(beforeHome, homeIdentity(home, fsImpl))) throw catalogUnavailable();
87
- return [];
88
- }
89
- const rows = [];
90
- const dir = fsImpl.opendirSync(profileRoot);
91
- try {
92
- let count = 0;
93
- for (let entry; (entry = dir.readSync()) !== null;) {
94
- if (++count > 4096) throw catalogUnavailable();
95
- const name = entry.name;
96
- if (!PROFILE_NAME.test(name)) continue;
97
- const target = resolveSelectedProfile(home, name);
98
- let stat;
99
- try { stat = fsImpl.lstatSync(target, { bigint: true }); }
100
- catch (error) {
101
- if (error.code === 'ENOENT') continue;
102
- throw error;
103
- }
104
- if (stat.isDirectory() && !stat.isSymbolicLink()) rows.push({ name, target, stat });
105
- }
106
- } finally { dir.closeSync(); }
107
- if (!sameDirectory(beforeHome, homeIdentity(home, fsImpl))
108
- || !sameDirectory(beforeProfiles, directoryIdentity(profileRoot, fsImpl))) throw catalogUnavailable();
109
- for (const row of rows) {
110
- if (!sameDirectory(row.stat, directoryIdentity(row.target, fsImpl))) throw catalogUnavailable();
111
- }
112
- if (!sameDirectory(beforeHome, homeIdentity(home, fsImpl))
113
- || !sameDirectory(beforeProfiles, directoryIdentity(profileRoot, fsImpl))) throw catalogUnavailable();
114
- return rows.map(row => row.name).sort();
115
- } catch {
116
- throw catalogUnavailable();
117
- }
118
- }
119
-
120
- module.exports = { parseProfileLaunchArgs, resolveSelectedProfile, listExistingProfiles };