gipity 1.0.394 → 1.0.396
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/auth.js +110 -46
- package/dist/colors.js +22 -7
- package/dist/commands/claude.js +8 -4
- package/dist/commands/deploy.js +2 -1
- package/dist/commands/generate.js +5 -0
- package/package.json +2 -2
package/dist/auth.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync, chmodSync } from 'fs';
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync, chmodSync, openSync, closeSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { homedir } from 'os';
|
|
4
4
|
import { decodeJwtExp } from './utils.js';
|
|
@@ -8,6 +8,7 @@ import { decodeJwtExp } from './utils.js';
|
|
|
8
8
|
// so the `claude` subprocess and git/npm still use the real home.
|
|
9
9
|
const AUTH_DIR = process.env.GIPITY_DIR || join(homedir(), '.gipity');
|
|
10
10
|
const AUTH_FILE = join(AUTH_DIR, 'auth.json');
|
|
11
|
+
const AUTH_LOCK_FILE = join(AUTH_DIR, 'auth.lock');
|
|
11
12
|
let cached = null;
|
|
12
13
|
export function getAuth() {
|
|
13
14
|
if (cached)
|
|
@@ -70,16 +71,65 @@ export function sessionExpired() {
|
|
|
70
71
|
return Date.now() > exp * 1000;
|
|
71
72
|
}
|
|
72
73
|
const delay = (ms) => new Promise(r => setTimeout(r, ms));
|
|
74
|
+
// ─── Cross-process refresh lock ────────────────────────────────
|
|
75
|
+
// Serializes token refreshes across every `gipity` process that shares this
|
|
76
|
+
// ~/.gipity/auth.json (foreground commands, the file-sync hook, the relay
|
|
77
|
+
// daemon). Without it, siblings race to refresh the SINGLE-USE refresh token:
|
|
78
|
+
// the first wins and rotates it, the rest submit the now-dead token and 401.
|
|
79
|
+
// Retry-and-re-read alone left a window (a sibling could 401 before the winner
|
|
80
|
+
// finished writing the file). Holding the lock closes that window — siblings
|
|
81
|
+
// wait, then re-read and ADOPT the freshly-rotated token instead of refreshing.
|
|
82
|
+
const LOCK_WAIT_MS = 10_000; // refresh is one quick round-trip; cap the wait
|
|
83
|
+
const LOCK_POLL_MS = 100;
|
|
84
|
+
/** Acquire the global auth-refresh lock. Returns a release fn, or null if we
|
|
85
|
+
* couldn't get it within the wait window (caller then proceeds best-effort —
|
|
86
|
+
* refresh must never block a command indefinitely). Mirrors sync.ts's advisory
|
|
87
|
+
* lock: O_EXCL create, PID payload, stale-holder reclaim. Exported for tests. */
|
|
88
|
+
export async function acquireRefreshLock() {
|
|
89
|
+
mkdirSync(AUTH_DIR, { recursive: true, mode: 0o700 });
|
|
90
|
+
const start = Date.now();
|
|
91
|
+
while (true) {
|
|
92
|
+
try {
|
|
93
|
+
const fd = openSync(AUTH_LOCK_FILE, 'wx'); // fails if the file exists
|
|
94
|
+
writeFileSync(fd, String(process.pid));
|
|
95
|
+
closeSync(fd);
|
|
96
|
+
return () => { try {
|
|
97
|
+
unlinkSync(AUTH_LOCK_FILE);
|
|
98
|
+
}
|
|
99
|
+
catch { /* already gone */ } };
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// Lock held (or a transient create error). Reclaim it if the holder PID is dead.
|
|
103
|
+
try {
|
|
104
|
+
const pid = parseInt(readFileSync(AUTH_LOCK_FILE, 'utf-8').trim(), 10);
|
|
105
|
+
if (pid && !isNaN(pid)) {
|
|
106
|
+
try {
|
|
107
|
+
process.kill(pid, 0);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
try {
|
|
111
|
+
unlinkSync(AUTH_LOCK_FILE);
|
|
112
|
+
}
|
|
113
|
+
catch { /* race */ }
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch { /* unreadable - retry */ }
|
|
119
|
+
if (Date.now() - start > LOCK_WAIT_MS)
|
|
120
|
+
return null; // give up waiting, proceed best-effort
|
|
121
|
+
await delay(LOCK_POLL_MS);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
73
125
|
/** Renew the access token (5-min buffer) before an authenticated call, surviving
|
|
74
126
|
* the case that broke overnight fix-mode runs: MANY concurrent `gipity` processes
|
|
75
127
|
* (relay daemon, file-sync hook, parallel commands) sharing one ~/.gipity/auth.json.
|
|
76
128
|
* Refresh tokens are SINGLE-USE — the server rotates them, so when several siblings
|
|
77
|
-
* race to refresh the same token, the first wins and the rest get a 401.
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* retry the race/transient failures, re-reading each attempt so we ADOPT whatever
|
|
82
|
-
* token a sibling just rotated in rather than resubmitting the rotated-away one.
|
|
129
|
+
* race to refresh the same token, the first wins and the rest get a 401. We guard
|
|
130
|
+
* the refresh with a cross-process lock so only one sibling refreshes at a time; the
|
|
131
|
+
* others wait, re-read the file, and ADOPT the freshly-rotated token. If the lock
|
|
132
|
+
* can't be had in time we still try (re-reading first), so this never hangs a command.
|
|
83
133
|
* Stays void / never throws / never clears auth: a genuine dead token still flows to
|
|
84
134
|
* the caller's existing 401 path (which messages "run: gipity login"). */
|
|
85
135
|
export async function refreshTokenIfNeeded() {
|
|
@@ -90,57 +140,71 @@ export async function refreshTokenIfNeeded() {
|
|
|
90
140
|
const buffer = 5 * 60 * 1000; // refresh 5 min before the access token lapses
|
|
91
141
|
const fresh = (a) => Date.now() <= new Date(a.expiresAt).getTime() - buffer;
|
|
92
142
|
if (fresh(auth))
|
|
93
|
-
return;
|
|
143
|
+
return; // fast path: token still good, no lock needed
|
|
94
144
|
// If the refresh token itself has expired, re-login is genuinely required; leave the
|
|
95
145
|
// expired auth in place so the caller's existing 401 path prompts `gipity login`.
|
|
96
146
|
const refreshExp = decodeJwtExp(auth.refreshToken);
|
|
97
147
|
if (refreshExp && Date.now() > refreshExp * 1000)
|
|
98
148
|
return;
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
149
|
+
// Serialize with sibling processes so we don't race the single-use refresh token.
|
|
150
|
+
const release = await acquireRefreshLock();
|
|
151
|
+
try {
|
|
152
|
+
// Re-check under the lock: a sibling may have refreshed while we waited.
|
|
153
|
+
const held = readAuthFresh();
|
|
154
|
+
if (held && fresh(held)) {
|
|
155
|
+
cached = held;
|
|
105
156
|
return;
|
|
106
157
|
}
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
158
|
+
const { resolveApiBase } = await import('./config.js');
|
|
159
|
+
const apiBase = resolveApiBase();
|
|
160
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
161
|
+
const cur = readAuthFresh(); // a sibling may have just refreshed for us
|
|
162
|
+
if (cur && fresh(cur)) {
|
|
163
|
+
cached = cur;
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const refreshToken = cur?.refreshToken ?? auth.refreshToken;
|
|
167
|
+
let res;
|
|
168
|
+
try {
|
|
169
|
+
res = await fetch(`${apiBase}/auth/refresh`, {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
headers: { 'Content-Type': 'application/json' },
|
|
172
|
+
body: JSON.stringify({ refreshToken }),
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
124
176
|
await delay(attempt * 300);
|
|
125
|
-
continue;
|
|
177
|
+
continue; // network blip - retry
|
|
126
178
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (after && fresh(after)) {
|
|
136
|
-
cached = after;
|
|
179
|
+
if (res.ok) {
|
|
180
|
+
const json = await res.json().catch(() => null);
|
|
181
|
+
const exp = json && decodeJwtExp(json.accessToken);
|
|
182
|
+
if (!json || !exp) {
|
|
183
|
+
await delay(attempt * 300);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
saveAuth({ accessToken: json.accessToken, refreshToken: json.refreshToken, email: auth.email, expiresAt: new Date(exp * 1000).toISOString() });
|
|
137
187
|
return;
|
|
138
188
|
}
|
|
139
|
-
|
|
189
|
+
// 401/403 → the refresh token was rejected outright (rotated away by a sibling
|
|
190
|
+
// that beat us to the lock, or genuinely expired). Re-read once more in case a
|
|
191
|
+
// sibling's fresh token just landed; otherwise stop and let the caller re-login.
|
|
192
|
+
if (res.status === 401 || res.status === 403) {
|
|
193
|
+
const after = readAuthFresh();
|
|
194
|
+
if (after && fresh(after)) {
|
|
195
|
+
cached = after;
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
await delay(attempt * 300); // 5xx / unexpected → transient, retry
|
|
140
201
|
}
|
|
141
|
-
|
|
202
|
+
// Retries exhausted: leave the existing token. The caller's request will 401 and the
|
|
203
|
+
// existing handler messages the user — we never delete the shared auth.json here.
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
if (release)
|
|
207
|
+
release();
|
|
142
208
|
}
|
|
143
|
-
// Retries exhausted: leave the existing token. The caller's request will 401 and the
|
|
144
|
-
// existing handler messages the user — we never delete the shared auth.json here.
|
|
145
209
|
}
|
|
146
210
|
//# sourceMappingURL=auth.js.map
|
package/dist/colors.js
CHANGED
|
@@ -47,10 +47,14 @@ function detectColorLevel() {
|
|
|
47
47
|
return 2;
|
|
48
48
|
if (/-256(color)?$/.test(term) || term.includes('256'))
|
|
49
49
|
return 2;
|
|
50
|
-
//
|
|
51
|
-
// conhost
|
|
50
|
+
// Windows Terminal / VS Code set COLORTERM=truecolor (caught above). The
|
|
51
|
+
// classic console host (conhost, the standalone PowerShell window) advertises
|
|
52
|
+
// nothing, but every still-supported Windows build (10 v1703+, 2017) handles
|
|
53
|
+
// 256-color VT sequences reliably - so 256 is the safe floor. Orange then
|
|
54
|
+
// downscales to xterm-214 (a real orange) instead of the bright-yellow the
|
|
55
|
+
// 16-color palette is forced into (it has no orange slot at all).
|
|
52
56
|
if (process.platform === 'win32')
|
|
53
|
-
return
|
|
57
|
+
return 2;
|
|
54
58
|
if (term)
|
|
55
59
|
return 1;
|
|
56
60
|
return 0;
|
|
@@ -60,7 +64,8 @@ const COLOR_LEVEL = detectColorLevel();
|
|
|
60
64
|
const identity = (s) => s;
|
|
61
65
|
// ── RGB downgrade helpers ───────────────────────────────────────────────
|
|
62
66
|
// RGB → nearest xterm-256 palette index (6x6x6 cube + grayscale ramp).
|
|
63
|
-
|
|
67
|
+
// Exported for unit tests that pin the documented downscale (orange → 214).
|
|
68
|
+
export function rgbTo256(r, g, b) {
|
|
64
69
|
if (r === g && g === b) {
|
|
65
70
|
if (r < 8)
|
|
66
71
|
return 16;
|
|
@@ -74,7 +79,9 @@ function rgbTo256(r, g, b) {
|
|
|
74
79
|
Math.round((b / 255) * 5));
|
|
75
80
|
}
|
|
76
81
|
// RGB → nearest 16-color SGR foreground code (30-37 / 90-97).
|
|
77
|
-
|
|
82
|
+
// Exported for unit tests that pin the documented downscale (orange → bright
|
|
83
|
+
// yellow, i.e. the palette has no orange slot).
|
|
84
|
+
export function rgbTo16(r, g, b) {
|
|
78
85
|
const value = Math.round((Math.max(r, g, b) / 255) * 3);
|
|
79
86
|
if (value === 0)
|
|
80
87
|
return 30;
|
|
@@ -87,7 +94,13 @@ function rgbTo16(r, g, b) {
|
|
|
87
94
|
return code;
|
|
88
95
|
}
|
|
89
96
|
// ── Low-level builders ──────────────────────────────────────────────────
|
|
90
|
-
|
|
97
|
+
// `lowColorFallback` controls the 16-color (level 1) tier. The ANSI 16-color
|
|
98
|
+
// palette has no orange and only crude approximations of off-palette hues, so a
|
|
99
|
+
// color that can't be represented reads as a bug (brand orange → bright yellow).
|
|
100
|
+
// Off-palette brand colors pass a monochrome fallback (e.g. `bold`) to convey
|
|
101
|
+
// emphasis without a wrong hue; semantic colors that map cleanly (red, green,
|
|
102
|
+
// blue) omit it and keep their nearest-16 approximation.
|
|
103
|
+
export function makeFg(r, g, b, lowColorFallback) {
|
|
91
104
|
if (COLOR_LEVEL === 0)
|
|
92
105
|
return identity;
|
|
93
106
|
if (COLOR_LEVEL === 3) {
|
|
@@ -97,6 +110,8 @@ export function makeFg(r, g, b) {
|
|
|
97
110
|
const n = rgbTo256(r, g, b);
|
|
98
111
|
return (s) => `${ESC}[38;5;${n}m${s}${ESC}[39m`;
|
|
99
112
|
}
|
|
113
|
+
if (lowColorFallback)
|
|
114
|
+
return lowColorFallback;
|
|
100
115
|
const code = rgbTo16(r, g, b);
|
|
101
116
|
return (s) => `${ESC}[${code}m${s}${ESC}[39m`;
|
|
102
117
|
}
|
|
@@ -130,7 +145,7 @@ export const underline = makeStyle(4, 24);
|
|
|
130
145
|
// ── Gipity platform palette ────────────────────────────────────────────
|
|
131
146
|
// Colors sourced from platform/client/src/css/styles.css and
|
|
132
147
|
// platform/apps/gipitsm/src/css/tokens.css
|
|
133
|
-
export const brand = makeFg(254, 166, 14); // Gipity orange #fea60e
|
|
148
|
+
export const brand = makeFg(254, 166, 14, bold); // Gipity orange #fea60e (→ bold on 16-color; no orange in palette)
|
|
134
149
|
export const error = makeFg(239, 68, 68); // #ef4444
|
|
135
150
|
export const warning = makeFg(245, 158, 11); // #f59e0b
|
|
136
151
|
export const success = makeFg(34, 197, 94); // #22c55e
|
package/dist/commands/claude.js
CHANGED
|
@@ -17,7 +17,7 @@ function resolveCommand(cmd) {
|
|
|
17
17
|
return `${cmd}.cmd`;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
import { getAuth, saveAuth
|
|
20
|
+
import { getAuth, saveAuth } from '../auth.js';
|
|
21
21
|
import { get, post, publicPost, ApiError, getAccountSlug } from '../api.js';
|
|
22
22
|
import { getConfig, saveConfigAt, clearConfigCache, getApiBaseOverride, DEFAULT_API_BASE, getConfigPath } from '../config.js';
|
|
23
23
|
import { sync } from '../sync.js';
|
|
@@ -339,7 +339,9 @@ export const claudeCommand = new Command('claude')
|
|
|
339
339
|
}
|
|
340
340
|
catch (err) {
|
|
341
341
|
if (err instanceof ApiError && err.statusCode === 401) {
|
|
342
|
-
clearAuth()
|
|
342
|
+
// Don't clearAuth() — the file is shared with concurrent gipity
|
|
343
|
+
// processes (sync hook, relay); deleting it logs them all out. A
|
|
344
|
+
// re-login overwrites it anyway. Leave it and just point the user.
|
|
343
345
|
console.error(` ${clrError('Your session expired.')} ${muted('Run: gipity login')}`);
|
|
344
346
|
}
|
|
345
347
|
else {
|
|
@@ -480,7 +482,9 @@ export const claudeCommand = new Command('claude')
|
|
|
480
482
|
process.exit(1);
|
|
481
483
|
}
|
|
482
484
|
if (err instanceof ApiError && err.statusCode === 401 && !reauthed && !nonInteractive) {
|
|
483
|
-
clearAuth()
|
|
485
|
+
// No clearAuth(): interactiveLogin() saves fresh tokens over the
|
|
486
|
+
// file. Deleting it first would log out any sibling process (sync
|
|
487
|
+
// hook, relay) sharing this ~/.gipity/auth.json mid-run.
|
|
484
488
|
console.log(` ${muted('Your session expired. Let\'s sign you back in.')}\n`);
|
|
485
489
|
auth = await interactiveLogin();
|
|
486
490
|
console.log('');
|
|
@@ -488,7 +492,7 @@ export const claudeCommand = new Command('claude')
|
|
|
488
492
|
continue;
|
|
489
493
|
}
|
|
490
494
|
if (err instanceof ApiError && err.statusCode === 401) {
|
|
491
|
-
|
|
495
|
+
// Leave the shared auth.json in place (see above) — just message.
|
|
492
496
|
console.error(` ${clrError('Your session expired.')}`);
|
|
493
497
|
console.error(` ${muted('Run: gipity login')}`);
|
|
494
498
|
process.exit(1);
|
package/dist/commands/deploy.js
CHANGED
|
@@ -22,7 +22,8 @@ export const deployCommand = new Command('deploy')
|
|
|
22
22
|
.option('--only <phases>', 'Run only specific phases (comma-separated)')
|
|
23
23
|
.option('--force', 'Re-run all phases (ignore checksums) and bypass the sync bulk-deletion guard')
|
|
24
24
|
.option('--no-sync', 'Skip sync-up before deploy')
|
|
25
|
-
.option('--optimize', '
|
|
25
|
+
.option('--optimize', 'Force Vite build optimization on (default for prod; use this to optimize a dev deploy too)')
|
|
26
|
+
.option('--no-optimize', 'Skip build optimization and upload files as-is - the escape hatch for plain-HTML apps whose <script src> tags are not type="module"')
|
|
26
27
|
.option('--json', 'Output as JSON')
|
|
27
28
|
.action((target, opts) => run('Deploy', async () => {
|
|
28
29
|
if (target !== 'dev' && target !== 'prod') {
|
|
@@ -66,6 +66,7 @@ Examples:
|
|
|
66
66
|
.option('--quality <quality>', 'Quality: low|medium|high|auto (gpt-image-2)')
|
|
67
67
|
.option('--aspect-ratio <ratio>', 'Aspect ratio (Gemini only): 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 4:5, 5:4, 21:9')
|
|
68
68
|
.option('--image-size <size>', 'Output resolution (Gemini only): 512, 1K, 2K, 4K')
|
|
69
|
+
.option('--seed <n>', 'Deterministic seed (BFL only): reuse one seed to keep a set of images visually coherent', (v) => parseInt(v, 10))
|
|
69
70
|
.option('-o, --output <file>', 'Output path (default ./generated.png). For an image your app ships, write it into the source tree so it deploys, e.g. -o src/assets/images/hero.png; the cwd default is fine for one-off generation.')
|
|
70
71
|
.option('--json', 'Output as JSON')
|
|
71
72
|
.action(async (prompt, opts) => {
|
|
@@ -79,6 +80,7 @@ Examples:
|
|
|
79
80
|
quality: opts.quality,
|
|
80
81
|
aspect_ratio: opts.aspectRatio,
|
|
81
82
|
image_size: opts.imageSize,
|
|
83
|
+
seed: Number.isFinite(opts.seed) ? opts.seed : undefined,
|
|
82
84
|
});
|
|
83
85
|
const ext = result.content_type.includes('png') ? 'png' : 'jpg';
|
|
84
86
|
const filename = opts.output || `generated.${ext}`;
|
|
@@ -90,6 +92,9 @@ Examples:
|
|
|
90
92
|
const sizeKb = Math.round(result.size_bytes / 1024);
|
|
91
93
|
console.log(`${muted(`Generated with ${result.provider}/${result.model} (${sizeKb}KB)`)}`);
|
|
92
94
|
console.log(success(`Saved to ${savedPath}`));
|
|
95
|
+
if (result.seed !== undefined) {
|
|
96
|
+
console.log(muted(`Seed ${result.seed} — pass --seed ${result.seed} to keep the next image coherent`));
|
|
97
|
+
}
|
|
93
98
|
}
|
|
94
99
|
}
|
|
95
100
|
catch (err) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gipity",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.396",
|
|
4
4
|
"description": "The full-stack platform tuned for AI agents. Database, storage, auth, functions, deploy, and drop-in kits - all agent-tuned. Pair with Claude Code or use standalone.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"gipity": "dist/updater/shim.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"build": "tsc && chmod +x dist/index.js dist/gipcc.js dist/gipccd.js dist/updater/shim.js dist/updater/check.js",
|
|
13
13
|
"dev": "tsc --watch",
|
|
14
14
|
"test": "npm run test:smoke",
|
|
15
|
-
"test:smoke": "tsc && node --test dist/__tests__/utils.test.js dist/__tests__/config.test.js dist/__tests__/sync.test.js dist/__tests__/sync-apply.test.js dist/__tests__/sync-lock.test.js dist/__tests__/push-cas.test.js dist/__tests__/upload.test.js dist/__tests__/progress.test.js dist/__tests__/updater.test.js dist/__tests__/cli-smoke.test.js dist/__tests__/claude-noninteractive.test.js dist/__tests__/claude-trust.test.js dist/__tests__/relay-state.test.js dist/__tests__/relay-daemon.test.js dist/__tests__/relay-installers.test.js dist/__tests__/relay-bridge-abort.test.js dist/__tests__/relay-redact.test.js dist/__tests__/relay-machine-id.test.js dist/__tests__/stream-json.test.js dist/__tests__/relay-ingest-contract.test.js dist/__tests__/prompts.test.js dist/__tests__/capture-transcript.test.js dist/__tests__/flag-aliases.test.js dist/__tests__/adopt-cwd.test.js dist/__tests__/cli-cmd-agent.test.js dist/__tests__/cli-cmd-approval.test.js dist/__tests__/cli-cmd-audit.test.js dist/__tests__/cli-cmd-chat.test.js dist/__tests__/cli-cmd-credits.test.js dist/__tests__/cli-cmd-db.test.js dist/__tests__/cli-cmd-deploy.test.js dist/__tests__/cli-cmd-domain.test.js dist/__tests__/cli-cmd-email.test.js dist/__tests__/cli-cmd-file.test.js dist/__tests__/cli-cmd-fn.test.js dist/__tests__/cli-cmd-service.test.js dist/__tests__/cli-cmd-job.test.js dist/__tests__/cli-cmd-generate.test.js dist/__tests__/cli-cmd-gmail.test.js dist/__tests__/cli-cmd-info.test.js dist/__tests__/cli-cmd-init.test.js dist/__tests__/cli-cmd-location.test.js dist/__tests__/cli-cmd-text.test.js dist/__tests__/cli-cmd-login.test.js dist/__tests__/cli-cmd-logout.test.js dist/__tests__/cli-cmd-token.test.js dist/__tests__/cli-cmd-logs.test.js dist/__tests__/cli-cmd-memory.test.js dist/__tests__/cli-cmd-page.test.js dist/__tests__/cli-cmd-plan.test.js dist/__tests__/cli-cmd-project.test.js dist/__tests__/cli-cmd-rbac.test.js dist/__tests__/cli-cmd-realtime.test.js dist/__tests__/cli-cmd-records.test.js dist/__tests__/cli-cmd-relay.test.js dist/__tests__/cli-cmd-sandbox.test.js dist/__tests__/cli-cmd-add.test.js dist/__tests__/cli-cmd-remove.test.js dist/__tests__/cli-cmd-skill.test.js dist/__tests__/cli-cmd-test.test.js dist/__tests__/cli-cmd-workflow.test.js dist/__tests__/setup-skills-block.test.js dist/__tests__/setup-hooks.test.js",
|
|
15
|
+
"test:smoke": "tsc && node --test dist/__tests__/utils.test.js dist/__tests__/colors.test.js dist/__tests__/config.test.js dist/__tests__/sync.test.js dist/__tests__/sync-apply.test.js dist/__tests__/sync-lock.test.js dist/__tests__/auth-lock.test.js dist/__tests__/push-cas.test.js dist/__tests__/upload.test.js dist/__tests__/progress.test.js dist/__tests__/updater.test.js dist/__tests__/cli-smoke.test.js dist/__tests__/claude-noninteractive.test.js dist/__tests__/claude-trust.test.js dist/__tests__/relay-state.test.js dist/__tests__/relay-daemon.test.js dist/__tests__/relay-installers.test.js dist/__tests__/relay-bridge-abort.test.js dist/__tests__/relay-redact.test.js dist/__tests__/relay-machine-id.test.js dist/__tests__/stream-json.test.js dist/__tests__/relay-ingest-contract.test.js dist/__tests__/prompts.test.js dist/__tests__/capture-transcript.test.js dist/__tests__/flag-aliases.test.js dist/__tests__/adopt-cwd.test.js dist/__tests__/cli-cmd-agent.test.js dist/__tests__/cli-cmd-approval.test.js dist/__tests__/cli-cmd-audit.test.js dist/__tests__/cli-cmd-chat.test.js dist/__tests__/cli-cmd-credits.test.js dist/__tests__/cli-cmd-db.test.js dist/__tests__/cli-cmd-deploy.test.js dist/__tests__/cli-cmd-domain.test.js dist/__tests__/cli-cmd-email.test.js dist/__tests__/cli-cmd-file.test.js dist/__tests__/cli-cmd-fn.test.js dist/__tests__/cli-cmd-service.test.js dist/__tests__/cli-cmd-job.test.js dist/__tests__/cli-cmd-generate.test.js dist/__tests__/cli-cmd-gmail.test.js dist/__tests__/cli-cmd-info.test.js dist/__tests__/cli-cmd-init.test.js dist/__tests__/cli-cmd-location.test.js dist/__tests__/cli-cmd-text.test.js dist/__tests__/cli-cmd-login.test.js dist/__tests__/cli-cmd-logout.test.js dist/__tests__/cli-cmd-token.test.js dist/__tests__/cli-cmd-logs.test.js dist/__tests__/cli-cmd-memory.test.js dist/__tests__/cli-cmd-page.test.js dist/__tests__/cli-cmd-plan.test.js dist/__tests__/cli-cmd-project.test.js dist/__tests__/cli-cmd-rbac.test.js dist/__tests__/cli-cmd-realtime.test.js dist/__tests__/cli-cmd-records.test.js dist/__tests__/cli-cmd-relay.test.js dist/__tests__/cli-cmd-sandbox.test.js dist/__tests__/cli-cmd-add.test.js dist/__tests__/cli-cmd-remove.test.js dist/__tests__/cli-cmd-skill.test.js dist/__tests__/cli-cmd-test.test.js dist/__tests__/cli-cmd-workflow.test.js dist/__tests__/setup-skills-block.test.js dist/__tests__/setup-hooks.test.js",
|
|
16
16
|
"test:e2e": "tsc && GIPITY_E2E=1 node --test --test-timeout=180000 dist/__tests__/cli-e2e-live.test.js dist/__tests__/cli-e2e-services-media-live.test.js dist/__tests__/cli-e2e-workflow-live.test.js dist/__tests__/cli-e2e-sandbox-live.test.js dist/__tests__/cli-e2e-page-fetch-live.test.js dist/__tests__/cli-e2e-page-test-live.test.js",
|
|
17
17
|
"test:e2e:sandbox": "tsc && GIPITY_E2E=1 node --test --test-timeout=180000 dist/__tests__/cli-e2e-sandbox-live.test.js"
|
|
18
18
|
},
|