gipity 1.0.422 → 1.0.424
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/add.js +8 -3
- package/dist/commands/claude.js +20 -2
- package/dist/commands/deploy.js +29 -1
- package/dist/commands/page-eval.js +12 -2
- package/dist/commands/page-inspect.js +200 -185
- package/dist/commands/push.js +12 -7
- package/dist/commands/sandbox.js +55 -14
- package/dist/commands/test.js +13 -0
- package/dist/helpers/sync.js +8 -1
- package/dist/index.js +19930 -386
- package/dist/knowledge.js +6 -5
- package/dist/sync.js +29 -0
- package/dist/updater/check.js +159 -84
- package/dist/updater/shim.js +153 -71
- package/package.json +5 -3
package/dist/knowledge.js
CHANGED
|
@@ -37,9 +37,9 @@ Kits are reusable building blocks added to an existing app, not whole templates
|
|
|
37
37
|
- \`gipity add chatbot\` - Drop-in chatbot - configurable persona, scope guardrails, static knowledge (20k budget), streaming responses. Headless engine + bubble widget; bring your own UI if you want. Works in any app.
|
|
38
38
|
- \`gipity add audio-align\` - Audio + lyrics -> word-level timing JSON. Demucs vocal isolation + MMS_FA forced alignment, runs as a Modal L4 GPU job (~$0.01 per 3-min song). For karaoke captions, subtitling, language learning, dubbing alignment.
|
|
39
39
|
- \`gipity add i18n\` - Multi-language for web apps - language picker, locale persistence, RTL, plural/translation lookup. Scaffolds src/js/strings.js and wires it up; move your copy there and read it with t('key'). Web only.
|
|
40
|
-
- \`gipity add records\` - Registry-driven records: declare objects/fields as data, get generic CRUD functions with validation, full-text search, soft delete, ACTOR provenance, and an audit event spine - every write is transactional (row + event). Field types include relations ({id,label}), currency, emails/phones/links composites. Ships backend functions + migrations. Needs a database (web-fullstack/api template).
|
|
41
|
-
- \`gipity add views\` - Generic UI over records-kit objects: sortable/filterable table with full-text search, create/edit/delete forms with type-appropriate widgets, kanban board with drag-to-update. Renders entirely from the field registry - zero per-object UI code. Requires the records kit.
|
|
42
|
-
- \`gipity add agent-api\` - Make your app agent-operable: named API keys (kit_api_keys) let agents and scripts write through the records kit's single write path with AGENT/API actor attribution - machine writes land on the same audit spine as human edits. Requires the records kit.
|
|
40
|
+
- \`gipity add records\` - Registry-driven records: declare objects/fields as data, get generic CRUD functions with validation, full-text search, soft delete, ACTOR provenance, and an audit event spine - every write is transactional (row + event). Field types include relations ({id,label}), currency, emails/phones/links composites. Ships backend functions + migrations. Needs a database (web-fullstack/api template). See the \`app-records\` skill.
|
|
41
|
+
- \`gipity add views\` - Generic UI over records-kit objects: sortable/filterable table with full-text search, create/edit/delete forms with type-appropriate widgets, kanban board with drag-to-update. Renders entirely from the field registry - zero per-object UI code. Requires the records kit. See the \`app-records\` skill.
|
|
42
|
+
- \`gipity add agent-api\` - Make your app agent-operable: named API keys (kit_api_keys) let agents and scripts write through the records kit's single write path with AGENT/API actor attribution - machine writes land on the same audit spine as human edits. Requires the records kit. See the \`app-records\` skill.
|
|
43
43
|
- \`gipity add contacts\` - Source-agnostic contact data layer for lead-gen/CRM apps: import people from LinkedIn CSV + Gmail + pasted lists, resolve duplicates into one person while keeping EVERY value from every source with provenance (multi-valued attributes, never overwrites). Exact email/URL auto-merge; fuzzy name+company goes to a human merge-review queue (reversible). Re-imports detect job changes and emit signals. User-definable tags, full-text search, and a transactional event spine. Ships backend functions + migrations. Needs a database (web-fullstack/api template).
|
|
44
44
|
- \`gipity add stripe\` - Charge your app's end-users for one-time purchases and subscriptions via Stripe. Owner connects their own Stripe account through Gipity-hosted onboarding (no API keys to paste); money lands in their account, Gipity takes a small platform fee. Ships a buy-button / pricing component, a subscription-status helper for gating UI, a webhook-verified fulfillment function, and the payments/subscriptions tables. The platform brokers checkout + signature-verified webhooks. Needs a database (web-fullstack/api template).
|
|
45
45
|
- \`gipity add notify\` - Web push notifications for any web app, including iOS home-screen web apps (iOS 16.4+). The platform owns the VAPID keys, encryption, and delivery — no keys to paste, no crypto, no server. Ships a <gipity-notify-button>, a service worker, and a PWA manifest; the device subscribes itself and self-heals stale subscriptions. Send from a function with the injected notify() service (one flat credit per send, owner-billed) or test with \`gipity notify test\`. Works in any template — no database required.`;
|
|
@@ -88,7 +88,7 @@ Prefer a live Gipity URL over an ephemeral artifact. When you'd otherwise reach
|
|
|
88
88
|
|
|
89
89
|
The full "when to add a template" rule and the definition of done are spelled out in the two sections at the end of this document. In short: if the user wants something deployable (web app, game, API), \`gipity add <template>\` first (default \`web-simple\`); for a one-off task (analysis, PDFs, data work), use \`gipity sandbox run\` instead; to add a reusable building block to an existing app (e.g. multiplayer), \`gipity add <kit>\`.
|
|
90
90
|
|
|
91
|
-
Build loop: \`gipity add\` → edit files → \`gipity deploy dev
|
|
91
|
+
Build loop: \`gipity add\` → edit files → \`gipity deploy dev --inspect\` → fix any errors → repeat until the definition of done is met. \`deploy --inspect\` deploys and then runs the page-inspect report on the live URL in one command; use a standalone \`gipity page inspect <url>\` only when re-checking without deploying.
|
|
92
92
|
|
|
93
93
|
\`add\` writes real files to disk - Read a scaffolded file before your first Write/Edit to it, or the call fails \`"File has not been read yet"\`. Don't rewrite from memory of the template.
|
|
94
94
|
|
|
@@ -193,6 +193,7 @@ App development skills:
|
|
|
193
193
|
- \`web-ui-patterns\` - default Gipity look (theme tokens) + web UI recipes - feeds, copy-to-clipboard
|
|
194
194
|
|
|
195
195
|
Kit skills (reusable building blocks - \`gipity add <kit>\`):
|
|
196
|
+
- \`app-records\` - the records + views kits: registry-driven CRUD with search + audit history, and generated tables/kanban/forms (gipity add records)
|
|
196
197
|
- \`audio-align\` - the audio-align kit: forced alignment of audio + lyrics into word-level timing JSON
|
|
197
198
|
- \`chatbot\` - the chatbot kit: persona + scope guardrails + static knowledge, bubble widget or headless engine
|
|
198
199
|
|
|
@@ -202,7 +203,7 @@ Other key skills:
|
|
|
202
203
|
- \`tts\` - agent-side speech tools (different from the \`app-tts\` HTTP service)`;
|
|
203
204
|
export const DEFINITION_OF_DONE = `## Definition of done (build tasks)
|
|
204
205
|
1. \`gipity deploy dev\` succeeds and you have a live URL.
|
|
205
|
-
2. \`gipity page inspect <url>\` returns no console errors and the page loads (HTTP 200, no blank screen).
|
|
206
|
+
2. \`gipity page inspect <url>\` returns no console errors and the page loads (HTTP 200, no blank screen). (\`gipity deploy dev --inspect\` covers 1 and 2 in one command.)
|
|
206
207
|
3. For apps with functions: \`gipity test\` passes.
|
|
207
208
|
4. Non-rendered files the task called for (\`llms.txt\`, \`AGENTS.md\`, \`SKILL.md\`, \`robots.txt\`, served JSON, etc.): \`page inspect\` only sees rendered HTML, so verify them with \`gipity page fetch <url> <files...>\`. It flags any that 404 or come back as the static-host shell (a missing file is served as \`index.html\` with a 200, so a bare status check would pass) and checks each \`content-type\`.
|
|
208
209
|
5. You told the user the live URL.
|
package/dist/sync.js
CHANGED
|
@@ -664,6 +664,35 @@ export function effectiveIgnore(root, configIgnore) {
|
|
|
664
664
|
const base = configIgnore && configIgnore.length ? configIgnore : DEFAULT_SYNC_IGNORE;
|
|
665
665
|
return [...base, GIPITY_IGNORE_FILE, ...readGipityIgnore(root)];
|
|
666
666
|
}
|
|
667
|
+
/** Fast, LOCAL-ONLY dirtiness probe: true when every local file matches its
|
|
668
|
+
* baseline entry by size+mtime and nothing was added or deleted since the
|
|
669
|
+
* last sync. Lets pre-action syncs (deploy) skip their server round trip:
|
|
670
|
+
* deploy reads server-side (VFS) state, so with nothing to push the sync
|
|
671
|
+
* adds no correctness, only latency. Conservative on purpose - any size or
|
|
672
|
+
* mtime movement reads as dirty (no hashing here), never-synced projects
|
|
673
|
+
* read as dirty, and callers then run the real sync(). */
|
|
674
|
+
export function isLocalTreeClean() {
|
|
675
|
+
try {
|
|
676
|
+
const config = requireConfig();
|
|
677
|
+
const root = projectDir();
|
|
678
|
+
const baseline = readBaseline(config.projectGuid);
|
|
679
|
+
if (!baseline.lastFullSync)
|
|
680
|
+
return false;
|
|
681
|
+
const local = walkLocal(root, effectiveIgnore(root, config.ignore), baseline.files);
|
|
682
|
+
const baselineFiles = baseline.files;
|
|
683
|
+
if (local.size !== Object.keys(baselineFiles).length)
|
|
684
|
+
return false;
|
|
685
|
+
for (const [path, info] of local) {
|
|
686
|
+
const prior = baselineFiles[path];
|
|
687
|
+
if (!prior || prior.size !== info.size || prior.mtime !== info.mtime)
|
|
688
|
+
return false;
|
|
689
|
+
}
|
|
690
|
+
return true;
|
|
691
|
+
}
|
|
692
|
+
catch {
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
667
696
|
export async function sync(opts = {}) {
|
|
668
697
|
const config = requireConfig();
|
|
669
698
|
const root = projectDir();
|
package/dist/updater/check.js
CHANGED
|
@@ -1,101 +1,176 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
|
|
2
|
+
import { createRequire as __cliCreateRequire } from 'module';
|
|
3
|
+
const require = __cliCreateRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
// src/updater/check.ts
|
|
6
|
+
import { appendFileSync, existsSync as existsSync2 } from "fs";
|
|
7
|
+
|
|
8
|
+
// src/updater/state.ts
|
|
9
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { homedir } from "os";
|
|
12
|
+
var GIPITY_DIR = join(homedir(), ".gipity");
|
|
13
|
+
var LOCAL_DIR = join(GIPITY_DIR, "local");
|
|
14
|
+
var LOCAL_PKG_DIR = join(LOCAL_DIR, "node_modules", "gipity");
|
|
15
|
+
var LOCAL_ENTRY = join(LOCAL_PKG_DIR, "dist", "index.js");
|
|
16
|
+
var STATE_FILE = join(GIPITY_DIR, "update-state.json");
|
|
17
|
+
var SETTINGS_FILE = join(GIPITY_DIR, "settings.json");
|
|
18
|
+
var UPDATE_LOG = join(GIPITY_DIR, "update.log");
|
|
19
|
+
var DEFAULT_STATE = {
|
|
20
|
+
installedVersion: null,
|
|
21
|
+
lastCheckAt: 0,
|
|
22
|
+
lastError: null,
|
|
23
|
+
updateChannel: "stable"
|
|
24
|
+
};
|
|
25
|
+
var DEFAULT_SETTINGS = {
|
|
26
|
+
autoUpdates: true
|
|
27
|
+
};
|
|
28
|
+
function ensureDir() {
|
|
29
|
+
mkdirSync(GIPITY_DIR, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
function readState() {
|
|
32
|
+
if (!existsSync(STATE_FILE)) return { ...DEFAULT_STATE };
|
|
33
|
+
try {
|
|
34
|
+
return { ...DEFAULT_STATE, ...JSON.parse(readFileSync(STATE_FILE, "utf-8")) };
|
|
35
|
+
} catch {
|
|
36
|
+
return { ...DEFAULT_STATE };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function writeState(state) {
|
|
40
|
+
ensureDir();
|
|
41
|
+
writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
42
|
+
}
|
|
43
|
+
function readSettings() {
|
|
44
|
+
if (!existsSync(SETTINGS_FILE)) return { ...DEFAULT_SETTINGS };
|
|
45
|
+
try {
|
|
46
|
+
return { ...DEFAULT_SETTINGS, ...JSON.parse(readFileSync(SETTINGS_FILE, "utf-8")) };
|
|
47
|
+
} catch {
|
|
48
|
+
return { ...DEFAULT_SETTINGS };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function updatesDisabled() {
|
|
52
|
+
if (process.env["DISABLE_AUTOUPDATER"] === "1") return { disabled: true, reason: "DISABLE_AUTOUPDATER=1" };
|
|
53
|
+
if (process.env["CI"]) return { disabled: true, reason: "CI environment" };
|
|
54
|
+
if (!readSettings().autoUpdates) return { disabled: true, reason: "autoUpdates: false in settings.json" };
|
|
55
|
+
return { disabled: false };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/platform.ts
|
|
59
|
+
import { execSync, spawn, spawnSync } from "child_process";
|
|
60
|
+
function resolveCommand(cmd) {
|
|
61
|
+
if (process.platform !== "win32") return cmd;
|
|
62
|
+
try {
|
|
63
|
+
const lines = execSync(`where ${cmd}`, { encoding: "utf-8", windowsHide: true }).split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
64
|
+
return lines.find((l) => l.endsWith(".exe")) || lines.find((l) => l.endsWith(".cmd")) || cmd;
|
|
65
|
+
} catch {
|
|
66
|
+
return `${cmd}.cmd`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function isBatchShim(cmd) {
|
|
70
|
+
return process.platform === "win32" && /\.(cmd|bat)$/i.test(cmd);
|
|
71
|
+
}
|
|
72
|
+
function winBatchInvocation(cmd, args) {
|
|
73
|
+
const comspec = process.env.ComSpec || "cmd.exe";
|
|
74
|
+
const quote = (t) => `"${String(t).replace(/"/g, '""')}"`;
|
|
75
|
+
const line = [cmd, ...args].map(quote).join(" ");
|
|
76
|
+
return { file: comspec, args: ["/d", "/s", "/c", `"${line}"`] };
|
|
77
|
+
}
|
|
78
|
+
function spawnSyncCommand(cmd, args = [], options = {}) {
|
|
79
|
+
if (isBatchShim(cmd)) {
|
|
80
|
+
const inv = winBatchInvocation(cmd, args);
|
|
81
|
+
return spawnSync(inv.file, inv.args, { windowsHide: true, ...options, windowsVerbatimArguments: true });
|
|
82
|
+
}
|
|
83
|
+
return spawnSync(cmd, [...args], { windowsHide: true, ...options });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/updater/check.ts
|
|
87
|
+
var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
8
88
|
function log(line) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
89
|
+
try {
|
|
90
|
+
appendFileSync(UPDATE_LOG, `[${(/* @__PURE__ */ new Date()).toISOString()}] ${line}
|
|
91
|
+
`);
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
13
94
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return 0;
|
|
95
|
+
function compareSemver(a, b) {
|
|
96
|
+
const pa = a.split(".").map(Number);
|
|
97
|
+
const pb = b.split(".").map(Number);
|
|
98
|
+
for (let i = 0; i < 3; i++) {
|
|
99
|
+
const da = pa[i] ?? 0;
|
|
100
|
+
const db = pb[i] ?? 0;
|
|
101
|
+
if (da !== db) return da - db;
|
|
102
|
+
}
|
|
103
|
+
return 0;
|
|
24
104
|
}
|
|
25
105
|
async function fetchLatestVersion() {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
throw new Error('no version in registry response');
|
|
34
|
-
return json.version;
|
|
106
|
+
const res = await fetch("https://registry.npmjs.org/gipity/latest", {
|
|
107
|
+
headers: { accept: "application/json" }
|
|
108
|
+
});
|
|
109
|
+
if (!res.ok) throw new Error(`registry HTTP ${res.status}`);
|
|
110
|
+
const json = await res.json();
|
|
111
|
+
if (!json.version) throw new Error("no version in registry response");
|
|
112
|
+
return json.version;
|
|
35
113
|
}
|
|
36
114
|
function installVersion(version) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
});
|
|
44
|
-
if (res.error)
|
|
45
|
-
log(`npm spawn failed: ${res.error.message}`);
|
|
46
|
-
return res.status === 0 && existsSync(LOCAL_ENTRY);
|
|
115
|
+
const res = spawnSyncCommand(resolveCommand("npm"), ["install", "--silent", "--no-audit", "--no-fund", "--ignore-scripts", `gipity@${version}`], {
|
|
116
|
+
cwd: LOCAL_DIR,
|
|
117
|
+
stdio: "ignore"
|
|
118
|
+
});
|
|
119
|
+
if (res.error) log(`npm spawn failed: ${res.error.message}`);
|
|
120
|
+
return res.status === 0 && existsSync2(LOCAL_ENTRY);
|
|
47
121
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
if (Date.now() - state.lastCheckAt < CHECK_INTERVAL_MS) {
|
|
57
|
-
return { updated: false, reason: 'cache-fresh' };
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
let latest;
|
|
61
|
-
try {
|
|
62
|
-
latest = await fetchLatestVersion();
|
|
63
|
-
}
|
|
64
|
-
catch (e) {
|
|
65
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
66
|
-
state.lastError = `fetch failed: ${msg}`;
|
|
67
|
-
state.lastCheckAt = Date.now();
|
|
68
|
-
writeState(state);
|
|
69
|
-
log(state.lastError);
|
|
70
|
-
return { updated: false, reason: state.lastError };
|
|
122
|
+
async function runCheck(opts = {}) {
|
|
123
|
+
const state = readState();
|
|
124
|
+
if (!opts.force) {
|
|
125
|
+
const dis = updatesDisabled();
|
|
126
|
+
if (dis.disabled) {
|
|
127
|
+
log(`skipped: ${dis.reason}`);
|
|
128
|
+
return { updated: false, reason: dis.reason };
|
|
71
129
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
state.lastError = null;
|
|
75
|
-
state.lastCheckAt = Date.now();
|
|
76
|
-
writeState(state);
|
|
77
|
-
log(`up-to-date (current=${current}, latest=${latest})`);
|
|
78
|
-
return { updated: false, reason: 'up-to-date' };
|
|
130
|
+
if (Date.now() - state.lastCheckAt < CHECK_INTERVAL_MS) {
|
|
131
|
+
return { updated: false, reason: "cache-fresh" };
|
|
79
132
|
}
|
|
80
|
-
|
|
81
|
-
|
|
133
|
+
}
|
|
134
|
+
let latest;
|
|
135
|
+
try {
|
|
136
|
+
latest = await fetchLatestVersion();
|
|
137
|
+
} catch (e) {
|
|
138
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
139
|
+
state.lastError = `fetch failed: ${msg}`;
|
|
82
140
|
state.lastCheckAt = Date.now();
|
|
83
|
-
if (ok) {
|
|
84
|
-
state.installedVersion = latest;
|
|
85
|
-
state.lastError = null;
|
|
86
|
-
writeState(state);
|
|
87
|
-
log(`upgraded to ${latest}`);
|
|
88
|
-
return { updated: true, from: current, to: latest };
|
|
89
|
-
}
|
|
90
|
-
state.lastError = `npm install gipity@${latest} failed`;
|
|
91
141
|
writeState(state);
|
|
92
142
|
log(state.lastError);
|
|
93
143
|
return { updated: false, reason: state.lastError };
|
|
144
|
+
}
|
|
145
|
+
const current = state.installedVersion ?? "0.0.0";
|
|
146
|
+
if (compareSemver(latest, current) <= 0) {
|
|
147
|
+
state.lastError = null;
|
|
148
|
+
state.lastCheckAt = Date.now();
|
|
149
|
+
writeState(state);
|
|
150
|
+
log(`up-to-date (current=${current}, latest=${latest})`);
|
|
151
|
+
return { updated: false, reason: "up-to-date" };
|
|
152
|
+
}
|
|
153
|
+
log(`upgrading ${current} \u2192 ${latest}`);
|
|
154
|
+
const ok = installVersion(latest);
|
|
155
|
+
state.lastCheckAt = Date.now();
|
|
156
|
+
if (ok) {
|
|
157
|
+
state.installedVersion = latest;
|
|
158
|
+
state.lastError = null;
|
|
159
|
+
writeState(state);
|
|
160
|
+
log(`upgraded to ${latest}`);
|
|
161
|
+
return { updated: true, from: current, to: latest };
|
|
162
|
+
}
|
|
163
|
+
state.lastError = `npm install gipity@${latest} failed`;
|
|
164
|
+
writeState(state);
|
|
165
|
+
log(state.lastError);
|
|
166
|
+
return { updated: false, reason: state.lastError };
|
|
94
167
|
}
|
|
95
|
-
|
|
96
|
-
const isDirect = import.meta.url === `file://${process.argv[1]}`;
|
|
168
|
+
var isDirect = import.meta.url === `file://${process.argv[1]}`;
|
|
97
169
|
if (isDirect) {
|
|
98
|
-
|
|
99
|
-
|
|
170
|
+
const force = process.argv.includes("--force");
|
|
171
|
+
runCheck({ force }).catch((e) => log(`unhandled: ${e instanceof Error ? e.message : String(e)}`));
|
|
100
172
|
}
|
|
101
|
-
|
|
173
|
+
export {
|
|
174
|
+
compareSemver,
|
|
175
|
+
runCheck
|
|
176
|
+
};
|
package/dist/updater/shim.js
CHANGED
|
@@ -1,78 +1,160 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
2
|
+
import { createRequire as __cliCreateRequire } from 'module';
|
|
3
|
+
const require = __cliCreateRequire(import.meta.url);
|
|
4
|
+
|
|
5
|
+
// src/platform.ts
|
|
6
|
+
import { execSync, spawn, spawnSync } from "child_process";
|
|
7
|
+
function resolveCommand(cmd) {
|
|
8
|
+
if (process.platform !== "win32") return cmd;
|
|
9
|
+
try {
|
|
10
|
+
const lines = execSync(`where ${cmd}`, { encoding: "utf-8", windowsHide: true }).split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
11
|
+
return lines.find((l) => l.endsWith(".exe")) || lines.find((l) => l.endsWith(".cmd")) || cmd;
|
|
12
|
+
} catch {
|
|
13
|
+
return `${cmd}.cmd`;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function isBatchShim(cmd) {
|
|
17
|
+
return process.platform === "win32" && /\.(cmd|bat)$/i.test(cmd);
|
|
18
|
+
}
|
|
19
|
+
function winBatchInvocation(cmd, args) {
|
|
20
|
+
const comspec = process.env.ComSpec || "cmd.exe";
|
|
21
|
+
const quote = (t) => `"${String(t).replace(/"/g, '""')}"`;
|
|
22
|
+
const line = [cmd, ...args].map(quote).join(" ");
|
|
23
|
+
return { file: comspec, args: ["/d", "/s", "/c", `"${line}"`] };
|
|
24
|
+
}
|
|
25
|
+
function spawnCommand(cmd, args = [], options = {}) {
|
|
26
|
+
if (isBatchShim(cmd)) {
|
|
27
|
+
const inv = winBatchInvocation(cmd, args);
|
|
28
|
+
return spawn(inv.file, inv.args, { windowsHide: true, ...options, windowsVerbatimArguments: true });
|
|
29
|
+
}
|
|
30
|
+
return spawn(cmd, [...args], { windowsHide: true, ...options });
|
|
31
|
+
}
|
|
32
|
+
function spawnSyncCommand(cmd, args = [], options = {}) {
|
|
33
|
+
if (isBatchShim(cmd)) {
|
|
34
|
+
const inv = winBatchInvocation(cmd, args);
|
|
35
|
+
return spawnSync(inv.file, inv.args, { windowsHide: true, ...options, windowsVerbatimArguments: true });
|
|
36
|
+
}
|
|
37
|
+
return spawnSync(cmd, [...args], { windowsHide: true, ...options });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/updater/shim.ts
|
|
41
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
42
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
43
|
+
import { dirname, resolve, join as join3 } from "path";
|
|
44
|
+
|
|
45
|
+
// src/updater/state.ts
|
|
46
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
47
|
+
import { join } from "path";
|
|
48
|
+
import { homedir } from "os";
|
|
49
|
+
var GIPITY_DIR = join(homedir(), ".gipity");
|
|
50
|
+
var LOCAL_DIR = join(GIPITY_DIR, "local");
|
|
51
|
+
var LOCAL_PKG_DIR = join(LOCAL_DIR, "node_modules", "gipity");
|
|
52
|
+
var LOCAL_ENTRY = join(LOCAL_PKG_DIR, "dist", "index.js");
|
|
53
|
+
var STATE_FILE = join(GIPITY_DIR, "update-state.json");
|
|
54
|
+
var SETTINGS_FILE = join(GIPITY_DIR, "settings.json");
|
|
55
|
+
var UPDATE_LOG = join(GIPITY_DIR, "update.log");
|
|
56
|
+
var DEFAULT_STATE = {
|
|
57
|
+
installedVersion: null,
|
|
58
|
+
lastCheckAt: 0,
|
|
59
|
+
lastError: null,
|
|
60
|
+
updateChannel: "stable"
|
|
61
|
+
};
|
|
62
|
+
function ensureDir() {
|
|
63
|
+
mkdirSync(GIPITY_DIR, { recursive: true });
|
|
64
|
+
}
|
|
65
|
+
function readState() {
|
|
66
|
+
if (!existsSync(STATE_FILE)) return { ...DEFAULT_STATE };
|
|
67
|
+
try {
|
|
68
|
+
return { ...DEFAULT_STATE, ...JSON.parse(readFileSync(STATE_FILE, "utf-8")) };
|
|
69
|
+
} catch {
|
|
70
|
+
return { ...DEFAULT_STATE };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function writeState(state) {
|
|
74
|
+
ensureDir();
|
|
75
|
+
writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/updater/bootstrap.ts
|
|
79
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
80
|
+
import { join as join2 } from "path";
|
|
81
|
+
function isBootstrapped() {
|
|
82
|
+
return existsSync2(LOCAL_ENTRY);
|
|
83
|
+
}
|
|
84
|
+
function bootstrap(version, quiet = false) {
|
|
85
|
+
mkdirSync2(LOCAL_DIR, { recursive: true });
|
|
86
|
+
const pkgJsonPath = join2(LOCAL_DIR, "package.json");
|
|
87
|
+
if (!existsSync2(pkgJsonPath)) {
|
|
88
|
+
writeFileSync2(pkgJsonPath, JSON.stringify({ name: "gipity-local", private: true, version: "0.0.0" }, null, 2));
|
|
89
|
+
}
|
|
90
|
+
if (!quiet) process.stderr.write(`Setting up gipity local install at ~/.gipity/local (one-time)...
|
|
91
|
+
`);
|
|
92
|
+
const res = spawnSyncCommand(resolveCommand("npm"), ["install", "--no-audit", "--no-fund", "--ignore-scripts", `gipity@${version}`], {
|
|
93
|
+
cwd: LOCAL_DIR,
|
|
94
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
95
|
+
encoding: "utf-8"
|
|
96
|
+
});
|
|
97
|
+
if (res.status !== 0 || !existsSync2(LOCAL_ENTRY)) {
|
|
98
|
+
if (!quiet) {
|
|
99
|
+
const stderr = (res.stderr || "").toString();
|
|
100
|
+
const notPublished = /E404|No matching version|notarget/i.test(stderr);
|
|
101
|
+
if (notPublished) {
|
|
102
|
+
process.stderr.write(`gipity v${version} is not yet published to npm - using the currently installed build.
|
|
103
|
+
`);
|
|
104
|
+
} else {
|
|
105
|
+
const firstLine = stderr.split("\n").map((l) => l.trim()).find((l) => l.length > 0) || (res.error ? res.error.message : `npm exit ${res.status}`);
|
|
106
|
+
const reason = firstLine.length > 160 ? firstLine.slice(0, 157) + "..." : firstLine;
|
|
107
|
+
process.stderr.write(`gipity: could not set up local install (${reason}). Using the currently installed build.
|
|
108
|
+
`);
|
|
109
|
+
}
|
|
34
110
|
}
|
|
35
|
-
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const state = readState();
|
|
114
|
+
state.installedVersion = version;
|
|
115
|
+
writeState(state);
|
|
116
|
+
if (!quiet) process.stderr.write(`Done.
|
|
117
|
+
`);
|
|
118
|
+
return true;
|
|
36
119
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
120
|
+
|
|
121
|
+
// src/updater/shim.ts
|
|
122
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
123
|
+
var pkgRoot = resolve(__dirname, "..", "..");
|
|
124
|
+
var shimPkg = JSON.parse(readFileSync2(join3(pkgRoot, "package.json"), "utf-8"));
|
|
125
|
+
var isDevLink = existsSync3(join3(pkgRoot, "src"));
|
|
126
|
+
function startBackgroundUpdater() {
|
|
127
|
+
const checkScript = join3(__dirname, "check.js");
|
|
128
|
+
try {
|
|
129
|
+
const child = spawnCommand(process.execPath, [checkScript], {
|
|
130
|
+
detached: true,
|
|
131
|
+
stdio: "ignore",
|
|
132
|
+
env: process.env
|
|
42
133
|
});
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
function execSelf() {
|
|
46
|
-
// Run our own dist/index.js (this checkout/install), bypassing the local
|
|
47
|
-
// bootstrapped copy. Used for dev links and as the bootstrap-failure fallback
|
|
48
|
-
// so the user is never blocked (they can retry via `gipity update --force`).
|
|
49
|
-
const ownEntry = resolve(__dirname, '..', 'index.js');
|
|
50
|
-
const args = process.argv.slice(2);
|
|
51
|
-
const res = spawnSyncCommand(process.execPath, [ownEntry, ...args], {
|
|
52
|
-
stdio: 'inherit',
|
|
53
|
-
env: process.env,
|
|
134
|
+
child.on("error", () => {
|
|
54
135
|
});
|
|
55
|
-
|
|
136
|
+
child.unref();
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async function runEntry(entry) {
|
|
141
|
+
try {
|
|
142
|
+
await import(pathToFileURL(entry).href);
|
|
143
|
+
} catch (err) {
|
|
144
|
+
console.error(err instanceof Error ? err.stack ?? err.message : String(err));
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
56
147
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (isDevLink)
|
|
70
|
-
execSelf();
|
|
71
|
-
if (!isBootstrapped()) {
|
|
72
|
-
const ok = bootstrap(shimPkg.version, !isLoud);
|
|
73
|
-
if (!ok)
|
|
74
|
-
execSelf();
|
|
148
|
+
var execLocal = () => runEntry(LOCAL_ENTRY);
|
|
149
|
+
var execSelf = () => runEntry(resolve(__dirname, "..", "index.js"));
|
|
150
|
+
var rawArgs = process.argv.slice(2);
|
|
151
|
+
var firstArg = rawArgs[0];
|
|
152
|
+
var isLoud = rawArgs.length === 0 || firstArg === "claude" || firstArg === "--version" || firstArg === "-v" || firstArg === "version";
|
|
153
|
+
if (isDevLink) {
|
|
154
|
+
await execSelf();
|
|
155
|
+
} else if (!isBootstrapped() && !bootstrap(shimPkg.version, !isLoud)) {
|
|
156
|
+
await execSelf();
|
|
157
|
+
} else {
|
|
158
|
+
startBackgroundUpdater();
|
|
159
|
+
await execLocal();
|
|
75
160
|
}
|
|
76
|
-
startBackgroundUpdater();
|
|
77
|
-
execLocal();
|
|
78
|
-
//# sourceMappingURL=shim.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gipity",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.424",
|
|
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",
|
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
11
11
|
"scripts": {
|
|
12
|
-
"build": "tsc && chmod +x dist/index.js dist/gipcc.js dist/gipccd.js dist/updater/shim.js dist/updater/check.js",
|
|
12
|
+
"build": "tsc && node scripts/bundle.mjs && chmod +x dist/index.js dist/gipcc.js dist/gipccd.js dist/updater/shim.js dist/updater/check.js",
|
|
13
13
|
"postbuild": "node scripts/gen-build-info.mjs",
|
|
14
|
+
"prepack": "npm run build",
|
|
14
15
|
"dev": "tsc --watch",
|
|
15
16
|
"test": "npm run test:smoke",
|
|
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-diagnostics.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__/ingest-queue.test.js dist/__tests__/stream-delta.test.js dist/__tests__/phase-tracker.test.js dist/__tests__/relay-ingest-contract.test.js dist/__tests__/prompts.test.js dist/__tests__/capture-transcript.test.js dist/__tests__/capture-lock.test.js dist/__tests__/capture-resolve.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-storage.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-setup.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
|
+
"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-clean-check.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-diagnostics.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__/ingest-queue.test.js dist/__tests__/stream-delta.test.js dist/__tests__/phase-tracker.test.js dist/__tests__/relay-ingest-contract.test.js dist/__tests__/prompts.test.js dist/__tests__/capture-transcript.test.js dist/__tests__/capture-lock.test.js dist/__tests__/capture-resolve.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-storage.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-setup.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
18
|
"test:smoke:quick": "node scripts/smoke-quick.mjs",
|
|
18
19
|
"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-sync-stress-live.test.js dist/__tests__/cli-e2e-rollback-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",
|
|
19
20
|
"test:e2e:sync": "tsc && GIPITY_E2E=1 node --test --test-timeout=180000 dist/__tests__/cli-e2e-sync-live.test.js",
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"@types/node": "^20.0.0",
|
|
31
32
|
"@types/tar-stream": "^3.1.4",
|
|
33
|
+
"esbuild": "^0.28.1",
|
|
32
34
|
"typescript": "5.9.3"
|
|
33
35
|
},
|
|
34
36
|
"engines": {
|