gipity 1.0.406 → 1.0.408
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/banner.js +16 -1
- package/dist/commands/claude.js +9 -9
- package/dist/commands/sandbox.js +5 -0
- package/dist/commands/test.js +6 -0
- package/dist/knowledge.js +2 -0
- package/dist/platform.js +53 -6
- package/dist/relay/daemon.js +8 -30
- package/dist/relay/installers.js +10 -2
- package/dist/setup.js +4 -4
- package/dist/updater/bootstrap.js +2 -3
- package/dist/updater/check.js +2 -3
- package/package.json +3 -4
- package/hooks/post-write.sh +0 -17
- package/hooks/pre-turn.sh +0 -20
package/dist/banner.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
// ── Gipity CLI Startup Banner ──────────────────────────────────────────
|
|
2
2
|
// Two-panel box showing all AI models, platform tools, and sandbox capabilities.
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { sep } from 'path';
|
|
3
5
|
import { brand, bold, faint, muted, fg } from './colors.js';
|
|
6
|
+
/** Abbreviate a home-relative path to `~`, cross-platform. On Windows `HOME`
|
|
7
|
+
* is usually unset (it's `USERPROFILE`), and `str.replace('', '~')` prepends
|
|
8
|
+
* a stray `~`, so use os.homedir() and a real prefix check. */
|
|
9
|
+
function tildify(p) {
|
|
10
|
+
const home = homedir();
|
|
11
|
+
if (!home)
|
|
12
|
+
return p;
|
|
13
|
+
if (p === home)
|
|
14
|
+
return '~';
|
|
15
|
+
if (p.startsWith(home + sep))
|
|
16
|
+
return '~' + p.slice(home.length);
|
|
17
|
+
return p;
|
|
18
|
+
}
|
|
4
19
|
// ── Static content ─────────────────────────────────────────────────────
|
|
5
20
|
// ── Feature groups ────────────────────────────────────────────────────
|
|
6
21
|
const AI_MODELS = [
|
|
@@ -174,7 +189,7 @@ function buildLeftPanel(opts, panelW) {
|
|
|
174
189
|
leftLines.push(center(line, panelW));
|
|
175
190
|
}
|
|
176
191
|
if (opts.cwd) {
|
|
177
|
-
const short = leadingEllipsify(opts.cwd
|
|
192
|
+
const short = leadingEllipsify(tildify(opts.cwd), panelW);
|
|
178
193
|
leftLines.push('');
|
|
179
194
|
leftLines.push(center(muted(short), panelW));
|
|
180
195
|
leftLines.push('');
|
package/dist/commands/claude.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import { join, dirname, resolve, basename } from 'path';
|
|
2
|
+
import { join, dirname, resolve, basename, sep } from 'path';
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, readdirSync, statSync } from 'fs';
|
|
4
|
-
import { spawn } from 'child_process';
|
|
5
4
|
import { homedir } from 'os';
|
|
6
5
|
import { fileURLToPath } from 'url';
|
|
7
|
-
import { resolveCommand } from '../platform.js';
|
|
6
|
+
import { resolveCommand, spawnCommand } from '../platform.js';
|
|
8
7
|
import { getAuth, saveAuth, sessionExpired, accessTokenExpired, refreshTokenIfNeeded } from '../auth.js';
|
|
9
8
|
import { get, post, publicPost, ApiError, getAccountSlug } from '../api.js';
|
|
10
9
|
import { getConfig, saveConfigAt, clearConfigCache, getApiBaseOverride, DEFAULT_API_BASE, getConfigPath } from '../config.js';
|
|
@@ -234,7 +233,7 @@ export const claudeCommand = new Command('claude')
|
|
|
234
233
|
// Forwarded to `claude` via the unknown-arg passthrough below (NOT in the
|
|
235
234
|
// gipity strip lists). Declared here only so it shows up in --help — without
|
|
236
235
|
// this, callers can't discover that the session model is selectable.
|
|
237
|
-
.option('--model <model>', 'Model for the Claude session, forwarded to claude (e.g. sonnet, opus, or a full id like claude-sonnet-
|
|
236
|
+
.option('--model <model>', 'Model for the Claude session, forwarded to claude (e.g. sonnet, opus, or a full id like claude-sonnet-5)')
|
|
238
237
|
.allowUnknownOption(true)
|
|
239
238
|
.allowExcessArguments(true)
|
|
240
239
|
.action(async (opts) => {
|
|
@@ -822,8 +821,9 @@ export const claudeCommand = new Command('claude')
|
|
|
822
821
|
allArgs.push('--verbose');
|
|
823
822
|
}
|
|
824
823
|
}
|
|
825
|
-
// Resolve
|
|
826
|
-
//
|
|
824
|
+
// Resolve the real path on Windows; spawnCommand then routes the `.cmd`
|
|
825
|
+
// shim through cmd.exe with verbatim args (a bare `spawn` of a `.cmd`
|
|
826
|
+
// throws EINVAL on Node >=18.20.2/20.12.2 - the CVE-2024-27980 fix).
|
|
827
827
|
const claudeCmd = resolveCommand('claude');
|
|
828
828
|
const childEnv = { ...process.env };
|
|
829
829
|
// Gate hook-based capture: when the daemon is streaming via
|
|
@@ -844,7 +844,7 @@ export const claudeCommand = new Command('claude')
|
|
|
844
844
|
// `-p` runs skip the dialog already, so this is only needed interactively.
|
|
845
845
|
if (!nonInteractive)
|
|
846
846
|
markFolderTrusted(process.cwd());
|
|
847
|
-
const child =
|
|
847
|
+
const child = spawnCommand(claudeCmd, allArgs, {
|
|
848
848
|
stdio: 'inherit',
|
|
849
849
|
cwd: process.cwd(),
|
|
850
850
|
env: childEnv,
|
|
@@ -945,10 +945,10 @@ function formatNewProjectLabel(existingSlugs) {
|
|
|
945
945
|
const slug = suggestProjectName(existingSlugs);
|
|
946
946
|
const root = getProjectsRoot();
|
|
947
947
|
const home = homedir();
|
|
948
|
-
const display = root.startsWith(home +
|
|
948
|
+
const display = root === home || root.startsWith(home + sep)
|
|
949
949
|
? '~' + root.slice(home.length)
|
|
950
950
|
: root;
|
|
951
|
-
return `${display}
|
|
951
|
+
return `${display}${sep}${slug}`;
|
|
952
952
|
}
|
|
953
953
|
/** Run the size-tier scan, surface the right UX:
|
|
954
954
|
* - easy → silent, return true.
|
package/dist/commands/sandbox.js
CHANGED
|
@@ -190,6 +190,11 @@ GCC/Rust).
|
|
|
190
190
|
if (res.data.autoMirrorSkipped) {
|
|
191
191
|
console.error(dim(`Note: ${res.data.autoMirrorSkipped.reason}`));
|
|
192
192
|
}
|
|
193
|
+
if (res.data.mirrorWarnings && res.data.mirrorWarnings.length > 0) {
|
|
194
|
+
console.error(dim(`Note: ${res.data.mirrorWarnings.length} project file(s) could not be mirrored into the sandbox and were skipped:`));
|
|
195
|
+
for (const w of res.data.mirrorWarnings)
|
|
196
|
+
console.error(dim(` - ${w}`));
|
|
197
|
+
}
|
|
193
198
|
if (res.data.stdout)
|
|
194
199
|
console.log(res.data.stdout);
|
|
195
200
|
if (res.data.stderr)
|
package/dist/commands/test.js
CHANGED
|
@@ -168,6 +168,12 @@ export const testCommand = new Command('test')
|
|
|
168
168
|
console.log(clrError(`No tests matched filter: ${filterPath}`));
|
|
169
169
|
process.exit(1);
|
|
170
170
|
}
|
|
171
|
+
if (!filterPath && data.total === 0 && data.results.length === 0) {
|
|
172
|
+
console.log(muted('No tests ran - this app has no tests/*.test.js files.'));
|
|
173
|
+
console.log(muted('gipity test runs server-function tests only; a frontend-only app (no functions/) has nothing here to run.'));
|
|
174
|
+
console.log(muted('Verify a frontend app by driving the live page: gipity page inspect <url> (or gipity page eval).'));
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
171
177
|
if (data.status === 'failed' && data.errorMessage) {
|
|
172
178
|
console.log(clrError(`Run failed: ${data.errorMessage}`));
|
|
173
179
|
console.log('');
|
package/dist/knowledge.js
CHANGED
|
@@ -155,8 +155,10 @@ App services skills (load before calling \`/services/*\` endpoints):
|
|
|
155
155
|
|
|
156
156
|
App development skills:
|
|
157
157
|
- \`agent-deploy\` - headless auth via agent API tokens (GIPITY_TOKEN) for unattended deploys
|
|
158
|
+
- \`app-database\` - app Postgres database: migrations, the db helper, transactions, table permissions
|
|
158
159
|
- \`app-debugging\` - debug a deployed app: page inspect/eval, screenshots, function logs
|
|
159
160
|
- \`app-development\` - functions, database, and API
|
|
161
|
+
- \`app-testing\` - testing deployed app functions (ctx.fn.call/callAs, the isolated test DB)
|
|
160
162
|
- \`deploy\` - the deploy pipeline & gipity.yaml manifest
|
|
161
163
|
- \`jobs\` - long-running CPU + GPU compute jobs (Python / Node / bash)
|
|
162
164
|
- \`realtime-scheduled-app\` - recipe: realtime presence/messages + DB function + scheduled poster, end-to-end
|
package/dist/platform.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { execSync } from 'child_process';
|
|
1
|
+
import { execSync, spawn, spawnSync } from 'child_process';
|
|
2
2
|
/**
|
|
3
|
-
* Resolve a command to
|
|
3
|
+
* Resolve a command to a concrete path when possible.
|
|
4
4
|
*
|
|
5
5
|
* On Windows, npm-installed CLIs (npm, npx, gipity, claude) are `.cmd` batch
|
|
6
|
-
* shims, not `.exe`s.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* shims, not `.exe`s. A bare `npm` fails to spawn with ENOENT, so we resolve
|
|
7
|
+
* the real path (preferring a native `.exe`, falling back to the `.cmd` shim).
|
|
8
|
+
*
|
|
9
|
+
* NOTE: resolving to the `.cmd` path is NOT enough on its own. Since Node
|
|
10
|
+
* 18.20.2 / 20.12.2 (the CVE-2024-27980 fix), `spawn`/`spawnSync` REFUSE to
|
|
11
|
+
* launch a `.cmd`/`.bat` target unless `shell: true` - they throw `EINVAL`.
|
|
12
|
+
* So always launch a resolved command through `spawnCommand` /
|
|
13
|
+
* `spawnSyncCommand` below, which route batch shims through cmd.exe safely.
|
|
10
14
|
*/
|
|
11
15
|
export function resolveCommand(cmd) {
|
|
12
16
|
if (process.platform !== 'win32')
|
|
@@ -23,4 +27,47 @@ export function resolveCommand(cmd) {
|
|
|
23
27
|
return `${cmd}.cmd`;
|
|
24
28
|
}
|
|
25
29
|
}
|
|
30
|
+
/** True for a Windows batch shim that Node cannot spawn without a shell. */
|
|
31
|
+
export function isBatchShim(cmd) {
|
|
32
|
+
return process.platform === 'win32' && /\.(cmd|bat)$/i.test(cmd);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build a cmd.exe invocation that launches a `.cmd`/`.bat` shim with its args
|
|
36
|
+
* passed through verbatim - the correct way to run a batch file post-CVE
|
|
37
|
+
* without `shell: true` mangling argument quoting.
|
|
38
|
+
*
|
|
39
|
+
* `cmd.exe /d /s /c "<line>"`: `/d` skips AutoRun, `/s` + the wrapping outer
|
|
40
|
+
* quotes make cmd strip exactly the first and last quote of the whole line
|
|
41
|
+
* (leaving each already-quoted token intact). We quote every token ourselves
|
|
42
|
+
* and set `windowsVerbatimArguments` so Node hands our line to cmd untouched.
|
|
43
|
+
*/
|
|
44
|
+
export function winBatchInvocation(cmd, args) {
|
|
45
|
+
const comspec = process.env.ComSpec || 'cmd.exe';
|
|
46
|
+
// Double-quote each token; escape any embedded double-quote as "" (cmd's
|
|
47
|
+
// in-quote escape). Our call sites pass flags/paths/guids with no cmd
|
|
48
|
+
// metacharacters, so this conservative quoting is sufficient and safe.
|
|
49
|
+
const quote = (t) => `"${String(t).replace(/"/g, '""')}"`;
|
|
50
|
+
const line = [cmd, ...args].map(quote).join(' ');
|
|
51
|
+
return { file: comspec, args: ['/d', '/s', '/c', `"${line}"`] };
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Drop-in `spawn` that survives Windows batch shims. When `cmd` is a `.cmd`/
|
|
55
|
+
* `.bat` on win32, it is launched via cmd.exe with verbatim arguments;
|
|
56
|
+
* otherwise this is a plain `spawn`. Use for anything from `resolveCommand`.
|
|
57
|
+
*/
|
|
58
|
+
export function spawnCommand(cmd, args = [], options = {}) {
|
|
59
|
+
if (isBatchShim(cmd)) {
|
|
60
|
+
const inv = winBatchInvocation(cmd, args);
|
|
61
|
+
return spawn(inv.file, inv.args, { ...options, windowsVerbatimArguments: true });
|
|
62
|
+
}
|
|
63
|
+
return spawn(cmd, [...args], options);
|
|
64
|
+
}
|
|
65
|
+
/** Drop-in `spawnSync` counterpart of {@link spawnCommand}. */
|
|
66
|
+
export function spawnSyncCommand(cmd, args = [], options = {}) {
|
|
67
|
+
if (isBatchShim(cmd)) {
|
|
68
|
+
const inv = winBatchInvocation(cmd, args);
|
|
69
|
+
return spawnSync(inv.file, inv.args, { ...options, windowsVerbatimArguments: true });
|
|
70
|
+
}
|
|
71
|
+
return spawnSync(cmd, [...args], options);
|
|
72
|
+
}
|
|
26
73
|
//# sourceMappingURL=platform.js.map
|
package/dist/relay/daemon.js
CHANGED
|
@@ -1,27 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Gipity relay daemon - the `gipity-relay` long-running helper that backs
|
|
3
|
-
* `gipity relay run`. Runs two concurrent loops against the paired Gipity
|
|
4
|
-
* account using the device's bearer token:
|
|
5
|
-
*
|
|
6
|
-
* 1. Heartbeat every 60s → POST /remote-devices/heartbeat. Drives the
|
|
7
|
-
* web CLI's presence indicator.
|
|
8
|
-
* 2. Long-poll → GET /remote-devices/next. On a 200 claim, look up the
|
|
9
|
-
* dispatch's project in the local allowlist, spawn `gipity claude -p
|
|
10
|
-
* "<msg>"` in that project's cwd, wait for it to exit, POST ack.
|
|
11
|
-
*
|
|
12
|
-
* The conversation stream (prompts, tool calls, assistant output) flows
|
|
13
|
-
* back to the web CLI *automatically* via the capture hooks installed in
|
|
14
|
-
* `.claude/settings.json` - the daemon itself doesn't forward content.
|
|
15
|
-
*
|
|
16
|
-
* Graceful exit:
|
|
17
|
-
* - SIGINT / SIGTERM → stop both loops, wait for in-flight child, exit 0.
|
|
18
|
-
* - 401 from heartbeat or /next → device was revoked; exit 0.
|
|
19
|
-
* - Any other backend error → log and retry with exponential backoff.
|
|
20
|
-
*
|
|
21
|
-
* See docs/feature-backlog/gipity-relay-phases.md (Phase A Step 7).
|
|
22
|
-
*/
|
|
23
|
-
import { spawn } from 'child_process';
|
|
24
|
-
import { resolveCommand } from '../platform.js';
|
|
1
|
+
import { resolveCommand, spawnCommand } from '../platform.js';
|
|
25
2
|
import { appendFileSync, mkdirSync, existsSync, readFileSync, writeFileSync, chmodSync, closeSync, openSync, unlinkSync } from 'fs';
|
|
26
3
|
import { stat, readFile } from 'fs/promises';
|
|
27
4
|
import { createInterface } from 'readline';
|
|
@@ -528,14 +505,15 @@ function isSafeSessionId(s) {
|
|
|
528
505
|
return /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(s);
|
|
529
506
|
}
|
|
530
507
|
/** Resolve Claude Code's on-disk transcript path for measuring resume
|
|
531
|
-
* size. Claude encodes the project cwd into a slug by replacing
|
|
532
|
-
*
|
|
533
|
-
*
|
|
508
|
+
* size. Claude encodes the project cwd into a slug by replacing every
|
|
509
|
+
* non-alphanumeric char with `-` (so `/`, and on Windows `\` and `:`, all
|
|
510
|
+
* collapse). We only read this file cosmetically (to show "resume 5 KB" in
|
|
511
|
+
* the Invoking marker); actual capture is via stream-json. Returns null for
|
|
534
512
|
* a sessionId that fails the safety check. */
|
|
535
513
|
function transcriptPathFor(cwd, sessionId) {
|
|
536
514
|
if (!isSafeSessionId(sessionId))
|
|
537
515
|
return null;
|
|
538
|
-
const slug = cwd.replace(
|
|
516
|
+
const slug = cwd.replace(/[^a-zA-Z0-9]/g, '-');
|
|
539
517
|
return join(homedir(), '.claude', 'projects', slug, `${sessionId}.jsonl`);
|
|
540
518
|
}
|
|
541
519
|
/** `18.4s` when under a minute, `3:12.2` above. */
|
|
@@ -867,7 +845,7 @@ async function spawnSync(cwd, timeoutMs) {
|
|
|
867
845
|
// verbatim (it may be a full path); only the default name is resolved.
|
|
868
846
|
const cmd = process.env.GIPITY_RELAY_CLAUDE_CMD || resolveCommand('gipity');
|
|
869
847
|
return new Promise((resolve, reject) => {
|
|
870
|
-
const child =
|
|
848
|
+
const child = spawnCommand(cmd, ['sync', '--json'], {
|
|
871
849
|
cwd,
|
|
872
850
|
env: process.env,
|
|
873
851
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
@@ -921,7 +899,7 @@ export async function spawnGipityClaude(args, cwd, d) {
|
|
|
921
899
|
const fullArgs = [...args, '--output-format', 'stream-json', '--verbose'];
|
|
922
900
|
const env = { ...process.env, GIPITY_CONVERSATION_GUID: d.conversation_guid };
|
|
923
901
|
return new Promise((resolve, reject) => {
|
|
924
|
-
const child =
|
|
902
|
+
const child = spawnCommand(cmd, fullArgs, { cwd, env, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
925
903
|
// `exited` fires when the child fully unwinds (exit event). Callers
|
|
926
904
|
// like `killRunningForConv` await this before spawning a replacement
|
|
927
905
|
// so the outgoing child has a chance to post its cancelled marker
|
package/dist/relay/installers.js
CHANGED
|
@@ -126,6 +126,14 @@ WantedBy=default.target
|
|
|
126
126
|
function windowsTaskPlan(cliPath) {
|
|
127
127
|
const taskName = 'GipityRelay';
|
|
128
128
|
const path = join(homedir(), 'AppData', 'Local', 'Gipity', 'relay-task.xml');
|
|
129
|
+
// Launch through node.exe explicitly. Task Scheduler's <Command> runs the
|
|
130
|
+
// target via CreateProcess, and a `.js` cliPath (what resolveCliPath yields)
|
|
131
|
+
// would resolve to its file association - Windows Script Host - which chokes
|
|
132
|
+
// on the shebang with "Invalid character" (800A03F6). Passing the entry as a
|
|
133
|
+
// node argument runs it under Node like every other platform.
|
|
134
|
+
const runsViaNode = /\.[cm]?js$/i.test(cliPath);
|
|
135
|
+
const command = runsViaNode ? process.execPath : cliPath;
|
|
136
|
+
const argLine = runsViaNode ? `"${cliPath}" relay run` : 'relay run';
|
|
129
137
|
const content = `<?xml version="1.0" encoding="UTF-16"?>
|
|
130
138
|
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
131
139
|
<RegistrationInfo>
|
|
@@ -151,8 +159,8 @@ function windowsTaskPlan(cliPath) {
|
|
|
151
159
|
</Settings>
|
|
152
160
|
<Actions>
|
|
153
161
|
<Exec>
|
|
154
|
-
<Command>${
|
|
155
|
-
<Arguments
|
|
162
|
+
<Command>${command}</Command>
|
|
163
|
+
<Arguments>${argLine}</Arguments>
|
|
156
164
|
</Exec>
|
|
157
165
|
</Actions>
|
|
158
166
|
</Task>
|
package/dist/setup.js
CHANGED
|
@@ -5,7 +5,7 @@ import { resolve, join, dirname } from 'path';
|
|
|
5
5
|
import { homedir } from 'os';
|
|
6
6
|
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
7
7
|
import { spawnSync } from 'child_process';
|
|
8
|
-
import { resolveCommand } from './platform.js';
|
|
8
|
+
import { resolveCommand, spawnSyncCommand } from './platform.js';
|
|
9
9
|
import { SKILLS_CONTENT, BUILD_VS_NON_BUILD_RULE, DEFINITION_OF_DONE } from './knowledge.js';
|
|
10
10
|
export { SKILLS_CONTENT };
|
|
11
11
|
/** Canonical list of workstation artifacts that are NOT part of the project.
|
|
@@ -137,7 +137,7 @@ export const GIPITY_MARKETPLACE_REPO = 'GipityAI/claude-plugin';
|
|
|
137
137
|
// an installed plugin when the marketplace advances - only an explicit
|
|
138
138
|
// `plugin install`/`update` does - so this constant is how a CLI upgrade tells
|
|
139
139
|
// ensureGipityPluginInstalled() to refresh a stale user-scope install.
|
|
140
|
-
export const GIPITY_PLUGIN_VERSION = '0.4.
|
|
140
|
+
export const GIPITY_PLUGIN_VERSION = '0.4.1';
|
|
141
141
|
/** True for hook commands the CLI itself wrote into settings.json in past
|
|
142
142
|
* versions. Matched by signature so migration strips exactly our own
|
|
143
143
|
* entries and never touches user-authored hooks. */
|
|
@@ -288,11 +288,11 @@ export function ensureGipityPluginInstalled() {
|
|
|
288
288
|
// without an explicit path, so resolve it (otherwise the install silently
|
|
289
289
|
// ENOENTs and the plugin's hooks never land at user scope).
|
|
290
290
|
const claudeCmd = resolveCommand('claude');
|
|
291
|
-
|
|
291
|
+
spawnSyncCommand(claudeCmd, ['plugin', 'marketplace', 'update', GIPITY_MARKETPLACE_NAME], {
|
|
292
292
|
stdio: 'ignore',
|
|
293
293
|
timeout: 120_000,
|
|
294
294
|
});
|
|
295
|
-
|
|
295
|
+
spawnSyncCommand(claudeCmd, ['plugin', 'install', GIPITY_PLUGIN_ID, '--scope', 'user'], {
|
|
296
296
|
stdio: 'ignore',
|
|
297
297
|
timeout: 120_000,
|
|
298
298
|
});
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
2
|
-
import { spawnSync } from 'child_process';
|
|
3
2
|
import { join } from 'path';
|
|
4
3
|
import { LOCAL_DIR, LOCAL_ENTRY, LOCAL_PKG_DIR, writeState, readState } from './state.js';
|
|
5
|
-
import { resolveCommand } from '../platform.js';
|
|
4
|
+
import { resolveCommand, spawnSyncCommand } from '../platform.js';
|
|
6
5
|
export function isBootstrapped() {
|
|
7
6
|
return existsSync(LOCAL_ENTRY);
|
|
8
7
|
}
|
|
@@ -26,7 +25,7 @@ export function bootstrap(version, quiet = false) {
|
|
|
26
25
|
// --ignore-scripts: don't run install lifecycle hooks (gipity ships
|
|
27
26
|
// precompiled, deps need no build), so a compromised package can't execute
|
|
28
27
|
// code during this self-managed install.
|
|
29
|
-
const res =
|
|
28
|
+
const res = spawnSyncCommand(resolveCommand('npm'), ['install', '--no-audit', '--no-fund', '--ignore-scripts', `gipity@${version}`], {
|
|
30
29
|
cwd: LOCAL_DIR,
|
|
31
30
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
32
31
|
encoding: 'utf-8',
|
package/dist/updater/check.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// Background updater. Invoked detached by the shim; can also be invoked
|
|
3
3
|
// directly by `gipity update --force`.
|
|
4
|
-
import { spawnSync } from 'child_process';
|
|
5
4
|
import { appendFileSync, existsSync } from 'fs';
|
|
6
5
|
import { LOCAL_DIR, LOCAL_ENTRY, UPDATE_LOG, readState, writeState, updatesDisabled } from './state.js';
|
|
7
|
-
import { resolveCommand } from '../platform.js';
|
|
6
|
+
import { resolveCommand, spawnSyncCommand } from '../platform.js';
|
|
8
7
|
const CHECK_INTERVAL_MS = 4 * 60 * 60 * 1000; // 4 hours
|
|
9
8
|
function log(line) {
|
|
10
9
|
try {
|
|
@@ -38,7 +37,7 @@ function installVersion(version) {
|
|
|
38
37
|
// --ignore-scripts: this runs unattended in the background, so don't let a
|
|
39
38
|
// compromised package's install lifecycle hooks execute. gipity ships
|
|
40
39
|
// precompiled (dist/) and its deps need no build step, so nothing is lost.
|
|
41
|
-
const res =
|
|
40
|
+
const res = spawnSyncCommand(resolveCommand('npm'), ['install', '--silent', '--no-audit', '--no-fund', '--ignore-scripts', `gipity@${version}`], {
|
|
42
41
|
cwd: LOCAL_DIR,
|
|
43
42
|
stdio: 'ignore',
|
|
44
43
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gipity",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.408",
|
|
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",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"postbuild": "node scripts/gen-build-info.mjs",
|
|
14
14
|
"dev": "tsc --watch",
|
|
15
15
|
"test": "npm run test:smoke",
|
|
16
|
-
"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__/api-401-retry.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__/client-context.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-doctor.test.js dist/__tests__/claude-setup.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
|
+
"test:smoke": "tsc && node --test dist/__tests__/utils.test.js dist/__tests__/platform.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__/api-401-retry.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__/client-context.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-doctor.test.js dist/__tests__/claude-setup.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",
|
|
17
17
|
"test:e2e": "tsc && GIPITY_E2E=1 node --test --test-timeout=180000 dist/__tests__/cli-e2e-live.test.js dist/__tests__/cli-e2e-sync-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",
|
|
18
18
|
"test:e2e:sync": "tsc && GIPITY_E2E=1 node --test --test-timeout=180000 dist/__tests__/cli-e2e-sync-live.test.js",
|
|
19
19
|
"test:e2e:sandbox": "tsc && GIPITY_E2E=1 node --test --test-timeout=180000 dist/__tests__/cli-e2e-sandbox-live.test.js"
|
|
@@ -33,8 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"files": [
|
|
35
35
|
"dist/**/*.js",
|
|
36
|
-
"!dist/__tests__/**"
|
|
37
|
-
"hooks"
|
|
36
|
+
"!dist/__tests__/**"
|
|
38
37
|
],
|
|
39
38
|
"license": "MIT"
|
|
40
39
|
}
|
package/hooks/post-write.sh
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# PostToolUse hook: push file to Gipity after Write/Edit
|
|
3
|
-
# Runs after CC's Write or Edit tool. Fires gipity push in background.
|
|
4
|
-
|
|
5
|
-
INPUT=$(cat)
|
|
6
|
-
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
|
|
7
|
-
|
|
8
|
-
# Skip if no file path extracted
|
|
9
|
-
[ -z "$FILE_PATH" ] && exit 0
|
|
10
|
-
|
|
11
|
-
# Skip if not a Gipity project
|
|
12
|
-
[ ! -f ".gipity.json" ] && exit 0
|
|
13
|
-
|
|
14
|
-
# Push in background, suppress output
|
|
15
|
-
gipity push "$FILE_PATH" --quiet &
|
|
16
|
-
disown
|
|
17
|
-
exit 0
|
package/hooks/pre-turn.sh
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# UserPromptSubmit hook: sync check before each CC turn
|
|
3
|
-
# Pulls remote changes and reports diff as systemMessage.
|
|
4
|
-
|
|
5
|
-
# Skip if not a Gipity project
|
|
6
|
-
[ ! -f ".gipity.json" ] && exit 0
|
|
7
|
-
|
|
8
|
-
# Sync down with JSON output
|
|
9
|
-
RESULT=$(gipity sync down --json 2>/dev/null)
|
|
10
|
-
|
|
11
|
-
# Check if any files were pulled
|
|
12
|
-
PULLED=$(echo "$RESULT" | jq -r '.pulled // 0' 2>/dev/null)
|
|
13
|
-
|
|
14
|
-
if [ "$PULLED" -gt 0 ]; then
|
|
15
|
-
SUMMARY=$(echo "$RESULT" | jq -r '.summary // "Files changed remotely."' 2>/dev/null)
|
|
16
|
-
# Output systemMessage so CC sees the diff
|
|
17
|
-
echo "{\"systemMessage\": \"Gipity sync: ${SUMMARY}\"}"
|
|
18
|
-
fi
|
|
19
|
-
|
|
20
|
-
exit 0
|