gipity 1.0.389 → 1.0.391
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/claude.js +8 -2
- package/dist/commands/init.js +3 -2
- package/dist/commands/status.js +13 -4
- package/dist/setup.js +102 -5
- package/package.json +1 -1
package/dist/commands/claude.js
CHANGED
|
@@ -21,7 +21,7 @@ import { getAuth, saveAuth, clearAuth } from '../auth.js';
|
|
|
21
21
|
import { get, post, publicPost, ApiError, getAccountSlug } from '../api.js';
|
|
22
22
|
import { getConfig, saveConfigAt, clearConfigCache, getApiBaseOverride, DEFAULT_API_BASE, getConfigPath } from '../config.js';
|
|
23
23
|
import { sync } from '../sync.js';
|
|
24
|
-
import { slugify, setupClaudeHooks, setupClaudeMd, setupAgentsMd, setupGitignore, DEFAULT_SYNC_IGNORE, isSyncIgnored } from '../setup.js';
|
|
24
|
+
import { slugify, setupClaudeHooks, ensureGipityPluginInstalled, setupClaudeMd, setupAgentsMd, setupGitignore, DEFAULT_SYNC_IGNORE, isSyncIgnored } from '../setup.js';
|
|
25
25
|
import { buildProjectContextBlock as buildProjectContextBlockText, buildNewProjectPrompt, buildResumeWrap, buildFreshWrap, } from '../prompts.js';
|
|
26
26
|
import * as relayState from '../relay/state.js';
|
|
27
27
|
import { maybeOfferRelayOn, ensureDaemonRunning } from '../relay/onboarding.js';
|
|
@@ -513,7 +513,9 @@ export const claudeCommand = new Command('claude')
|
|
|
513
513
|
// .gipity.json into cwd (no projects-root materialization).
|
|
514
514
|
const cwdBase = basename(process.cwd());
|
|
515
515
|
const adoptSlug = slugify(cwdBase) || 'project';
|
|
516
|
-
|
|
516
|
+
// Server caps name at 100 chars; clamp so a very long dir name
|
|
517
|
+
// doesn't trip a "Too big" 400 (slugify already clamps the slug).
|
|
518
|
+
const adoptName = (cwdBase || adoptSlug).slice(0, 100);
|
|
517
519
|
accountSlug = await getAccountSlug();
|
|
518
520
|
const adopted = await adoptCurrentDir({
|
|
519
521
|
cwd: process.cwd(),
|
|
@@ -599,6 +601,10 @@ export const claudeCommand = new Command('claude')
|
|
|
599
601
|
console.log(` Then: cd ${process.cwd()} && claude`);
|
|
600
602
|
return;
|
|
601
603
|
}
|
|
604
|
+
// Ensure the Gipity plugin is actually installed at user scope (not just
|
|
605
|
+
// enabled declaratively) so its capture + file-sync hooks load in this
|
|
606
|
+
// run's cwd. No-ops once the current version is installed; best-effort.
|
|
607
|
+
ensureGipityPluginInstalled();
|
|
602
608
|
// Resolve (or create) the backing Gipity conversation for this
|
|
603
609
|
// Claude Code run. The conv_guid is handed to the child (and thus
|
|
604
610
|
// every capture hook spawned by Claude Code) via env var so every
|
package/dist/commands/init.js
CHANGED
|
@@ -112,8 +112,9 @@ Working with an existing Gipity project:
|
|
|
112
112
|
process.exit(1);
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
-
// Resolve project name
|
|
116
|
-
|
|
115
|
+
// Resolve project name. Server caps name at 100 chars; clamp so a very
|
|
116
|
+
// long dir name doesn't trip a "Too big" 400 (slugify clamps the slug).
|
|
117
|
+
const projectName = (name || basename(cwd)).slice(0, 100);
|
|
117
118
|
const projectSlug = slugify(projectName);
|
|
118
119
|
if (!projectSlug) {
|
|
119
120
|
console.error(clrError('Could not derive a valid project slug. Provide a name: gipity init my-app'));
|
package/dist/commands/status.js
CHANGED
|
@@ -5,10 +5,14 @@ import { homedir } from 'os';
|
|
|
5
5
|
import { getAuth, sessionExpired } from '../auth.js';
|
|
6
6
|
import { getConfig, liveUrl } from '../config.js';
|
|
7
7
|
import { brand, success, warning, muted, error as clrError } from '../colors.js';
|
|
8
|
-
import { GIPITY_PLUGIN_ID, GIPITY_MARKETPLACE_NAME, setupClaudeHooks, ensureGipityPlugin } from '../setup.js';
|
|
9
|
-
/** Hooks ship in the Gipity Claude Code plugin now
|
|
10
|
-
* user-scope settings register the marketplace and
|
|
11
|
-
*
|
|
8
|
+
import { GIPITY_PLUGIN_ID, GIPITY_MARKETPLACE_NAME, setupClaudeHooks, ensureGipityPlugin, ensureGipityPluginInstalled, userScopePluginCurrent } from '../setup.js';
|
|
9
|
+
/** Hooks ship in the Gipity Claude Code plugin now. "Installed" means three
|
|
10
|
+
* things must all hold: the user-scope settings register the marketplace and
|
|
11
|
+
* enable the plugin (declarative), AND Claude Code actually has a user-scope
|
|
12
|
+
* install of the current version on disk. The last check matters because
|
|
13
|
+
* CC >=2.1.x does not materialize a user-scope install from enablement alone -
|
|
14
|
+
* without it the hooks never load and capture/file-sync silently die, so
|
|
15
|
+
* reporting "ok" on the declarative keys alone would be a false green. */
|
|
12
16
|
function checkGipityPlugin() {
|
|
13
17
|
const path = join(homedir(), '.claude', 'settings.json');
|
|
14
18
|
let settings = {};
|
|
@@ -23,6 +27,8 @@ function checkGipityPlugin() {
|
|
|
23
27
|
missing.push('marketplace');
|
|
24
28
|
if (settings?.enabledPlugins?.[GIPITY_PLUGIN_ID] !== true)
|
|
25
29
|
missing.push('plugin');
|
|
30
|
+
if (!userScopePluginCurrent())
|
|
31
|
+
missing.push('install');
|
|
26
32
|
return { missing, ok: missing.length === 0 };
|
|
27
33
|
}
|
|
28
34
|
export const statusCommand = new Command('status')
|
|
@@ -82,6 +88,9 @@ export const statusCommand = new Command('status')
|
|
|
82
88
|
// force: an explicit repair request overrides a previous disable.
|
|
83
89
|
ensureGipityPlugin(true);
|
|
84
90
|
setupClaudeHooks();
|
|
91
|
+
// Re-enabling the declarative keys isn't enough on CC >=2.1.x - also
|
|
92
|
+
// materialize the user-scope install so the hooks actually load.
|
|
93
|
+
ensureGipityPluginInstalled();
|
|
85
94
|
console.log(`${muted('Hooks:')} ${success('repaired - Gipity plugin re-enabled')}`);
|
|
86
95
|
}
|
|
87
96
|
else {
|
package/dist/setup.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { resolve, join, dirname } from 'path';
|
|
5
5
|
import { homedir } from 'os';
|
|
6
6
|
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
7
|
+
import { spawnSync } from 'child_process';
|
|
7
8
|
import { SKILLS_CONTENT, BUILD_VS_NON_BUILD_RULE, DEFINITION_OF_DONE } from './knowledge.js';
|
|
8
9
|
export { SKILLS_CONTENT };
|
|
9
10
|
/** Canonical list of workstation artifacts that are NOT part of the project.
|
|
@@ -100,13 +101,27 @@ export const PERMISSIONS_SETTINGS = {
|
|
|
100
101
|
// into each project's .claude/settings.json with absolute paths baked in -
|
|
101
102
|
// that left orphaned entries behind on uninstall (the CLI keeps no inventory
|
|
102
103
|
// of projects it touched) and could even land in the user-global settings
|
|
103
|
-
// when a gipity command ran from $HOME. The plugin replaces all of it
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
104
|
+
// when a gipity command ran from $HOME. The plugin replaces all of it: Claude
|
|
105
|
+
// Code resolves script paths via ${CLAUDE_PLUGIN_ROOT} and uninstall/disable
|
|
106
|
+
// removes every hook at once.
|
|
107
|
+
//
|
|
108
|
+
// Two steps are needed to make it load, split by testability and cost:
|
|
109
|
+
// - ensureGipityPlugin() - declarative: register the marketplace +
|
|
110
|
+
// enable the plugin in ~/.claude/settings.json. Pure file writes.
|
|
111
|
+
// - ensureGipityPluginInstalled() - imperative: actually install the plugin
|
|
112
|
+
// at USER scope via the `claude plugin` CLI. Required because CC >=2.1.x no
|
|
113
|
+
// longer materializes a user-scope install from enablement alone; without
|
|
114
|
+
// it the hooks load only inside whatever project happened to install the
|
|
115
|
+
// plugin (often nowhere), silently taking capture + file-sync down.
|
|
107
116
|
export const GIPITY_PLUGIN_ID = 'gipity@gipity';
|
|
108
117
|
export const GIPITY_MARKETPLACE_NAME = 'gipity';
|
|
109
118
|
export const GIPITY_MARKETPLACE_REPO = 'GipityAI/claude-plugin';
|
|
119
|
+
// The plugin version this CLI requires. Bump in lockstep with
|
|
120
|
+
// claude-plugin/.claude-plugin/plugin.json: Claude Code does NOT auto-upgrade
|
|
121
|
+
// an installed plugin when the marketplace advances - only an explicit
|
|
122
|
+
// `plugin install`/`update` does - so this constant is how a CLI upgrade tells
|
|
123
|
+
// ensureGipityPluginInstalled() to refresh a stale user-scope install.
|
|
124
|
+
export const GIPITY_PLUGIN_VERSION = '0.4.0';
|
|
110
125
|
/** True for hook commands the CLI itself wrote into settings.json in past
|
|
111
126
|
* versions. Matched by signature so migration strips exactly our own
|
|
112
127
|
* entries and never touches user-authored hooks. */
|
|
@@ -192,6 +207,76 @@ export function ensureGipityPlugin(force = false) {
|
|
|
192
207
|
mkdirSync(claudeDir, { recursive: true });
|
|
193
208
|
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
194
209
|
}
|
|
210
|
+
/** Dotted-numeric version compare: true when `have` >= `want` (e.g. "0.4.0"). */
|
|
211
|
+
function versionGte(have, want) {
|
|
212
|
+
const h = have.split('.').map((n) => parseInt(n, 10) || 0);
|
|
213
|
+
const w = want.split('.').map((n) => parseInt(n, 10) || 0);
|
|
214
|
+
for (let i = 0; i < Math.max(h.length, w.length); i++) {
|
|
215
|
+
const a = h[i] ?? 0;
|
|
216
|
+
const b = w[i] ?? 0;
|
|
217
|
+
if (a !== b)
|
|
218
|
+
return a > b;
|
|
219
|
+
}
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
/** True when Claude Code already records a USER-scope install of the Gipity
|
|
223
|
+
* plugin at >= the version this CLI needs - the common case, letting the
|
|
224
|
+
* caller skip the (slow) reinstall. Reads installed_plugins.json directly so
|
|
225
|
+
* the check costs no subprocess. Exported so `gipity status` can tell an
|
|
226
|
+
* actually-loaded plugin apart from one that's merely enabled-but-uninstalled
|
|
227
|
+
* (which would otherwise read as a false-green "hooks enabled"). */
|
|
228
|
+
export function userScopePluginCurrent() {
|
|
229
|
+
try {
|
|
230
|
+
const p = join(homedir(), '.claude', 'plugins', 'installed_plugins.json');
|
|
231
|
+
const data = JSON.parse(readFileSync(p, 'utf-8'));
|
|
232
|
+
const entries = data?.plugins?.[GIPITY_PLUGIN_ID];
|
|
233
|
+
if (!Array.isArray(entries))
|
|
234
|
+
return false;
|
|
235
|
+
return entries.some((e) => e?.scope === 'user' &&
|
|
236
|
+
typeof e?.version === 'string' &&
|
|
237
|
+
versionGte(e.version, GIPITY_PLUGIN_VERSION));
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function claudeOnPath() {
|
|
244
|
+
const probe = spawnSync(process.platform === 'win32' ? 'where' : 'which', ['claude'], {
|
|
245
|
+
encoding: 'utf-8',
|
|
246
|
+
});
|
|
247
|
+
return probe.status === 0 && !!probe.stdout?.trim();
|
|
248
|
+
}
|
|
249
|
+
/** Materialize the Gipity plugin at USER scope via Claude Code's own plugin
|
|
250
|
+
* CLI, so its hooks (session capture + file sync) load in EVERY directory.
|
|
251
|
+
*
|
|
252
|
+
* ensureGipityPlugin() only writes the declarative `enabledPlugins` /
|
|
253
|
+
* `extraKnownMarketplaces` keys. That was enough on older Claude Code, but
|
|
254
|
+
* CC >=2.1.x no longer materializes a user-scope install from an enablement
|
|
255
|
+
* entry alone: without an actual user-scope install the plugin loads only in
|
|
256
|
+
* whatever project happened to install it (often nowhere), so capture and
|
|
257
|
+
* file-sync silently go dark everywhere else. We drive the supported
|
|
258
|
+
* `claude plugin` commands rather than trust implicit resolution.
|
|
259
|
+
*
|
|
260
|
+
* Best-effort and non-fatal - a missing `claude` or a failed install must
|
|
261
|
+
* never break `gipity claude`. Skips entirely when the user-scope install is
|
|
262
|
+
* already current, so it shells out at most once per plugin-version bump. */
|
|
263
|
+
export function ensureGipityPluginInstalled() {
|
|
264
|
+
if (userScopePluginCurrent())
|
|
265
|
+
return;
|
|
266
|
+
if (!claudeOnPath())
|
|
267
|
+
return;
|
|
268
|
+
// Refresh the marketplace clone so `install` resolves the current version,
|
|
269
|
+
// then (re)install at user scope - idempotent, and upgrades an older or
|
|
270
|
+
// project-scoped install to the current one at user scope.
|
|
271
|
+
spawnSync('claude', ['plugin', 'marketplace', 'update', GIPITY_MARKETPLACE_NAME], {
|
|
272
|
+
stdio: 'ignore',
|
|
273
|
+
timeout: 120_000,
|
|
274
|
+
});
|
|
275
|
+
spawnSync('claude', ['plugin', 'install', GIPITY_PLUGIN_ID, '--scope', 'user'], {
|
|
276
|
+
stdio: 'ignore',
|
|
277
|
+
timeout: 120_000,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
195
280
|
export function setupClaudeHooks() {
|
|
196
281
|
// All hooks ship in the plugin - enable it at user scope (and clean up any
|
|
197
282
|
// legacy hook blocks in the user-global settings while we're there).
|
|
@@ -404,11 +489,23 @@ export function setupGitignore() {
|
|
|
404
489
|
writeFileSync(gitignorePath, entries.join('\n') + '\n');
|
|
405
490
|
}
|
|
406
491
|
}
|
|
492
|
+
/** The server caps slugs at 50 (MAX_PROJECT_SLUG_LENGTH); we cap shorter for
|
|
493
|
+
* readability, since the slug is also the on-disk folder and the URL path
|
|
494
|
+
* segment. Keeps long-named directories from producing valid-but-ugly slugs. */
|
|
495
|
+
export const MAX_SLUG_LENGTH = 40;
|
|
407
496
|
export function slugify(name) {
|
|
408
|
-
|
|
497
|
+
const slug = name
|
|
409
498
|
.toLowerCase()
|
|
410
499
|
.replace(/[^a-z0-9-]/g, '-')
|
|
411
500
|
.replace(/-+/g, '-')
|
|
412
501
|
.replace(/^-|-$/g, '');
|
|
502
|
+
if (slug.length <= MAX_SLUG_LENGTH)
|
|
503
|
+
return slug;
|
|
504
|
+
// Cut at the last word (hyphen) boundary within the cap so we don't slice
|
|
505
|
+
// mid-word (e.g. "...call-no"). Fall back to a hard cut if the first word
|
|
506
|
+
// alone already exceeds the cap.
|
|
507
|
+
const cut = slug.slice(0, MAX_SLUG_LENGTH);
|
|
508
|
+
const lastHyphen = cut.lastIndexOf('-');
|
|
509
|
+
return (lastHyphen > 0 ? cut.slice(0, lastHyphen) : cut).replace(/-+$/, '');
|
|
413
510
|
}
|
|
414
511
|
//# sourceMappingURL=setup.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gipity",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.391",
|
|
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",
|