vigthoria-cli 1.13.20 → 1.13.23

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 (187) hide show
  1. package/completions/_vigthoria +49 -0
  2. package/completions/vigthoria.bash +6 -0
  3. package/completions/vigthoria.fish +41 -0
  4. package/dist/commands/auth.d.ts +1 -0
  5. package/dist/commands/auth.js +63 -128
  6. package/dist/commands/background.d.ts +0 -2
  7. package/dist/commands/background.js +26 -34
  8. package/dist/commands/bridge.js +45 -41
  9. package/dist/commands/cancel.d.ts +1 -0
  10. package/dist/commands/cancel.js +22 -16
  11. package/dist/commands/chat.d.ts +3 -42
  12. package/dist/commands/chat.js +378 -1123
  13. package/dist/commands/coding-registration.d.ts +4 -0
  14. package/dist/commands/coding-registration.js +24 -0
  15. package/dist/commands/config.js +23 -29
  16. package/dist/commands/conversation-registration.d.ts +4 -0
  17. package/dist/commands/conversation-registration.js +122 -0
  18. package/dist/commands/deploy.d.ts +8 -2
  19. package/dist/commands/deploy.js +92 -90
  20. package/dist/commands/device.d.ts +1 -2
  21. package/dist/commands/device.js +37 -21
  22. package/dist/commands/doctor-registration.d.ts +4 -0
  23. package/dist/commands/doctor-registration.js +207 -0
  24. package/dist/commands/edit.js +22 -33
  25. package/dist/commands/explain.js +7 -10
  26. package/dist/commands/fork.d.ts +1 -2
  27. package/dist/commands/fork.js +72 -22
  28. package/dist/commands/game.d.ts +1 -1
  29. package/dist/commands/game.js +17 -6
  30. package/dist/commands/generate.js +7 -9
  31. package/dist/commands/history.js +11 -7
  32. package/dist/commands/hub.d.ts +2 -2
  33. package/dist/commands/hub.js +34 -35
  34. package/dist/commands/legion.d.ts +0 -1
  35. package/dist/commands/legion.js +62 -79
  36. package/dist/commands/music.d.ts +1 -2
  37. package/dist/commands/music.js +62 -27
  38. package/dist/commands/platform-registration.d.ts +4 -0
  39. package/dist/commands/platform-registration.js +45 -0
  40. package/dist/commands/preview.d.ts +0 -1
  41. package/dist/commands/preview.js +82 -35
  42. package/dist/commands/product-run-registration.d.ts +4 -0
  43. package/dist/commands/product-run-registration.js +490 -0
  44. package/dist/commands/replay.d.ts +1 -2
  45. package/dist/commands/replay.js +15 -11
  46. package/dist/commands/repo.d.ts +14 -7
  47. package/dist/commands/repo.js +244 -198
  48. package/dist/commands/review.js +9 -12
  49. package/dist/commands/security.d.ts +1 -2
  50. package/dist/commands/security.js +12 -6
  51. package/dist/commands/update-registration.d.ts +3 -0
  52. package/dist/commands/update-registration.js +368 -0
  53. package/dist/commands/v4-registration.d.ts +4 -0
  54. package/dist/commands/v4-registration.js +24 -0
  55. package/dist/commands/v4.d.ts +1 -1
  56. package/dist/commands/v4.js +46 -8
  57. package/dist/commands/wallet.d.ts +1 -3
  58. package/dist/commands/wallet.js +18 -45
  59. package/dist/commands/workflow.d.ts +2 -0
  60. package/dist/commands/workflow.js +52 -39
  61. package/dist/index.js +124 -1589
  62. package/dist/utils/agent-stream-state.d.ts +27 -0
  63. package/dist/utils/agent-stream-state.js +93 -0
  64. package/dist/utils/agentRoute.d.ts +2 -1
  65. package/dist/utils/agentRoute.js +22 -9
  66. package/dist/utils/agentRunOutcome.d.ts +16 -0
  67. package/dist/utils/agentRunOutcome.js +37 -2
  68. package/dist/utils/api-client-factory.d.ts +8 -0
  69. package/dist/utils/api-client-factory.js +8 -0
  70. package/dist/utils/api.d.ts +44 -266
  71. package/dist/utils/api.js +647 -3180
  72. package/dist/utils/auth-session.d.ts +41 -0
  73. package/dist/utils/auth-session.js +224 -0
  74. package/dist/utils/brain-hub-client.d.ts +0 -4
  75. package/dist/utils/brain-hub-client.js +6 -3
  76. package/dist/utils/bridge-client.js +2 -0
  77. package/dist/utils/capability-health-service.d.ts +48 -0
  78. package/dist/utils/capability-health-service.js +64 -0
  79. package/dist/utils/chat-prompt-policy.d.ts +18 -0
  80. package/dist/utils/chat-prompt-policy.js +61 -0
  81. package/dist/utils/chat-tool-call-parser.d.ts +11 -0
  82. package/dist/utils/chat-tool-call-parser.js +71 -0
  83. package/dist/utils/cli-state.d.ts +22 -4
  84. package/dist/utils/cli-state.js +105 -47
  85. package/dist/utils/code-operations-service.d.ts +104 -0
  86. package/dist/utils/code-operations-service.js +837 -0
  87. package/dist/utils/codebase-indexer.d.ts +1 -0
  88. package/dist/utils/codebase-indexer.js +28 -8
  89. package/dist/utils/command-contract.d.ts +61 -0
  90. package/dist/utils/command-contract.js +149 -0
  91. package/dist/utils/command-policy.d.ts +10 -0
  92. package/dist/utils/command-policy.js +54 -0
  93. package/dist/utils/config.d.ts +13 -5
  94. package/dist/utils/config.js +220 -94
  95. package/dist/utils/context-ranker.js +11 -2
  96. package/dist/utils/context-state.d.ts +39 -0
  97. package/dist/utils/context-state.js +52 -0
  98. package/dist/utils/deckEvents.d.ts +0 -5
  99. package/dist/utils/deckEvents.js +3 -2
  100. package/dist/utils/desktop-bridge-client.js +2 -0
  101. package/dist/utils/direct-output-policy.d.ts +3 -0
  102. package/dist/utils/direct-output-policy.js +76 -0
  103. package/dist/utils/durable-json.d.ts +57 -0
  104. package/dist/utils/durable-json.js +319 -0
  105. package/dist/utils/fastAgentRouter.d.ts +5 -6
  106. package/dist/utils/fastAgentRouter.js +17 -25
  107. package/dist/utils/files.js +21 -13
  108. package/dist/utils/frontend-preview-service.d.ts +76 -0
  109. package/dist/utils/frontend-preview-service.js +482 -0
  110. package/dist/utils/goaEvents.d.ts +0 -4
  111. package/dist/utils/goaEvents.js +5 -2
  112. package/dist/utils/logger.d.ts +2 -1
  113. package/dist/utils/logger.js +27 -20
  114. package/dist/utils/mcp-context-client.d.ts +24 -0
  115. package/dist/utils/mcp-context-client.js +58 -0
  116. package/dist/utils/model-governance.d.ts +18 -0
  117. package/dist/utils/model-governance.js +75 -0
  118. package/dist/utils/model-transport-service.d.ts +44 -0
  119. package/dist/utils/model-transport-service.js +111 -0
  120. package/dist/utils/mutation-journal.d.ts +42 -0
  121. package/dist/utils/mutation-journal.js +387 -0
  122. package/dist/utils/network-policy.d.ts +24 -0
  123. package/dist/utils/network-policy.js +202 -0
  124. package/dist/utils/operator-client.d.ts +45 -0
  125. package/dist/utils/operator-client.js +159 -0
  126. package/dist/utils/post-write-validator.js +7 -9
  127. package/dist/utils/preview-screenshot-adapter.d.ts +15 -0
  128. package/dist/utils/preview-screenshot-adapter.js +51 -0
  129. package/dist/utils/process-policy.d.ts +23 -0
  130. package/dist/utils/process-policy.js +284 -0
  131. package/dist/utils/project-memory.d.ts +13 -3
  132. package/dist/utils/project-memory.js +70 -17
  133. package/dist/utils/prompt-workspace-resolver.d.ts +14 -0
  134. package/dist/utils/prompt-workspace-resolver.js +64 -0
  135. package/dist/utils/release-install.d.ts +11 -0
  136. package/dist/utils/release-install.js +155 -0
  137. package/dist/utils/release-policy.d.ts +64 -0
  138. package/dist/utils/release-policy.js +293 -0
  139. package/dist/utils/requestIntent.js +22 -3
  140. package/dist/utils/runtime-capability.d.ts +8 -0
  141. package/dist/utils/runtime-capability.js +16 -0
  142. package/dist/utils/runtime-temp.d.ts +76 -0
  143. package/dist/utils/runtime-temp.js +492 -0
  144. package/dist/utils/secret-policy.d.ts +20 -0
  145. package/dist/utils/secret-policy.js +160 -0
  146. package/dist/utils/session.d.ts +17 -3
  147. package/dist/utils/session.js +354 -110
  148. package/dist/utils/tool-approval-service.d.ts +17 -0
  149. package/dist/utils/tool-approval-service.js +78 -0
  150. package/dist/utils/tool-capability-providers.d.ts +57 -0
  151. package/dist/utils/tool-capability-providers.js +57 -0
  152. package/dist/utils/tools.d.ts +2 -23
  153. package/dist/utils/tools.js +226 -512
  154. package/dist/utils/update-policy.d.ts +18 -0
  155. package/dist/utils/update-policy.js +137 -0
  156. package/dist/utils/v3-agent-client.d.ts +40 -0
  157. package/dist/utils/v3-agent-client.js +165 -0
  158. package/dist/utils/v3-workspace-service.d.ts +28 -0
  159. package/dist/utils/v3-workspace-service.js +279 -0
  160. package/dist/utils/vigflow-client.d.ts +95 -0
  161. package/dist/utils/vigflow-client.js +105 -0
  162. package/dist/utils/workspace-boundary.d.ts +45 -0
  163. package/dist/utils/workspace-boundary.js +377 -0
  164. package/dist/utils/workspace-brain-service.d.ts +2 -0
  165. package/dist/utils/workspace-brain-service.js +11 -1
  166. package/dist/utils/workspace-cache.js +37 -15
  167. package/dist/utils/workspace-stream.js +35 -10
  168. package/install.ps1 +115 -142
  169. package/install.sh +112 -81
  170. package/package.json +43 -9
  171. package/release-policy.json +43 -0
  172. package/scripts/release/LOCAL_MACHINE_USER_VERIFICATION.md +1 -1
  173. package/scripts/release/generate-completions.mjs +24 -0
  174. package/scripts/release/install-release.mjs +10 -0
  175. package/scripts/release/publish-cli-release.mjs +116 -0
  176. package/scripts/release/publish-cli-release.sh +2 -70
  177. package/scripts/release/resolve-release-manifest.mjs +26 -0
  178. package/scripts/release/test-balanced-model-live.sh +45 -0
  179. package/scripts/release/validate-live-service-gates.sh +93 -0
  180. package/scripts/release/validate-no-go-gates.sh +145 -174
  181. package/scripts/release/verify-runtime-consistency.mjs +4 -1
  182. package/dist/commands/index.d.ts +0 -12
  183. package/dist/commands/index.js +0 -194
  184. package/dist/commands/update.d.ts +0 -9
  185. package/dist/commands/update.js +0 -301
  186. package/dist/utils/templateInstantPath.d.ts +0 -18
  187. package/dist/utils/templateInstantPath.js +0 -228
@@ -0,0 +1,293 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { createPublicKey, verify as verifySignature } from 'node:crypto';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { CliCommandError } from './command-contract.js';
6
+ import { compareSemanticVersions } from './update-policy.js';
7
+ const SHA256 = /^[a-f0-9]{64}$/;
8
+ const SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
9
+ const TOP_LEVEL_FIELDS = new Set(['schemaVersion', 'channels']);
10
+ const ENTRY_FIELDS = new Set(['version', 'url', 'sha256', 'size', 'archiveFilename', 'packageName', 'packageVersion', 'publishedAt', 'signature', 'sbom', 'provenance', 'notes']);
11
+ const SIGNATURE_FIELDS = new Set(['algorithm', 'keyId', 'url']);
12
+ const EVIDENCE_FIELDS = new Set(['url', 'sha256']);
13
+ function fail(message, code = 'RELEASE_MANIFEST_INVALID') {
14
+ throw new CliCommandError(message, { code, category: 'configuration' });
15
+ }
16
+ function policyPath() {
17
+ const moduleDirectory = path.dirname(fileURLToPath(import.meta.url));
18
+ const candidates = [
19
+ path.resolve(moduleDirectory, '../../release-policy.json'),
20
+ path.resolve(moduleDirectory, '../release-policy.json'),
21
+ path.resolve(process.cwd(), 'release-policy.json'),
22
+ ];
23
+ const resolved = candidates.find((candidate) => fs.existsSync(candidate));
24
+ if (!resolved)
25
+ return fail('The packaged release-policy.json file is missing.', 'RELEASE_POLICY_MISSING');
26
+ return resolved;
27
+ }
28
+ let cachedPolicy = null;
29
+ export function getReleasePolicy() {
30
+ if (cachedPolicy)
31
+ return cachedPolicy;
32
+ const raw = JSON.parse(fs.readFileSync(policyPath(), 'utf8'));
33
+ if (raw.schemaVersion !== 1 || raw.manifest?.schemaVersion !== 1 || raw.signature?.algorithm !== 'Ed25519') {
34
+ return fail('Unsupported release policy schema.', 'RELEASE_POLICY_UNSUPPORTED');
35
+ }
36
+ cachedPolicy = Object.freeze(raw);
37
+ return cachedPolicy;
38
+ }
39
+ function assertExactFields(value, allowed, label) {
40
+ for (const field of Object.keys(value)) {
41
+ if (!allowed.has(field))
42
+ fail(`${label} contains unknown field: ${field}`);
43
+ }
44
+ }
45
+ export function assertReleaseUrl(raw, kind = 'artifact') {
46
+ const policy = getReleasePolicy();
47
+ if (typeof raw !== 'string' || !raw || /[\\\u0000-\u001f\u007f]/.test(raw))
48
+ fail(`Invalid ${kind} URL.`);
49
+ let url;
50
+ try {
51
+ url = new URL(raw);
52
+ }
53
+ catch {
54
+ return fail(`Invalid ${kind} URL.`);
55
+ }
56
+ if (url.protocol !== 'https:' || url.username || url.password || (url.port && Number(url.port) !== policy.origins.port)) {
57
+ fail(`${kind} URL must use HTTPS without credentials on the policy port.`);
58
+ }
59
+ if (!policy.origins.allowedHosts.includes(url.hostname.toLowerCase()))
60
+ fail(`${kind} URL host is not allowlisted.`);
61
+ if (kind === 'manifest' && url.toString() !== policy.origins.manifest)
62
+ fail('Manifest URL does not match the canonical release policy origin.');
63
+ return url;
64
+ }
65
+ function parseEvidence(raw, label) {
66
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
67
+ return fail(`${label} metadata is required.`);
68
+ const record = raw;
69
+ assertExactFields(record, EVIDENCE_FIELDS, label);
70
+ const url = assertReleaseUrl(record.url, 'evidence').toString();
71
+ const sha256 = String(record.sha256 || '').toLowerCase();
72
+ if (!SHA256.test(sha256))
73
+ fail(`${label} SHA-256 is malformed.`);
74
+ return { url, sha256 };
75
+ }
76
+ export function parseReleaseManifest(input, channel = 'stable', serializedBytes) {
77
+ const policy = getReleasePolicy();
78
+ if (serializedBytes !== undefined && serializedBytes > policy.manifest.maximumBytes)
79
+ fail('Release manifest exceeds the policy size limit.');
80
+ if (!input || typeof input !== 'object' || Array.isArray(input))
81
+ return fail('Release manifest must be a JSON object.');
82
+ const manifest = input;
83
+ assertExactFields(manifest, TOP_LEVEL_FIELDS, 'Release manifest');
84
+ if (manifest.schemaVersion !== policy.manifest.schemaVersion)
85
+ fail('Release manifest schemaVersion is missing or unsupported.');
86
+ if (!policy.manifest.allowedChannels.includes(channel))
87
+ fail(`Release channel is not allowed: ${channel}`);
88
+ if (!manifest.channels || typeof manifest.channels !== 'object' || Array.isArray(manifest.channels))
89
+ fail('Release manifest channels object is required.');
90
+ const channels = manifest.channels;
91
+ for (const name of Object.keys(channels))
92
+ if (!policy.manifest.allowedChannels.includes(name))
93
+ fail(`Release manifest contains unknown channel: ${name}`);
94
+ for (const name of policy.manifest.requiredChannels)
95
+ if (!(name in channels))
96
+ fail(`Release manifest is missing required channel: ${name}`);
97
+ const raw = channels[channel];
98
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
99
+ return fail(`Release manifest has no entry for channel ${channel}.`);
100
+ const entry = raw;
101
+ assertExactFields(entry, ENTRY_FIELDS, `Release channel ${channel}`);
102
+ const version = String(entry.version || '');
103
+ const packageVersion = String(entry.packageVersion || '');
104
+ const archiveFilename = String(entry.archiveFilename || '');
105
+ const packageName = String(entry.packageName || '');
106
+ const sha256 = String(entry.sha256 || '').toLowerCase();
107
+ const size = Number(entry.size);
108
+ if (!SEMVER.test(version) || compareSemanticVersions(version, version) !== 0)
109
+ fail('Release version is invalid.');
110
+ if (version !== packageVersion)
111
+ fail('Release version conflicts with packageVersion.');
112
+ if (packageName !== policy.packageName)
113
+ fail('Release packageName conflicts with policy.');
114
+ if (!SHA256.test(sha256))
115
+ fail('Release artifact SHA-256 is malformed.');
116
+ if (!Number.isSafeInteger(size) || size <= 0 || size > policy.artifact.maximumBytes)
117
+ fail('Release artifact size is invalid or exceeds policy.');
118
+ if (!new RegExp(policy.artifact.filenamePattern).test(archiveFilename) || archiveFilename !== `${policy.packageName}-${version}.tgz`)
119
+ fail('Release archive filename conflicts with version identity.');
120
+ const artifactUrl = assertReleaseUrl(entry.url, 'artifact');
121
+ if (path.posix.basename(artifactUrl.pathname) !== archiveFilename)
122
+ fail('Release URL filename conflicts with archiveFilename.');
123
+ if (!policy.channels[channel].allowPrerelease && version.includes('-'))
124
+ fail(`Prerelease versions are forbidden on channel ${channel}.`);
125
+ const publishedAt = String(entry.publishedAt || '');
126
+ if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(publishedAt) || !Number.isFinite(Date.parse(publishedAt)))
127
+ fail('Release publishedAt is invalid.');
128
+ if (!entry.signature || typeof entry.signature !== 'object' || Array.isArray(entry.signature))
129
+ return fail('Detached signature metadata is required.');
130
+ const signature = entry.signature;
131
+ assertExactFields(signature, SIGNATURE_FIELDS, 'Release signature');
132
+ const algorithm = String(signature.algorithm || '');
133
+ const keyId = String(signature.keyId || '');
134
+ if (algorithm !== policy.signature.algorithm)
135
+ fail('Release signature algorithm conflicts with policy.');
136
+ if (!Object.hasOwn(policy.signature.trustedKeys, keyId))
137
+ fail('Release signature key is not trusted.');
138
+ const signatureUrl = assertReleaseUrl(signature.url, 'signature');
139
+ if (path.posix.basename(signatureUrl.pathname) !== `${archiveFilename}.sig`)
140
+ fail('Detached signature filename conflicts with archive identity.');
141
+ return {
142
+ version,
143
+ url: artifactUrl.toString(),
144
+ sha256,
145
+ size,
146
+ archiveFilename,
147
+ packageName,
148
+ packageVersion,
149
+ publishedAt,
150
+ signature: { algorithm: 'Ed25519', keyId, url: signatureUrl.toString() },
151
+ sbom: parseEvidence(entry.sbom, 'SBOM'),
152
+ provenance: parseEvidence(entry.provenance, 'Provenance'),
153
+ ...(typeof entry.notes === 'string' ? { notes: entry.notes } : {}),
154
+ };
155
+ }
156
+ export function parseReleaseManifestText(text, channel = 'stable') {
157
+ const bytes = Buffer.byteLength(text, 'utf8');
158
+ if (bytes > getReleasePolicy().manifest.maximumBytes)
159
+ fail('Release manifest exceeds the policy size limit.');
160
+ let index = 0;
161
+ const whitespace = () => { while (/\s/.test(text[index] || ''))
162
+ index += 1; };
163
+ const parseString = () => {
164
+ whitespace();
165
+ if (text[index] !== '"')
166
+ fail('Release manifest JSON is malformed.');
167
+ const start = index++;
168
+ let escaped = false;
169
+ while (index < text.length) {
170
+ const character = text[index++];
171
+ if (escaped) {
172
+ escaped = false;
173
+ continue;
174
+ }
175
+ if (character === '\\') {
176
+ escaped = true;
177
+ continue;
178
+ }
179
+ if (character === '"') {
180
+ try {
181
+ return JSON.parse(text.slice(start, index));
182
+ }
183
+ catch {
184
+ return fail('Release manifest JSON string is malformed.');
185
+ }
186
+ }
187
+ if (character.charCodeAt(0) < 0x20)
188
+ fail('Release manifest JSON string contains a control character.');
189
+ }
190
+ return fail('Release manifest JSON string is unterminated.');
191
+ };
192
+ const parseValue = () => {
193
+ whitespace();
194
+ if (text[index] === '{') {
195
+ index += 1;
196
+ const keys = new Set();
197
+ whitespace();
198
+ if (text[index] === '}') {
199
+ index += 1;
200
+ return;
201
+ }
202
+ while (index < text.length) {
203
+ const key = parseString();
204
+ if (keys.has(key))
205
+ fail(`Release manifest contains duplicate field: ${key}`);
206
+ keys.add(key);
207
+ whitespace();
208
+ if (text[index++] !== ':')
209
+ fail('Release manifest JSON object is malformed.');
210
+ parseValue();
211
+ whitespace();
212
+ const separator = text[index++];
213
+ if (separator === '}')
214
+ return;
215
+ if (separator !== ',')
216
+ fail('Release manifest JSON object is malformed.');
217
+ }
218
+ fail('Release manifest JSON object is unterminated.');
219
+ }
220
+ if (text[index] === '[') {
221
+ index += 1;
222
+ whitespace();
223
+ if (text[index] === ']') {
224
+ index += 1;
225
+ return;
226
+ }
227
+ while (index < text.length) {
228
+ parseValue();
229
+ whitespace();
230
+ const separator = text[index++];
231
+ if (separator === ']')
232
+ return;
233
+ if (separator !== ',')
234
+ fail('Release manifest JSON array is malformed.');
235
+ }
236
+ fail('Release manifest JSON array is unterminated.');
237
+ }
238
+ if (text[index] === '"') {
239
+ parseString();
240
+ return;
241
+ }
242
+ const remainder = text.slice(index);
243
+ const primitive = /^(?:true|false|null|-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)/.exec(remainder);
244
+ if (!primitive)
245
+ fail('Release manifest JSON value is malformed.');
246
+ index += primitive[0].length;
247
+ };
248
+ parseValue();
249
+ whitespace();
250
+ if (index !== text.length)
251
+ fail('Release manifest JSON has trailing content.');
252
+ let parsed;
253
+ try {
254
+ parsed = JSON.parse(text);
255
+ }
256
+ catch {
257
+ return fail('Release manifest JSON is malformed.');
258
+ }
259
+ return parseReleaseManifest(parsed, channel, bytes);
260
+ }
261
+ function canonicalize(value) {
262
+ if (Array.isArray(value))
263
+ return `[${value.map(canonicalize).join(',')}]`;
264
+ if (value && typeof value === 'object') {
265
+ const record = value;
266
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonicalize(record[key])}`).join(',')}}`;
267
+ }
268
+ return JSON.stringify(value);
269
+ }
270
+ export function releaseSignaturePayload(channel, entry) {
271
+ return Buffer.from(canonicalize({ channel, entry }), 'utf8');
272
+ }
273
+ export function verifyReleaseSignature(channel, entry, detachedBase64, trustedKeys) {
274
+ const keys = trustedKeys || getReleasePolicy().signature.trustedKeys;
275
+ const publicKey = keys[entry.signature.keyId];
276
+ if (!publicKey)
277
+ fail('Detached signature key is not trusted.', 'RELEASE_SIGNATURE_UNTRUSTED');
278
+ const encoded = String(detachedBase64 || '').trim();
279
+ if (!/^[A-Za-z0-9+/]+={0,2}$/.test(encoded))
280
+ fail('Detached signature encoding is malformed.', 'RELEASE_SIGNATURE_INVALID');
281
+ const signature = Buffer.from(encoded, 'base64');
282
+ if (signature.length !== 64 || !verifySignature(null, releaseSignaturePayload(channel, entry), createPublicKey(publicKey), signature)) {
283
+ fail('Detached release signature verification failed.', 'RELEASE_SIGNATURE_INVALID');
284
+ }
285
+ }
286
+ export function assertReleaseTransition(currentVersion, entry, channel, allowDowngrade = false) {
287
+ const channelPolicy = getReleasePolicy().channels[channel];
288
+ if (!channelPolicy)
289
+ fail(`Release channel is not allowed: ${channel}`);
290
+ if (compareSemanticVersions(entry.version, currentVersion) < 0 && !(allowDowngrade && channelPolicy.allowDowngrade)) {
291
+ fail(`Downgrade from ${currentVersion} to ${entry.version} is prohibited.`, 'RELEASE_DOWNGRADE_PROHIBITED');
292
+ }
293
+ }
@@ -4,12 +4,13 @@
4
4
  */
5
5
  const CLI_SHAPING_BLOCK = /(?:^|\n\n)Platform:\s*(?:Windows|macOS|Linux)\.[\s\S]*?(?=\n\n[A-Z][^\n]{0,40}:|\s*$)/i;
6
6
  const READONLY_SHAPING_BLOCK = /(?:^|\n\n)(?:Read-only analysis mode is active\.|Diagnostic mode is active\.)[\s\S]*?(?=\n\n[A-Z][^\n]{0,40}:|\s*$)/i;
7
- const BUILD_VERBS = /\b(build|create|make|implement|complete|redesign|overhaul|rebuild|transform|polish|art-direct|fix|repair|edit|modify|write|generate|add|finish|scaffold|develop|update|change|refactor|want|need|require|looking for|let's|let us|we need|we should|erstelle|erstellen|schreib|schreibe|bearbeite)\b/i;
7
+ const BUILD_VERBS = /\b(build|create|make|implement|complete|redesign|overhaul|rebuild|transform|polish|refine|art-direct|fix|repair|correct|edit|modify|write|generate|add|finish|scaffold|develop|update|change|refactor|want|need|require|looking for|let's|let us|we need|we should|erstelle|erstellen|schreib|schreibe|bearbeite)\b/i;
8
8
  const ARTIFACT_NOUNS = /\b(file|files|project|game|spiel|app|website|html5|frontend|component|feature|code|workspace|repo|clone|replica|remake|page|site|design|showcase|screen|button|popup|modal|alert|canvas|sprite|level|levels|enemy|enemies|character|npc|world|scene|script|module|api|database|config|landing|dashboard|platformer|arcade|playable|collectible|scoreboard|leaderboard|pitfall|pacman|rogue|html|css|javascript|typescript)\b/i;
9
9
  /** Canvas/playable games only — bare "html5" or "website" must NOT match. */
10
10
  const GAME_INTENT = /\b(game|spiel|playable|babylon(?:\.js|js)?|vge|webgl|3d\s+(?:game|runner|prototype|world|experience)|html5\s+(?:game|canvas)|html5\s+game|canvas\s+game|game\s+canvas|arcade|platformer|side[- ]?scroller|pitfall|pac[- ]?man|tetris|snake|breakout|pong|roguelike|metroidvania|tower\s+defense|clone\s+of\s+(?:a\s+)?(?:game|pitfall|pac|mario|zelda|arcade)|gameplay|collectible|boss\s+fight|level\s+design|sprite\s+sheet|wild\s+(?:boar|pig|forest)|forest\s+pig)\b/i;
11
11
  const WEB_PAGE_INTENT = /\b(website|web\s*site|webpage|web\s*page|landing\s+page|home\s*page|index\.html|html\s+page|static\s+page|single\s+page|popup|alert|modal|hello\s+world)\b/i;
12
12
  const WEB_SHOWCASE_INTENT = /\b(web[- ]?design\s+showcase|frontend|marketing\s+site|dashboard|saas)\b/i;
13
+ const COMPREHENSIVE_WEB_BUILD = /\b(?:redesign|overhaul|rebuild|transform|art[- ]direct|enterprise[- ]grade|premium\s+(?:website|web|design)|showcase\s+templates?|five\s+(?:distinct\s+)?(?:pages?|templates?))\b/i;
13
14
  const CLONE_BUILD = /\bclone\s+of\b|\b(build|create|make)\s+(?:a|an|the|us|me)?\s*(?:clone|replica|remake|port)\b/i;
14
15
  const READ_ONLY_INTENT = /\b(analy[sz]e|analyse|analysis|audit|review|inspect|proof|understand|summari[sz]e|scan|read[\s-]?only|where we left|what is|how does|show me|tell me|identify\s+gaps?|gap\s+analysis|production\s+blockers?)\b/i;
15
16
  const EXPLICIT_WRITE_VERBS = /\b(implement|write|edit|modify|update|redesign|overhaul|rebuild|transform|polish|art-direct|fix|repair|create|build|generate|scaffold|deploy|refactor|develop|integrate|correct|apply|patch)\b/i;
@@ -17,7 +18,7 @@ const TRIVIAL_HTML_PAGE = /\b(hello\s*world|simple\s+(?:html|web|page|site)|html
17
18
  /** User explicitly grants write permission after an analysis or confirmation gate. */
18
19
  const WRITE_PERMISSION_GRANT = /\b(?:hereby\s+confirm|i\s+confirm|confirm(?:ed)?\s+that|give\s+(?:you|permission)|granting\s+permission|allow\s+(?:you|me\s+to)|you\s+(?:may|can|have\s+permission\s+to)|permission\s+to|authorized?\s+to|approve(?:d)?\s+(?:the\s+)?(?:changes?|writes?|edits?)|go\s+ahead\s+and(?:\s+write|\s+apply|\s+make|\s+do)?|do\s+all\s+the\s+changes|apply\s+(?:the\s+)?(?:changes?|fixes?|fix)|proceed\s+with\s+(?:the\s+)?(?:changes?|fixes?|implementation|writes?)|make\s+(?:the\s+)?changes|please\s+write)\b/i;
19
20
  /** Fix/correct/repair syntax or errors — write path without requiring artifact nouns. */
20
- const FIX_CORRECT_INTENT = /\b(correct|fix|repair|resolve|patch|address|remedy)\b[\s\S]{0,48}\b(syntax|errors?|bugs?|issues?|mistakes?|typos?)\b|\b(syntax|errors?|bugs?|issues?)\b[\s\S]{0,48}\b(correct|fix|repair|resolve|patch)\b/i;
21
+ const FIX_CORRECT_INTENT = /\b(correct|fix|repair|resolve|patch|address|remedy)\b[\s\S]{0,48}\b(syntax|errors?|bugs?|issues?|defects?|mistakes?|typos?)\b|\b(syntax|errors?|bugs?|issues?|defects?)\b[\s\S]{0,48}\b(correct|fix|repair|resolve|patch)\b/i;
21
22
  /** Read-only audit: check/review/find issues without an paired fix/implement verb nearby. */
22
23
  const READ_ONLY_CHECK = /\b(check|verify|audit|inspect|review|investigate|look\s+for|find|scan|validate|examine)\b[\s\S]{0,60}\b(syntax|errors?|bugs?|issues?|missing|gaps?|functionality)\b/i;
23
24
  /** Strip CLI-appended platform / mode shaping so it cannot flip quality profiles. */
@@ -77,6 +78,14 @@ export function isAgentContinuePrompt(prompt) {
77
78
  if (isBuiltContinuePrompt(text) || isBuiltRetryPrompt(text)) {
78
79
  return false;
79
80
  }
81
+ const concreteFileScope = /(?<![A-Za-z0-9_.-])[A-Za-z0-9_./\\-]+\.[A-Za-z0-9]{1,16}(?![A-Za-z0-9_.-])/.test(text);
82
+ const detailedMutationFollowUp = EXPLICIT_WRITE_VERBS.test(text) && (concreteFileScope || text.split(/\s+/).length > 20);
83
+ if (detailedMutationFollowUp) {
84
+ // A user may naturally say "continue" while also supplying new defect
85
+ // evidence, exact file ownership, or revised acceptance criteria. That is
86
+ // a new scoped follow-up, not shorthand for replaying the stored prompt.
87
+ return false;
88
+ }
80
89
  if (/^\/(?:continue|contiune|contiunue)$/i.test(text)) {
81
90
  return true;
82
91
  }
@@ -128,7 +137,7 @@ export function isTrivialHtmlPageRequest(prompt) {
128
137
  if (text.length > 420) {
129
138
  return false;
130
139
  }
131
- if (/\b(multi[- ]?page|full\s+saas|dashboard|e[\s-]?commerce|auth|database|backend|api|microservice)\b/i.test(text)) {
140
+ if (/\b(multi[- ]?page|five\s+pages?|showcase|enterprise(?:[- ]grade)?|animated?|motion|redesign|overhaul|existing\s+(?:site|website|project)|full\s+saas|dashboard|e[\s-]?commerce|auth|database|backend|api|microservice)\b/i.test(text)) {
132
141
  return false;
133
142
  }
134
143
  return TRIVIAL_HTML_PAGE.test(text)
@@ -247,6 +256,16 @@ export function inferAgentTaskType(prompt) {
247
256
  }
248
257
  return 'implementation';
249
258
  }
259
+ // A comprehensive website redesign remains a web-build even when the brief
260
+ // also says to fix/repair defects found during the audit. Treating the repair
261
+ // verb as globally dominant collapses the required markup/style/interaction
262
+ // decomposition into a narrow three-step bug-fix workflow.
263
+ if (hasWebPageIntent(prompt)
264
+ && hasBuildVerb(prompt)
265
+ && COMPREHENSIVE_WEB_BUILD.test(text)
266
+ && !hasGameIntent(prompt)) {
267
+ return 'web-build';
268
+ }
250
269
  if (hasFixOrCorrectIntent(prompt)) {
251
270
  if (hasGameIntent(prompt)) {
252
271
  return 'game-build';
@@ -0,0 +1,8 @@
1
+ export type RuntimeCapabilities = {
2
+ loopbackServices: boolean;
3
+ localV3Agent: boolean;
4
+ };
5
+ /** Explicit operator grants only; never infer trust from hostname, cwd, OS, or container state. */
6
+ export declare function resolveRuntimeCapabilities(environment?: NodeJS.ProcessEnv): RuntimeCapabilities;
7
+ export declare function hasLoopbackServiceCapability(environment?: NodeJS.ProcessEnv): boolean;
8
+ export declare function hasLocalV3AgentCapability(environment?: NodeJS.ProcessEnv): boolean;
@@ -0,0 +1,16 @@
1
+ /** Explicit operator grants only; never infer trust from hostname, cwd, OS, or container state. */
2
+ export function resolveRuntimeCapabilities(environment = process.env) {
3
+ const loopbackServices = environment.VIGTHORIA_ALLOW_LOCAL_SERVICES === '1'
4
+ || environment.VIGTHORIA_ALLOW_LOOPBACK === '1'
5
+ || environment.VIGTHORIA_LOCAL_TEST_MODE === '1';
6
+ return {
7
+ loopbackServices,
8
+ localV3Agent: loopbackServices && environment.VIGTHORIA_ALLOW_LOCAL_V3_AGENT === '1',
9
+ };
10
+ }
11
+ export function hasLoopbackServiceCapability(environment = process.env) {
12
+ return resolveRuntimeCapabilities(environment).loopbackServices;
13
+ }
14
+ export function hasLocalV3AgentCapability(environment = process.env) {
15
+ return resolveRuntimeCapabilities(environment).localV3Agent;
16
+ }
@@ -0,0 +1,76 @@
1
+ export interface RuntimeTempOptions {
2
+ homeDirectory?: string;
3
+ environment?: NodeJS.ProcessEnv;
4
+ platform?: NodeJS.Platform;
5
+ now?: () => number;
6
+ pid?: number;
7
+ isProcessAlive?: (pid: number) => boolean;
8
+ systemTempDirectory?: string;
9
+ }
10
+ export interface RuntimeTempCleanupResult {
11
+ removedEntries: number;
12
+ removedBytes: number;
13
+ skippedActiveEntries: number;
14
+ legacyRemovedEntries: number;
15
+ legacyRemovedBytes: number;
16
+ }
17
+ export interface RuntimeTempStatus extends RuntimeTempCleanupResult {
18
+ root: string;
19
+ source: 'per-user-default' | 'explicit-override';
20
+ writable: boolean;
21
+ sharedSystemTemp: boolean;
22
+ maxBytes: number;
23
+ minimumFreeBytes: number;
24
+ ttlHours: number;
25
+ usedBytes: number;
26
+ entryCount: number;
27
+ freeBytes: number | null;
28
+ error: string | null;
29
+ }
30
+ export declare class RuntimeTempError extends Error {
31
+ readonly code: string;
32
+ readonly details: Record<string, unknown>;
33
+ constructor(message: string, code: string, details?: Record<string, unknown>);
34
+ }
35
+ export declare function resolveRuntimeTempRoot(options?: RuntimeTempOptions): {
36
+ root: string;
37
+ source: RuntimeTempStatus['source'];
38
+ };
39
+ export declare class RuntimeTempManager {
40
+ private readonly environment;
41
+ private readonly platform;
42
+ private readonly homeDirectory;
43
+ private readonly now;
44
+ private readonly pid;
45
+ private readonly isProcessAlive;
46
+ private readonly systemTempRoot;
47
+ private readonly configuredRoot;
48
+ private readonly source;
49
+ private readonly maxBytes;
50
+ private readonly minimumFreeBytes;
51
+ private readonly ttlMs;
52
+ private initializedRoot;
53
+ private initializedIdentity;
54
+ private initializationError;
55
+ private lastCleanup;
56
+ constructor(options?: RuntimeTempOptions);
57
+ initialize(): RuntimeTempStatus;
58
+ createDirectory(prefix?: string): string;
59
+ removeDirectory(directory: string): void;
60
+ scavenge(options?: {
61
+ includeLegacy?: boolean;
62
+ }): RuntimeTempCleanupResult;
63
+ status(): RuntimeTempStatus;
64
+ private requireRoot;
65
+ private readEntries;
66
+ private entrySize;
67
+ private freeBytes;
68
+ private measure;
69
+ private removeEntry;
70
+ private cleanupLegacySystemTemp;
71
+ }
72
+ export declare function getRuntimeTempManager(): RuntimeTempManager;
73
+ export declare function initializeRuntimeTempStorage(): RuntimeTempStatus;
74
+ export declare function runtimeTempStatus(): RuntimeTempStatus;
75
+ export declare function createRuntimeTempDirectory(prefix: string): string;
76
+ export declare function removeRuntimeTempDirectory(directory: string): void;