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.
- package/README.md +11 -56
- package/SECURITY_HARDENING.md +2 -4
- package/dist/commands/auth.js +16 -14
- package/dist/commands/cancel.d.ts +1 -0
- package/dist/commands/cancel.js +21 -4
- package/dist/commands/chat.d.ts +13 -0
- package/dist/commands/chat.js +170 -14
- package/dist/commands/fork.js +8 -3
- package/dist/commands/history.js +8 -3
- package/dist/commands/legion.js +1 -1
- package/dist/commands/replay.js +8 -3
- package/dist/commands/update-registration.js +63 -206
- package/dist/commands/v4-menu.d.ts +0 -1
- package/dist/commands/v4-menu.js +8 -6
- package/dist/commands/v4-registration.js +0 -2
- package/dist/commands/v4.js +9 -4
- package/dist/commands/wallet.d.ts +1 -1
- package/dist/commands/wallet.js +3 -3
- package/dist/index.js +2 -3
- package/dist/utils/agent-stream-state.d.ts +7 -0
- package/dist/utils/agent-stream-state.js +31 -0
- package/dist/utils/agentRunOutcome.js +5 -1
- package/dist/utils/api.d.ts +19 -4
- package/dist/utils/api.js +322 -550
- package/dist/utils/frontend-preview-service.d.ts +10 -1
- package/dist/utils/frontend-preview-service.js +162 -17
- package/dist/utils/javascript-syntax.d.ts +19 -0
- package/dist/utils/javascript-syntax.js +35 -0
- package/dist/utils/localTestMode.js +1 -1
- package/dist/utils/mutation-journal.d.ts +10 -0
- package/dist/utils/mutation-journal.js +104 -76
- package/dist/utils/network-policy.js +7 -10
- package/dist/utils/preview-screenshot-adapter.d.ts +81 -0
- package/dist/utils/preview-screenshot-adapter.js +615 -38
- package/dist/utils/release-install.d.ts +0 -1
- package/dist/utils/release-install.js +44 -7
- package/dist/utils/requestIntent.d.ts +1 -1
- package/dist/utils/requestIntent.js +17 -3
- package/dist/utils/tools.js +21 -15
- package/dist/utils/update-policy.d.ts +0 -4
- package/dist/utils/update-policy.js +5 -9
- package/dist/utils/v3-agent-client.js +25 -11
- package/install.ps1 +30 -50
- package/install.sh +13 -24
- package/package.json +4 -2
- package/release-policy.json +1 -5
- package/scripts/release/LOCAL_MACHINE_USER_VERIFICATION.md +6 -7
- package/scripts/release/install-release.mjs +5 -4
- package/scripts/release/publish-cli-release.mjs +21 -8
- package/scripts/release/test-balanced-model-live.sh +4 -1
- package/scripts/release/validate-live-service-gates.sh +27 -5
|
@@ -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
|
|
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 =
|
|
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)
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
package/dist/utils/tools.js
CHANGED
|
@@ -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
|
|
1353
|
+
const syntaxModes = resolveJavaScriptSyntaxModes(source);
|
|
1354
|
+
const tempFiles = syntaxModes.map((mode) => path.join(tempDirectory, `candidate.${mode === 'module' ? 'mjs' : 'cjs'}`));
|
|
1353
1355
|
try {
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
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',
|
|
1376
|
+
this.cleanupAfterToolError('syntax_check', 'remove temporary JavaScript syntax files', () => {
|
|
1371
1377
|
removeRuntimeTempDirectory(tempDirectory);
|
|
1372
1378
|
});
|
|
1373
1379
|
}
|
|
@@ -101,14 +101,10 @@ export function resolveUpdateSource(rawTarget, options = {}) {
|
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
103
|
if (target.startsWith('vigthoria-cli@')) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
|
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
|
|
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):(
|
|
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
|
|
21
|
-
const local = [
|
|
20
|
+
const explicitUrls = [
|
|
22
21
|
process.env.VIGTHORIA_V3_AGENT_URL,
|
|
23
22
|
process.env.V3_AGENT_URL,
|
|
24
|
-
|
|
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 = {
|
|
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://
|
|
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.
|
|
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
|
-
#
|
|
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 "[
|
|
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-
|
|
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
|
|
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 (
|
|
179
|
-
|
|
180
|
-
|
|
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 "[
|
|
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
|
-
|
|
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
|
-
|
|
225
|
-
|
|
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
|
|
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 "
|
|
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.
|
|
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
|
-
|
|
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
|
|
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://
|
|
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.
|
|
29
|
+
CLI_VERSION="1.13.42"
|
|
30
30
|
INSTALL_DIR="$HOME/.vigthoria"
|
|
31
|
-
MANIFEST_URL="
|
|
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
|
-
#
|
|
36
|
-
#
|
|
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
|
|
63
|
-
#
|
|
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 "
|
|
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"
|
|
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
|
-
|
|
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
|
|
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.
|
|
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": [
|
package/release-policy.json
CHANGED
|
@@ -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
|