@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.
- package/README.md +3 -158
- package/dist/cli.js +143 -114
- package/dist/cli.js.map +1 -1
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +2 -2
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/types.d.ts +1 -1
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/zai.d.ts +17 -8
- package/dist/providers/zai.d.ts.map +1 -1
- package/dist/providers/zai.js +34 -13
- package/dist/providers/zai.js.map +1 -1
- package/dist/services/config.service.d.ts +1 -5
- package/dist/services/config.service.d.ts.map +1 -1
- package/dist/services/config.service.js +0 -20
- package/dist/services/config.service.js.map +1 -1
- package/dist/services/git.service.d.ts +0 -4
- package/dist/services/git.service.d.ts.map +1 -1
- package/dist/services/git.service.js +0 -30
- package/dist/services/git.service.js.map +1 -1
- package/dist/services/storage.service.d.ts +1 -24
- package/dist/services/storage.service.d.ts.map +1 -1
- package/dist/services/storage.service.js +0 -108
- package/dist/services/storage.service.js.map +1 -1
- package/dist/tools/gaia/index.d.ts +5 -8
- package/dist/tools/gaia/index.d.ts.map +1 -1
- package/dist/tools/gaia/index.js +16 -115
- package/dist/tools/gaia/index.js.map +1 -1
- package/dist/tools/gaia/storage.d.ts +13 -0
- package/dist/tools/gaia/storage.d.ts.map +1 -1
- package/dist/tools/gaia/storage.js +285 -1
- package/dist/tools/gaia/storage.js.map +1 -1
- package/dist/tools/seldon/index.d.ts +1 -12
- package/dist/tools/seldon/index.d.ts.map +1 -1
- package/dist/tools/seldon/index.js +1 -183
- package/dist/tools/seldon/index.js.map +1 -1
- package/dist/types/index.d.ts +0 -78
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/packages/ui/dist/assets/index-DVS_pYGH.css +1 -0
- package/packages/ui/dist/index.html +2 -2
- package/packages/ui/dist/assets/index-fYt-vaxP.css +0 -1
- /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
|
|
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 (
|
|
244
|
+
**Tools (20 total):**
|
|
258
245
|
|
|
259
|
-
#### Workflow Tools (
|
|
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
|
|
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
|
|
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
|
|
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
|
-
| \`
|
|
114
|
-
| \`
|
|
115
|
-
| \`
|
|
116
|
-
| \`
|
|
117
|
-
| \`
|
|
118
|
-
| \`
|
|
119
|
-
| \`
|
|
120
|
-
| \`
|
|
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)') + '
|
|
343
|
-
console.log(chalk.cyan(' Seldon (
|
|
344
|
-
console.log(chalk.cyan(' Gaia (
|
|
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
|
-
//
|
|
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:
|
|
452
|
-
|
|
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: '.
|
|
461
|
-
timeout:
|
|
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:
|
|
470
|
-
|
|
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.
|
|
483
|
-
const
|
|
484
|
-
mkdirSync(
|
|
485
|
-
|
|
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('
|
|
516
|
-
console.log(chalk.green(' ✓') + ' ' + chalk.cyan('
|
|
517
|
-
console.log(chalk.green(' ✓') + ' ' + chalk.cyan('
|
|
518
|
-
console.log(chalk.green(' ✓') + ' ' + chalk.cyan('
|
|
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('
|
|
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
|