gipity 1.0.429 → 1.1.2

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.
Files changed (45) hide show
  1. package/README.md +67 -29
  2. package/dist/agents/claude-code.js +48 -0
  3. package/dist/agents/codex.js +45 -0
  4. package/dist/agents/grok.js +50 -0
  5. package/dist/agents/index.js +23 -0
  6. package/dist/agents/types.js +18 -0
  7. package/dist/api.js +14 -4
  8. package/dist/capture/sources/codex.js +216 -0
  9. package/dist/capture/sources/grok.js +178 -0
  10. package/dist/catalog.js +46 -0
  11. package/dist/client-context.js +2 -0
  12. package/dist/commands/add.js +9 -22
  13. package/dist/commands/build.js +1330 -0
  14. package/dist/commands/chat.js +9 -3
  15. package/dist/commands/claude.js +4 -13
  16. package/dist/commands/db.js +22 -5
  17. package/dist/commands/deploy.js +7 -0
  18. package/dist/commands/doctor.js +8 -2
  19. package/dist/commands/fn.js +24 -1
  20. package/dist/commands/init.js +9 -15
  21. package/dist/commands/logs.js +21 -2
  22. package/dist/commands/page-eval.js +25 -10
  23. package/dist/commands/page-inspect.js +7 -3
  24. package/dist/commands/page-screenshot.js +62 -23
  25. package/dist/commands/project.js +1 -1
  26. package/dist/commands/relay-install.js +1 -1
  27. package/dist/commands/relay.js +3 -3
  28. package/dist/commands/sandbox.js +62 -16
  29. package/dist/commands/setup.js +16 -10
  30. package/dist/commands/status.js +35 -7
  31. package/dist/commands/test.js +7 -0
  32. package/dist/commands/uninstall.js +25 -3
  33. package/dist/flag-aliases.js +1 -0
  34. package/dist/hooks/capture-runner.js +127 -38
  35. package/dist/index.js +1118 -361
  36. package/dist/knowledge.js +3 -3
  37. package/dist/prefs.js +42 -0
  38. package/dist/project-setup.js +2 -10
  39. package/dist/relay/daemon.js +124 -16
  40. package/dist/relay/diagnostics.js +4 -2
  41. package/dist/relay/onboarding.js +9 -9
  42. package/dist/relay/setup.js +8 -8
  43. package/dist/relay/state.js +1 -1
  44. package/dist/setup.js +258 -17
  45. package/package.json +4 -3
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Grok Build chat_history.jsonl transcript → ingest entries.
3
+ *
4
+ * Grok Build persists each session under
5
+ * ~/.grok/sessions/<urlencoded-cwd>/<session_id>/
6
+ * with several files; `chat_history.jsonl` is the clean one-message-per-line
7
+ * conversation log and our parse target (events.jsonl is lifecycle noise,
8
+ * updates.jsonl is a chunked ACP stream). Verified against real sessions
9
+ * (Grok Build / grok-4.5, 2026-07-13). Line shapes:
10
+ *
11
+ * { type: 'system', content } → SKIP (system prompt)
12
+ * { type: 'user', content, synthetic_reason?, prompt_index? }
13
+ * synthetic_reason present → SKIP (injected context, not the user)
14
+ * else → prompt entry
15
+ * { type: 'assistant', content, tool_calls?: [{id,name,arguments}],
16
+ * model_id?, reasoning_effort? } → assistant (+ tool_use per call)
17
+ * { type: 'tool_result', tool_call_id, content } → tool_result
18
+ * { type: 'reasoning', encrypted_content, summary } → SKIP (parity with Claude parser)
19
+ *
20
+ * Grok hook payloads may not carry a transcript path; the capture runner
21
+ * derives it from the hook's cwd + session_id
22
+ * (`~/.grok/sessions/<encodeURIComponent(cwd)>/<session_id>/chat_history.jsonl`).
23
+ *
24
+ * Dedup/watermark: chat_history lines carry no uuid or timestamp, so uuids
25
+ * are synthesized. tool_use/tool_result key off the stable `tool_calls[].id`
26
+ * (`call-<uuid>-N`), which survives file rewrites; assistant/prompt entries
27
+ * use positional `<session_id>#<lineIndex>` uuids. The watermark is
28
+ * positional; a foreign watermark (session id mismatch / rotated file) makes
29
+ * the caller replay from the top, and the server's source_uuid unique index
30
+ * collapses anything already forwarded.
31
+ */
32
+ function positional(sessionId, idx) {
33
+ return `${sessionId}#${idx}`;
34
+ }
35
+ function watermarkIndex(afterUuid, sessionId) {
36
+ if (!afterUuid || !sessionId)
37
+ return null;
38
+ const prefix = `${sessionId}#`;
39
+ if (!afterUuid.startsWith(prefix))
40
+ return null;
41
+ const idx = parseInt(afterUuid.slice(prefix.length), 10);
42
+ return Number.isInteger(idx) && idx >= 0 ? idx : null;
43
+ }
44
+ function contentToText(content) {
45
+ if (typeof content === 'string')
46
+ return content;
47
+ if (Array.isArray(content)) {
48
+ // Defensive: some harness versions may block-structure content.
49
+ const parts = [];
50
+ for (const b of content) {
51
+ if (b && typeof b.text === 'string')
52
+ parts.push(b.text);
53
+ }
54
+ return parts.join('\n');
55
+ }
56
+ return '';
57
+ }
58
+ function lineToEntries(parsed, sessionId, idx, toolNames) {
59
+ if (!parsed || typeof parsed !== 'object' || typeof parsed.type !== 'string')
60
+ return [];
61
+ if (parsed.type === 'user') {
62
+ if (parsed.synthetic_reason)
63
+ return []; // injected context, not the user
64
+ let prompt = contentToText(parsed.content);
65
+ if (!prompt)
66
+ return [];
67
+ // Grok also injects an environment block as a PLAIN user line (no
68
+ // synthetic_reason) at session start - recognizable by its wrapper tag.
69
+ if (prompt.startsWith('<user_info>'))
70
+ return [];
71
+ // The real prompt arrives wrapped in <user_query> tags - unwrap for
72
+ // clean display; the wrapper is Grok plumbing, not what the user typed.
73
+ const m = prompt.match(/^<user_query>\s*([\s\S]*?)\s*<\/user_query>$/);
74
+ if (m)
75
+ prompt = m[1];
76
+ if (!prompt)
77
+ return [];
78
+ return [{ kind: 'prompt', prompt, source_uuid: positional(sessionId, idx) }];
79
+ }
80
+ if (parsed.type === 'assistant') {
81
+ const text = contentToText(parsed.content);
82
+ const out = [];
83
+ const calls = Array.isArray(parsed.tool_calls) ? parsed.tool_calls : [];
84
+ if (text || calls.length) {
85
+ out.push({
86
+ kind: 'assistant',
87
+ text,
88
+ blocks: text ? [{ type: 'text', text }] : [],
89
+ ...(typeof parsed.model_id === 'string' ? { model: parsed.model_id } : {}),
90
+ source_uuid: positional(sessionId, idx),
91
+ });
92
+ }
93
+ for (const call of calls) {
94
+ if (!call || typeof call.id !== 'string' || !call.id)
95
+ continue;
96
+ const toolName = typeof call.name === 'string' && call.name ? call.name : 'tool';
97
+ toolNames.set(call.id, toolName);
98
+ let toolInput = call.arguments ?? null;
99
+ if (typeof toolInput === 'string') {
100
+ try {
101
+ toolInput = JSON.parse(toolInput);
102
+ }
103
+ catch { /* keep raw string */ }
104
+ }
105
+ out.push({
106
+ kind: 'tool_use',
107
+ tool_use_id: call.id,
108
+ tool_name: toolName,
109
+ tool_input: toolInput,
110
+ source_uuid: call.id,
111
+ });
112
+ }
113
+ return out;
114
+ }
115
+ if (parsed.type === 'tool_result') {
116
+ if (typeof parsed.tool_call_id !== 'string' || !parsed.tool_call_id)
117
+ return [];
118
+ return [{
119
+ kind: 'tool_result',
120
+ tool_use_id: parsed.tool_call_id,
121
+ tool_name: toolNames.get(parsed.tool_call_id),
122
+ content: parsed.content ?? null,
123
+ source_uuid: `${parsed.tool_call_id}#out`,
124
+ }];
125
+ }
126
+ return []; // system, reasoning, unknown
127
+ }
128
+ /** Parse the full chat_history JSONL and emit every ingest entry that comes
129
+ * *after* the positional watermark `afterUuid`. Same contract as the
130
+ * claude-code parser. */
131
+ export function parseTranscript(content, afterUuid, ctx = {}) {
132
+ const sessionId = ctx.sessionId ?? '';
133
+ const lines = content.split('\n');
134
+ // A watermark pointing past EOF means the file shrank under the same
135
+ // session id (e.g. a rewind rewrote chat_history). Treat it as not-found
136
+ // so the caller replays from the top - otherwise capture wedges silently.
137
+ let startAfter = watermarkIndex(afterUuid, sessionId);
138
+ if (startAfter !== null && startAfter >= lines.length)
139
+ startAfter = null;
140
+ const foundWatermark = afterUuid === null || startAfter !== null;
141
+ const out = [];
142
+ const toolNames = new Map();
143
+ let lastIdx = startAfter;
144
+ for (let i = 0; i < lines.length; i++) {
145
+ const line = lines[i].trim();
146
+ if (!line)
147
+ continue;
148
+ let parsed;
149
+ try {
150
+ parsed = JSON.parse(line);
151
+ }
152
+ catch {
153
+ continue;
154
+ }
155
+ if (startAfter !== null && i <= startAfter) {
156
+ // Pre-watermark: record tool names only, so a post-watermark
157
+ // tool_result still resolves the name of an already-forwarded call.
158
+ if (parsed?.type === 'assistant' && Array.isArray(parsed.tool_calls)) {
159
+ for (const call of parsed.tool_calls) {
160
+ if (call && typeof call.id === 'string' && call.id) {
161
+ toolNames.set(call.id, typeof call.name === 'string' && call.name ? call.name : 'tool');
162
+ }
163
+ }
164
+ }
165
+ continue;
166
+ }
167
+ const entries = lineToEntries(parsed, sessionId, i, toolNames);
168
+ for (const e of entries)
169
+ out.push(e);
170
+ lastIdx = i;
171
+ }
172
+ return {
173
+ entries: out,
174
+ lastUuid: lastIdx === null ? afterUuid : positional(sessionId, lastIdx),
175
+ foundWatermark,
176
+ };
177
+ }
178
+ //# sourceMappingURL=grok.js.map
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The `gipity add` catalog - template + kit keys with terse list hints.
3
+ *
4
+ * AUTO-GENERATED - do not edit directly.
5
+ * Source: platform/packages/shared/src/constants.ts (TEMPLATES/KITS cliHint fields)
6
+ * Run `just build-knowledge` to refresh.
7
+ */
8
+ /** Visible starter templates (complete working demos). */
9
+ export const STARTERS = [
10
+ { key: 'web-vision-cam', hint: 'fullscreen camera app with on-device vision (MediaPipe)' },
11
+ { key: 'object-spotter', hint: 'camera app that boxes, labels, and counts objects (YOLOX on-device)' },
12
+ { key: '2d-game', hint: '2D games with Phaser 3 - platformer, arcade, puzzle' },
13
+ { key: '3d-world', hint: 'playable 3D multiplayer rocket-launcher demo' },
14
+ { key: 'karaoke-captions', hint: 'audio + lyrics -> word-synced karaoke captions (GPU job)' },
15
+ { key: 'outreach-agent', hint: 'AI-run outreach funnel - import contacts, draft + auto-send staged emails' },
16
+ { key: 'paid-app', hint: 'storefront that charges real money - Stripe checkout, members area, billing' },
17
+ { key: 'notify-demo', hint: 'web-push demo - enable notifications, send a real ping' },
18
+ ];
19
+ /** Visible blank-wiring templates. */
20
+ export const BLANK = [
21
+ { key: 'web-simple', hint: 'static frontend-only site - pages, dashboards, simple games' },
22
+ { key: 'web-fullstack', hint: 'backend API + database wiring - frontend, functions, migrations; deploys green' },
23
+ { key: '3d-engine', hint: '3D multiplayer wiring - Three.js + Rapier + Gipity Realtime' },
24
+ { key: 'api', hint: 'pure API backend, no frontend - one example function + test' },
25
+ ];
26
+ /** Hidden templates - installable by exact key, omitted from listings. */
27
+ export const HIDDEN = [
28
+ { key: 'app-itsm', hint: 'IT service management / helpdesk / ticketing' },
29
+ { key: 'monitor', hint: 'account observability dashboard (auto-installed per account)' },
30
+ ];
31
+ /** Kits - building blocks added into an existing app. */
32
+ export const KITS = [
33
+ { key: 'realtime', hint: 'multiplayer / presence / shared state' },
34
+ { key: 'web-vision-mediapipe', hint: 'browser camera vision - gesture, pose, object detection' },
35
+ { key: 'web-vision-detect', hint: 'browser object detection - YOLOX, WebGPU/WASM, custom models' },
36
+ { key: 'chatbot', hint: 'drop-in chatbot - persona, guardrails, streaming responses' },
37
+ { key: 'audio-align', hint: 'audio + lyrics -> word-level timing JSON (GPU job)' },
38
+ { key: 'i18n', hint: 'multi-language web apps - language picker, RTL, translations' },
39
+ { key: 'records', hint: 'registry-driven data plane - generic CRUD, validation, search, audit spine' },
40
+ { key: 'views', hint: 'registry-driven UI over records - table, forms, kanban' },
41
+ { key: 'agent-api', hint: 'named API keys for agent/script writes through the records kit' },
42
+ { key: 'contacts', hint: 'multi-source contact layer - LinkedIn/Gmail import, dedupe with provenance' },
43
+ { key: 'stripe', hint: 'charge your users - Stripe checkout, subscriptions, brokered webhooks' },
44
+ { key: 'notify', hint: 'web push notifications - platform-owned keys, works on iOS home screen' },
45
+ ];
46
+ //# sourceMappingURL=catalog.js.map
@@ -27,6 +27,8 @@ export function detectHarness() {
27
27
  }
28
28
  if (hasEnvPrefix('CODEX_'))
29
29
  return { harness: 'codex' };
30
+ if (hasEnvPrefix('GROK_'))
31
+ return { harness: 'grok', harnessSession: process.env.GROK_SESSION_ID };
30
32
  if (process.env.CURSOR_TRACE_ID || hasEnvPrefix('CURSOR_') || (process.env.TERM_PROGRAM ?? '').toLowerCase().includes('cursor')) {
31
33
  return { harness: 'cursor' };
32
34
  }
@@ -8,28 +8,15 @@ import { sync } from '../sync.js';
8
8
  import { success, muted, bold, warning, error as clrError } from '../colors.js';
9
9
  import { run } from '../helpers/index.js';
10
10
  import { createProgressReporter, withSpinner } from '../progress.js';
11
- const STARTERS = [
12
- { key: 'web-vision-cam', hint: 'fullscreen camera app with on-device vision (MediaPipe)' },
13
- { key: 'object-spotter', hint: 'camera app that boxes, labels, and counts objects (YOLOX on-device)' },
14
- { key: '2d-game', hint: '2D games with Phaser 3 - platformer, arcade, puzzle' },
15
- { key: '3d-world', hint: 'playable 3D multiplayer rocket-launcher demo' },
16
- { key: 'karaoke-captions', hint: 'audio + lyrics -> word-synced karaoke captions (GPU job)' },
17
- ];
18
- const BLANK = [
19
- { key: 'web-simple', hint: 'static frontend-only site - pages, dashboards, simple games' },
20
- { key: 'web-fullstack', hint: 'backend API + database wiring - frontend, functions, migrations; deploys green' },
21
- { key: 'api', hint: 'pure API backend, no frontend - one example function + test' },
22
- { key: '3d-engine', hint: '3D multiplayer wiring - Three.js + Rapier + Gipity Realtime' },
23
- ];
24
- const HIDDEN = [{ key: 'app-itsm', hint: 'IT service management / helpdesk / ticketing' }];
25
- const KITS = [
26
- { key: 'realtime', hint: 'multiplayer / presence / shared state' },
27
- { key: 'web-vision-mediapipe', hint: 'browser camera vision - gesture, pose, object detection' },
28
- { key: 'web-vision-detect', hint: 'browser object detection - YOLOX, WebGPU/WASM, custom models' },
29
- { key: 'chatbot', hint: 'drop-in chatbot - persona, guardrails, streaming responses' },
30
- { key: 'audio-align', hint: 'audio + lyrics -> word-level timing JSON (GPU job)' },
31
- { key: 'i18n', hint: 'multi-language web apps - language picker, RTL, translations' },
32
- ];
11
+ // Catalog GENERATED from platform/packages/shared (TEMPLATES + KITS cliHint
12
+ // fields) into src/catalog.ts by platform/scripts/build-knowledge.ts - the CLI
13
+ // ships as a standalone npm package and can't depend on the private shared
14
+ // workspace. The hand-mirrored copy that used to live here silently dropped
15
+ // every new catalog entry; edit constants.ts + `just build-knowledge` instead.
16
+ //
17
+ // Templates install a whole app (blank wiring or a working starter demo).
18
+ // Kits are reusable building blocks added into an existing app's src/packages/.
19
+ import { STARTERS, BLANK, KITS } from '../catalog.js';
33
20
  // The catalog block, rendered once and reused by the full help output
34
21
  // (`gipity add` / `gipity add --help`) and the bare listing (`gipity add
35
22
  // --list`) so they can never drift. Three sections, one entry per line, keys