@sashabogi/foundation 2.0.0 → 2.1.0

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 (44) hide show
  1. package/README.md +3 -158
  2. package/dist/cli.js +143 -114
  3. package/dist/cli.js.map +1 -1
  4. package/dist/providers/anthropic.d.ts +2 -2
  5. package/dist/providers/anthropic.d.ts.map +1 -1
  6. package/dist/providers/anthropic.js +2 -2
  7. package/dist/providers/anthropic.js.map +1 -1
  8. package/dist/providers/types.d.ts +1 -1
  9. package/dist/providers/types.d.ts.map +1 -1
  10. package/dist/providers/zai.d.ts +17 -8
  11. package/dist/providers/zai.d.ts.map +1 -1
  12. package/dist/providers/zai.js +34 -13
  13. package/dist/providers/zai.js.map +1 -1
  14. package/dist/services/config.service.d.ts +1 -5
  15. package/dist/services/config.service.d.ts.map +1 -1
  16. package/dist/services/config.service.js +0 -20
  17. package/dist/services/config.service.js.map +1 -1
  18. package/dist/services/git.service.d.ts +0 -4
  19. package/dist/services/git.service.d.ts.map +1 -1
  20. package/dist/services/git.service.js +0 -30
  21. package/dist/services/git.service.js.map +1 -1
  22. package/dist/services/storage.service.d.ts +1 -24
  23. package/dist/services/storage.service.d.ts.map +1 -1
  24. package/dist/services/storage.service.js +0 -108
  25. package/dist/services/storage.service.js.map +1 -1
  26. package/dist/tools/gaia/index.d.ts +5 -8
  27. package/dist/tools/gaia/index.d.ts.map +1 -1
  28. package/dist/tools/gaia/index.js +16 -115
  29. package/dist/tools/gaia/index.js.map +1 -1
  30. package/dist/tools/gaia/storage.d.ts +13 -0
  31. package/dist/tools/gaia/storage.d.ts.map +1 -1
  32. package/dist/tools/gaia/storage.js +285 -1
  33. package/dist/tools/gaia/storage.js.map +1 -1
  34. package/dist/tools/seldon/index.d.ts +1 -12
  35. package/dist/tools/seldon/index.d.ts.map +1 -1
  36. package/dist/tools/seldon/index.js +1 -183
  37. package/dist/tools/seldon/index.js.map +1 -1
  38. package/dist/types/index.d.ts +0 -78
  39. package/dist/types/index.d.ts.map +1 -1
  40. package/package.json +1 -1
  41. package/packages/ui/dist/assets/index-DVS_pYGH.css +1 -0
  42. package/packages/ui/dist/index.html +2 -2
  43. package/packages/ui/dist/assets/index-fYt-vaxP.css +0 -1
  44. /package/packages/ui/dist/assets/{index-B7zz_B5Q.js → index-WNO_oIqP.js} +0 -0
package/README.md CHANGED
@@ -1,16 +1,6 @@
1
- <p align="center">
2
- <img src="docs/foundation-banner.jpg" alt="Foundation - Unified MCP Server" width="100%">
3
- </p>
4
-
5
- <p align="center">
6
- <a href="https://www.npmjs.com/package/@sashabogi/foundation"><img src="https://img.shields.io/npm/v/@sashabogi/foundation.svg" alt="npm version"></a>
7
- <a href="https://www.npmjs.com/package/@sashabogi/foundation"><img src="https://img.shields.io/npm/dm/@sashabogi/foundation.svg" alt="npm downloads"></a>
8
- <a href="https://github.com/sashabogi/foundation/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@sashabogi/foundation.svg" alt="license"></a>
9
- </p>
10
-
11
1
  # Foundation v2.0
12
2
 
13
- > **Production-grade MCP server for AI-assisted development with advanced memory**
3
+ > **Production-grade MCP server for AI-assisted development**
14
4
  >
15
5
  > *"The future is not fixed, but it can be guided."* — Hari Seldon
16
6
 
@@ -153,7 +143,6 @@ gaia_save({
153
143
  tags: ["auth", "jwt", "security"],
154
144
  related_files: ["src/auth/jwt.ts"]
155
145
  })
156
- // Returns: { success: true, memory: { id: "mem_abc123", ... } }
157
146
  ```
158
147
 
159
148
  ### 3. Search Memories
@@ -164,7 +153,6 @@ gaia_search({
164
153
  tiers: ["project", "global"],
165
154
  limit: 10
166
155
  })
167
- // Returns ranked results with BM25 + composite scoring
168
156
  ```
169
157
 
170
158
  ### 4. Link Memories
@@ -177,7 +165,6 @@ gaia_link({
177
165
  })
178
166
 
179
167
  gaia_graph({ memory_id: "mem_impl_456" })
180
- // Returns: { depends_on: [{ id: "mem_decision_123", content: "...", ... }] }
181
168
  ```
182
169
 
183
170
  ---
@@ -254,9 +241,9 @@ Gaia provides **workflow patterns and persistent memory**. Version 2.0 transform
254
241
  - Searching past conversations
255
242
  - Capturing patterns and learnings
256
243
 
257
- **Tools (19 total):**
244
+ **Tools (20 total):**
258
245
 
259
- #### Workflow Tools (12)
246
+ #### Workflow Tools (9)
260
247
  ```
261
248
  gaia_checkpoint // Save structured session state
262
249
  gaia_status // Lightweight index card (~150 tokens)
@@ -264,9 +251,6 @@ gaia_query // Keyword search checkpoint
264
251
  gaia_get_decisions // List architectural decisions
265
252
  gaia_get_progress // Task progress summary
266
253
  gaia_get_changes // Files changed
267
- gaia_handoff // Create session handoff document (NEW v2.0)
268
- gaia_observe // Auto-detect patterns and observations (NEW v2.0)
269
- gaia_migrate // Migrate v1 checkpoint data to v2 (NEW v2.0)
270
254
  gaia_learn // Record correction for CLAUDE.md
271
255
  gaia_apply // Apply learnings to CLAUDE.md
272
256
  gaia_review // Review learnings
@@ -377,30 +361,25 @@ Returns:
377
361
  Build **dependency graphs** across memories with 5 typed links:
378
362
 
379
363
  ```typescript
380
- // Save a decision
381
364
  const decision = gaia_save({
382
365
  tier: "project",
383
366
  content: "Decision: Use React 18 with TypeScript",
384
367
  tags: ["decision", "architecture"]
385
368
  })
386
369
 
387
- // Save an implementation
388
370
  const impl = gaia_save({
389
371
  tier: "project",
390
372
  content: "Implementation: Set up Vite with React 18 + TS",
391
373
  tags: ["implementation"]
392
374
  })
393
375
 
394
- // Link them
395
376
  gaia_link({
396
377
  from_memory_id: impl.memory.id,
397
378
  to_memory_id: decision.memory.id,
398
379
  link_type: "depends_on"
399
380
  })
400
381
 
401
- // Later - retrieve the graph
402
382
  gaia_graph({ memory_id: impl.memory.id })
403
- // Shows: implementation depends_on decision
404
383
  ```
405
384
 
406
385
  **Link Types:**
@@ -459,7 +438,6 @@ CREATE TABLE memory_links (
459
438
  ### Example 1: Building a Knowledge Base
460
439
 
461
440
  ```typescript
462
- // Save architectural decisions
463
441
  gaia_save({
464
442
  tier: "project",
465
443
  content: "Decision: Use PostgreSQL with Drizzle ORM for type safety",
@@ -468,7 +446,6 @@ gaia_save({
468
446
  metadata: { decision_type: "technical", impact: "high" }
469
447
  })
470
448
 
471
- // Save implementation details
472
449
  gaia_save({
473
450
  tier: "project",
474
451
  content: "PostgreSQL connection pool configured with max 20 connections",
@@ -476,7 +453,6 @@ gaia_save({
476
453
  related_files: ["src/db/index.ts"]
477
454
  })
478
455
 
479
- // Later - search your decisions
480
456
  gaia_search({
481
457
  query: "database PostgreSQL decision",
482
458
  tiers: ["project"],
@@ -487,14 +463,12 @@ gaia_search({
487
463
  ### Example 2: Cross-Prompt Dependencies
488
464
 
489
465
  ```typescript
490
- // Day 1: Make a decision
491
466
  const decision = gaia_save({
492
467
  tier: "project",
493
468
  content: "Decision: Use tRPC for type-safe API",
494
469
  tags: ["decision", "api"]
495
470
  })
496
471
 
497
- // Day 2: Implement it
498
472
  const impl = gaia_save({
499
473
  tier: "project",
500
474
  content: "Created tRPC router with user and auth procedures",
@@ -502,35 +476,29 @@ const impl = gaia_save({
502
476
  related_files: ["src/server/trpc.ts"]
503
477
  })
504
478
 
505
- // Link them
506
479
  gaia_link({
507
480
  from_memory_id: impl.memory.id,
508
481
  to_memory_id: decision.memory.id,
509
482
  link_type: "depends_on"
510
483
  })
511
484
 
512
- // Day 30: Review decision chain
513
485
  gaia_graph({ memory_id: impl.memory.id })
514
- // Shows the full dependency graph
515
486
  ```
516
487
 
517
488
  ### Example 3: Session Workflow
518
489
 
519
490
  ```typescript
520
- // Session start - load context
521
491
  gaia_search({
522
492
  query: "authentication JWT implementation",
523
493
  current_file: "src/auth/verify.ts"
524
494
  })
525
495
 
526
- // During session - save observations
527
496
  gaia_save({
528
497
  tier: "session",
529
498
  content: "Bug: JWT verification doesn't handle expired tokens gracefully",
530
499
  tags: ["bug", "jwt"]
531
500
  })
532
501
 
533
- // Session end - create checkpoint
534
502
  gaia_checkpoint({
535
503
  summary: "Fixed JWT token expiration handling",
536
504
  decisions: [{
@@ -546,127 +514,6 @@ gaia_checkpoint({
546
514
  })
547
515
  ```
548
516
 
549
- ### Example 4: Session Handoff
550
-
551
- ```typescript
552
- // At session end - create checkpoint
553
- gaia_checkpoint({
554
- summary: "Implemented user authentication with JWT",
555
- purpose: "Build secure auth system",
556
- project: "acme-app",
557
- decisions: [{
558
- topic: "Authentication",
559
- decision: "Use JWT with RS256",
560
- rationale: "Industry standard, secure, stateless"
561
- }],
562
- progress: [{
563
- task: "Implement login endpoint",
564
- status: "completed"
565
- }, {
566
- task: "Add refresh token logic",
567
- status: "in_progress"
568
- }],
569
- changes: [{
570
- file: "src/auth/jwt.ts",
571
- action: "created",
572
- summary: "JWT token generation and verification"
573
- }],
574
- context: {
575
- branch: "feat/auth",
576
- openQuestions: [
577
- "Should we implement refresh token rotation?",
578
- "What expiration time for access tokens?"
579
- ],
580
- relevantFiles: ["src/auth/jwt.ts", "src/auth/middleware.ts"]
581
- }
582
- })
583
-
584
- // Create handoff document for next session
585
- gaia_handoff({
586
- next_steps: [
587
- "Implement refresh token rotation strategy",
588
- "Add rate limiting to login endpoint",
589
- "Write integration tests for auth flow",
590
- "Update API documentation with auth examples"
591
- ],
592
- context_notes: "Auth system nearly complete. Main work remaining is refresh token security and testing. Consider implementing exponential backoff on failed login attempts.",
593
- include_memories: true,
594
- memory_query: "authentication JWT security"
595
- })
596
-
597
- // Returns markdown document at ~/.foundation/handoffs/handoff-2026-02-16T10-30-00.md
598
- // Includes:
599
- // - Full checkpoint state (decisions, progress, changes)
600
- // - Relevant memories with BM25 ranking
601
- // - Next steps
602
- // - Context notes
603
- // - Links to related files
604
- ```
605
-
606
- ### Example 5: Autonomous Observation
607
-
608
- ```typescript
609
- // System automatically detects patterns from session activity
610
- gaia_observe({
611
- lookback_days: 30,
612
- auto_save: true,
613
- min_confidence: "medium"
614
- })
615
-
616
- // Returns analysis like:
617
- //
618
- // ## Observations Detected (6)
619
- //
620
- // 1. 🔴 **Repeated decision-making on: Authentication**
621
- // - Evidence: 3 decisions made about Authentication in current session
622
- // - Confidence: high
623
- // - Saved: mem_obs_abc123
624
- //
625
- // 2. 🔴 **Task blockers detected**
626
- // - Evidence: 2 blocked task(s): "Add rate limiting", "Write auth tests"
627
- // - Confidence: high
628
- // - Saved: mem_obs_def456
629
- //
630
- // 3. 🟡 **Frequent modifications to: src/auth/jwt.ts**
631
- // - Evidence: 3 changes to src/auth/jwt.ts in current session
632
- // - Confidence: medium
633
- // - Saved: mem_obs_ghi789
634
- //
635
- // 4. 🟡 **Multiple open questions - potential knowledge gaps**
636
- // - Evidence: 4 unresolved questions
637
- // - Confidence: medium
638
- // - Saved: mem_obs_jkl012
639
- //
640
- // 5. 🔴 **High activity in areas: authentication, security, jwt**
641
- // - Evidence: Frequent tags in recent memories
642
- // - Confidence: high
643
- // - Saved: mem_obs_mno345
644
- //
645
- // 6. 🟡 **File created and deleted: src/temp/test.ts**
646
- // - Evidence: May indicate trial-and-error or false start
647
- // - Confidence: medium
648
- // - Saved: mem_obs_pqr678
649
-
650
- // Observations are saved to 'observation' tier
651
- // Automatically enriched with metadata for pattern analysis
652
- // Can be searched like any other memory
653
-
654
- // Later - search observations
655
- gaia_search({
656
- query: "blocked tasks authentication",
657
- tiers: ["observation"],
658
- limit: 5
659
- })
660
- ```
661
-
662
- **Pattern types detected:**
663
- - Repeated topics (same decisions multiple times)
664
- - Task blockers (blocked status in progress)
665
- - Frequent file changes (same file modified 3+ times)
666
- - Knowledge gaps (multiple open questions)
667
- - Activity hotspots (frequent tags in recent memories)
668
- - Anti-patterns (created then deleted files)
669
-
670
517
  ---
671
518
 
672
519
  ## Performance
@@ -704,13 +551,11 @@ Database:
704
551
  **Optional:** Start using the new memory tools for persistent knowledge:
705
552
 
706
553
  ```typescript
707
- // v1.x approach (still works)
708
554
  gaia_checkpoint({
709
555
  summary: "Implemented auth",
710
556
  decisions: [...]
711
557
  })
712
558
 
713
- // v2.0 approach (recommended - searchable + persistent)
714
559
  gaia_save({
715
560
  tier: "project",
716
561
  content: "Auth implementation uses JWT with RS256",
package/dist/cli.js CHANGED
@@ -14,7 +14,7 @@
14
14
  import { Command } from 'commander';
15
15
  import chalk from 'chalk';
16
16
  import ora from 'ora';
17
- import { existsSync, mkdirSync, writeFileSync, readFileSync, createReadStream, readdirSync, chmodSync } from 'fs';
17
+ import { existsSync, mkdirSync, writeFileSync, readFileSync, createReadStream, readdirSync } from 'fs';
18
18
  import { execSync } from 'child_process';
19
19
  import { homedir } from 'os';
20
20
  import { join, dirname } from 'path';
@@ -25,6 +25,7 @@ const __filename = fileURLToPath(import.meta.url);
25
25
  const __dirname = dirname(__filename);
26
26
  import { ConfigService } from './services/config.service.js';
27
27
  import { runSetupWizard, addProvider, testProvider, listProviders, } from './cli/setup-wizard.js';
28
+ import { MemoriaStorage } from './tools/gaia/storage.js';
28
29
  // Read version from package.json dynamically
29
30
  const packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
30
31
  const VERSION = packageJson.version;
@@ -68,7 +69,7 @@ const FOUNDATION_CLAUDE_MD = `
68
69
 
69
70
  > **CRITICAL: These tools are ALREADY LOADED. Use them directly without ToolSearch.**
70
71
 
71
- Foundation provides 41 tools for AI-assisted development. All tools use \`mcp__foundation__\` prefix.
72
+ Foundation provides 37 tools for AI-assisted development. All tools use \`mcp__foundation__\` prefix.
72
73
 
73
74
  ### Demerzel — Codebase Intelligence
74
75
  *"I have been watching for 20,000 years."*
@@ -92,16 +93,16 @@ Foundation provides 41 tools for AI-assisted development. All tools use \`mcp__f
92
93
 
93
94
  | Tool | Purpose |
94
95
  |------|---------|
95
- | \`seldon_invoke\` | Invoke agent role (coder, critic, reviewer, designer) |
96
+ | \`seldon_invoke\` | Invoke agent role (coder, critic, reviewer) |
96
97
  | \`seldon_compare\` | Compare multiple agent perspectives |
97
98
  | \`seldon_critique\` | Get critical review |
98
99
  | \`seldon_review\` | Code review |
99
100
  | \`seldon_plan\` | Generate implementation plan |
100
101
  | \`seldon_phase_create\` | Break plan into phases |
102
+ | \`seldon_phase_list\` | List phases and status |
101
103
  | \`seldon_verify\` | Verify implementation |
102
104
  | \`seldon_fix\` | Generate fixes |
103
105
  | \`seldon_execute_verified\` | Execute with verification loop |
104
- | \`seldon_execute_parallel\` | Execute phases in parallel |
105
106
  | \`seldon_providers_list\` | List providers |
106
107
  | \`seldon_providers_test\` | Test provider health |
107
108
 
@@ -110,14 +111,22 @@ Foundation provides 41 tools for AI-assisted development. All tools use \`mcp__f
110
111
 
111
112
  | Tool | Purpose |
112
113
  |------|---------|
113
- | \`gaia_worktree_create\` | Create git worktree |
114
- | \`gaia_worktree_list\` | List worktrees |
115
- | \`gaia_session_register\` | Register session |
116
- | \`gaia_session_handoff\` | Create handoff document |
117
- | \`gaia_learn\` | Capture learning |
118
- | \`gaia_apply\` | Apply learnings to CLAUDE.md |
119
- | \`gaia_remember\` | Save context |
120
- | \`gaia_recall\` | Recall context |
114
+ | \`gaia_checkpoint\` | Save structured session state |
115
+ | \`gaia_status\` | Get checkpoint index card (~150 tokens) |
116
+ | \`gaia_query\` | Search checkpoint by keyword |
117
+ | \`gaia_get_decisions\` | Get architectural decisions |
118
+ | \`gaia_get_progress\` | Get task progress |
119
+ | \`gaia_get_changes\` | Get files changed |
120
+ | \`gaia_handoff\` | Create handoff document |
121
+ | \`gaia_observe\` | Analyze session patterns |
122
+ | \`gaia_migrate\` | Migrate v1 checkpoints to v2 |
123
+ | \`gaia_save\` | Save a memory |
124
+ | \`gaia_search\` | Search memories |
125
+ | \`gaia_get\` | Get memory by ID |
126
+ | \`gaia_delete\` | Delete a memory |
127
+ | \`gaia_stats\` | Get memory statistics |
128
+ | \`gaia_link\` | Create typed link between memories |
129
+ | \`gaia_graph\` | Get memory link graph |
121
130
  `;
122
131
  const program = new Command();
123
132
  program
@@ -236,16 +245,6 @@ worktrees:
236
245
  max_count: 10
237
246
  auto_cleanup: true
238
247
  stale_after_hours: 48
239
-
240
- learning:
241
- auto_apply: false
242
- categories:
243
- - code_style
244
- - architecture
245
- - testing
246
- - performance
247
- - security
248
- - documentation
249
248
  `;
250
249
  writeFileSync(CONFIG_FILE, defaultConfig);
251
250
  spinner.succeed('Foundation initialized!');
@@ -339,9 +338,9 @@ mcpCommand
339
338
  console.log(chalk.bold('Foundation is now available in all Claude Code sessions.'));
340
339
  console.log();
341
340
  console.log('Available tools:');
342
- console.log(chalk.cyan(' Demerzel (9)') + ' - Codebase intelligence');
343
- console.log(chalk.cyan(' Seldon (19)') + ' - Multi-agent orchestration');
344
- console.log(chalk.cyan(' Gaia (13)') + ' - Workflow patterns');
341
+ console.log(chalk.cyan(' Demerzel (9)') + ' - Codebase intelligence');
342
+ console.log(chalk.cyan(' Seldon (12)') + ' - Multi-agent orchestration');
343
+ console.log(chalk.cyan(' Gaia (16)') + ' - Workflow patterns + memory');
345
344
  console.log();
346
345
  console.log(chalk.bold('Optional:'));
347
346
  console.log(' Run ' + chalk.cyan('foundation hooks install') + ' in a project to enable');
@@ -384,72 +383,26 @@ mcpCommand
384
383
  const hooksCommand = program
385
384
  .command('hooks')
386
385
  .description('Manage Gaia lifecycle hooks');
387
- // Hook script templates (embedded so they work when installed from npm)
388
- const HOOK_SESSION_START = `#!/bin/bash
389
- # Gaia v2 SessionStart hook
390
- # Injects the latest checkpoint index card into Claude's context.
391
-
392
- find_foundation_dir() {
393
- local dir="\${CLAUDE_PROJECT_DIR:-\$PWD}"
394
- local count=0
395
- while [ \$count -lt 5 ]; do
396
- if [ -f "\$dir/.foundation/sessions/latest/index.txt" ]; then
397
- echo "\$dir"
398
- return 0
399
- fi
400
- dir="\$(dirname "\$dir")"
401
- count=\$((count + 1))
402
- done
403
- return 1
404
- }
405
-
406
- PROJECT_DIR=\$(find_foundation_dir)
407
- if [ \$? -eq 0 ]; then
408
- INDEX_FILE="\$PROJECT_DIR/.foundation/sessions/latest/index.txt"
409
- python3 -c "
410
- import json, sys
411
- try:
412
- with open(sys.argv[1], 'r') as f:
413
- content = f.read().strip()
414
- if content:
415
- output = {'hookSpecificOutput': {'additionalContext': '[Gaia Checkpoint]\\n' + content}}
416
- print(json.dumps(output))
417
- except Exception:
418
- pass
419
- " "\$INDEX_FILE"
420
- fi
421
- `;
422
- const HOOK_PRE_COMPACT = `#!/bin/bash
423
- # Gaia v2 PreCompact hook — reminds to checkpoint before context compaction
424
- printf '{"hookSpecificOutput":{"additionalContext":"[Gaia] Context compaction imminent. If you have unsaved session state (decisions, progress, changes), run gaia_checkpoint now to preserve it before context is lost."}}'
425
- `;
426
- const HOOK_POST_TASK = `#!/bin/bash
427
- # Gaia v2 PostToolUse hook (Task matcher)
428
- INPUT=\$(cat)
429
- AGENT_TYPE=\$(echo "\$INPUT" | python3 -c "
430
- import json, sys
431
- try:
432
- data = json.load(sys.stdin)
433
- tool_input = data.get('tool_input', {})
434
- print(tool_input.get('subagent_type', ''))
435
- except Exception:
436
- print('')
437
- " 2>/dev/null)
438
-
439
- if [ "\$AGENT_TYPE" = "Explore" ]; then
440
- exit 0
441
- fi
442
-
443
- printf '{"hookSpecificOutput":{"additionalContext":"[Gaia] Sub-agent completed. Consider updating your checkpoint if significant progress was made."}}'
444
- `;
386
+ // Inline hook commands (no external .sh files needed)
445
387
  const HOOKS_SETTINGS_CONFIG = {
446
388
  hooks: {
447
389
  SessionStart: [{
448
390
  matcher: '',
449
391
  hooks: [{
450
392
  type: 'command',
451
- command: '.claude/hooks/gaia-session-start.sh',
452
- timeout: 5,
393
+ command: `python3 -c "
394
+ import json, os, pathlib
395
+ d = os.environ.get('CLAUDE_PROJECT_DIR', os.getcwd())
396
+ for _ in range(5):
397
+ f = os.path.join(d, '.foundation', 'sessions', 'latest', 'index.txt')
398
+ if os.path.isfile(f):
399
+ c = pathlib.Path(f).read_text().strip()
400
+ if c:
401
+ print(json.dumps({'hookSpecificOutput':{'additionalContext':'[Gaia Checkpoint]\\\\n'+c}}))
402
+ break
403
+ d = os.path.dirname(d)
404
+ "`,
405
+ timeout: 5000,
453
406
  statusMessage: 'Loading Gaia checkpoint...',
454
407
  }],
455
408
  }],
@@ -457,8 +410,8 @@ const HOOKS_SETTINGS_CONFIG = {
457
410
  matcher: '',
458
411
  hooks: [{
459
412
  type: 'command',
460
- command: '.claude/hooks/gaia-pre-compact.sh',
461
- timeout: 5,
413
+ command: 'echo \'{"hookSpecificOutput":{"additionalContext":"[Gaia] Context compaction imminent. If you have unsaved session state (decisions, progress, changes), run gaia_checkpoint now to preserve it before context is lost."}}\'',
414
+ timeout: 5000,
462
415
  statusMessage: 'Gaia checkpoint reminder',
463
416
  }],
464
417
  }],
@@ -466,8 +419,17 @@ const HOOKS_SETTINGS_CONFIG = {
466
419
  matcher: 'Task',
467
420
  hooks: [{
468
421
  type: 'command',
469
- command: '.claude/hooks/gaia-post-task.sh',
470
- timeout: 5,
422
+ command: `python3 -c "
423
+ import json, sys
424
+ try:
425
+ data = json.load(sys.stdin)
426
+ if data.get('tool_input',{}).get('subagent_type','') == 'Explore':
427
+ sys.exit(0)
428
+ except Exception:
429
+ pass
430
+ print(json.dumps({'hookSpecificOutput':{'additionalContext':'[Gaia] Sub-agent completed. Consider updating your checkpoint if significant progress was made.'}}))
431
+ "`,
432
+ timeout: 5000,
471
433
  }],
472
434
  }],
473
435
  },
@@ -479,23 +441,10 @@ hooksCommand
479
441
  const spinner = ora('Installing Gaia hooks...').start();
480
442
  const cwd = process.cwd();
481
443
  try {
482
- // 1. Create .claude/hooks/ directory
483
- const hooksDir = join(cwd, '.claude', 'hooks');
484
- mkdirSync(hooksDir, { recursive: true });
485
- spinner.text = 'Created .claude/hooks/ directory';
486
- // 2. Write hook scripts
487
- const hookFiles = [
488
- { name: 'gaia-session-start.sh', content: HOOK_SESSION_START },
489
- { name: 'gaia-pre-compact.sh', content: HOOK_PRE_COMPACT },
490
- { name: 'gaia-post-task.sh', content: HOOK_POST_TASK },
491
- ];
492
- for (const hook of hookFiles) {
493
- const hookPath = join(hooksDir, hook.name);
494
- writeFileSync(hookPath, hook.content);
495
- chmodSync(hookPath, 0o755);
496
- }
497
- spinner.text = 'Wrote hook scripts';
498
- // 3. Merge hook configuration into .claude/settings.json
444
+ // 1. Ensure .claude/ directory exists
445
+ const claudeDir = join(cwd, '.claude');
446
+ mkdirSync(claudeDir, { recursive: true });
447
+ // 2. Merge hook configuration into .claude/settings.json
499
448
  const settingsPath = join(cwd, '.claude', 'settings.json');
500
449
  let settings = {};
501
450
  try {
@@ -512,15 +461,12 @@ hooksCommand
512
461
  writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
513
462
  spinner.succeed('Gaia hooks installed!');
514
463
  console.log();
515
- console.log(chalk.bold('Installed hooks:'));
516
- console.log(chalk.green(' ✓') + ' ' + chalk.cyan('gaia-session-start.sh') + ' — Injects checkpoint on session start');
517
- console.log(chalk.green(' ✓') + ' ' + chalk.cyan('gaia-pre-compact.sh') + ' — Reminds to checkpoint before compaction');
518
- console.log(chalk.green(' ✓') + ' ' + chalk.cyan('gaia-post-task.sh') + ' — Reminds to checkpoint after sub-agent tasks');
464
+ console.log(chalk.bold('Configured hooks (inline commands):'));
465
+ console.log(chalk.green(' ✓') + ' ' + chalk.cyan('SessionStart') + ' — Injects checkpoint on session start');
466
+ console.log(chalk.green(' ✓') + ' ' + chalk.cyan('PreCompact') + ' — Reminds to checkpoint before compaction');
467
+ console.log(chalk.green(' ✓') + ' ' + chalk.cyan('PostToolUse') + ' — Reminds to checkpoint after sub-agent tasks');
519
468
  console.log();
520
- console.log(chalk.bold('Files written:'));
521
- console.log(' ' + chalk.gray(join(hooksDir, 'gaia-session-start.sh')));
522
- console.log(' ' + chalk.gray(join(hooksDir, 'gaia-pre-compact.sh')));
523
- console.log(' ' + chalk.gray(join(hooksDir, 'gaia-post-task.sh')));
469
+ console.log(chalk.bold('Updated:'));
524
470
  console.log(' ' + chalk.gray(settingsPath));
525
471
  console.log();
526
472
  console.log(chalk.gray('Hooks will activate on the next Claude Code session in this project.'));
@@ -786,6 +732,89 @@ program
786
732
  }
787
733
  return;
788
734
  }
735
+ // ---- Memory API endpoints ----
736
+ if (url.startsWith('/api/memories/stats')) {
737
+ try {
738
+ const dbPath = join(homedir(), '.foundation', 'gaia-memory.db');
739
+ const storage = new MemoriaStorage(dbPath);
740
+ try {
741
+ const gaia = storage.getStats();
742
+ const rescue = storage.getRescueStats();
743
+ res.writeHead(200, { 'Content-Type': 'application/json', ...corsHeaders });
744
+ res.end(JSON.stringify({ gaia, rescue }));
745
+ }
746
+ finally {
747
+ storage.close();
748
+ }
749
+ }
750
+ catch (err) {
751
+ res.writeHead(500, { 'Content-Type': 'application/json', ...corsHeaders });
752
+ res.end(JSON.stringify({ error: err.message }));
753
+ }
754
+ return;
755
+ }
756
+ if (url.startsWith('/api/memories/recent')) {
757
+ try {
758
+ const urlObj = new URL(url, `http://localhost:${port}`);
759
+ const limit = parseInt(urlObj.searchParams.get('limit') || '50', 10);
760
+ const tierParam = urlObj.searchParams.get('tier');
761
+ const tiers = tierParam ? tierParam.split(',') : undefined;
762
+ const dbPath = join(homedir(), '.foundation', 'gaia-memory.db');
763
+ const storage = new MemoriaStorage(dbPath);
764
+ try {
765
+ const results = storage.getRecent({ limit, tiers });
766
+ res.writeHead(200, { 'Content-Type': 'application/json', ...corsHeaders });
767
+ res.end(JSON.stringify(results));
768
+ }
769
+ finally {
770
+ storage.close();
771
+ }
772
+ }
773
+ catch (err) {
774
+ res.writeHead(500, { 'Content-Type': 'application/json', ...corsHeaders });
775
+ res.end(JSON.stringify({ error: err.message }));
776
+ }
777
+ return;
778
+ }
779
+ if (url.startsWith('/api/memories/search')) {
780
+ try {
781
+ const urlObj = new URL(url, `http://localhost:${port}`);
782
+ const query = urlObj.searchParams.get('q') || '';
783
+ const tierParam = urlObj.searchParams.get('tier');
784
+ const tiers = tierParam ? tierParam.split(',') : undefined;
785
+ const limit = parseInt(urlObj.searchParams.get('limit') || '25', 10);
786
+ const sourceFilter = urlObj.searchParams.get('source') || 'all';
787
+ const dbPath = join(homedir(), '.foundation', 'gaia-memory.db');
788
+ const storage = new MemoriaStorage(dbPath);
789
+ try {
790
+ let results;
791
+ if (!query) {
792
+ // No query = return recent
793
+ results = storage.getRecent({ limit, tiers });
794
+ }
795
+ else {
796
+ results = storage.search({ query, tiers, limit });
797
+ }
798
+ // Apply source filter client-side
799
+ if (sourceFilter === 'gaia') {
800
+ results = results.filter(r => !r.memory.id.startsWith('rescue_'));
801
+ }
802
+ else if (sourceFilter === 'rescued') {
803
+ results = results.filter(r => r.memory.id.startsWith('rescue_'));
804
+ }
805
+ res.writeHead(200, { 'Content-Type': 'application/json', ...corsHeaders });
806
+ res.end(JSON.stringify(results));
807
+ }
808
+ finally {
809
+ storage.close();
810
+ }
811
+ }
812
+ catch (err) {
813
+ res.writeHead(500, { 'Content-Type': 'application/json', ...corsHeaders });
814
+ res.end(JSON.stringify({ error: err.message }));
815
+ }
816
+ return;
817
+ }
789
818
  // Serve static files
790
819
  let filePath = join(uiDistPath, url === '/' ? 'index.html' : url);
791
820
  // Handle SPA routing - serve index.html for non-file paths