vigthoria-cli 1.13.34 → 1.13.42

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 (51) hide show
  1. package/README.md +11 -56
  2. package/SECURITY_HARDENING.md +2 -4
  3. package/dist/commands/auth.js +16 -14
  4. package/dist/commands/cancel.d.ts +1 -0
  5. package/dist/commands/cancel.js +21 -4
  6. package/dist/commands/chat.d.ts +13 -0
  7. package/dist/commands/chat.js +170 -14
  8. package/dist/commands/fork.js +8 -3
  9. package/dist/commands/history.js +8 -3
  10. package/dist/commands/legion.js +1 -1
  11. package/dist/commands/replay.js +8 -3
  12. package/dist/commands/update-registration.js +63 -206
  13. package/dist/commands/v4-menu.d.ts +0 -1
  14. package/dist/commands/v4-menu.js +8 -6
  15. package/dist/commands/v4-registration.js +0 -2
  16. package/dist/commands/v4.js +9 -4
  17. package/dist/commands/wallet.d.ts +1 -1
  18. package/dist/commands/wallet.js +3 -3
  19. package/dist/index.js +2 -3
  20. package/dist/utils/agent-stream-state.d.ts +7 -0
  21. package/dist/utils/agent-stream-state.js +31 -0
  22. package/dist/utils/agentRunOutcome.js +5 -1
  23. package/dist/utils/api.d.ts +19 -4
  24. package/dist/utils/api.js +322 -550
  25. package/dist/utils/frontend-preview-service.d.ts +10 -1
  26. package/dist/utils/frontend-preview-service.js +162 -17
  27. package/dist/utils/javascript-syntax.d.ts +19 -0
  28. package/dist/utils/javascript-syntax.js +35 -0
  29. package/dist/utils/localTestMode.js +1 -1
  30. package/dist/utils/mutation-journal.d.ts +10 -0
  31. package/dist/utils/mutation-journal.js +104 -76
  32. package/dist/utils/network-policy.js +7 -10
  33. package/dist/utils/preview-screenshot-adapter.d.ts +81 -0
  34. package/dist/utils/preview-screenshot-adapter.js +615 -38
  35. package/dist/utils/release-install.d.ts +0 -1
  36. package/dist/utils/release-install.js +44 -7
  37. package/dist/utils/requestIntent.d.ts +1 -1
  38. package/dist/utils/requestIntent.js +17 -3
  39. package/dist/utils/tools.js +21 -15
  40. package/dist/utils/update-policy.d.ts +0 -4
  41. package/dist/utils/update-policy.js +5 -9
  42. package/dist/utils/v3-agent-client.js +25 -11
  43. package/install.ps1 +30 -50
  44. package/install.sh +13 -24
  45. package/package.json +4 -2
  46. package/release-policy.json +1 -5
  47. package/scripts/release/LOCAL_MACHINE_USER_VERIFICATION.md +6 -7
  48. package/scripts/release/install-release.mjs +5 -4
  49. package/scripts/release/publish-cli-release.mjs +21 -8
  50. package/scripts/release/test-balanced-model-live.sh +4 -1
  51. package/scripts/release/validate-live-service-gates.sh +27 -5
@@ -7,5 +7,4 @@ export type ReleaseInstallResult = {
7
7
  };
8
8
  export declare function installReleaseTransaction(packageSpec: string, expectedVersion: string, options?: {
9
9
  homeDirectory?: string;
10
- npmRegistry?: string;
11
10
  }): ReleaseInstallResult;
@@ -6,7 +6,23 @@ import { execFileSync } from 'node:child_process';
6
6
  import { getReleasePolicy } from './release-policy.js';
7
7
  import { safeChildProcessEnv } from './secret-policy.js';
8
8
  import { assertProcessNetworkAllowed } from './process-policy.js';
9
- function npmExecutable() { return process.platform === 'win32' ? 'npm.cmd' : 'npm'; }
9
+ function npmInvocation() {
10
+ if (process.platform !== 'win32') {
11
+ return { executable: 'npm', leadingArguments: [], policyExecutable: 'npm' };
12
+ }
13
+ // Node 24 rejects direct execFile/spawn of .cmd launchers on Windows with
14
+ // EINVAL. Invoking npm through cmd.exe would reintroduce shell parsing for
15
+ // the archive and prefix paths. Execute npm's JavaScript entry through the
16
+ // already-trusted Node binary instead.
17
+ const candidates = [
18
+ path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js'),
19
+ path.resolve(path.dirname(process.execPath), '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
20
+ ];
21
+ const npmCli = candidates.find((candidate) => fs.statSync(candidate, { throwIfNoEntry: false })?.isFile());
22
+ if (!npmCli)
23
+ throw new Error('The npm runtime bundled with Node could not be located safely.');
24
+ return { executable: process.execPath, leadingArguments: [npmCli], policyExecutable: 'npm.cmd' };
25
+ }
10
26
  function readInstalledIdentity(prefix) {
11
27
  const packageDirectory = path.join(prefix, 'node_modules', 'vigthoria-cli');
12
28
  const manifest = JSON.parse(fs.readFileSync(path.join(packageDirectory, 'package.json'), 'utf8'));
@@ -25,6 +41,25 @@ function smokeCandidate(prefix, expectedVersion, homeDirectory) {
25
41
  VIGTHORIA_NO_UPDATE_CHECK: '1',
26
42
  NO_COLOR: '1',
27
43
  };
44
+ // The parent CLI has already redirected TEMP/TMP/TMPDIR into its managed
45
+ // per-user root. Seed only a known native shared-temp boundary while the
46
+ // child imports runtime-temp; CLI startup immediately replaces it with the
47
+ // managed per-user root before the command executes. On Windows Node 24,
48
+ // deleting TEMP/TMP is insufficient because os.tmpdir() may reconstruct the
49
+ // user-scoped managed value from the remaining process environment.
50
+ for (const key of Object.keys(environment)) {
51
+ if (['TEMP', 'TMP', 'TMPDIR'].includes(key.toUpperCase()))
52
+ delete environment[key];
53
+ }
54
+ if (process.platform === 'win32') {
55
+ const systemRoot = String(environment.SystemRoot || environment.SYSTEMROOT || 'C:\\Windows');
56
+ const nativeTempBoundary = path.win32.join(systemRoot, 'Temp');
57
+ environment.TEMP = nativeTempBoundary;
58
+ environment.TMP = nativeTempBoundary;
59
+ }
60
+ else {
61
+ environment.TMPDIR = '/tmp';
62
+ }
28
63
  for (const args of [['--version'], ['--help'], ['doctor', '--json']]) {
29
64
  const output = execFileSync(process.execPath, [identity.entry, ...args], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, timeout: 30_000, env: environment });
30
65
  if (args[0] === '--version' && output.trim() !== expectedVersion)
@@ -67,17 +102,19 @@ export function installReleaseTransaction(packageSpec, expectedVersion, options
67
102
  let switched = false;
68
103
  let previousTarget = null;
69
104
  try {
70
- const npm = npmExecutable();
105
+ const npm = npmInvocation();
71
106
  const args = ['install', '--prefix', stage, '--ignore-scripts', '--no-audit', '--no-fund', '--install-strategy=nested'];
72
- const localArchive = path.isAbsolute(packageSpec) && fs.statSync(packageSpec, { throwIfNoEntry: false })?.isFile();
107
+ const localArchive = path.isAbsolute(packageSpec)
108
+ && packageSpec.toLowerCase().endsWith('.tgz')
109
+ && fs.statSync(packageSpec, { throwIfNoEntry: false })?.isFile();
110
+ if (!localArchive)
111
+ throw new Error('Release activation accepts only an existing absolute local .tgz archive.');
73
112
  if (localArchive && process.env.VIGTHORIA_OFFLINE === '1')
74
113
  args.push('--offline');
75
- if (options.npmRegistry)
76
- args.push(`--registry=${options.npmRegistry}`);
77
114
  args.push(packageSpec);
78
115
  if (!(localArchive && args.includes('--offline')))
79
- assertProcessNetworkAllowed(npm, args);
80
- execFileSync(npm, args, {
116
+ assertProcessNetworkAllowed(npm.policyExecutable, args);
117
+ execFileSync(npm.executable, [...npm.leadingArguments, ...args], {
81
118
  stdio: 'pipe',
82
119
  windowsHide: true,
83
120
  timeout: 180_000,
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Shared prompt intent detection for CLI routing, V3 hints, and rescue gating.
3
- * Keep aligned with V3-Code-Agent/agent.py _classify_request heuristics.
3
+ * Keep aligned with the isolated V3 CLI lane's server-side request classifier.
4
4
  */
5
5
  export type IntentContext = {
6
6
  priorPrompt?: string | null;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Shared prompt intent detection for CLI routing, V3 hints, and rescue gating.
3
- * Keep aligned with V3-Code-Agent/agent.py _classify_request heuristics.
3
+ * Keep aligned with the isolated V3 CLI lane's server-side request classifier.
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;
@@ -177,7 +177,15 @@ export function isBuiltWriteConfirmationPrompt(prompt) {
177
177
  return /^The user confirmed they want file changes applied/i.test(stripExecutionShaping(prompt));
178
178
  }
179
179
  export function hasFixOrCorrectIntent(prompt) {
180
- return FIX_CORRECT_INTENT.test(stripExecutionShaping(prompt));
180
+ const text = stripExecutionShaping(prompt);
181
+ // An explicit repair verb is sufficient even when the user describes the
182
+ // exact value change instead of repeating a generic "bug" or "issue" noun.
183
+ // Remove negated repair clauses first so safety/scope instructions do not
184
+ // manufacture write intent. Comprehensive redesign intent is resolved ahead
185
+ // of this predicate by inferAgentTaskType.
186
+ const affirmative = text.replace(/\b(?:not|is\s+not|isn't|no|do\s+not|don't|without)\s+(?:an?\s+)?(?:(?:narrow|focused|small|minor|simple|atomic)\s+)?(?:fix|repair|patch|debug)(?:ing|\s+job)?\b/gi, ' ');
187
+ return FIX_CORRECT_INTENT.test(affirmative)
188
+ || /\b(?:fix|repair|patch|resolve|correct|debug)\b/i.test(affirmative);
181
189
  }
182
190
  export function isReadOnlyCheckIntent(prompt) {
183
191
  const text = stripExecutionShaping(prompt);
@@ -187,7 +195,13 @@ export function isReadOnlyCheckIntent(prompt) {
187
195
  if (hasFixOrCorrectIntent(prompt) || isWritePermissionGrant(prompt)) {
188
196
  return false;
189
197
  }
190
- if (/\b(?:fix|correct|repair|implement|apply|write|change|update)\b/i.test(text)) {
198
+ // A build brief commonly ends with "verify syntax/runtime". The old
199
+ // narrow exception list did not include build/create/generate/develop, so
200
+ // that trailing verification clause reclassified an explicit greenfield
201
+ // request as read-only debugging. Keep the write vocabulary aligned with
202
+ // EXPLICIT_WRITE_VERBS so verification remains a release gate for the
203
+ // requested mutation rather than overriding it.
204
+ if (EXPLICIT_WRITE_VERBS.test(text)) {
191
205
  return false;
192
206
  }
193
207
  return true;
@@ -29,6 +29,7 @@ import { assertProcessNetworkAllowed, buildApprovalScope, hardenGitArguments, pa
29
29
  import { containsHighConfidenceSecret, isSensitivePath, safeChildProcessEnv } from './secret-policy.js';
30
30
  import { isOfflineNetworkMode } from './network-policy.js';
31
31
  import { createRuntimeTempDirectory, removeRuntimeTempDirectory } from './runtime-temp.js';
32
+ import { resolveJavaScriptSyntaxModes } from './javascript-syntax.js';
32
33
  import { ToolApprovalService } from './tool-approval-service.js';
33
34
  import { DelegationToolProvider, FilesystemToolProvider, NetworkBrowserToolProvider, ProcessToolProvider, RepositoryToolProvider, SearchToolProvider, SshToolProvider, ToolCapabilityRegistry, } from './tool-capability-providers.js';
34
35
  const STREAM_RESPONSE_MAX_YIELD_CHARS = 32 * 1024;
@@ -1349,25 +1350,30 @@ export class AgenticTools {
1349
1350
  catch (error) {
1350
1351
  return this.formatExternalToolError('syntax_check', 'allocate bounded temporary storage', error);
1351
1352
  }
1352
- const tempFile = path.join(tempDirectory, 'candidate.js');
1353
+ const syntaxModes = resolveJavaScriptSyntaxModes(source);
1354
+ const tempFiles = syntaxModes.map((mode) => path.join(tempDirectory, `candidate.${mode === 'module' ? 'mjs' : 'cjs'}`));
1353
1355
  try {
1354
- try {
1355
- fs.writeFileSync(tempFile, source, 'utf-8');
1356
- }
1357
- catch (writeError) {
1358
- return this.formatExternalToolError('syntax_check', `write temporary file ${tempFile}`, writeError);
1359
- }
1360
- try {
1361
- execFileSync(process.execPath, ['--check', tempFile], { stdio: 'pipe', timeout: 10_000, windowsHide: true, env: safeChildProcessEnv() });
1362
- return null;
1363
- }
1364
- catch (error) {
1365
- const stderr = error.stderr?.toString()?.trim();
1366
- return stderr || error.message || this.formatExternalToolError('syntax_check', `node --check ${tempFile}`, error);
1356
+ let firstError = null;
1357
+ for (const tempFile of tempFiles) {
1358
+ try {
1359
+ fs.writeFileSync(tempFile, source, 'utf-8');
1360
+ }
1361
+ catch (writeError) {
1362
+ return this.formatExternalToolError('syntax_check', `write temporary file ${tempFile}`, writeError);
1363
+ }
1364
+ try {
1365
+ execFileSync(process.execPath, ['--check', tempFile], { stdio: 'pipe', timeout: 10_000, windowsHide: true, env: safeChildProcessEnv() });
1366
+ return null;
1367
+ }
1368
+ catch (error) {
1369
+ const stderr = error.stderr?.toString()?.trim();
1370
+ firstError ||= stderr || error.message || this.formatExternalToolError('syntax_check', `node --check ${tempFile}`, error);
1371
+ }
1367
1372
  }
1373
+ return firstError || 'JavaScript syntax check failed.';
1368
1374
  }
1369
1375
  finally {
1370
- this.cleanupAfterToolError('syntax_check', `remove temporary file ${tempFile}`, () => {
1376
+ this.cleanupAfterToolError('syntax_check', 'remove temporary JavaScript syntax files', () => {
1371
1377
  removeRuntimeTempDirectory(tempDirectory);
1372
1378
  });
1373
1379
  }
@@ -1,8 +1,4 @@
1
1
  export type ResolvedUpdateSource = {
2
- kind: 'registry';
3
- installTarget: string;
4
- expectedSha256: null;
5
- } | {
6
2
  kind: 'local';
7
3
  installTarget: string;
8
4
  expectedSha256: string | null;
@@ -101,14 +101,10 @@ export function resolveUpdateSource(rawTarget, options = {}) {
101
101
  });
102
102
  }
103
103
  if (target.startsWith('vigthoria-cli@')) {
104
- parseSemanticVersion(target.slice('vigthoria-cli@'.length));
105
- if (expectedSha256) {
106
- throw new CliCommandError('--sha256 applies only to local or HTTPS archive sources.', {
107
- code: 'UPDATE_CHECKSUM_NOT_APPLICABLE',
108
- category: 'usage',
109
- });
110
- }
111
- return { kind: 'registry', installTarget: target, expectedSha256: null };
104
+ throw new CliCommandError('Registry package sources are disabled; use the signed extension manifest or an approved local archive.', {
105
+ code: 'UPDATE_REGISTRY_SOURCE_DISABLED',
106
+ category: 'usage',
107
+ });
112
108
  }
113
109
  const candidatePath = path.resolve(options.cwd || process.cwd(), target);
114
110
  if (target.toLowerCase().endsWith('.tgz') || fs.existsSync(candidatePath)) {
@@ -130,7 +126,7 @@ export function resolveUpdateSource(rawTarget, options = {}) {
130
126
  }
131
127
  return { kind: 'local', installTarget: fs.realpathSync(candidatePath), expectedSha256 };
132
128
  }
133
- throw new CliCommandError('Update source must be an exact vigthoria-cli@<version> package or a local/HTTPS .tgz archive.', {
129
+ throw new CliCommandError('Update source must be a local .tgz archive or an HTTPS .tgz archive on extension.vigthoria.io.', {
134
130
  code: 'UPDATE_SOURCE_INVALID',
135
131
  category: 'usage',
136
132
  });
@@ -8,35 +8,49 @@ export class V3AgentClient {
8
8
  }
9
9
  isDirectBaseUrl(baseUrl) {
10
10
  try {
11
- return new URL(String(baseUrl)).port.endsWith('8030');
11
+ return new Set(['8032', '18032']).has(new URL(String(baseUrl)).port);
12
12
  }
13
13
  catch {
14
- return /(?:127\.0\.0\.1|localhost|172\.19\.0\.1|host\.lan):(?:\d*8030|8030)/.test(String(baseUrl));
14
+ return /(?:127\.0\.0\.1|localhost|172\.19\.0\.1|host\.lan):(?:8032|18032)/.test(String(baseUrl));
15
15
  }
16
16
  }
17
17
  getBaseUrls(preferLocal = false) {
18
18
  const configured = String(this.dependencies.getConfiguredApiUrl() || 'https://coder.vigthoria.io').replace(/\/$/, '');
19
19
  const localTestMode = isLocalTestfarmMode();
20
- const explicit = Boolean(process.env.VIGTHORIA_V3_AGENT_URL || process.env.V3_AGENT_URL);
21
- const local = [
20
+ const explicitUrls = [
22
21
  process.env.VIGTHORIA_V3_AGENT_URL,
23
22
  process.env.V3_AGENT_URL,
24
- ...(hasLocalV3AgentCapability() ? ['http://127.0.0.1:8030'] : []),
23
+ ].filter(Boolean).map((url) => String(url).replace(/\/$/, ''));
24
+ const explicit = explicitUrls.length > 0;
25
+ const local = [
26
+ ...explicitUrls,
27
+ ...(hasLocalV3AgentCapability() ? ['http://127.0.0.1:8032'] : []),
25
28
  ].filter(Boolean).map((url) => String(url).replace(/\/$/, ''));
26
29
  const remote = (localTestMode ? [configured] : [configured, 'https://coder.vigthoria.io'])
27
30
  .filter(Boolean).map((url) => String(url).replace(/\/$/, ''));
31
+ // An explicit endpoint is an operator-selected runtime boundary, not a
32
+ // preference hint. Falling through from a failed isolated CLI lane to the
33
+ // public gateway can execute the same mutation against a different runtime
34
+ // and also turns an internal failure into a misleading login error.
35
+ if (explicit)
36
+ return [...new Set(explicitUrls)];
28
37
  return [...new Set((preferLocal || localTestMode || explicit) && local.length ? [...local, ...remote] : [...remote, ...local])];
29
38
  }
30
- runUrl(baseUrl) { return `${baseUrl}${this.isDirectBaseUrl(baseUrl) ? '/api/agent/run' : '/api/v3-agent/run'}`; }
31
- continueUrl(baseUrl) { return `${baseUrl}${this.isDirectBaseUrl(baseUrl) ? '/api/agent/continue' : '/api/v3-agent/continue'}`; }
39
+ runUrl(baseUrl) { return `${baseUrl}${this.isDirectBaseUrl(baseUrl) ? '/api/agent/run' : '/api/v3-agent-cli/run'}`; }
40
+ continueUrl(baseUrl) { return `${baseUrl}${this.isDirectBaseUrl(baseUrl) ? '/api/agent/continue' : '/api/v3-agent-cli/continue'}`; }
32
41
  backgroundUrl(baseUrl, suffix = '') {
33
42
  const clean = suffix ? `/${suffix.replace(/^\/+/, '')}` : '';
34
- return `${baseUrl}${this.isDirectBaseUrl(baseUrl) ? '/api/agent/background' : '/api/v3-agent/background'}${clean}`;
43
+ return `${baseUrl}${this.isDirectBaseUrl(baseUrl) ? '/api/agent/background' : '/api/v3-agent-cli/background'}${clean}`;
35
44
  }
36
- approvalUrl(baseUrl) { return `${baseUrl}${this.isDirectBaseUrl(baseUrl) ? '/api/agent/approval' : '/api/v3-agent/approval'}`; }
37
- healthUrl(baseUrl) { return `${baseUrl}${this.isDirectBaseUrl(baseUrl) ? '/health' : '/api/v3-agent/health'}`; }
45
+ approvalUrl(baseUrl) { return `${baseUrl}${this.isDirectBaseUrl(baseUrl) ? '/api/agent/approval' : '/api/v3-agent-cli/approval'}`; }
46
+ healthUrl(baseUrl) { return `${baseUrl}${this.isDirectBaseUrl(baseUrl) ? '/health' : '/api/v3-agent-cli/health'}`; }
38
47
  headers() {
39
- const headers = { 'Content-Type': 'application/json', Accept: 'text/event-stream' };
48
+ const headers = {
49
+ 'Content-Type': 'application/json',
50
+ Accept: 'text/event-stream',
51
+ 'X-Vigthoria-Agent-Lane': 'cli',
52
+ 'X-Vigthoria-Source-Product': 'vigthoria-cli',
53
+ };
40
54
  const token = this.dependencies.getAccessToken();
41
55
  if (token) {
42
56
  headers.Authorization = `Bearer ${token}`;
package/install.ps1 CHANGED
@@ -1,27 +1,23 @@
1
1
  # Vigthoria CLI Installer for Windows
2
- # Usage: irm https://cli.vigthoria.io/install.ps1 | iex
2
+ # Usage: irm https://extension.vigthoria.io/downloads/install.ps1 | iex
3
3
  # Alternative: PowerShell -ExecutionPolicy Bypass -File install.ps1
4
4
 
5
5
  $ErrorActionPreference = "Stop"
6
6
 
7
7
  # Configuration
8
- $CLI_VERSION = "1.13.34"
8
+ $CLI_VERSION = "1.13.42"
9
9
  $INSTALL_DIR = "$env:USERPROFILE\.vigthoria"
10
- $NPM_PACKAGE = "vigthoria-cli"
11
10
  $MANIFEST_URL = "https://extension.vigthoria.io/downloads/manifest.json"
12
11
  $HOSTED_TARBALL_URL = "https://extension.vigthoria.io/downloads/vigthoria-cli-$CLI_VERSION.tgz"
13
12
  # Packaged installs resolve the signed manifest. The standalone hosted script
14
13
  # is pinned after packing to the immutable archive digest; a pipe-to-iex copy
15
- # has no PSScriptRoot and safely falls back to the exact npm package.
16
- $HOSTED_TARBALL_SHA256 = ""
14
+ # stays on the same canonical extension archive.
15
+ $HOSTED_TARBALL_SHA256 = "d778aac8cbcf22da7ac7ca7d6007520e8996591a653dddf9b10443eaea70a4f0"
17
16
  $RELEASE_RESOLVER = if ($PSScriptRoot) { Join-Path $PSScriptRoot "scripts\release\resolve-release-manifest.mjs" } else { "" }
18
17
  $RELEASE_INSTALLER = if ($PSScriptRoot) { Join-Path $PSScriptRoot "scripts\release\install-release.mjs" } else { "" }
19
18
 
20
19
  function Assert-TrustedReleaseUrl([string]$Value) {
21
- $allowed = @(
22
- "extension.vigthoria.io", "landing.vigthoria.io", "cli.vigthoria.io",
23
- "coder.vigthoria.io", "market.vigthoria.io", "registry.npmjs.org"
24
- )
20
+ $allowed = @("extension.vigthoria.io")
25
21
  try { $uri = [Uri]$Value } catch { throw "Invalid release URL" }
26
22
  if ($uri.Scheme -ne "https" -or -not $uri.IsDefaultPort -or $uri.UserInfo -or $allowed -notcontains $uri.DnsSafeHost.ToLowerInvariant() -or $Value.Contains("\")) {
27
23
  throw "Release URL must use HTTPS on an exact approved host and port"
@@ -75,16 +71,7 @@ function Test-NetworkConnectivity {
75
71
  return $true
76
72
  }
77
73
  catch {
78
- Write-Host "[WARN] Hosted package unavailable, checking npm registry..." -ForegroundColor Yellow
79
- }
80
-
81
- try {
82
- $response = Invoke-WebRequest -Uri "https://registry.npmjs.org/vigthoria-cli" -UseBasicParsing -MaximumRedirection 0 -TimeoutSec 10 -ErrorAction Stop
83
- Write-Host "[OK] npm registry is reachable" -ForegroundColor Green
84
- return $true
85
- }
86
- catch {
87
- Write-Host "[ERROR] Cannot reach hosted package or npm registry" -ForegroundColor Red
74
+ Write-Host "[ERROR] Cannot reach the canonical extension package" -ForegroundColor Red
88
75
  return $false
89
76
  }
90
77
  }
@@ -162,11 +149,11 @@ function Get-VigthoriaTempRoot {
162
149
  return $fullRoot
163
150
  }
164
151
 
165
- function Install-VigthoriaCLI-NPM {
152
+ function Install-VigthoriaCLI-Package {
166
153
  Write-Host ""
167
154
  Write-Host "[INSTALL] Installing Vigthoria CLI..." -ForegroundColor Cyan
168
155
 
169
- if ($HOSTED_TARBALL_SHA256 -and $RELEASE_INSTALLER -and (Test-Path -LiteralPath $RELEASE_INSTALLER)) {
156
+ if ($HOSTED_TARBALL_SHA256) {
170
157
  $releaseTemp = Join-Path (Get-VigthoriaTempRoot) ("install-" + [Guid]::NewGuid().ToString("N"))
171
158
  $releaseArchive = Join-Path $releaseTemp "candidate.tgz"
172
159
  try {
@@ -175,14 +162,19 @@ function Install-VigthoriaCLI-NPM {
175
162
  Invoke-WebRequest -Uri $trustedTarball -OutFile $releaseArchive -UseBasicParsing -MaximumRedirection 0 -TimeoutSec 60 -ErrorAction Stop
176
163
  $actualSha256 = (Get-FileHash -Path $releaseArchive -Algorithm SHA256).Hash.ToLowerInvariant()
177
164
  if ($actualSha256 -ne $HOSTED_TARBALL_SHA256) { throw "Release checksum mismatch" }
178
- if (-not $RELEASE_INSTALLER -or -not (Test-Path -LiteralPath $RELEASE_INSTALLER)) { throw "Transactional release installer is unavailable" }
179
- & node $RELEASE_INSTALLER $releaseArchive $CLI_VERSION
180
- if ($LASTEXITCODE -ne 0) { throw "transactional installer exited with status $LASTEXITCODE" }
165
+ if ($RELEASE_INSTALLER -and (Test-Path -LiteralPath $RELEASE_INSTALLER)) {
166
+ & node $RELEASE_INSTALLER $releaseArchive $CLI_VERSION
167
+ if ($LASTEXITCODE -ne 0) { throw "transactional installer exited with status $LASTEXITCODE" }
168
+ } else {
169
+ npm install -g --force $releaseArchive
170
+ if ($LASTEXITCODE -ne 0) { throw "local archive installer exited with status $LASTEXITCODE" }
171
+ }
181
172
  Write-Host "[OK] Vigthoria CLI installed from the checksum-verified release!" -ForegroundColor Green
182
173
  return $true
183
174
  }
184
175
  catch {
185
- Write-Host "[WARN] Verified hosted package install failed, trying npm registry: $_" -ForegroundColor Yellow
176
+ Write-Host "[ERROR] Verified extension package install failed: $_" -ForegroundColor Red
177
+ return $false
186
178
  }
187
179
  finally {
188
180
  if (Test-Path $releaseTemp) { Remove-Item -Recurse -Force $releaseTemp }
@@ -191,21 +183,7 @@ function Install-VigthoriaCLI-NPM {
191
183
  Write-Host "[WARN] Hosted package has no trusted manifest SHA-256; skipping direct URL installation." -ForegroundColor Yellow
192
184
  }
193
185
 
194
- try {
195
- if ($RELEASE_INSTALLER -and (Test-Path -LiteralPath $RELEASE_INSTALLER)) {
196
- & node $RELEASE_INSTALLER "$NPM_PACKAGE@$CLI_VERSION" $CLI_VERSION
197
- if ($LASTEXITCODE -ne 0) { throw "transactional installer exited with status $LASTEXITCODE" }
198
- } else {
199
- npm install -g --registry=https://registry.npmjs.org/ "$NPM_PACKAGE@$CLI_VERSION"
200
- if ($LASTEXITCODE -ne 0) { throw "npm exited with status $LASTEXITCODE" }
201
- }
202
- Write-Host "[OK] Vigthoria CLI installed successfully!" -ForegroundColor Green
203
- return $true
204
- }
205
- catch {
206
- Write-Host "[ERROR] Install failed: no checksum-verified artifact or exact npm release $CLI_VERSION is available: $_" -ForegroundColor Red
207
- return $false
208
- }
186
+ return $false
209
187
  }
210
188
 
211
189
  function Install-VigthoriaCLI-Direct {
@@ -215,14 +193,18 @@ function Install-VigthoriaCLI-Direct {
215
193
  $tarballPath = Join-Path $releaseTemp "candidate.tgz"
216
194
  try {
217
195
  if (-not $HOSTED_TARBALL_SHA256) { throw "Direct installation requires a signed manifest SHA-256" }
218
- if (-not $RELEASE_INSTALLER -or -not (Test-Path -LiteralPath $RELEASE_INSTALLER)) { throw "Transactional release installer is unavailable" }
219
196
  New-Item -ItemType Directory -Path $releaseTemp -ErrorAction Stop | Out-Null
220
197
  $tarballUrl = Assert-TrustedReleaseUrl $HOSTED_TARBALL_URL
221
198
  Invoke-WebRequest -Uri $tarballUrl -OutFile $tarballPath -UseBasicParsing -MaximumRedirection 0 -TimeoutSec 60 -ErrorAction Stop
222
199
  $actualSha256 = (Get-FileHash -Path $tarballPath -Algorithm SHA256).Hash.ToLowerInvariant()
223
200
  if ($actualSha256 -ne $HOSTED_TARBALL_SHA256) { throw "Release checksum mismatch" }
224
- & node $RELEASE_INSTALLER $tarballPath $CLI_VERSION
225
- if ($LASTEXITCODE -ne 0) { throw "transactional installer exited with status $LASTEXITCODE" }
201
+ if ($RELEASE_INSTALLER -and (Test-Path -LiteralPath $RELEASE_INSTALLER)) {
202
+ & node $RELEASE_INSTALLER $tarballPath $CLI_VERSION
203
+ if ($LASTEXITCODE -ne 0) { throw "transactional installer exited with status $LASTEXITCODE" }
204
+ } else {
205
+ npm install -g --force $tarballPath
206
+ if ($LASTEXITCODE -ne 0) { throw "local archive installer exited with status $LASTEXITCODE" }
207
+ }
226
208
  Write-Host "[OK] Vigthoria CLI installed successfully!" -ForegroundColor Green
227
209
  return $true
228
210
  }
@@ -241,10 +223,10 @@ function Show-NetworkTroubleshooting {
241
223
  Write-Host " NETWORK TROUBLESHOOTING" -ForegroundColor Yellow
242
224
  Write-Host "===============================================================" -ForegroundColor Yellow
243
225
  Write-Host ""
244
- Write-Host "The hosted package and npm registry could not be reached. Try these solutions:" -ForegroundColor White
226
+ Write-Host "The canonical extension package could not be reached. Try these solutions:" -ForegroundColor White
245
227
  Write-Host ""
246
228
  Write-Host "1. Check your internet connection" -ForegroundColor Cyan
247
- Write-Host " ping registry.npmjs.org" -ForegroundColor Gray
229
+ Write-Host " Test-NetConnection extension.vigthoria.io -Port 443" -ForegroundColor Gray
248
230
  Write-Host ""
249
231
  Write-Host "2. If behind a corporate proxy, configure npm:" -ForegroundColor Cyan
250
232
  Write-Host " npm config set proxy http://proxy.company.com:8080" -ForegroundColor Gray
@@ -254,9 +236,8 @@ function Show-NetworkTroubleshooting {
254
236
  Write-Host ""
255
237
  Write-Host "4. Try using a VPN" -ForegroundColor Cyan
256
238
  Write-Host ""
257
- Write-Host "5. Manual download alternative:" -ForegroundColor Cyan
239
+ Write-Host "5. Canonical manual download:" -ForegroundColor Cyan
258
240
  Write-Host " Hosted package: $HOSTED_TARBALL_URL" -ForegroundColor Gray
259
- Write-Host " npm package: https://www.npmjs.com/package/vigthoria-cli" -ForegroundColor Gray
260
241
  Write-Host ""
261
242
  }
262
243
 
@@ -293,14 +274,13 @@ if (-not (Test-Prerequisites)) {
293
274
  $networkOk = Test-NetworkConnectivity
294
275
 
295
276
  if ($networkOk) {
296
- # Try npm install first
297
- if (Install-VigthoriaCLI-NPM) {
277
+ if (Install-VigthoriaCLI-Package) {
298
278
  Show-Success
299
279
  exit 0
300
280
  }
301
281
  }
302
282
 
303
- # Network failed or npm install failed
283
+ # Network or canonical package installation failed
304
284
  Show-NetworkTroubleshooting
305
285
 
306
286
  Write-Host "Would you like to try the checksum-verified direct download?" -ForegroundColor Yellow
package/install.sh CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/bash
2
2
  #
3
3
  # Vigthoria CLI Installer
4
- # Usage: curl -fsSL https://cli.vigthoria.io/install.sh | bash
4
+ # Usage: curl -fsSL https://extension.vigthoria.io/downloads/install.sh | bash
5
5
  #
6
6
  # Supports: Linux, macOS (Intel and Apple Silicon)
7
7
  #
@@ -26,15 +26,15 @@ else
26
26
  fi
27
27
 
28
28
  # Configuration
29
- CLI_VERSION="1.13.34"
29
+ CLI_VERSION="1.13.42"
30
30
  INSTALL_DIR="$HOME/.vigthoria"
31
- MANIFEST_URL="${VIGTHORIA_UPDATE_MANIFEST_URL:-https://extension.vigthoria.io/downloads/manifest.json}"
31
+ MANIFEST_URL="https://extension.vigthoria.io/downloads/manifest.json"
32
32
  HOSTED_TARBALL_URL="https://extension.vigthoria.io/downloads/vigthoria-cli-${CLI_VERSION}.tgz"
33
33
  # The packaged installer resolves the signed manifest. The independently
34
34
  # hosted installer is rendered after packing with this release's exact digest.
35
- # An empty package fallback uses the exact npm version instead of trusting an
36
- # unsigned or circularly self-referential checksum.
37
- HOSTED_TARBALL_SHA256=""
35
+ # The standalone installer uses this immutable digest when the packaged
36
+ # signature resolver is not locally available.
37
+ HOSTED_TARBALL_SHA256="d778aac8cbcf22da7ac7ca7d6007520e8996591a653dddf9b10443eaea70a4f0"
38
38
  INSTALLER_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd || true)"
39
39
  RELEASE_RESOLVER="$INSTALLER_ROOT/scripts/release/resolve-release-manifest.mjs"
40
40
  RELEASE_INSTALLER="$INSTALLER_ROOT/scripts/release/install-release.mjs"
@@ -43,10 +43,7 @@ validate_release_url() {
43
43
  python3 - "$1" <<'PY'
44
44
  import sys
45
45
  from urllib.parse import urlsplit
46
- allowed = {
47
- 'extension.vigthoria.io', 'landing.vigthoria.io', 'cli.vigthoria.io',
48
- 'coder.vigthoria.io', 'market.vigthoria.io', 'registry.npmjs.org',
49
- }
46
+ allowed = {'extension.vigthoria.io'}
50
47
  try:
51
48
  parsed = urlsplit(sys.argv[1])
52
49
  valid = parsed.scheme == 'https' and parsed.hostname in allowed and parsed.port in (None, 443) and not parsed.username and not parsed.password and '\\' not in sys.argv[1]
@@ -59,8 +56,8 @@ PY
59
56
  resolve_release_manifest() {
60
57
  # Direct artifacts are accepted only when the packaged shared verifier is
61
58
  # present and validates the strict manifest plus detached Ed25519 signature.
62
- # A curl-piped legacy installer therefore falls back to the exact pinned npm
63
- # version instead of trusting an unsigned manifest.
59
+ # A curl-piped installer therefore stays pinned to the immutable extension
60
+ # archive instead of changing package origins.
64
61
  if [[ ! -f "$RELEASE_RESOLVER" ]] || ! command -v node >/dev/null 2>&1 || ! command -v python3 >/dev/null 2>&1; then
65
62
  return 0
66
63
  fi
@@ -147,7 +144,7 @@ detect_platform() {
147
144
  ;;
148
145
  *)
149
146
  echo -e "${RED}Unsupported operating system: $OS${NC}"
150
- echo "Please use the npm install method: npm install -g vigthoria-cli"
147
+ echo "No signed Vigthoria CLI release is available for this operating system."
151
148
  exit 1
152
149
  ;;
153
150
  esac
@@ -257,7 +254,7 @@ install_cli() {
257
254
  mkdir -p "$INSTALL_DIR"
258
255
 
259
256
  # Option 1: Download and verify the exact hosted release package.
260
- if [[ -n "$HOSTED_TARBALL_SHA256" && -f "$RELEASE_INSTALLER" ]]; then
257
+ if [[ -n "$HOSTED_TARBALL_SHA256" ]]; then
261
258
  echo "Downloading checksum-verified hosted release package..."
262
259
  VIGTHORIA_INSTALL_TEMP_ROOT="$(prepare_temp_root)" || return 1
263
260
  RELEASE_TMP_DIR="$(mktemp -d "$VIGTHORIA_INSTALL_TEMP_ROOT/install.XXXXXX")"
@@ -288,19 +285,11 @@ install_cli() {
288
285
  if [[ -f "$RELEASE_INSTALLER" ]]; then
289
286
  node "$RELEASE_INSTALLER" "$RELEASE_ARCHIVE" "$CLI_VERSION"
290
287
  else
291
- echo -e "${RED}✗ Transactional release installer is unavailable${NC}"
292
- exit 1
288
+ npm install -g --force "$RELEASE_ARCHIVE"
293
289
  fi
294
290
  rm -rf "$RELEASE_TMP_DIR"
295
- elif npm view --registry=https://registry.npmjs.org/ "vigthoria-cli@${CLI_VERSION}" version &> /dev/null; then
296
- echo "Installing exact version ${CLI_VERSION} from npm registry..."
297
- if [[ -f "$RELEASE_INSTALLER" ]]; then
298
- node "$RELEASE_INSTALLER" "vigthoria-cli@${CLI_VERSION}" "$CLI_VERSION"
299
- else
300
- npm install -g --force --registry=https://registry.npmjs.org/ "vigthoria-cli@${CLI_VERSION}"
301
- fi
302
291
  else
303
- echo -e "${RED}✗ No checksum-verified artifact or exact npm release ${CLI_VERSION} is available${NC}"
292
+ echo -e "${RED}✗ No checksum-verified extension release ${CLI_VERSION} is available${NC}"
304
293
  return 1
305
294
  fi
306
295
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vigthoria-cli",
3
- "version": "1.13.34",
3
+ "version": "1.13.42",
4
4
  "description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -72,10 +72,11 @@
72
72
  "test:repo:payload-fallback": "node scripts/test-repo-payload-fallback.mjs",
73
73
  "test:repo:public-clone": "npm run build && node scripts/test-public-repo-clone.mjs",
74
74
  "test:command:timeouts": "npm run build && node scripts/test-timeout-cancellation.mjs",
75
+ "test:agent:signal-rollback": "npm run build && node scripts/test-agent-signal-rollback.mjs",
75
76
  "test:game:live": "npm run build && node scripts/test-live-game-push.js",
76
77
  "proof:agent": "npm run build && node scripts/proof-agent-mode.js",
77
78
  "test:fresh-install": "node scripts/test-fresh-install.js",
78
- "prepublishOnly": "npm run build && npm run validate:no-go && npm run test:repo:auth-fallback && npm run test:repo:payload-fallback && node scripts/verify-package-hygiene.js && node scripts/test-fresh-install.js",
79
+ "prepublishOnly": "npm run build && npm run test:banner && npm run validate:no-go && npm run test:repo:auth-fallback && npm run test:repo:payload-fallback && node scripts/verify-package-hygiene.js && node scripts/test-fresh-install.js",
79
80
  "precheck:services": "node scripts/precheck-local-services.js",
80
81
  "test:model:governance": "npm run build && node scripts/test-model-governance-no-agent.js",
81
82
  "validate:no-go": "bash scripts/release/validate-no-go-gates.sh",
@@ -107,6 +108,7 @@
107
108
  "test:phase3:command-contract": "npm run build && node scripts/test-command-contract.mjs",
108
109
  "test:phase3:update-policy": "npm run build && node scripts/test-update-policy.mjs",
109
110
  "test:phase6:delivery": "npm run build && node scripts/test-release-delivery.mjs",
111
+ "test:banner": "node scripts/test-startup-banner.mjs",
110
112
  "architecture:graph": "node scripts/architecture/verify-import-graph.mjs"
111
113
  },
112
114
  "keywords": [
@@ -11,11 +11,7 @@
11
11
  "manifest": "https://extension.vigthoria.io/downloads/manifest.json",
12
12
  "artifacts": "https://extension.vigthoria.io/downloads/",
13
13
  "allowedHosts": [
14
- "extension.vigthoria.io",
15
- "cli.vigthoria.io",
16
- "coder.vigthoria.io",
17
- "landing.vigthoria.io",
18
- "market.vigthoria.io"
14
+ "extension.vigthoria.io"
19
15
  ],
20
16
  "port": 443,
21
17
  "maximumRedirects": 0