vigthoria-cli 1.13.26 → 1.13.30

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 (59) hide show
  1. package/README.md +12 -0
  2. package/completions/_vigthoria +1 -0
  3. package/completions/vigthoria.bash +1 -1
  4. package/completions/vigthoria.fish +1 -0
  5. package/dist/commands/chat.js +73 -26
  6. package/dist/commands/config.js +4 -4
  7. package/dist/commands/creative-registration.d.ts +13 -0
  8. package/dist/commands/creative-registration.js +88 -0
  9. package/dist/commands/fork.d.ts +3 -2
  10. package/dist/commands/fork.js +124 -123
  11. package/dist/commands/game.d.ts +8 -0
  12. package/dist/commands/game.js +113 -9
  13. package/dist/commands/history.d.ts +0 -1
  14. package/dist/commands/history.js +8 -22
  15. package/dist/commands/hub.d.ts +20 -0
  16. package/dist/commands/hub.js +17 -3
  17. package/dist/commands/preview.js +7 -2
  18. package/dist/commands/product-run-registration.js +1 -1
  19. package/dist/commands/replay.d.ts +0 -1
  20. package/dist/commands/replay.js +10 -19
  21. package/dist/commands/repo.js +16 -4
  22. package/dist/commands/update-registration.js +2 -2
  23. package/dist/commands/workflow.d.ts +4 -0
  24. package/dist/commands/workflow.js +27 -0
  25. package/dist/index.js +8 -4
  26. package/dist/utils/agentRunOutcome.d.ts +7 -0
  27. package/dist/utils/agentRunOutcome.js +13 -0
  28. package/dist/utils/api.d.ts +20 -5
  29. package/dist/utils/api.js +428 -43
  30. package/dist/utils/command-policy.js +3 -1
  31. package/dist/utils/config.d.ts +2 -0
  32. package/dist/utils/config.js +22 -9
  33. package/dist/utils/frontend-preview-service.d.ts +1 -0
  34. package/dist/utils/frontend-preview-service.js +54 -5
  35. package/dist/utils/model-governance.js +23 -14
  36. package/dist/utils/model-transport-service.js +1 -1
  37. package/dist/utils/network-policy.js +15 -3
  38. package/dist/utils/operator-client.js +23 -4
  39. package/dist/utils/post-write-validator.js +7 -3
  40. package/dist/utils/preview-screenshot-adapter.d.ts +16 -41
  41. package/dist/utils/preview-screenshot-adapter.js +273 -64
  42. package/dist/utils/runtime-capability.d.ts +7 -0
  43. package/dist/utils/runtime-capability.js +11 -0
  44. package/dist/utils/runtime-temp.d.ts +5 -2
  45. package/dist/utils/runtime-temp.js +131 -30
  46. package/dist/utils/tools.js +1 -1
  47. package/dist/utils/v3-stream-events.js +10 -2
  48. package/dist/utils/v3-workspace-service.d.ts +1 -0
  49. package/dist/utils/v3-workspace-service.js +38 -1
  50. package/dist/utils/vigflow-client.d.ts +9 -0
  51. package/dist/utils/vigflow-client.js +48 -2
  52. package/dist/utils/workspace-reference.d.ts +8 -0
  53. package/dist/utils/workspace-reference.js +21 -0
  54. package/install.ps1 +2 -2
  55. package/install.sh +2 -2
  56. package/package.json +4 -6
  57. package/scripts/release/LOCAL_MACHINE_USER_VERIFICATION.md +2 -2
  58. package/scripts/release/validate-live-service-gates.sh +3 -3
  59. package/scripts/release/validate-no-go-gates.sh +2 -0
@@ -81,7 +81,7 @@ export class PreviewCommand {
81
81
  // Run Template Service preview proof gate
82
82
  if (isPreviewProofRequested(options)) {
83
83
  try {
84
- await this.runProofGate(projectPath, options.screenshot);
84
+ await this.runProofGate(projectPath, options.screenshot, options.screenshot === true && options.proof !== true);
85
85
  }
86
86
  catch (error) {
87
87
  this.api.destroy();
@@ -435,7 +435,7 @@ export class PreviewCommand {
435
435
  /**
436
436
  * Run Template Service preview gate and persist proof bundle
437
437
  */
438
- async runProofGate(projectPath, captureScreenshot) {
438
+ async runProofGate(projectPath, captureScreenshot, localScreenshotProof = false) {
439
439
  const spinner = createSpinner('Running preview proof gate...').start();
440
440
  try {
441
441
  const result = await this.api.runTemplateServicePreviewGate('', {
@@ -444,6 +444,11 @@ export class PreviewCommand {
444
444
  targetPath: projectPath,
445
445
  forceFrontendPreview: true,
446
446
  requireScreenshot: captureScreenshot === true,
447
+ // An explicit screenshot-only command is a local operation. Do not
448
+ // upload the user's frontend or require an ecosystem login merely to
449
+ // capture local visual evidence. `--proof` retains the hosted proof
450
+ // contract, including when combined with `--screenshot`.
451
+ localScreenshotProof,
447
452
  });
448
453
  spinner.stop();
449
454
  console.log(chalk.bold.white(` ${CH.hLine.repeat(3)} Preview Proof Gate ${CH.hLine.repeat(39)}`));
@@ -386,7 +386,7 @@ Examples:
386
386
  .option('--no-open', 'Do not auto-open browser')
387
387
  .option('--diff', 'Show consolidated diff of recent agent changes')
388
388
  .option('--proof', 'Run Template Service preview gate and persist proof bundle')
389
- .option('--screenshot', 'Capture screenshot via Puppeteer')
389
+ .option('--screenshot', 'Capture screenshot via an installed system browser')
390
390
  .action(async (options) => {
391
391
  const preview = new PreviewCommand(config, logger);
392
392
  await preview.run({
@@ -10,7 +10,6 @@ export declare class ReplayCommand {
10
10
  constructor(config: Config, _logger: Logger);
11
11
  private getHeaders;
12
12
  private getBaseUrl;
13
- private resolveWorkspaceRoot;
14
13
  private sleep;
15
14
  run(runId: string, options: ReplayOptions): Promise<void>;
16
15
  }
@@ -3,10 +3,10 @@ import { hasLocalV3AgentCapability } from '../utils/runtime-capability.js';
3
3
  * replay.ts — Replay events from a V3 agent run step-by-step.
4
4
  */
5
5
  import chalk from 'chalk';
6
- import { createRequire } from 'node:module';
7
6
  import { createSpinner, CH } from '../utils/logger.js';
8
7
  import { CliCommandError, commandFailure, formatSuccessJson } from '../utils/command-contract.js';
9
- const require = createRequire(import.meta.url);
8
+ import { buildLocalWorkspaceReference } from '../utils/workspace-reference.js';
9
+ import { guardedFetch } from '../utils/network-policy.js';
10
10
  export class ReplayCommand {
11
11
  config;
12
12
  constructor(config, _logger) {
@@ -34,33 +34,24 @@ export class ReplayCommand {
34
34
  (allowLocal ? 'http://127.0.0.1:8030' : null) ||
35
35
  configuredApiUrl);
36
36
  }
37
- resolveWorkspaceRoot(project) {
38
- if (/^[a-zA-Z]:[\\/]/.test(project) || /^\\\\/.test(project))
39
- return '';
40
- if (typeof require !== 'undefined') {
41
- try {
42
- const path = require('path');
43
- if (!path.isAbsolute(project))
44
- return '';
45
- }
46
- catch { }
47
- }
48
- return project;
49
- }
50
37
  sleep(ms) {
51
38
  return new Promise((resolve) => setTimeout(resolve, ms));
52
39
  }
53
40
  async run(runId, options) {
54
41
  const speed = options.speed || 200;
55
42
  const project = options.project || process.cwd();
56
- const workspace = this.resolveWorkspaceRoot(project);
43
+ const workspaceRef = buildLocalWorkspaceReference(project, String(this.config.get('userId') || this.config.get('email') || ''));
57
44
  const spinner = createSpinner(`Loading events for run ${runId}...`).start();
58
45
  try {
59
46
  const baseUrl = this.getBaseUrl();
60
- const params = new URLSearchParams({ workspace_root: workspace });
61
- const resp = await fetch(`${baseUrl}/api/runs/${encodeURIComponent(runId)}/events?${params}`, {
62
- headers: this.getHeaders(),
47
+ const params = new URLSearchParams({
48
+ workspace_root: '',
49
+ local_workspace_path: workspaceRef,
50
+ project_path: workspaceRef,
63
51
  });
52
+ const resp = await guardedFetch(`${baseUrl}/api/runs/${encodeURIComponent(runId)}/events?${params}`, {
53
+ headers: this.getHeaders(),
54
+ }, { audience: 'v3' });
64
55
  if (!resp.ok) {
65
56
  spinner.stop();
66
57
  if (resp.status === 404) {
@@ -161,6 +161,9 @@ export class RepoCommand {
161
161
  };
162
162
  try {
163
163
  const proxyResponse = await attempt(proxyPath, 'coder');
164
+ if (options.terminalStatuses?.includes(proxyResponse.status)) {
165
+ return proxyResponse;
166
+ }
164
167
  // A large repository payload can exceed the Coder API's general
165
168
  // 50 MiB parser while remaining valid under Community's 100 MiB
166
169
  // repository contract. Retry that one status directly.
@@ -615,7 +618,7 @@ export class RepoCommand {
615
618
  if (fs.existsSync(outputPath))
616
619
  validateExtractedWorkspace(outputPath);
617
620
  if (isCompleteRepositoryInlinePayload(data)) {
618
- const stagingRoot = createRuntimeTempDirectory('repo-inline-');
621
+ const stagingRoot = createRuntimeTempDirectory('repo-inline-', 128 * 1024 * 1024);
619
622
  try {
620
623
  let totalBytes = 0;
621
624
  for (const file of data.files) {
@@ -650,7 +653,7 @@ export class RepoCommand {
650
653
  throw new Error('Failed to download project archive');
651
654
  const archiveBuffer = Buffer.from(await archiveResponse.arrayBuffer());
652
655
  inspectZipArchive(archiveBuffer);
653
- const stagingRoot = createRuntimeTempDirectory('repo-pull-');
656
+ const stagingRoot = createRuntimeTempDirectory('repo-pull-', 256 * 1024 * 1024);
654
657
  const tempArchive = path.join(stagingRoot, 'archive.zip');
655
658
  const extractedPath = path.join(stagingRoot, 'extracted');
656
659
  try {
@@ -920,11 +923,20 @@ export class RepoCommand {
920
923
  const spinner = createSpinner('Deleting project...').start();
921
924
  try {
922
925
  const operationId = createOperationId();
923
- const repo = await this.resolveRepoByName(projectName);
926
+ // A numeric canonical ID is safe to retry directly even after the
927
+ // first deletion removed it from the active repository listing.
928
+ const repo = /^\d+$/.test(projectName.trim())
929
+ ? { id: projectName.trim() }
930
+ : await this.resolveRepoByName(projectName);
924
931
  const response = await this.repoFetch(`/api/repo/projects/${encodeURIComponent(String(repo.id))}`, {
925
932
  method: 'DELETE',
926
933
  headers: { 'X-Vigthoria-Operation-Id': operationId },
927
- }, { operationId });
934
+ }, { operationId, terminalStatuses: /^\d+$/.test(projectName.trim()) ? [404] : undefined });
935
+ if (response.status === 404 && /^\d+$/.test(projectName.trim())) {
936
+ spinner.succeed(chalk.green('Project was already deleted from Vigthoria Community Repository'));
937
+ console.log(chalk.gray('\nNote: Your local files are not affected.\n'));
938
+ return;
939
+ }
928
940
  if (!response.ok) {
929
941
  const error = await response.json();
930
942
  throw new Error(error.error || 'Failed to delete project');
@@ -186,7 +186,7 @@ export function registerUpdateCommand(program, version) {
186
186
  let updateTempDirectory = null;
187
187
  try {
188
188
  if (source.kind === 'remote') {
189
- updateTempDirectory = createRuntimeTempDirectory('update-');
189
+ updateTempDirectory = createRuntimeTempDirectory('update-', 320 * 1024 * 1024);
190
190
  installTarget = path.join(updateTempDirectory, 'candidate.tgz');
191
191
  await downloadFile(source.downloadUrl, installTarget);
192
192
  }
@@ -304,7 +304,7 @@ export function registerUpdateCommand(program, version) {
304
304
  && compareVersions(manifestEntry.version, currentVersion) > 0);
305
305
  if (manifestIsAuthoritative && manifestEntry) {
306
306
  assertReleaseTransition(currentVersion, manifestEntry, channel, allowDowngrade);
307
- const updateTempDirectory = createRuntimeTempDirectory('update-');
307
+ const updateTempDirectory = createRuntimeTempDirectory('update-', 320 * 1024 * 1024);
308
308
  const tmpFile = path.join(updateTempDirectory, 'candidate.tgz');
309
309
  try {
310
310
  console.log(chalk.cyan(`Downloading release package (${manifestEntry.version})...`));
@@ -19,6 +19,9 @@ interface WorkflowRunOptions extends WorkflowOutputOptions {
19
19
  interface WorkflowStatusOptions extends WorkflowOutputOptions {
20
20
  brain?: boolean;
21
21
  }
22
+ interface WorkflowDeleteOptions extends WorkflowOutputOptions {
23
+ yes?: boolean;
24
+ }
22
25
  export declare class WorkflowCommand {
23
26
  private config;
24
27
  private logger;
@@ -35,6 +38,7 @@ export declare class WorkflowCommand {
35
38
  useTemplate(templateId: string, options: WorkflowUseOptions): Promise<void>;
36
39
  run(workflowId: string, options: WorkflowRunOptions): Promise<void>;
37
40
  status(executionId: string, options: WorkflowStatusOptions): Promise<void>;
41
+ delete(selector: string, options: WorkflowDeleteOptions): Promise<void>;
38
42
  }
39
43
  export declare function registerWorkflowCommands(program: Command, config: Config, logger: Logger): void;
40
44
  export {};
@@ -190,6 +190,29 @@ export class WorkflowCommand {
190
190
  `Completed: ${execution.completedAt || '-'}`,
191
191
  ].join('\n'), 'Workflow Status');
192
192
  }
193
+ async delete(selector, options) {
194
+ this.ensureAuthenticated();
195
+ if (options.yes !== true) {
196
+ throw new CliCommandError('Workflow deletion requires explicit confirmation with --yes.', {
197
+ code: 'WORKFLOW_DELETE_CONFIRMATION_REQUIRED',
198
+ category: 'usage',
199
+ });
200
+ }
201
+ let deleted;
202
+ try {
203
+ deleted = await this.api.deleteVigFlowWorkflow(selector);
204
+ }
205
+ catch (error) {
206
+ throw commandFailure(error, { code: 'WORKFLOW_DELETE_FAILED' });
207
+ }
208
+ if (options.json) {
209
+ this.printJson('workflow delete', { deleted });
210
+ return;
211
+ }
212
+ this.logger.success(deleted.alreadyDeleted
213
+ ? `Workflow ${deleted.id} was already deleted.`
214
+ : `Workflow ${deleted.name || deleted.id} deleted.`);
215
+ }
193
216
  }
194
217
  export function registerWorkflowCommands(program, config, logger) {
195
218
  const workflowCommand = program.command('workflow').alias('flow')
@@ -215,5 +238,9 @@ export function registerWorkflowCommands(program, config, logger) {
215
238
  .option('--no-brain', 'Do not remember this workflow status in local Project Brain')
216
239
  .option('--json', 'Emit machine-readable JSON output', false)
217
240
  .action(async (executionId, options) => new WorkflowCommand(config, logger).status(executionId, options));
241
+ workflowCommand.command('delete <workflowIdOrName>').alias('rm').description('Delete an owned workflow (idempotent by workflow ID)')
242
+ .option('--yes', 'Confirm permanent workflow deletion', false)
243
+ .option('--json', 'Emit machine-readable JSON output', false)
244
+ .action(async (selector, options) => new WorkflowCommand(config, logger).delete(selector, options));
218
245
  workflowCommand.action(async () => new WorkflowCommand(config, logger).templates({}));
219
246
  }
package/dist/index.js CHANGED
@@ -29,6 +29,7 @@ import { registerWorkflowCommands } from './commands/workflow.js';
29
29
  import { LegionCommand } from './commands/legion.js';
30
30
  import { WalletCommand } from './commands/wallet.js';
31
31
  import { registerV4Commands } from './commands/v4-registration.js';
32
+ import { registerCreativeCommands } from './commands/creative-registration.js';
32
33
  import { Config } from './utils/config.js';
33
34
  import { Logger, CH } from './utils/logger.js';
34
35
  import chalk from 'chalk';
@@ -51,6 +52,7 @@ import { installConsoleRedaction } from './utils/secret-policy.js';
51
52
  import { commandNameFromArgv, failureEnvelope, normalizeCommandError, CliCommandError, } from './utils/command-contract.js';
52
53
  import { commandAuthRequirement, commanderCommandPath } from './utils/command-policy.js';
53
54
  import { initializeRuntimeTempStorage } from './utils/runtime-temp.js';
55
+ import { hasLocalV3ServiceIdentity } from './utils/runtime-capability.js';
54
56
  initializeRuntimeTempStorage();
55
57
  applyLocalTestfarmDefaults();
56
58
  if (process.env.VIGTHORIA_CAPTURE_RUNTIME_MODEL !== '1')
@@ -418,6 +420,7 @@ export async function main(args) {
418
420
  registerPlatformCommands(program, config, logger);
419
421
  registerCodingCommands(program, config, logger);
420
422
  registerWorkflowCommands(program, config, logger);
423
+ registerCreativeCommands(program, config, logger);
421
424
  registerProductAndRunCommands(program, config, logger);
422
425
  // ==================== AUTH COMMANDS ====================
423
426
  // Auth commands
@@ -534,11 +537,12 @@ export async function main(args) {
534
537
  const authRequirement = commandAuthRequirement(commandPath);
535
538
  if (authRequirement === 'none')
536
539
  return;
537
- // On-box service identities are authenticated by their destination
538
- // service and must not be confused with a user gateway session.
539
- const hasServiceKey = Boolean(process.env.HYPERLOOP_SERVICE_KEY || process.env.V3_SERVICE_KEY);
540
+ // A local V3 service identity is valid only for Agent. It must never
541
+ // bypass session policy for coding, repository, deploy, workflow, or any
542
+ // other command merely because a service key exists on this host.
543
+ const localAgentServiceIdentity = commandPath === 'agent' && hasLocalV3ServiceIdentity();
540
544
  const legionCortex = commandPath === 'legion' && actionCommand.opts().cortex === true;
541
- if (hasServiceKey || legionCortex)
545
+ if (localAgentServiceIdentity || legionCortex)
542
546
  return;
543
547
  const explicitEnvToken = Boolean(process.env.VIGTHORIA_TOKEN || process.env.VIGTHORIA_AUTH_TOKEN);
544
548
  if (authRequirement === 'required-session' && !config.isAuthenticated() && !explicitEnvToken) {
@@ -37,6 +37,13 @@ export interface RunEvaluation {
37
37
  statusHeadline: string;
38
38
  uiTheme: 'success' | 'warning' | 'error';
39
39
  }
40
+ /** Preserve mutation-journal truth while avoiding a false partial-mutation
41
+ * classification for a read-only run that changed no files. A failed or
42
+ * unknown rollback always wins over the observed final file count because a
43
+ * rollback can remove the changed-file snapshot while still leaving state
44
+ * uncertain on disk.
45
+ */
46
+ export declare function resolveAgentPartialMutation(changedFileCount: number, reported: unknown): false | 'unknown';
40
47
  export declare function createLiveOutcome(): LiveOutcome;
41
48
  export declare function isExecutorTimeoutFailure(liveOutcome: LiveOutcome): boolean;
42
49
  export declare function isInferenceDegradedFailure(liveOutcome: LiveOutcome): boolean;
@@ -2,6 +2,19 @@
2
2
  * Task-and-quality-validated success evaluation for V3 agent runs.
3
3
  * Decouples CLI verdict from raw file-change counts (1.11.0+).
4
4
  */
5
+ /** Preserve mutation-journal truth while avoiding a false partial-mutation
6
+ * classification for a read-only run that changed no files. A failed or
7
+ * unknown rollback always wins over the observed final file count because a
8
+ * rollback can remove the changed-file snapshot while still leaving state
9
+ * uncertain on disk.
10
+ */
11
+ export function resolveAgentPartialMutation(changedFileCount, reported) {
12
+ if (reported === true || reported === 'unknown')
13
+ return 'unknown';
14
+ if (reported === false)
15
+ return false;
16
+ return changedFileCount > 0 ? 'unknown' : false;
17
+ }
5
18
  export function createLiveOutcome() {
6
19
  return {
7
20
  executorFailed: false,
@@ -30,6 +30,17 @@ export type ChatRequestOptions = {
30
30
  export interface APIClientDependencies {
31
31
  screenshotAdapter?: PreviewScreenshotPort;
32
32
  }
33
+ type V3ClientToolMutation = {
34
+ path: string;
35
+ content: string;
36
+ sha256: string;
37
+ };
38
+ type V3ClientToolResult = {
39
+ success: boolean;
40
+ output: string;
41
+ error?: string;
42
+ mutation?: V3ClientToolMutation;
43
+ };
33
44
  export declare class CLIError extends Error {
34
45
  category: CLIErrorCategory;
35
46
  statusCode?: number;
@@ -167,6 +178,11 @@ export declare class APIClient {
167
178
  executionOptions?: Record<string, unknown>;
168
179
  }): Promise<VigFlowExecutionResult>;
169
180
  getVigFlowExecutionStatus(executionId: string): Promise<VigFlowExecutionStatus>;
181
+ deleteVigFlowWorkflow(selector: string): Promise<{
182
+ id: string;
183
+ name?: string;
184
+ alreadyDeleted?: boolean;
185
+ }>;
170
186
  getV3AgentHeaders(): Promise<Record<string, string>>;
171
187
  ensureV3ServiceKey(): Promise<void>;
172
188
  runV3HealthCheck(): Promise<{
@@ -229,12 +245,15 @@ export declare class APIClient {
229
245
  captureV3AgentStreamMutation(event: any, streamedFiles: Record<string, string>, serverRoot?: string | null): void;
230
246
  private applyV3AgentStreamEventToWorkspace;
231
247
  private resolveV3ClientToolPath;
248
+ private describeMissingV3ClientToolPath;
232
249
  private recordV3ClientToolMutation;
250
+ private buildV3ClientToolMutation;
233
251
  private executeV3ClientToolRequest;
234
252
  private handleV3ClientToolRequest;
235
253
  private writeV3AgentWorkspaceFile;
236
254
  recoverAgentWorkspaceFiles(context?: Record<string, any>, streamedFiles?: Record<string, string>, expectedFiles?: string[]): void;
237
255
  normalizeAgentWorkspaceRelativePath(rawPath: string, rootPath?: string): string;
256
+ private isExplicitSingleFileFrontendRequest;
238
257
  ensureAgentFrontendPolish(message?: string, context?: Record<string, any>): Promise<void>;
239
258
  private injectSectionBeforeFooter;
240
259
  private injectNavLink;
@@ -342,11 +361,7 @@ export declare class APIClient {
342
361
  getClientToolErrors(): string[];
343
362
  clearAgentRunDiagnostics(): void;
344
363
  private recordClientToolError;
345
- submitClientToolResult(contextId: string, callId: string, result: {
346
- success: boolean;
347
- output: string;
348
- error?: string;
349
- }, backendUrl?: string | null): Promise<void>;
364
+ submitClientToolResult(contextId: string, callId: string, result: V3ClientToolResult, backendUrl?: string | null): Promise<void>;
350
365
  private isHealthyServicePayload;
351
366
  private extractModelCount;
352
367
  private probeModelList;