vigthoria-cli 1.8.4 → 1.8.5
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/dist/commands/chat.d.ts +5 -0
- package/dist/commands/chat.js +32 -9
- package/dist/commands/repo.d.ts +8 -0
- package/dist/commands/repo.js +58 -0
- package/dist/index.js +32 -0
- package/dist/utils/api.js +23 -16
- package/package.json +3 -2
package/dist/commands/chat.d.ts
CHANGED
|
@@ -75,6 +75,11 @@ export declare class ChatCommand {
|
|
|
75
75
|
private v3ToolCallCount;
|
|
76
76
|
private v3LastActivity;
|
|
77
77
|
private v3StreamingStarted;
|
|
78
|
+
/**
|
|
79
|
+
* Strip server-internal path prefixes from tool output strings.
|
|
80
|
+
* Prevents exposing paths like /var/www/V3-Code-Agent/... to end users.
|
|
81
|
+
*/
|
|
82
|
+
private sanitizeServerPath;
|
|
78
83
|
private describeV3AgentTool;
|
|
79
84
|
private updateV3AgentSpinner;
|
|
80
85
|
private updateOperatorSpinner;
|
package/dist/commands/chat.js
CHANGED
|
@@ -299,6 +299,20 @@ class ChatCommand {
|
|
|
299
299
|
v3ToolCallCount = 0;
|
|
300
300
|
v3LastActivity = Date.now();
|
|
301
301
|
v3StreamingStarted = false;
|
|
302
|
+
/**
|
|
303
|
+
* Strip server-internal path prefixes from tool output strings.
|
|
304
|
+
* Prevents exposing paths like /var/www/V3-Code-Agent/... to end users.
|
|
305
|
+
*/
|
|
306
|
+
sanitizeServerPath(text) {
|
|
307
|
+
if (!text)
|
|
308
|
+
return text;
|
|
309
|
+
// Strip common server path prefixes from output
|
|
310
|
+
return text
|
|
311
|
+
.replace(/\/var\/www\/V3-Code-Agent\//g, '')
|
|
312
|
+
.replace(/\/var\/www\/[a-zA-Z0-9_-]+\//g, '')
|
|
313
|
+
.replace(/\/tmp\/vig-remote-[a-zA-Z0-9_-]+\//g, '')
|
|
314
|
+
.replace(/\/opt\/vigthoria[a-zA-Z0-9_/-]*\//g, '');
|
|
315
|
+
}
|
|
302
316
|
describeV3AgentTool(toolName) {
|
|
303
317
|
const normalized = String(toolName || '').toLowerCase();
|
|
304
318
|
if (/read|grep|search|list|find|glob/.test(normalized)) {
|
|
@@ -324,7 +338,8 @@ class ChatCommand {
|
|
|
324
338
|
this.v3ToolCallCount += 1;
|
|
325
339
|
const toolDesc = this.describeV3AgentTool(event.tool || event.name || event.tool_name);
|
|
326
340
|
const toolTarget = event.arguments?.path || event.arguments?.file_path || event.arguments?.pattern || '';
|
|
327
|
-
const
|
|
341
|
+
const sanitizedTarget = this.sanitizeServerPath(String(toolTarget));
|
|
342
|
+
const shortTarget = sanitizedTarget ? ` → ${sanitizedTarget.replace(/\\/g, '/').split('/').slice(-2).join('/')}` : '';
|
|
328
343
|
const stepLabel = chalk_1.default.cyan(` [${this.v3IterationCount}/${this.v3ToolCallCount}]`) + ` ${toolDesc}${shortTarget}`;
|
|
329
344
|
if (spinner.isSpinning)
|
|
330
345
|
spinner.stop();
|
|
@@ -350,10 +365,12 @@ class ChatCommand {
|
|
|
350
365
|
if (spinner.isSpinning)
|
|
351
366
|
spinner.stop();
|
|
352
367
|
process.stderr.write(`${indicator} ${toolName}\n`);
|
|
353
|
-
// Show output for failures, or brief summary for successes
|
|
354
|
-
const
|
|
368
|
+
// Show output for failures, or brief summary for successes — sanitize server paths
|
|
369
|
+
const rawOutput = typeof event.output === 'string' ? event.output.trim() : '';
|
|
370
|
+
const output = this.sanitizeServerPath(rawOutput);
|
|
355
371
|
if (!success && output) {
|
|
356
|
-
const
|
|
372
|
+
const sanitizedError = this.sanitizeServerPath(typeof event.error === 'string' ? event.error : output);
|
|
373
|
+
const lines = sanitizedError.split('\n').slice(0, 4);
|
|
357
374
|
process.stderr.write(chalk_1.default.red(` ${lines.join('\n ')}\n`));
|
|
358
375
|
}
|
|
359
376
|
else if (success && output && output.length > 0) {
|
|
@@ -452,7 +469,8 @@ class ChatCommand {
|
|
|
452
469
|
return;
|
|
453
470
|
}
|
|
454
471
|
if (event.type === 'file_mutation') {
|
|
455
|
-
const
|
|
472
|
+
const rawPath = typeof event.path === 'string' ? this.sanitizeServerPath(event.path) : '';
|
|
473
|
+
const filePath = rawPath ? rawPath.replace(/\\/g, '/').split('/').slice(-2).join('/') : '';
|
|
456
474
|
const action = event.action === 'delete' ? chalk_1.default.red('deleted') : chalk_1.default.green('wrote');
|
|
457
475
|
if (filePath) {
|
|
458
476
|
if (spinner.isSpinning)
|
|
@@ -1606,7 +1624,7 @@ class ChatCommand {
|
|
|
1606
1624
|
clientSurface: 'cli',
|
|
1607
1625
|
localMachineCapable: true,
|
|
1608
1626
|
agentTimeoutMs: DEFAULT_V3_AGENT_TIMEOUT_MS,
|
|
1609
|
-
agentIdleTimeoutMs:
|
|
1627
|
+
agentIdleTimeoutMs: 90000,
|
|
1610
1628
|
model: routingPolicy.selectedModel,
|
|
1611
1629
|
requestedModel: this.currentModel,
|
|
1612
1630
|
agentExecutionPolicy: routingPolicy,
|
|
@@ -1616,9 +1634,14 @@ class ChatCommand {
|
|
|
1616
1634
|
...runtimeContext,
|
|
1617
1635
|
onStreamEvent: spinner ? (event) => this.updateV3AgentSpinner(spinner, event) : undefined,
|
|
1618
1636
|
});
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1637
|
+
const response = await (rescueEligible
|
|
1638
|
+
? Promise.race([
|
|
1639
|
+
workflowPromise,
|
|
1640
|
+
new Promise((_, reject) => {
|
|
1641
|
+
setTimeout(() => reject(new Error('V3_SAAS_SOFT_TIMEOUT')), 240000);
|
|
1642
|
+
}),
|
|
1643
|
+
])
|
|
1644
|
+
: workflowPromise);
|
|
1622
1645
|
if (spinner) {
|
|
1623
1646
|
spinner.stop();
|
|
1624
1647
|
}
|
package/dist/commands/repo.d.ts
CHANGED
|
@@ -81,6 +81,14 @@ export declare class RepoCommand {
|
|
|
81
81
|
* Delete a project from Vigthoria Repository
|
|
82
82
|
*/
|
|
83
83
|
delete(projectName: string): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Open a project in a Vigthoria engine (shop, visual, game).
|
|
86
|
+
* Pushes to community if not yet there, then triggers engine import.
|
|
87
|
+
*/
|
|
88
|
+
openIn(engine: 'shop' | 'visual' | 'game', projectName?: string, options?: {
|
|
89
|
+
browser?: boolean;
|
|
90
|
+
shopId?: string;
|
|
91
|
+
}): Promise<void>;
|
|
84
92
|
/**
|
|
85
93
|
* Clone a public project from Vigthoria Repository
|
|
86
94
|
*/
|
package/dist/commands/repo.js
CHANGED
|
@@ -714,6 +714,64 @@ class RepoCommand {
|
|
|
714
714
|
console.log(chalk_1.default.red(`\n❌ Error: ${errMsg}\n`));
|
|
715
715
|
}
|
|
716
716
|
}
|
|
717
|
+
/**
|
|
718
|
+
* Open a project in a Vigthoria engine (shop, visual, game).
|
|
719
|
+
* Pushes to community if not yet there, then triggers engine import.
|
|
720
|
+
*/
|
|
721
|
+
async openIn(engine, projectName, options = {}) {
|
|
722
|
+
this.requireAuth();
|
|
723
|
+
const engineLabels = {
|
|
724
|
+
shop: 'Shop Engine',
|
|
725
|
+
visual: 'Visual Editor',
|
|
726
|
+
game: 'Gaming Engine'
|
|
727
|
+
};
|
|
728
|
+
const label = engineLabels[engine] || engine;
|
|
729
|
+
// Resolve project name from arg or current directory
|
|
730
|
+
const resolvedName = projectName || this.detectProjectInfo(process.cwd()).name;
|
|
731
|
+
const spinner = (0, logger_js_1.createSpinner)(`Opening "${resolvedName}" in ${label}...`).start();
|
|
732
|
+
try {
|
|
733
|
+
const response = await fetch(`${this.apiBase}/api/engine-import`, {
|
|
734
|
+
method: 'POST',
|
|
735
|
+
headers: this.getAuthHeaders(),
|
|
736
|
+
body: JSON.stringify({
|
|
737
|
+
engine,
|
|
738
|
+
projectName: resolvedName,
|
|
739
|
+
shopId: options.shopId || 'default',
|
|
740
|
+
source: 'repo'
|
|
741
|
+
})
|
|
742
|
+
});
|
|
743
|
+
if (!response.ok) {
|
|
744
|
+
const err = await response.json().catch(async () => ({ error: await response.text() }));
|
|
745
|
+
throw new Error(err.error || `Engine import failed (${response.status})`);
|
|
746
|
+
}
|
|
747
|
+
const data = await response.json();
|
|
748
|
+
spinner.succeed(chalk_1.default.green(`Project imported into ${label}!`));
|
|
749
|
+
console.log(chalk_1.default.cyan(`\n🚀 Open in browser:`));
|
|
750
|
+
console.log(chalk_1.default.bold(` ${data.url}\n`));
|
|
751
|
+
if (options.browser) {
|
|
752
|
+
try {
|
|
753
|
+
const { execSync } = await import('child_process');
|
|
754
|
+
const platform = process.platform;
|
|
755
|
+
if (platform === 'win32')
|
|
756
|
+
execSync(`start "" "${data.url}"`, { stdio: 'ignore' });
|
|
757
|
+
else if (platform === 'darwin')
|
|
758
|
+
execSync(`open "${data.url}"`, { stdio: 'ignore' });
|
|
759
|
+
else
|
|
760
|
+
execSync(`xdg-open "${data.url}"`, { stdio: 'ignore' });
|
|
761
|
+
}
|
|
762
|
+
catch { /* browser open is optional */ }
|
|
763
|
+
}
|
|
764
|
+
if (data.message) {
|
|
765
|
+
console.log(chalk_1.default.gray(` ${data.message}\n`));
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
catch (error) {
|
|
769
|
+
spinner.stop();
|
|
770
|
+
const errMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
771
|
+
console.log(chalk_1.default.red(`\n❌ ${label} import failed: ${errMsg}\n`));
|
|
772
|
+
console.log(chalk_1.default.gray('Tip: Make sure your project is pushed first with `vigthoria repo push`\n'));
|
|
773
|
+
}
|
|
774
|
+
}
|
|
717
775
|
/**
|
|
718
776
|
* Clone a public project from Vigthoria Repository
|
|
719
777
|
*/
|
package/dist/index.js
CHANGED
|
@@ -514,6 +514,8 @@ async function main() {
|
|
|
514
514
|
.option('-d, --description <text>', 'Project description')
|
|
515
515
|
.option('-f, --force', 'Overwrite existing project', false)
|
|
516
516
|
.option('-y, --yes', 'Run non-interactively with provided/default values', false)
|
|
517
|
+
.option('--open-in <engine>', 'After push, open project in engine: shop, visual, game')
|
|
518
|
+
.option('--browser', 'Open result URL in default browser', false)
|
|
517
519
|
.action(async (pathArg, options) => {
|
|
518
520
|
const repo = new repo_js_1.RepoCommand(config, logger);
|
|
519
521
|
await repo.push({
|
|
@@ -524,6 +526,15 @@ async function main() {
|
|
|
524
526
|
force: options.force,
|
|
525
527
|
yes: options.yes
|
|
526
528
|
});
|
|
529
|
+
if (options.openIn) {
|
|
530
|
+
const engine = options.openIn;
|
|
531
|
+
if (!['shop', 'visual', 'game'].includes(engine)) {
|
|
532
|
+
logger.warn(`Unknown engine "${engine}". Use: shop, visual, game`);
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
await repo.openIn(engine, options.name || undefined, { browser: options.browser });
|
|
536
|
+
}
|
|
537
|
+
}
|
|
527
538
|
});
|
|
528
539
|
repoCommand
|
|
529
540
|
.command('pull <name>')
|
|
@@ -582,6 +593,27 @@ async function main() {
|
|
|
582
593
|
force: options.force
|
|
583
594
|
});
|
|
584
595
|
});
|
|
596
|
+
repoCommand
|
|
597
|
+
.command('open-in <engine> [projectName]')
|
|
598
|
+
.description('Open a Vigthoria Repo project in the Shop Engine, Visual Editor, or Gaming Engine')
|
|
599
|
+
.option('--browser', 'Open result URL in default browser', false)
|
|
600
|
+
.option('--shop-id <id>', 'Target shop ID (for shop engine)', 'default')
|
|
601
|
+
.addHelpText('after', `
|
|
602
|
+
Examples:
|
|
603
|
+
vigthoria repo open-in shop my-store
|
|
604
|
+
vigthoria repo open-in visual my-website
|
|
605
|
+
vigthoria repo open-in game my-game --browser`)
|
|
606
|
+
.action(async (engine, projectName, options) => {
|
|
607
|
+
if (!['shop', 'visual', 'game'].includes(engine)) {
|
|
608
|
+
logger.error(`Unknown engine "${engine}". Valid options: shop, visual, game`);
|
|
609
|
+
process.exit(1);
|
|
610
|
+
}
|
|
611
|
+
const repo = new repo_js_1.RepoCommand(config, logger);
|
|
612
|
+
await repo.openIn(engine, projectName, {
|
|
613
|
+
browser: options.browser,
|
|
614
|
+
shopId: options.shopId
|
|
615
|
+
});
|
|
616
|
+
});
|
|
585
617
|
// Default repo action shows help with available subcommands
|
|
586
618
|
repoCommand.action(() => {
|
|
587
619
|
repoCommand.outputHelp();
|
package/dist/utils/api.js
CHANGED
|
@@ -89,24 +89,20 @@ function formatCLIError(err) {
|
|
|
89
89
|
return `${tag} ${err.message}`;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
// SSE-based architecture: NO hard timeouts. Streams stay open until
|
|
93
|
-
// complete/error/disconnect. Liveness is checked via heartbeat events.
|
|
94
|
-
// Set to 0 (disabled) by default. Only use a timeout as an emergency
|
|
95
|
-
// safety net when explicitly configured via env vars.
|
|
96
92
|
const DEFAULT_V3_AGENT_TIMEOUT_MS = (() => {
|
|
97
|
-
const rawValue = process.env.VIGTHORIA_AGENT_TIMEOUT_MS || process.env.V3_AGENT_TIMEOUT_MS || '
|
|
93
|
+
const rawValue = process.env.VIGTHORIA_AGENT_TIMEOUT_MS || process.env.V3_AGENT_TIMEOUT_MS || '1200000';
|
|
98
94
|
const parsed = Number.parseInt(rawValue, 10);
|
|
99
|
-
return Number.isFinite(parsed) && parsed
|
|
95
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 1200000;
|
|
100
96
|
})();
|
|
101
97
|
const DEFAULT_V3_AGENT_IDLE_TIMEOUT_MS = (() => {
|
|
102
|
-
const rawValue = process.env.VIGTHORIA_AGENT_IDLE_TIMEOUT_MS || process.env.V3_AGENT_IDLE_TIMEOUT_MS || '
|
|
98
|
+
const rawValue = process.env.VIGTHORIA_AGENT_IDLE_TIMEOUT_MS || process.env.V3_AGENT_IDLE_TIMEOUT_MS || '90000';
|
|
103
99
|
const parsed = Number.parseInt(rawValue, 10);
|
|
104
|
-
return Number.isFinite(parsed) && parsed
|
|
100
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 90000;
|
|
105
101
|
})();
|
|
106
102
|
const DEFAULT_OPERATOR_TIMEOUT_MS = (() => {
|
|
107
|
-
const rawValue = process.env.VIGTHORIA_OPERATOR_TIMEOUT_MS || process.env.OPERATOR_TIMEOUT_MS || '
|
|
103
|
+
const rawValue = process.env.VIGTHORIA_OPERATOR_TIMEOUT_MS || process.env.OPERATOR_TIMEOUT_MS || '300000';
|
|
108
104
|
const parsed = Number.parseInt(rawValue, 10);
|
|
109
|
-
return Number.isFinite(parsed) && parsed
|
|
105
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 300000;
|
|
110
106
|
})();
|
|
111
107
|
class APIClient {
|
|
112
108
|
client;
|
|
@@ -2736,6 +2732,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2736
2732
|
&& context.localMachineCapable !== false;
|
|
2737
2733
|
const rescueEligibleSaaS = preferLocalV3
|
|
2738
2734
|
&& /(saas|dashboard|analytics|billing|team management|activity feed|login screen)/i.test(message);
|
|
2735
|
+
const timeoutMs = rescueEligibleSaaS ? Math.min(baseTimeoutMs, 210000) : baseTimeoutMs;
|
|
2739
2736
|
const maxAttempts = preferLocalV3 ? 2 : 1;
|
|
2740
2737
|
let lastErrors = [];
|
|
2741
2738
|
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
@@ -2768,9 +2765,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2768
2765
|
stream: true,
|
|
2769
2766
|
};
|
|
2770
2767
|
for (const baseUrl of this.getV3AgentBaseUrls(preferLocalV3)) {
|
|
2771
|
-
// No hard timeout — SSE stream stays alive until server sends
|
|
2772
|
-
// complete/error/[DONE] or the TCP connection drops.
|
|
2773
2768
|
const controller = new AbortController();
|
|
2769
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
2774
2770
|
try {
|
|
2775
2771
|
const response = await this.executeV3AgentRunRequest(baseUrl, requestBody, requestExecutionContext, controller.signal);
|
|
2776
2772
|
if (!response.ok) {
|
|
@@ -2802,6 +2798,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2802
2798
|
stream: true,
|
|
2803
2799
|
};
|
|
2804
2800
|
const continueController = new AbortController();
|
|
2801
|
+
const continueTimeoutId = setTimeout(() => continueController.abort(), timeoutMs);
|
|
2805
2802
|
try {
|
|
2806
2803
|
const continueHeaders = await this.getV3AgentHeaders();
|
|
2807
2804
|
const continueResponse = await fetch(this.getV3AgentContinueUrl(baseUrl), {
|
|
@@ -2819,7 +2816,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2819
2816
|
break; // Fall through to normal completion with partial data
|
|
2820
2817
|
}
|
|
2821
2818
|
finally {
|
|
2822
|
-
|
|
2819
|
+
clearTimeout(continueTimeoutId);
|
|
2823
2820
|
}
|
|
2824
2821
|
}
|
|
2825
2822
|
// Use the final continuation data for workspace recovery
|
|
@@ -2875,6 +2872,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2875
2872
|
}
|
|
2876
2873
|
errors.push(`${baseUrl}: ${error?.message || String(error)}`);
|
|
2877
2874
|
}
|
|
2875
|
+
finally {
|
|
2876
|
+
clearTimeout(timeoutId);
|
|
2877
|
+
}
|
|
2878
2878
|
}
|
|
2879
2879
|
lastErrors = errors;
|
|
2880
2880
|
const shouldRetry = attempt < maxAttempts
|
|
@@ -2940,6 +2940,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2940
2940
|
}
|
|
2941
2941
|
async runOperatorWorkflow(message, context = {}) {
|
|
2942
2942
|
const executionContext = await this.bindExecutionContext(context);
|
|
2943
|
+
const timeoutMs = context.operatorTimeoutMs || DEFAULT_OPERATOR_TIMEOUT_MS;
|
|
2943
2944
|
const errors = [];
|
|
2944
2945
|
const authToken = this.config.get('authToken');
|
|
2945
2946
|
// Collect a lightweight workspace file listing so the operator can
|
|
@@ -2947,10 +2948,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
2947
2948
|
const workspacePath = executionContext.workspacePath || executionContext.projectPath || executionContext.targetPath || process.cwd();
|
|
2948
2949
|
const workspaceSummary = this.buildLocalWorkspaceSummary(workspacePath);
|
|
2949
2950
|
for (const baseUrl of this.getOperatorBaseUrls()) {
|
|
2950
|
-
// No hard timeout — SSE stream stays open until result/error/disconnect.
|
|
2951
|
-
// BMAD sends heartbeat events every 15s; if the TCP connection drops,
|
|
2952
|
-
// the fetch will throw naturally.
|
|
2953
2951
|
const controller = new AbortController();
|
|
2952
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
2954
2953
|
try {
|
|
2955
2954
|
const response = await fetch(this.getOperatorStreamUrl(baseUrl), {
|
|
2956
2955
|
method: 'POST',
|
|
@@ -3089,8 +3088,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
3089
3088
|
};
|
|
3090
3089
|
}
|
|
3091
3090
|
catch (error) {
|
|
3091
|
+
const isAbort = error?.name === 'AbortError' || error?.code === 'ABORT_ERR';
|
|
3092
|
+
if (isAbort) {
|
|
3093
|
+
const mins = Math.round(timeoutMs / 60000);
|
|
3094
|
+
throw new CLIError(`Operator workflow timed out after ${mins} minute(s). You can increase the timeout with VIGTHORIA_OPERATOR_TIMEOUT_MS.`, 'timeout', error);
|
|
3095
|
+
}
|
|
3092
3096
|
errors.push(`${baseUrl}: ${error?.message || String(error)}`);
|
|
3093
3097
|
}
|
|
3098
|
+
finally {
|
|
3099
|
+
clearTimeout(timeoutId);
|
|
3100
|
+
}
|
|
3094
3101
|
}
|
|
3095
3102
|
throw new CLIError(`Operator workflow failed on all endpoints: ${errors.join(' | ')}`, 'model_backend');
|
|
3096
3103
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigthoria-cli",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.5",
|
|
4
4
|
"description": "Vigthoria Coder CLI - AI-powered terminal coding assistant",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"test:repo:live": "npm run build && node scripts/test-live-repo-e2e.js",
|
|
44
44
|
"test:game:live": "npm run build && node scripts/test-live-game-push.js",
|
|
45
45
|
"proof:agent": "npm run build && node scripts/proof-agent-mode.js",
|
|
46
|
-
"test:fresh-install": "node scripts/test-fresh-install.js"
|
|
46
|
+
"test:fresh-install": "node scripts/test-fresh-install.js",
|
|
47
|
+
"prepublishOnly": "npm run build && node scripts/verify-package-hygiene.js && node scripts/test-fresh-install.js"
|
|
47
48
|
},
|
|
48
49
|
"keywords": [
|
|
49
50
|
"ai",
|