vigthoria-cli 1.13.31 → 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 +21 -3
  24. package/dist/utils/api.js +379 -550
  25. package/dist/utils/frontend-preview-service.d.ts +12 -2
  26. package/dist/utils/frontend-preview-service.js +214 -24
  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 +111 -1
  34. package/dist/utils/preview-screenshot-adapter.js +990 -7
  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 +12 -23
  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
@@ -3,8 +3,9 @@ import { installReleaseTransaction } from '../../dist/utils/release-install.js';
3
3
 
4
4
  const packageSpec = String(process.argv[2] || '');
5
5
  const expectedVersion = String(process.argv[3] || '');
6
- if (!packageSpec || !expectedVersion) throw new Error('Usage: install-release.mjs <package-spec> <expected-version>');
7
- const result = installReleaseTransaction(packageSpec, expectedVersion, {
8
- ...(packageSpec.startsWith('vigthoria-cli@') ? { npmRegistry: 'https://registry.npmjs.org/' } : {}),
9
- });
6
+ if (!packageSpec || !expectedVersion) throw new Error('Usage: install-release.mjs <local-package.tgz> <expected-version>');
7
+ if (!packageSpec.toLowerCase().endsWith('.tgz')) {
8
+ throw new Error('Release installer accepts only a locally verified .tgz archive');
9
+ }
10
+ const result = installReleaseTransaction(packageSpec, expectedVersion);
10
11
  process.stdout.write(`${JSON.stringify(result)}\n`);
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
- import { createHash, createPrivateKey, createPublicKey, sign } from 'node:crypto';
4
+ import { createHash } from 'node:crypto';
5
5
  import { spawnSync } from 'node:child_process';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import {
@@ -16,7 +16,7 @@ const version = String(process.argv[2] || '').trim();
16
16
  const channel = String(process.env.CHANNEL || 'stable').trim();
17
17
  const downloadsDirectory = String(process.env.HOST_DOWNLOADS_DIR || '');
18
18
  const manifestFile = String(process.env.HOST_MANIFEST_FILE || '');
19
- const privateKeyFile = String(process.env.RELEASE_SIGNING_PRIVATE_KEY_FILE || '');
19
+ const signerCommand = String(process.env.RELEASE_SIGNER_COMMAND || '');
20
20
  const keyId = String(process.env.RELEASE_SIGNING_KEY_ID || '');
21
21
  const sbomFile = String(process.env.RELEASE_SBOM_FILE || '');
22
22
  const provenanceFile = String(process.env.RELEASE_PROVENANCE_FILE || '');
@@ -39,7 +39,11 @@ function exactPackageMetadata(archive) {
39
39
 
40
40
  if (!version) stop('Usage: publish-cli-release.sh <version>');
41
41
  if (!downloadsDirectory || !manifestFile) stop('HOST_DOWNLOADS_DIR and HOST_MANIFEST_FILE are required.');
42
- requiredFile(privateKeyFile, 'RELEASE_SIGNING_PRIVATE_KEY_FILE');
42
+ if (!path.isAbsolute(signerCommand)) stop('RELEASE_SIGNER_COMMAND must name an absolute protected signer executable.');
43
+ const signerStat = fs.statSync(signerCommand, { throwIfNoEntry: false });
44
+ if (!signerStat?.isFile() || signerStat.uid !== 0 || (signerStat.mode & 0o022) !== 0 || (signerStat.mode & 0o111) === 0) {
45
+ stop('RELEASE_SIGNER_COMMAND must be a root-owned executable that is not group/world writable.');
46
+ }
43
47
  requiredFile(sbomFile, 'RELEASE_SBOM_FILE');
44
48
  requiredFile(provenanceFile, 'RELEASE_PROVENANCE_FILE');
45
49
  if (!Object.hasOwn(policy.signature.trustedKeys, keyId)) stop(`RELEASE_SIGNING_KEY_ID is not trusted by release-policy.json: ${keyId || '(unset)'}`);
@@ -85,11 +89,20 @@ try {
85
89
  provenance: { url: new URL(provenanceFilename, publicBase).toString(), sha256: digest(provenanceFile) },
86
90
  notes: String(process.env.RELEASE_NOTES || 'Vigthoria CLI release'),
87
91
  };
88
- const privateKey = createPrivateKey(fs.readFileSync(privateKeyFile));
89
- const configuredPublic = createPublicKey(policy.signature.trustedKeys[keyId]).export({ type: 'spki', format: 'der' });
90
- const signingPublic = createPublicKey(privateKey).export({ type: 'spki', format: 'der' });
91
- if (!configuredPublic.equals(signingPublic)) stop('Signing private key does not match the configured verification key.');
92
- const detached = sign(null, releaseSignaturePayload(channel, entry), privateKey).toString('base64');
92
+ const signingResult = spawnSync(signerCommand, ['--key-id', keyId], {
93
+ input: releaseSignaturePayload(channel, entry),
94
+ encoding: 'utf8',
95
+ timeout: 30_000,
96
+ maxBuffer: 16 * 1024,
97
+ env: {
98
+ PATH: '/usr/sbin:/usr/bin:/sbin:/bin',
99
+ LANG: 'C.UTF-8',
100
+ RELEASE_SIGNING_KEY_ID: keyId,
101
+ },
102
+ });
103
+ if (signingResult.status !== 0) stop('Protected release signer rejected the signing request.');
104
+ const detached = String(signingResult.stdout || '').trim();
105
+ if (!/^[A-Za-z0-9+/]{86}==$/.test(detached)) stop('Protected release signer returned an invalid Ed25519 signature encoding.');
93
106
  verifyReleaseSignature(channel, entry, detached);
94
107
 
95
108
  let manifest = { schemaVersion: policy.manifest.schemaVersion, channels: {} };
@@ -40,6 +40,9 @@ import fs from 'node:fs';
40
40
  const result = JSON.parse(fs.readFileSync(process.env.BALANCED_RESULT, 'utf8'));
41
41
  if (result.success !== true) throw new Error(`balanced probe failed: ${JSON.stringify(result)}`);
42
42
  const allowed = new Set(['Vigthoria-v4-Assistant-9B', 'vigthoria-balanced-4b', 'vigthoria-v3-balanced-4b']);
43
- if (!allowed.has(result.model)) throw new Error(`unexpected balanced model: ${result.model}`);
43
+ const model = result.data?.model ?? result.model;
44
+ if (!allowed.has(model)) throw new Error(`unexpected balanced model: ${model}`);
45
+ if (result.data?.requestedModel !== 'balanced-4b') throw new Error(`balanced alias was not preserved: ${JSON.stringify(result.data)}`);
46
+ if (typeof result.data?.content !== 'string' || !result.data.content.trim()) throw new Error('balanced probe returned empty content');
44
47
  console.log('[pass] credentialed balanced-4b live probe');
45
48
  EOF
@@ -24,12 +24,25 @@ export VIGTHORIA_NO_BANNER=1
24
24
  export VIGTHORIA_NO_UPDATE_CHECK=1
25
25
 
26
26
  echo "[AUTH PREFLIGHT] invalid session message"
27
- VIGTHORIA_AUTH_TOKEN=invalid-token-for-preflight node dist/index.js chat --no-agent --model balanced-4b --prompt "ok" --json >"$LIVE_TMP/auth.json" 2>/dev/null || true
27
+ # This assertion belongs to the public Coder authentication gateway. Release
28
+ # runners also configure local TestFarm transports for the service gates below;
29
+ # do not let those overrides silently turn this into a model-router probe.
30
+ env \
31
+ -u VIGTHORIA_SELF_HOSTED_MODELS_API_URL \
32
+ -u VIGTHORIA_LOCAL_TEST_MODE \
33
+ -u VIGTHORIA_LOCAL_TEST_TOKEN \
34
+ -u VIGTHORIA_ALLOW_LOCAL_SERVICES \
35
+ VIGTHORIA_AUTH_TOKEN=invalid-token-for-preflight \
36
+ node dist/index.js chat --no-agent --model balanced-4b --prompt "ok" --json >"$LIVE_TMP/auth.json" 2>/dev/null || true
28
37
  AUTH_RESULT="$LIVE_TMP/auth.json" node --input-type=module - <<'EOF'
29
38
  import fs from 'node:fs';
30
39
  const result = JSON.parse(fs.readFileSync(process.env.AUTH_RESULT, 'utf8'));
31
40
  const expected = 'Vigthoria Gate way user authentification failed. Please log out and login again.';
32
- if (result.success !== false || result.error !== expected) throw new Error(`unexpected auth preflight: ${JSON.stringify(result)}`);
41
+ const errorMessage = typeof result.error === 'string' ? result.error : result.error?.message;
42
+ const errorCode = typeof result.error === 'object' && result.error !== null ? result.error.code : undefined;
43
+ if (result.success !== false || errorMessage !== expected || (errorCode && errorCode !== 'AUTH_SESSION_INVALID')) {
44
+ throw new Error(`unexpected auth preflight: ${JSON.stringify(result)}`);
45
+ }
33
46
  console.log('[pass] live auth preflight message');
34
47
  EOF
35
48
 
@@ -65,9 +78,18 @@ console.log('[pass] live model inventory gates');
65
78
  EOF
66
79
 
67
80
  echo "[7.5 policy] secured hosted HyperLoop endpoint"
68
- if ! code="$(curl --silent --show-error --connect-timeout 5 --max-time 15 --output /dev/null --write-out '%{http_code}' https://coder.vigthoria.io/api/hyperloop/health)"; then
69
- block "hosted HyperLoop endpoint is unavailable"
70
- fi
81
+ code=""
82
+ for attempt in 1 2 3; do
83
+ if code="$(curl --silent --show-error --connect-timeout 5 --max-time 15 --output /dev/null --write-out '%{http_code}' https://coder.vigthoria.io/api/hyperloop/health)"; then
84
+ break
85
+ fi
86
+ code=""
87
+ if [[ "$attempt" != "3" ]]; then
88
+ echo "[retry] hosted HyperLoop policy probe transient failure ($attempt/3)"
89
+ sleep 2
90
+ fi
91
+ done
92
+ [[ -n "$code" ]] || block "hosted HyperLoop endpoint is unavailable after 3 bounded attempts"
71
93
  echo "unauth_hyperloop_code=$code"
72
94
  [[ "$code" == "401" || "$code" == "302" ]]
73
95