gipity 1.0.407 → 1.0.409
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/add.js +1 -1
- package/dist/commands/approval.js +1 -1
- package/dist/commands/claude.js +9 -9
- package/dist/commands/email.js +2 -1
- package/dist/commands/gmail.js +2 -1
- package/dist/commands/init.js +2 -1
- package/dist/commands/job.js +2 -1
- package/dist/commands/login.js +1 -0
- package/dist/commands/notify.js +2 -1
- package/dist/commands/page.js +1 -1
- package/dist/commands/payments.js +2 -1
- package/dist/commands/plan.js +1 -1
- package/dist/commands/remove.js +1 -1
- package/dist/commands/secrets.js +2 -1
- package/dist/commands/service.js +2 -1
- package/dist/commands/sync.js +2 -1
- package/dist/commands/test.js +6 -0
- package/dist/commands/text.js +2 -1
- package/dist/commands/token.js +2 -1
- package/dist/config.js +4 -4
- package/dist/helpers/output.js +42 -13
- 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 +3 -4
- package/dist/updater/check.js +2 -3
- package/package.json +3 -4
- package/dist/coding-guidelines.js +0 -52
- package/dist/commands/browser.js +0 -84
- package/dist/commands/checkpoint.js +0 -68
- package/dist/commands/hook-capture.js +0 -215
- package/dist/commands/scaffold.js +0 -58
- package/dist/commands/skills.js +0 -45
- package/dist/commands/start-cc.js +0 -313
- package/dist/gip3dw-guide.js +0 -18
- package/dist/platform-overview.js +0 -52
- package/dist/relay/transcripts.js +0 -119
- package/hooks/post-write.sh +0 -17
- package/hooks/pre-turn.sh +0 -20
|
@@ -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',
|
|
@@ -53,7 +52,7 @@ export function bootstrap(version, quiet = false) {
|
|
|
53
52
|
state.installedVersion = version;
|
|
54
53
|
writeState(state);
|
|
55
54
|
if (!quiet)
|
|
56
|
-
process.stderr.write(`Done.\n
|
|
55
|
+
process.stderr.write(`Done.\n`);
|
|
57
56
|
return true;
|
|
58
57
|
}
|
|
59
58
|
export { LOCAL_PKG_DIR };
|
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.409",
|
|
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
|
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared coding guidelines for Gipity-hosted projects.
|
|
3
|
-
* Single source of truth used by:
|
|
4
|
-
* - server/src/services/skills/web-app-basics.ts (web CLI agent)
|
|
5
|
-
* - tools/gipity-cli/src/setup.ts (CLAUDE.md template for Claude Code)
|
|
6
|
-
*
|
|
7
|
-
* The CLI build copies this file before compiling (see justfile cli-build).
|
|
8
|
-
*/
|
|
9
|
-
export const CODING_GUIDELINES = `## File Structure
|
|
10
|
-
- **Use src/ convention**: All app files live under \`src/\` — \`src/index.html\`, \`src/css/styles.css\`, \`src/js/main.js\`, \`src/images/\`
|
|
11
|
-
- **Separate files**: Split into \`index.html\`, \`styles.css\`, and \`app.js\` (or \`main.js\`). Never inline large blocks of CSS or JS in HTML.
|
|
12
|
-
- If the app grows, organize into folders: \`src/css/\`, \`src/js/\`, \`src/assets/\`, \`src/sounds/\`, \`src/images/\`, etc.
|
|
13
|
-
- **Use subfolders — don't flatten**: Reference assets from their folders (e.g. \`sounds/click.ogg\`, \`images/logo.png\`). Never copy files to the root just for convenience — deployed apps serve the full directory tree.
|
|
14
|
-
- Keep \`index.html\` clean — it should be structure/markup, not behavior or styling
|
|
15
|
-
|
|
16
|
-
## HTML
|
|
17
|
-
- Use semantic elements: \`<header>\`, \`<nav>\`, \`<main>\`, \`<section>\`, \`<footer>\`, \`<article>\`
|
|
18
|
-
- Always include \`<meta name="viewport" content="width=device-width, initial-scale=1.0">\`
|
|
19
|
-
- Add a proper \`<title>\` and favicon link
|
|
20
|
-
- Unless the user specifies a different CSS framework, include Water.css for automatic styling: \`<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.css">\`
|
|
21
|
-
- Water.css styles semantic HTML automatically (buttons, tables, forms, nav, cards) — no classes needed. It supports dark/light themes automatically. Add custom CSS on top for app-specific tweaks.
|
|
22
|
-
|
|
23
|
-
## CSS
|
|
24
|
-
- When using Water.css, it handles base styling, resets, and typography — don't duplicate what it provides
|
|
25
|
-
- Water.css exposes CSS variables for theming — override them in \`:root\` for custom colors/fonts
|
|
26
|
-
- Use CSS custom properties (variables) for app-specific colors, spacing, and fonts
|
|
27
|
-
- Add smooth transitions on interactive elements (buttons, links, hover states)
|
|
28
|
-
|
|
29
|
-
## JavaScript
|
|
30
|
-
- Use \`const\`/\`let\`, arrow functions, template literals, and modern ES6+ syntax
|
|
31
|
-
- Wait for DOM: wrap in \`DOMContentLoaded\` or place script at end of body
|
|
32
|
-
- Keep functions small and focused
|
|
33
|
-
- Use \`addEventListener\` — never inline \`onclick\` attributes in HTML
|
|
34
|
-
|
|
35
|
-
## Code Quality
|
|
36
|
-
- **Keep files under ~400 lines** unless the content genuinely requires it (e.g. a long data table, template string, or config object). When logic grows beyond that, split into focused modules (e.g. \`utils.js\`, \`api.js\`, \`ui.js\`).
|
|
37
|
-
- **Don't duplicate code.** If the same logic appears twice, extract it into a shared function. Before writing a new helper, check if one already exists or could be extended.
|
|
38
|
-
- **One responsibility per file.** A file that handles both UI rendering and API calls should be split.
|
|
39
|
-
- **Name things clearly.** Functions, variables, and files should describe what they do — no \`temp\`, \`data2\`, \`stuff.js\`.
|
|
40
|
-
- **Prefer simple, readable code** over clever code that hides bugs. Flat over nested — use early returns, avoid deep nesting.
|
|
41
|
-
- **Centralize configuration.** App settings, API URLs, feature flags, and magic numbers should live in a dedicated config file (e.g. \`config.js\` or \`constants.js\`), not scattered across the codebase.
|
|
42
|
-
- **Write utility functions** for repeated operations (formatting, validation, API calls). Keep them in a \`utils.js\` or \`helpers.js\` file. Small, pure functions are easy to test and reuse.
|
|
43
|
-
|
|
44
|
-
## Testing
|
|
45
|
-
- **Write tests for new functions** — especially utility/helper functions. Cover the happy path and edge cases (empty input, null, boundary values).
|
|
46
|
-
- **Don't mock unless absolutely required.** Tests should exercise real code paths. Only mock external paid services (APIs that cost money per call).
|
|
47
|
-
- **E2E tests should hit real infrastructure** (real API, real DB) — just clean up test data when done.
|
|
48
|
-
- **Test file naming**: \`*.test.js\` for unit tests, \`*.e2e.test.js\` for end-to-end tests.
|
|
49
|
-
|
|
50
|
-
## Deployment
|
|
51
|
-
- **src/ detection**: If a \`src/\` directory exists, only \`src/\` is deployed. Otherwise the full project root is deployed.`;
|
|
52
|
-
//# sourceMappingURL=coding-guidelines.js.map
|
package/dist/commands/browser.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { post } from '../api.js';
|
|
3
|
-
import { resolveProjectContext } from '../config.js';
|
|
4
|
-
import { formatSize } from '../utils.js';
|
|
5
|
-
import { brand, bold, error as clrError, warning, muted, info } from '../colors.js';
|
|
6
|
-
import { run } from '../helpers/index.js';
|
|
7
|
-
function shortUrl(url) {
|
|
8
|
-
try {
|
|
9
|
-
const u = new URL(url);
|
|
10
|
-
return u.pathname + u.search;
|
|
11
|
-
}
|
|
12
|
-
catch {
|
|
13
|
-
return url.length > 60 ? url.slice(-60) : url;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
export const browserCommand = new Command('browser')
|
|
17
|
-
.description('Inspect a URL: console errors, performance, failed resources')
|
|
18
|
-
.argument('<url>', 'URL to inspect')
|
|
19
|
-
.option('--wait <ms>', 'Wait before capture in ms', '3000')
|
|
20
|
-
.option('--json', 'Output as JSON')
|
|
21
|
-
.action((url, opts) => run('Browser inspect', async () => {
|
|
22
|
-
const { config } = await resolveProjectContext();
|
|
23
|
-
const waitMs = parseInt(opts.wait, 10) || 3000;
|
|
24
|
-
const res = await post(`/projects/${config.projectGuid}/browser/inspect`, { url, waitMs });
|
|
25
|
-
const b = res.data;
|
|
26
|
-
if (opts.json) {
|
|
27
|
-
console.log(JSON.stringify(b));
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
const timing = b.timing || { ttfb: 0, domReady: 0, load: 0 };
|
|
31
|
-
// ── Page Info ──
|
|
32
|
-
console.log(`\n${brand('Inspecting')} ${bold(b.url || url)}`);
|
|
33
|
-
console.log(` ${muted('Title:')} ${b.title || '(none)'}`);
|
|
34
|
-
console.log(` ${muted('Elements:')} ${b.elementCount || 0}`);
|
|
35
|
-
console.log(` ${muted('Page weight:')} ${info(formatSize(b.totalBytes || 0))}`);
|
|
36
|
-
// ── Timing ──
|
|
37
|
-
console.log(`\n ${bold('Timing:')}`);
|
|
38
|
-
console.log(` ${muted('TTFB:')} ${timing.ttfb}ms`);
|
|
39
|
-
console.log(` ${muted('DOM ready:')} ${timing.domReady}ms`);
|
|
40
|
-
console.log(` ${muted('Load:')} ${timing.load}ms`);
|
|
41
|
-
if (b.lcp) {
|
|
42
|
-
console.log(` LCP: ${b.lcp.time}ms (${b.lcp.element}${b.lcp.url ? ' ' + shortUrl(b.lcp.url) : ''})`);
|
|
43
|
-
}
|
|
44
|
-
// ── Console ──
|
|
45
|
-
if (b.console?.length > 0) {
|
|
46
|
-
console.log(`\n ${bold('Console')} ${muted(`(${b.console.length})`)}:`);
|
|
47
|
-
for (const line of b.console) {
|
|
48
|
-
console.log(` ${warning(line)}`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
console.log(`\n ${bold('Console:')} ${muted('(clean)')}`);
|
|
53
|
-
}
|
|
54
|
-
// ── Failed Resources ──
|
|
55
|
-
if (b.failedResources?.length > 0) {
|
|
56
|
-
console.log(`\n ${clrError(`Failed resources (${b.failedResources.length}):`)}`);
|
|
57
|
-
for (const r of b.failedResources) {
|
|
58
|
-
console.log(` ${clrError(r)}`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// ── Render Blocking ──
|
|
62
|
-
if (b.renderBlocking?.length > 0) {
|
|
63
|
-
console.log(`\n ${warning(`Render-blocking (${b.renderBlocking.length}):`)}`);
|
|
64
|
-
for (const r of b.renderBlocking) {
|
|
65
|
-
console.log(` ${shortUrl(r)}`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
// ── Large Resources ──
|
|
69
|
-
if (b.largeResources?.length > 0) {
|
|
70
|
-
console.log(`\n ${warning(`Large resources >100KB (${b.largeResources.length}):`)}`);
|
|
71
|
-
for (const r of b.largeResources) {
|
|
72
|
-
console.log(` ${info(formatSize(r.size).padEnd(10))} ${muted(r.type.padEnd(8))} ${shortUrl(r.url)}`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
// ── Oversized Images ──
|
|
76
|
-
if (b.oversizedImages?.length > 0) {
|
|
77
|
-
console.log(`\n ${warning(`Oversized images (${b.oversizedImages.length}):`)}`);
|
|
78
|
-
for (const img of b.oversizedImages) {
|
|
79
|
-
console.log(` ${img.natural} served, ${img.displayed} displayed — ${shortUrl(img.src)}`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
console.log('');
|
|
83
|
-
}));
|
|
84
|
-
//# sourceMappingURL=browser.js.map
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { get, post } from '../api.js';
|
|
3
|
-
import { requireConfig } from '../config.js';
|
|
4
|
-
import { syncDown } from '../sync.js';
|
|
5
|
-
import { formatAge } from '../utils.js';
|
|
6
|
-
import { error as clrError, muted, success } from '../colors.js';
|
|
7
|
-
export const checkpointCommand = new Command('checkpoint')
|
|
8
|
-
.description('Manage file checkpoints (snapshots for undo/restore)');
|
|
9
|
-
checkpointCommand
|
|
10
|
-
.command('list')
|
|
11
|
-
.description('List checkpoints')
|
|
12
|
-
.option('--limit <n>', 'Max results', '20')
|
|
13
|
-
.option('--json', 'Output as JSON')
|
|
14
|
-
.action(async (opts) => {
|
|
15
|
-
try {
|
|
16
|
-
const config = requireConfig();
|
|
17
|
-
const limit = parseInt(opts.limit, 10) || 20;
|
|
18
|
-
const res = await get(`/projects/${config.projectGuid}/checkpoints?limit=${limit}`);
|
|
19
|
-
if (opts.json) {
|
|
20
|
-
console.log(JSON.stringify(res.data));
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
if (res.data.length === 0) {
|
|
24
|
-
console.log('No checkpoints.');
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
for (const cp of res.data) {
|
|
28
|
-
const age = formatAge(cp.created_at);
|
|
29
|
-
const branch = cp.branched ? ' (branched)' : '';
|
|
30
|
-
console.log(` ${muted(cp.guid)} ${cp.label || muted('(auto)')} ${cp.fileCount} files ${muted(age)}${branch}`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
catch (err) {
|
|
36
|
-
console.error(clrError(`List failed: ${err.message}`));
|
|
37
|
-
process.exit(1);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
checkpointCommand
|
|
41
|
-
.command('restore <guid>')
|
|
42
|
-
.description('Restore files to a checkpoint (creates a backup checkpoint first)')
|
|
43
|
-
.option('--json', 'Output as JSON')
|
|
44
|
-
.action(async (guid, opts) => {
|
|
45
|
-
try {
|
|
46
|
-
const config = requireConfig();
|
|
47
|
-
const res = await post(`/projects/${config.projectGuid}/checkpoints/restore`, {
|
|
48
|
-
checkpoint_guid: guid,
|
|
49
|
-
});
|
|
50
|
-
// Sync down restored files (confirm deletions — restore may remove files)
|
|
51
|
-
const syncResult = await syncDown({ confirmDeletions: true });
|
|
52
|
-
if (opts.json) {
|
|
53
|
-
console.log(JSON.stringify({ ...res.data, synced: syncResult.pulled }));
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
console.log(success(`Restored to ${res.data.restoredTo}`));
|
|
57
|
-
console.log(`Backup created: ${res.data.backupCheckpoint}`);
|
|
58
|
-
if (syncResult.pulled > 0) {
|
|
59
|
-
console.log(`Pulled ${syncResult.pulled} files to local.`);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
console.error(clrError(`Restore failed: ${err.message}`));
|
|
65
|
-
process.exit(1);
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
//# sourceMappingURL=checkpoint.js.map
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hidden subcommand invoked by Claude Code hooks (see setup.ts HOOKS_SETTINGS).
|
|
3
|
-
* Reads Claude's hook JSON on stdin and POSTs a capture event to Gipity.
|
|
4
|
-
*
|
|
5
|
-
* The target conversation is identified by the `GIPITY_CONVERSATION_GUID`
|
|
6
|
-
* env var, which `gipity claude` exports before spawning Claude Code.
|
|
7
|
-
* Every capture event is tagged with that conv_guid — no server-side
|
|
8
|
-
* placeholder adoption, no guessing.
|
|
9
|
-
*
|
|
10
|
-
* Must never fail loudly — a hook that errors would degrade Claude Code's
|
|
11
|
-
* UX. All errors are swallowed (optionally logged to
|
|
12
|
-
* .gipity/hook-capture.log for debugging).
|
|
13
|
-
*/
|
|
14
|
-
import { Command } from 'commander';
|
|
15
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync, statSync, appendFileSync } from 'fs';
|
|
16
|
-
import { resolve, dirname } from 'path';
|
|
17
|
-
import { getConfig } from '../config.js';
|
|
18
|
-
import { getAuth } from '../auth.js';
|
|
19
|
-
import { post } from '../api.js';
|
|
20
|
-
function readStdin() {
|
|
21
|
-
return new Promise((r) => {
|
|
22
|
-
let data = '';
|
|
23
|
-
process.stdin.setEncoding('utf-8');
|
|
24
|
-
process.stdin.on('data', (c) => (data += c));
|
|
25
|
-
process.stdin.on('end', () => r(data));
|
|
26
|
-
process.stdin.on('error', () => r(data));
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
function debugLog(msg) {
|
|
30
|
-
if (!process.env.GIPITY_HOOK_DEBUG)
|
|
31
|
-
return;
|
|
32
|
-
try {
|
|
33
|
-
const cfg = getConfig();
|
|
34
|
-
if (!cfg)
|
|
35
|
-
return;
|
|
36
|
-
const logPath = resolve(process.cwd(), '.gipity', 'hook-capture.log');
|
|
37
|
-
mkdirSync(dirname(logPath), { recursive: true });
|
|
38
|
-
appendFileSync(logPath, `${new Date().toISOString()} ${msg}\n`);
|
|
39
|
-
}
|
|
40
|
-
catch { /* ignore */ }
|
|
41
|
-
}
|
|
42
|
-
const TTY = !!process.stderr.isTTY;
|
|
43
|
-
const dim = (s) => TTY ? `\x1b[2m${s}\x1b[0m` : s;
|
|
44
|
-
const cyan = (s) => TTY ? `\x1b[36m${s}\x1b[0m` : s;
|
|
45
|
-
const red = (s) => TTY ? `\x1b[31m${s}\x1b[0m` : s;
|
|
46
|
-
function hhmmss() {
|
|
47
|
-
const d = new Date();
|
|
48
|
-
const p = (n) => String(n).padStart(2, '0');
|
|
49
|
-
return `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
|
|
50
|
-
}
|
|
51
|
-
function friendlyLabel(path) {
|
|
52
|
-
const m = path.match(/\/remote-sessions\/[^/]+\/(.+)$/);
|
|
53
|
-
return m ? m[1] : path;
|
|
54
|
-
}
|
|
55
|
-
function summarize(body) {
|
|
56
|
-
if (!body || typeof body !== 'object')
|
|
57
|
-
return '';
|
|
58
|
-
const b = body;
|
|
59
|
-
if (typeof b.prompt === 'string') {
|
|
60
|
-
const p = b.prompt.replace(/\s+/g, ' ').trim();
|
|
61
|
-
return p.length > 80 ? `"${p.slice(0, 77)}…"` : `"${p}"`;
|
|
62
|
-
}
|
|
63
|
-
if (typeof b.tool_name === 'string')
|
|
64
|
-
return b.tool_name;
|
|
65
|
-
if (Array.isArray(b.entries))
|
|
66
|
-
return `${b.entries.length} transcript entr${b.entries.length === 1 ? 'y' : 'ies'}`;
|
|
67
|
-
if (typeof b.trigger === 'string')
|
|
68
|
-
return b.trigger;
|
|
69
|
-
if (typeof b.source === 'string')
|
|
70
|
-
return b.source;
|
|
71
|
-
return '';
|
|
72
|
-
}
|
|
73
|
-
async function safePost(path, body) {
|
|
74
|
-
const label = friendlyLabel(path);
|
|
75
|
-
const detail = summarize(body);
|
|
76
|
-
process.stderr.write(`${dim(hhmmss())} ${cyan('↗ gipity')} ${label}${detail ? ' ' + dim(detail) : ''}\n`);
|
|
77
|
-
try {
|
|
78
|
-
await post(path, body);
|
|
79
|
-
}
|
|
80
|
-
catch (err) {
|
|
81
|
-
process.stderr.write(`${dim(hhmmss())} ${red('✗ gipity')} ${label} ${dim(err?.message || String(err))}\n`);
|
|
82
|
-
debugLog(`POST ${path} failed: ${err?.message || err}`);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
function offsetPath(sessionId) {
|
|
86
|
-
return resolve(process.cwd(), '.gipity', 'transcripts', `${sessionId}.offset`);
|
|
87
|
-
}
|
|
88
|
-
function readOffset(sessionId) {
|
|
89
|
-
try {
|
|
90
|
-
return parseInt(readFileSync(offsetPath(sessionId), 'utf-8'), 10) || 0;
|
|
91
|
-
}
|
|
92
|
-
catch {
|
|
93
|
-
return 0;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
function writeOffset(sessionId, offset) {
|
|
97
|
-
const p = offsetPath(sessionId);
|
|
98
|
-
mkdirSync(dirname(p), { recursive: true });
|
|
99
|
-
writeFileSync(p, String(offset));
|
|
100
|
-
}
|
|
101
|
-
/** Parse JSONL delta from transcript_path starting at stored offset. */
|
|
102
|
-
function readTranscriptDelta(transcriptPath, sessionId) {
|
|
103
|
-
if (!existsSync(transcriptPath))
|
|
104
|
-
return { entries: [], newOffset: 0 };
|
|
105
|
-
const size = statSync(transcriptPath).size;
|
|
106
|
-
let offset = readOffset(sessionId);
|
|
107
|
-
if (offset > size)
|
|
108
|
-
offset = 0; // regressed — rescan
|
|
109
|
-
if (offset === size)
|
|
110
|
-
return { entries: [], newOffset: offset };
|
|
111
|
-
const fd = readFileSync(transcriptPath);
|
|
112
|
-
const slice = fd.slice(offset).toString('utf-8');
|
|
113
|
-
const lines = slice.split('\n').filter((l) => l.trim());
|
|
114
|
-
const entries = [];
|
|
115
|
-
for (const line of lines) {
|
|
116
|
-
try {
|
|
117
|
-
entries.push(JSON.parse(line));
|
|
118
|
-
}
|
|
119
|
-
catch { /* skip partial */ }
|
|
120
|
-
}
|
|
121
|
-
return { entries, newOffset: size };
|
|
122
|
-
}
|
|
123
|
-
/** Preflight: hooks are no-ops when we're not in a Gipity project, not
|
|
124
|
-
* authed, or (crucially) when the parent `gipity claude` never exported
|
|
125
|
-
* a conv_guid (unpaired device, failed create, etc.). Without the
|
|
126
|
-
* conv_guid there is no conversation to attach events to. */
|
|
127
|
-
function preflight() {
|
|
128
|
-
if (!getConfig())
|
|
129
|
-
return null;
|
|
130
|
-
if (!getAuth())
|
|
131
|
-
return null;
|
|
132
|
-
const convGuid = process.env.GIPITY_CONVERSATION_GUID;
|
|
133
|
-
if (!convGuid)
|
|
134
|
-
return null;
|
|
135
|
-
return { convGuid };
|
|
136
|
-
}
|
|
137
|
-
async function handleStart(payload, convGuid) {
|
|
138
|
-
const { session_id, cwd, source } = payload;
|
|
139
|
-
if (!session_id)
|
|
140
|
-
return;
|
|
141
|
-
// Attach this Claude Code run's session_id to the conv. Idempotent
|
|
142
|
-
// server-side; harmless to call multiple times (e.g. after --resume).
|
|
143
|
-
await safePost(`/remote-sessions/${encodeURIComponent(convGuid)}/attach-session`, {
|
|
144
|
-
session_id,
|
|
145
|
-
cwd: cwd || process.cwd(),
|
|
146
|
-
source: source || 'startup',
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
async function handlePrompt(payload, convGuid) {
|
|
150
|
-
const { prompt } = payload;
|
|
151
|
-
await safePost(`/remote-sessions/${encodeURIComponent(convGuid)}/prompt`, {
|
|
152
|
-
prompt: prompt || '',
|
|
153
|
-
ts: new Date().toISOString(),
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
async function handleTool(payload, convGuid) {
|
|
157
|
-
const { tool_name, tool_input, tool_response } = payload;
|
|
158
|
-
if (!tool_name)
|
|
159
|
-
return;
|
|
160
|
-
await safePost(`/remote-sessions/${encodeURIComponent(convGuid)}/tool`, {
|
|
161
|
-
tool_name,
|
|
162
|
-
tool_input: tool_input ?? null,
|
|
163
|
-
tool_response: tool_response ?? null,
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
async function handleStop(payload, convGuid) {
|
|
167
|
-
const { session_id, transcript_path } = payload;
|
|
168
|
-
if (!session_id || !transcript_path)
|
|
169
|
-
return;
|
|
170
|
-
const { entries, newOffset } = readTranscriptDelta(transcript_path, session_id);
|
|
171
|
-
if (entries.length === 0)
|
|
172
|
-
return;
|
|
173
|
-
await safePost(`/remote-sessions/${encodeURIComponent(convGuid)}/transcript`, { entries });
|
|
174
|
-
writeOffset(session_id, newOffset);
|
|
175
|
-
}
|
|
176
|
-
async function handleEnd(_payload, convGuid) {
|
|
177
|
-
await safePost(`/remote-sessions/${encodeURIComponent(convGuid)}/end`, {});
|
|
178
|
-
}
|
|
179
|
-
async function handleCompact(payload, convGuid) {
|
|
180
|
-
const { trigger } = payload;
|
|
181
|
-
await safePost(`/remote-sessions/${encodeURIComponent(convGuid)}/compact`, {
|
|
182
|
-
trigger: trigger || 'auto',
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
async function run(event) {
|
|
186
|
-
const pre = preflight();
|
|
187
|
-
if (!pre)
|
|
188
|
-
return;
|
|
189
|
-
const raw = await readStdin();
|
|
190
|
-
let payload;
|
|
191
|
-
try {
|
|
192
|
-
payload = JSON.parse(raw);
|
|
193
|
-
}
|
|
194
|
-
catch {
|
|
195
|
-
debugLog(`bad JSON on ${event}`);
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
switch (event) {
|
|
199
|
-
case 'start': return handleStart(payload, pre.convGuid);
|
|
200
|
-
case 'prompt': return handlePrompt(payload, pre.convGuid);
|
|
201
|
-
case 'tool': return handleTool(payload, pre.convGuid);
|
|
202
|
-
case 'stop': return handleStop(payload, pre.convGuid);
|
|
203
|
-
case 'end': return handleEnd(payload, pre.convGuid);
|
|
204
|
-
case 'compact': return handleCompact(payload, pre.convGuid);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
export const hookCaptureCommand = new Command('hook-capture')
|
|
208
|
-
.description('Internal: capture Claude Code hook events and forward to Gipity')
|
|
209
|
-
.argument('<event>', 'hook event: start|prompt|tool|stop|end|compact')
|
|
210
|
-
.action(async (event) => {
|
|
211
|
-
await run(event);
|
|
212
|
-
// Always succeed quietly — hooks must not surface errors to Claude Code.
|
|
213
|
-
process.exit(0);
|
|
214
|
-
});
|
|
215
|
-
//# sourceMappingURL=hook-capture.js.map
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { post } from '../api.js';
|
|
3
|
-
import { requireConfig } from '../config.js';
|
|
4
|
-
import { sync } from '../sync.js';
|
|
5
|
-
import { success } from '../colors.js';
|
|
6
|
-
import { run } from '../helpers/index.js';
|
|
7
|
-
// Scaffold types grouped by kind. Mirrors SCAFFOLD_TEMPLATES in
|
|
8
|
-
// platform/packages/shared - kept inline here because the CLI is published
|
|
9
|
-
// as a standalone npm package and can't depend on the private shared
|
|
10
|
-
// workspace. When adding/removing/promoting an entry, update both lists.
|
|
11
|
-
//
|
|
12
|
-
// Templates are minimal wiring (start fresh). Starter apps are working demos.
|
|
13
|
-
// Hidden entries are accepted by the server but not suggested by default -
|
|
14
|
-
// they're shown to the agent in a "do-not-suggest-unsolicited" line so the
|
|
15
|
-
// LLM can still pick one when the user asks for that domain by name.
|
|
16
|
-
const VISIBLE_TEMPLATES = ['web-simple', '3d-engine'];
|
|
17
|
-
const VISIBLE_STARTERS = ['web-fullstack', '2d-game', '3d-world', 'api'];
|
|
18
|
-
const HIDDEN_STARTERS = [
|
|
19
|
-
{ key: 'app-itsm', hint: 'IT service management / helpdesk / ticketing / incident management' },
|
|
20
|
-
];
|
|
21
|
-
const visibleTypeList = [
|
|
22
|
-
`templates: ${VISIBLE_TEMPLATES.join(', ')}`,
|
|
23
|
-
`starters: ${VISIBLE_STARTERS.join(', ')}`,
|
|
24
|
-
].join(' | ');
|
|
25
|
-
const hiddenTypeList = HIDDEN_STARTERS.length
|
|
26
|
-
? ' | hidden (do NOT suggest unsolicited; use only when the user explicitly asks for that domain): ' +
|
|
27
|
-
HIDDEN_STARTERS.map(h => `${h.key} (${h.hint})`).join(', ')
|
|
28
|
-
: '';
|
|
29
|
-
export const scaffoldCommand = new Command('scaffold')
|
|
30
|
-
.description('Create an app from a template')
|
|
31
|
-
.argument('[title]', 'App title (defaults to project name)')
|
|
32
|
-
.requiredOption('--type <type>', `Project type: ${visibleTypeList}${hiddenTypeList}`)
|
|
33
|
-
.option('--description <desc>', 'App description for meta tags')
|
|
34
|
-
.option('--json', 'Output as JSON')
|
|
35
|
-
.action((title, opts) => run('Scaffold', async () => {
|
|
36
|
-
const config = requireConfig();
|
|
37
|
-
const appTitle = title || config.projectSlug;
|
|
38
|
-
const res = await post(`/projects/${config.projectGuid}/scaffold`, {
|
|
39
|
-
title: appTitle,
|
|
40
|
-
description: opts.description,
|
|
41
|
-
type: opts.type,
|
|
42
|
-
});
|
|
43
|
-
// Sync down the created files
|
|
44
|
-
const syncResult = await sync({ interactive: false });
|
|
45
|
-
if (opts.json) {
|
|
46
|
-
console.log(JSON.stringify({ ...res.data, synced: syncResult.applied }));
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
console.log(success(`Scaffolded "${res.data.title}" with ${res.data.files.length} files:`));
|
|
50
|
-
for (const f of res.data.files) {
|
|
51
|
-
console.log(` ${f}`);
|
|
52
|
-
}
|
|
53
|
-
if (syncResult.applied > 0) {
|
|
54
|
-
console.log(`\nPulled ${syncResult.applied} files to local.`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}));
|
|
58
|
-
//# sourceMappingURL=scaffold.js.map
|
package/dist/commands/skills.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { get } from '../api.js';
|
|
3
|
-
import { resolveProjectContext } from '../config.js';
|
|
4
|
-
import { error as clrError, bold, muted } from '../colors.js';
|
|
5
|
-
import { run, printList } from '../helpers/index.js';
|
|
6
|
-
export const skillsCommand = new Command('skills')
|
|
7
|
-
.description('Read platform docs');
|
|
8
|
-
skillsCommand
|
|
9
|
-
.command('list')
|
|
10
|
-
.description('List skills')
|
|
11
|
-
.option('--json', 'Output as JSON')
|
|
12
|
-
.action((opts) => run('List', async () => {
|
|
13
|
-
const { config } = await resolveProjectContext();
|
|
14
|
-
if (!config.agentGuid) {
|
|
15
|
-
console.error(clrError('No agent configured for this project. Run `gipity init` to refresh.'));
|
|
16
|
-
process.exit(1);
|
|
17
|
-
}
|
|
18
|
-
const res = await get(`/skills?agent=${config.agentGuid}`);
|
|
19
|
-
printList(res.data, opts, 'No skills available.', s => `${bold(s.name)} ${muted(s.description)}`);
|
|
20
|
-
}));
|
|
21
|
-
skillsCommand
|
|
22
|
-
.command('read <name>')
|
|
23
|
-
.description('Read a skill')
|
|
24
|
-
.option('--json', 'Output as JSON')
|
|
25
|
-
.action((name, opts) => run('Read', async () => {
|
|
26
|
-
const { config } = await resolveProjectContext();
|
|
27
|
-
if (!config.agentGuid) {
|
|
28
|
-
console.error(clrError('No agent configured for this project. Run `gipity init` to refresh.'));
|
|
29
|
-
process.exit(1);
|
|
30
|
-
}
|
|
31
|
-
const listRes = await get(`/skills?agent=${config.agentGuid}`);
|
|
32
|
-
const match = listRes.data.find(s => s.name.toLowerCase() === name.toLowerCase());
|
|
33
|
-
if (!match) {
|
|
34
|
-
console.error(clrError(`Skill "${name}" not found. Run: gipity skills list`));
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
|
-
const res = await get(`/skills/${match.guid}?agent=${config.agentGuid}`);
|
|
38
|
-
if (opts.json) {
|
|
39
|
-
console.log(JSON.stringify(res.data, null, 2));
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
console.log(res.data.content);
|
|
43
|
-
}
|
|
44
|
-
}));
|
|
45
|
-
//# sourceMappingURL=skills.js.map
|