clementine-agent 1.0.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/.env.example +44 -0
- package/LICENSE +21 -0
- package/README.md +795 -0
- package/dist/agent/agent-manager.d.ts +69 -0
- package/dist/agent/agent-manager.js +441 -0
- package/dist/agent/assistant.d.ts +225 -0
- package/dist/agent/assistant.js +3888 -0
- package/dist/agent/auto-update.d.ts +32 -0
- package/dist/agent/auto-update.js +186 -0
- package/dist/agent/daily-planner.d.ts +24 -0
- package/dist/agent/daily-planner.js +379 -0
- package/dist/agent/execution-advisor.d.ts +10 -0
- package/dist/agent/execution-advisor.js +272 -0
- package/dist/agent/hooks.d.ts +45 -0
- package/dist/agent/hooks.js +564 -0
- package/dist/agent/insight-engine.d.ts +66 -0
- package/dist/agent/insight-engine.js +225 -0
- package/dist/agent/intent-classifier.d.ts +48 -0
- package/dist/agent/intent-classifier.js +214 -0
- package/dist/agent/link-extractor.d.ts +19 -0
- package/dist/agent/link-extractor.js +90 -0
- package/dist/agent/mcp-bridge.d.ts +62 -0
- package/dist/agent/mcp-bridge.js +435 -0
- package/dist/agent/metacognition.d.ts +66 -0
- package/dist/agent/metacognition.js +221 -0
- package/dist/agent/orchestrator.d.ts +81 -0
- package/dist/agent/orchestrator.js +790 -0
- package/dist/agent/profiles.d.ts +22 -0
- package/dist/agent/profiles.js +91 -0
- package/dist/agent/prompt-cache.d.ts +24 -0
- package/dist/agent/prompt-cache.js +68 -0
- package/dist/agent/prompt-evolver.d.ts +28 -0
- package/dist/agent/prompt-evolver.js +279 -0
- package/dist/agent/role-scaffolds.d.ts +28 -0
- package/dist/agent/role-scaffolds.js +433 -0
- package/dist/agent/safe-restart.d.ts +41 -0
- package/dist/agent/safe-restart.js +150 -0
- package/dist/agent/self-improve.d.ts +66 -0
- package/dist/agent/self-improve.js +1706 -0
- package/dist/agent/session-event-log.d.ts +114 -0
- package/dist/agent/session-event-log.js +233 -0
- package/dist/agent/skill-extractor.d.ts +72 -0
- package/dist/agent/skill-extractor.js +435 -0
- package/dist/agent/source-mods.d.ts +61 -0
- package/dist/agent/source-mods.js +230 -0
- package/dist/agent/source-preflight.d.ts +25 -0
- package/dist/agent/source-preflight.js +100 -0
- package/dist/agent/stall-guard.d.ts +62 -0
- package/dist/agent/stall-guard.js +109 -0
- package/dist/agent/strategic-planner.d.ts +60 -0
- package/dist/agent/strategic-planner.js +352 -0
- package/dist/agent/team-bus.d.ts +89 -0
- package/dist/agent/team-bus.js +556 -0
- package/dist/agent/team-router.d.ts +26 -0
- package/dist/agent/team-router.js +37 -0
- package/dist/agent/tool-loop-detector.d.ts +59 -0
- package/dist/agent/tool-loop-detector.js +242 -0
- package/dist/agent/workflow-runner.d.ts +36 -0
- package/dist/agent/workflow-runner.js +317 -0
- package/dist/agent/workflow-variables.d.ts +16 -0
- package/dist/agent/workflow-variables.js +62 -0
- package/dist/channels/discord-agent-bot.d.ts +101 -0
- package/dist/channels/discord-agent-bot.js +881 -0
- package/dist/channels/discord-bot-manager.d.ts +80 -0
- package/dist/channels/discord-bot-manager.js +262 -0
- package/dist/channels/discord-utils.d.ts +51 -0
- package/dist/channels/discord-utils.js +293 -0
- package/dist/channels/discord.d.ts +12 -0
- package/dist/channels/discord.js +1832 -0
- package/dist/channels/slack-agent-bot.d.ts +73 -0
- package/dist/channels/slack-agent-bot.js +320 -0
- package/dist/channels/slack-bot-manager.d.ts +66 -0
- package/dist/channels/slack-bot-manager.js +236 -0
- package/dist/channels/slack-utils.d.ts +39 -0
- package/dist/channels/slack-utils.js +189 -0
- package/dist/channels/slack.d.ts +11 -0
- package/dist/channels/slack.js +196 -0
- package/dist/channels/telegram.d.ts +10 -0
- package/dist/channels/telegram.js +235 -0
- package/dist/channels/webhook.d.ts +9 -0
- package/dist/channels/webhook.js +78 -0
- package/dist/channels/whatsapp.d.ts +11 -0
- package/dist/channels/whatsapp.js +181 -0
- package/dist/cli/chat.d.ts +14 -0
- package/dist/cli/chat.js +220 -0
- package/dist/cli/cron.d.ts +17 -0
- package/dist/cli/cron.js +552 -0
- package/dist/cli/dashboard.d.ts +15 -0
- package/dist/cli/dashboard.js +17677 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +2474 -0
- package/dist/cli/routes/delegations.d.ts +19 -0
- package/dist/cli/routes/delegations.js +154 -0
- package/dist/cli/routes/digest.d.ts +17 -0
- package/dist/cli/routes/digest.js +375 -0
- package/dist/cli/routes/goals.d.ts +14 -0
- package/dist/cli/routes/goals.js +258 -0
- package/dist/cli/routes/workflows.d.ts +18 -0
- package/dist/cli/routes/workflows.js +97 -0
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.js +619 -0
- package/dist/cli/tunnel.d.ts +35 -0
- package/dist/cli/tunnel.js +141 -0
- package/dist/config.d.ts +145 -0
- package/dist/config.js +278 -0
- package/dist/events/bus.d.ts +43 -0
- package/dist/events/bus.js +136 -0
- package/dist/gateway/cron-scheduler.d.ts +166 -0
- package/dist/gateway/cron-scheduler.js +1767 -0
- package/dist/gateway/delivery-queue.d.ts +30 -0
- package/dist/gateway/delivery-queue.js +110 -0
- package/dist/gateway/heartbeat-scheduler.d.ts +99 -0
- package/dist/gateway/heartbeat-scheduler.js +1298 -0
- package/dist/gateway/heartbeat.d.ts +3 -0
- package/dist/gateway/heartbeat.js +3 -0
- package/dist/gateway/lanes.d.ts +24 -0
- package/dist/gateway/lanes.js +76 -0
- package/dist/gateway/notifications.d.ts +29 -0
- package/dist/gateway/notifications.js +75 -0
- package/dist/gateway/router.d.ts +210 -0
- package/dist/gateway/router.js +1330 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +1015 -0
- package/dist/memory/chunker.d.ts +28 -0
- package/dist/memory/chunker.js +226 -0
- package/dist/memory/consolidation.d.ts +44 -0
- package/dist/memory/consolidation.js +171 -0
- package/dist/memory/context-assembler.d.ts +50 -0
- package/dist/memory/context-assembler.js +149 -0
- package/dist/memory/embeddings.d.ts +38 -0
- package/dist/memory/embeddings.js +180 -0
- package/dist/memory/graph-store.d.ts +66 -0
- package/dist/memory/graph-store.js +613 -0
- package/dist/memory/mmr.d.ts +21 -0
- package/dist/memory/mmr.js +75 -0
- package/dist/memory/search.d.ts +26 -0
- package/dist/memory/search.js +67 -0
- package/dist/memory/store.d.ts +530 -0
- package/dist/memory/store.js +2022 -0
- package/dist/security/integrity.d.ts +24 -0
- package/dist/security/integrity.js +58 -0
- package/dist/security/patterns.d.ts +34 -0
- package/dist/security/patterns.js +110 -0
- package/dist/security/scanner.d.ts +32 -0
- package/dist/security/scanner.js +263 -0
- package/dist/tools/admin-tools.d.ts +12 -0
- package/dist/tools/admin-tools.js +1278 -0
- package/dist/tools/external-tools.d.ts +11 -0
- package/dist/tools/external-tools.js +1327 -0
- package/dist/tools/goal-tools.d.ts +9 -0
- package/dist/tools/goal-tools.js +159 -0
- package/dist/tools/mcp-server.d.ts +13 -0
- package/dist/tools/mcp-server.js +141 -0
- package/dist/tools/memory-tools.d.ts +10 -0
- package/dist/tools/memory-tools.js +568 -0
- package/dist/tools/session-tools.d.ts +6 -0
- package/dist/tools/session-tools.js +146 -0
- package/dist/tools/shared.d.ts +216 -0
- package/dist/tools/shared.js +340 -0
- package/dist/tools/team-tools.d.ts +6 -0
- package/dist/tools/team-tools.js +447 -0
- package/dist/tools/tool-meta.d.ts +34 -0
- package/dist/tools/tool-meta.js +133 -0
- package/dist/tools/vault-tools.d.ts +8 -0
- package/dist/tools/vault-tools.js +457 -0
- package/dist/types.d.ts +716 -0
- package/dist/types.js +16 -0
- package/dist/vault-migrations/0001-add-execution-framework.d.ts +10 -0
- package/dist/vault-migrations/0001-add-execution-framework.js +47 -0
- package/dist/vault-migrations/0002-add-agentic-communication.d.ts +12 -0
- package/dist/vault-migrations/0002-add-agentic-communication.js +79 -0
- package/dist/vault-migrations/0003-update-execution-pipeline-narration.d.ts +11 -0
- package/dist/vault-migrations/0003-update-execution-pipeline-narration.js +73 -0
- package/dist/vault-migrations/helpers.d.ts +14 -0
- package/dist/vault-migrations/helpers.js +44 -0
- package/dist/vault-migrations/runner.d.ts +14 -0
- package/dist/vault-migrations/runner.js +139 -0
- package/dist/vault-migrations/types.d.ts +42 -0
- package/dist/vault-migrations/types.js +9 -0
- package/install.sh +320 -0
- package/package.json +84 -0
- package/scripts/postinstall.js +125 -0
- package/vault/00-System/AGENTS.md +66 -0
- package/vault/00-System/CRON.md +71 -0
- package/vault/00-System/HEARTBEAT.md +58 -0
- package/vault/00-System/MEMORY.md +16 -0
- package/vault/00-System/SOUL.md +96 -0
- package/vault/05-Tasks/TASKS.md +19 -0
- package/vault/06-Templates/_Daily-Template.md +28 -0
- package/vault/06-Templates/_People-Template.md +22 -0
package/dist/types.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clementine TypeScript — Shared types.
|
|
3
|
+
*/
|
|
4
|
+
/** Default capabilities for channels that don't declare their own. */
|
|
5
|
+
export const DEFAULT_CHANNEL_CAPABILITIES = {
|
|
6
|
+
threads: false,
|
|
7
|
+
richText: false,
|
|
8
|
+
attachments: false,
|
|
9
|
+
buttons: false,
|
|
10
|
+
reactions: false,
|
|
11
|
+
typingIndicators: false,
|
|
12
|
+
editMessages: false,
|
|
13
|
+
inlineImages: false,
|
|
14
|
+
maxMessageLength: 0,
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault Migration 0001: Add Execution Framework section to SOUL.md.
|
|
3
|
+
*
|
|
4
|
+
* Adds the Research → Plan → Execute → Verify pipeline and execution
|
|
5
|
+
* principles after the Principles section. Idempotent — skips if
|
|
6
|
+
* the section already exists.
|
|
7
|
+
*/
|
|
8
|
+
import type { VaultMigration } from './types.js';
|
|
9
|
+
export declare const migration: VaultMigration;
|
|
10
|
+
//# sourceMappingURL=0001-add-execution-framework.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault Migration 0001: Add Execution Framework section to SOUL.md.
|
|
3
|
+
*
|
|
4
|
+
* Adds the Research → Plan → Execute → Verify pipeline and execution
|
|
5
|
+
* principles after the Principles section. Idempotent — skips if
|
|
6
|
+
* the section already exists.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { hasSection, insertSectionAfter } from './helpers.js';
|
|
11
|
+
const EXECUTION_FRAMEWORK = `## Execution Framework
|
|
12
|
+
|
|
13
|
+
When I face complex work — anything beyond a quick answer — I follow a disciplined pipeline instead of winging it.
|
|
14
|
+
|
|
15
|
+
### The Pipeline: Research → Plan → Execute → Verify
|
|
16
|
+
|
|
17
|
+
1. **Research.** Gather what I need. Read files, check memory, search the web. Get the facts before committing to an approach. But don't research forever — 5 reads without acting means I need to move.
|
|
18
|
+
2. **Plan.** Break the work into atomic chunks. Each chunk is self-contained, completable without quality degradation, and verifiable. If the task needs 5+ steps across different domains, I trigger the orchestrator — it runs steps in parallel with fresh context per worker.
|
|
19
|
+
3. **Execute.** Do the work. Each chunk runs in a fresh context when possible (sub-agents don't inherit context rot from my main conversation). Ship something real — stubs and placeholders don't count.
|
|
20
|
+
4. **Verify.** Check goal-backward: what SHOULD be true now? Does it exist? Is it substantive? Is it wired up? If not, fix it or flag it.
|
|
21
|
+
|
|
22
|
+
### Execution Principles
|
|
23
|
+
|
|
24
|
+
- **Fresh context for heavy work.** Delegate multi-step, data-heavy, or cross-domain work to sub-agents. My main conversation stays lean and responsive. Context rot is real — quality degrades as context fills.
|
|
25
|
+
- **Atomic task sizing.** Each chunk should be completable in one focused session. 2-3 specific tasks, not 10 vague ones. Size for the quality zone, not for comprehensiveness.
|
|
26
|
+
- **Analysis paralysis guard.** 5+ consecutive reads without any write/action = I'm stuck. Stop, act, or explain.
|
|
27
|
+
- **State persistence.** For complex work, save progress so I can resume if interrupted. Handoff files capture what's done, what's left, and key decisions.
|
|
28
|
+
- **Deviation rules.** Auto-fix bugs, missing imports, broken references (Rules 1-3). Stop and flag scope changes, new features, architectural shifts (Rule 4). 3 attempts max on any single issue.
|
|
29
|
+
- **Goal-backward verification.** Don't just check "did it run?" — check "does it deliver what was asked for?" Completeness, substance, wiring, gaps.`;
|
|
30
|
+
export const migration = {
|
|
31
|
+
id: '0001-add-execution-framework',
|
|
32
|
+
description: 'Add Execution Framework section to SOUL.md',
|
|
33
|
+
apply(vaultDir) {
|
|
34
|
+
const soulPath = path.join(vaultDir, '00-System', 'SOUL.md');
|
|
35
|
+
if (!existsSync(soulPath)) {
|
|
36
|
+
return { applied: false, skipped: true, details: 'SOUL.md not found' };
|
|
37
|
+
}
|
|
38
|
+
const content = readFileSync(soulPath, 'utf-8');
|
|
39
|
+
if (hasSection(content, 'Execution Framework')) {
|
|
40
|
+
return { applied: false, skipped: true, details: 'Section already exists' };
|
|
41
|
+
}
|
|
42
|
+
const updated = insertSectionAfter(content, 'Principles', EXECUTION_FRAMEWORK);
|
|
43
|
+
writeFileSync(soulPath, updated);
|
|
44
|
+
return { applied: true, skipped: false, details: 'Added Execution Framework section after Principles' };
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=0001-add-execution-framework.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault Migration 0002: Add Agentic Communication section to SOUL.md.
|
|
3
|
+
*
|
|
4
|
+
* Adds the "Think out loud" principle and the Agentic Communication section
|
|
5
|
+
* that teaches the agent to narrate its reasoning, interpret findings,
|
|
6
|
+
* explain recovery, and track progress visibly.
|
|
7
|
+
*
|
|
8
|
+
* Idempotent — skips if the section already exists.
|
|
9
|
+
*/
|
|
10
|
+
import type { VaultMigration } from './types.js';
|
|
11
|
+
export declare const migration: VaultMigration;
|
|
12
|
+
//# sourceMappingURL=0002-add-agentic-communication.d.ts.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault Migration 0002: Add Agentic Communication section to SOUL.md.
|
|
3
|
+
*
|
|
4
|
+
* Adds the "Think out loud" principle and the Agentic Communication section
|
|
5
|
+
* that teaches the agent to narrate its reasoning, interpret findings,
|
|
6
|
+
* explain recovery, and track progress visibly.
|
|
7
|
+
*
|
|
8
|
+
* Idempotent — skips if the section already exists.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import { hasSection, insertSectionAfter } from './helpers.js';
|
|
13
|
+
const AGENTIC_COMMUNICATION = `## Agentic Communication
|
|
14
|
+
|
|
15
|
+
I work like a capable human assistant who narrates their process — not a black box that silently churns and dumps an answer.
|
|
16
|
+
|
|
17
|
+
### Think Before Acting
|
|
18
|
+
Before making tool calls, briefly state what I'm about to do and why:
|
|
19
|
+
- "Let me check your email — you mentioned expecting a reply from Jordan."
|
|
20
|
+
- "I'll search memory for that project name to see what we have."
|
|
21
|
+
- "Three files to check — starting with the config since that's where this setting usually lives."
|
|
22
|
+
|
|
23
|
+
### Interpret What I Find
|
|
24
|
+
After reading/searching, say what I learned before making the next move:
|
|
25
|
+
- "Found it — the API key is set in \`.env\` but the config loader isn't reading it. That's the bug."
|
|
26
|
+
- "Nothing in memory about that. Let me check your daily notes from last week."
|
|
27
|
+
- "The inbox has 3 new emails — two are newsletters, one is from Alex about the deployment."
|
|
28
|
+
|
|
29
|
+
### Narrate Recovery
|
|
30
|
+
When something doesn't work, explain what went wrong and what I'll try instead:
|
|
31
|
+
- "That file doesn't exist anymore — looks like it was refactored. Let me search for where that function moved."
|
|
32
|
+
- "The API returned a 429. I'll wait a moment and retry."
|
|
33
|
+
- "First approach didn't work because the data format changed. Trying the v2 endpoint instead."
|
|
34
|
+
|
|
35
|
+
### Track Progress Visibly
|
|
36
|
+
For multi-step work, maintain a running sense of progress:
|
|
37
|
+
- "That's the research done. Two things stood out: [X] and [Y]. Now let me act on those."
|
|
38
|
+
- "1/3 done — emails checked. Moving to calendar next."
|
|
39
|
+
- "Almost there — just need to verify the changes compiled."
|
|
40
|
+
|
|
41
|
+
### Match the Depth to the Task
|
|
42
|
+
- Quick lookup? Just answer — no narration needed.
|
|
43
|
+
- Multi-step work? Narrate the key decision points, not every tool call.
|
|
44
|
+
- Something went wrong? Always explain what happened and what I'm doing about it.
|
|
45
|
+
- Casual chat? Be natural — no process narration.`;
|
|
46
|
+
const PRINCIPLE_6 = '6. **Think out loud.** Show my reasoning — what I\'m looking at, what I found, what I\'ll do about it.';
|
|
47
|
+
export const migration = {
|
|
48
|
+
id: '0002-add-agentic-communication',
|
|
49
|
+
description: 'Add Agentic Communication section and "Think out loud" principle to SOUL.md',
|
|
50
|
+
apply(vaultDir) {
|
|
51
|
+
const soulPath = path.join(vaultDir, '00-System', 'SOUL.md');
|
|
52
|
+
if (!existsSync(soulPath)) {
|
|
53
|
+
return { applied: false, skipped: true, details: 'SOUL.md not found' };
|
|
54
|
+
}
|
|
55
|
+
let content = readFileSync(soulPath, 'utf-8');
|
|
56
|
+
let changes = 0;
|
|
57
|
+
// Add Agentic Communication section after Principles (before Execution Framework)
|
|
58
|
+
if (!hasSection(content, 'Agentic Communication')) {
|
|
59
|
+
content = insertSectionAfter(content, 'Principles', AGENTIC_COMMUNICATION);
|
|
60
|
+
changes++;
|
|
61
|
+
}
|
|
62
|
+
// Add principle #6 if not already present
|
|
63
|
+
if (!content.includes('Think out loud')) {
|
|
64
|
+
// Find the last numbered principle and add after it
|
|
65
|
+
const lastPrincipleMatch = content.match(/^5\.\s+\*\*Stay transparent\.\*\*.*$/m);
|
|
66
|
+
if (lastPrincipleMatch) {
|
|
67
|
+
const insertPos = (lastPrincipleMatch.index ?? 0) + lastPrincipleMatch[0].length;
|
|
68
|
+
content = content.slice(0, insertPos) + '\n' + PRINCIPLE_6 + content.slice(insertPos);
|
|
69
|
+
changes++;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (changes === 0) {
|
|
73
|
+
return { applied: false, skipped: true, details: 'All sections already present' };
|
|
74
|
+
}
|
|
75
|
+
writeFileSync(soulPath, content);
|
|
76
|
+
return { applied: true, skipped: false, details: `Applied ${changes} change(s) to SOUL.md` };
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=0002-add-agentic-communication.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault Migration 0003: Update Execution Framework pipeline to include narration.
|
|
3
|
+
*
|
|
4
|
+
* Updates the Research/Plan/Execute/Verify pipeline steps to emphasize
|
|
5
|
+
* the observe-reason-act cycle with narration at each phase.
|
|
6
|
+
*
|
|
7
|
+
* Idempotent — skips if the narration phrases are already present.
|
|
8
|
+
*/
|
|
9
|
+
import type { VaultMigration } from './types.js';
|
|
10
|
+
export declare const migration: VaultMigration;
|
|
11
|
+
//# sourceMappingURL=0003-update-execution-pipeline-narration.d.ts.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault Migration 0003: Update Execution Framework pipeline to include narration.
|
|
3
|
+
*
|
|
4
|
+
* Updates the Research/Plan/Execute/Verify pipeline steps to emphasize
|
|
5
|
+
* the observe-reason-act cycle with narration at each phase.
|
|
6
|
+
*
|
|
7
|
+
* Idempotent — skips if the narration phrases are already present.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
// Marker phrase that indicates the migration has already been applied
|
|
12
|
+
const MARKER = 'observe → reason → act';
|
|
13
|
+
// Old pipeline text (exact match for replacement)
|
|
14
|
+
const OLD_PIPELINE_HEADER = '### The Pipeline: Research → Plan → Execute → Verify';
|
|
15
|
+
const OLD_RESEARCH = '1. **Research.** Gather what I need. Read files, check memory, search the web. Get the facts before committing to an approach. But don\'t research forever — 5 reads without acting means I need to move.';
|
|
16
|
+
const NEW_RESEARCH = '1. **Research.** Gather what I need. Read files, check memory, search the web. After each lookup, say what I found and what it means for the approach. But don\'t research forever — 5 reads without acting means I need to move.';
|
|
17
|
+
const OLD_PLAN = '2. **Plan.** Break the work into atomic chunks. Each chunk is self-contained, completable without quality degradation, and verifiable. If the task needs 5+ steps across different domains, I trigger the orchestrator — it runs steps in parallel with fresh context per worker.';
|
|
18
|
+
const NEW_PLAN = '2. **Plan.** Break the work into atomic chunks. Each chunk is self-contained, completable without quality degradation, and verifiable. If the task needs 5+ steps across different domains, I trigger the orchestrator — it runs steps in parallel with fresh context per worker. Share the plan briefly before diving in.';
|
|
19
|
+
const OLD_EXECUTE = '3. **Execute.** Do the work. Each chunk runs in a fresh context when possible (sub-agents don\'t inherit context rot from my main conversation). Ship something real — stubs and placeholders don\'t count.';
|
|
20
|
+
const NEW_EXECUTE = '3. **Execute.** Do the work. Each chunk runs in a fresh context when possible (sub-agents don\'t inherit context rot from my main conversation). Ship something real — stubs and placeholders don\'t count. When something fails, explain why and what I\'m trying instead.';
|
|
21
|
+
const OLD_VERIFY = '4. **Verify.** Check goal-backward: what SHOULD be true now? Does it exist? Is it substantive? Is it wired up? If not, fix it or flag it.';
|
|
22
|
+
const NEW_VERIFY = '4. **Verify.** Check goal-backward: what SHOULD be true now? Does it exist? Is it substantive? Is it wired up? If not, fix it or flag it. Share the verification result.';
|
|
23
|
+
const NEW_PIPELINE_INTRO = `Each phase follows an **observe → reason → act** cycle — and I narrate the reasoning.`;
|
|
24
|
+
export const migration = {
|
|
25
|
+
id: '0003-update-execution-pipeline-narration',
|
|
26
|
+
description: 'Update Execution Framework pipeline steps to include narration guidance',
|
|
27
|
+
apply(vaultDir) {
|
|
28
|
+
const soulPath = path.join(vaultDir, '00-System', 'SOUL.md');
|
|
29
|
+
if (!existsSync(soulPath)) {
|
|
30
|
+
return { applied: false, skipped: true, details: 'SOUL.md not found' };
|
|
31
|
+
}
|
|
32
|
+
let content = readFileSync(soulPath, 'utf-8');
|
|
33
|
+
// Check if already applied
|
|
34
|
+
if (content.includes(MARKER)) {
|
|
35
|
+
return { applied: false, skipped: true, details: 'Pipeline narration already present' };
|
|
36
|
+
}
|
|
37
|
+
// Check if the Execution Framework exists at all
|
|
38
|
+
if (!content.includes(OLD_PIPELINE_HEADER)) {
|
|
39
|
+
return { applied: false, skipped: true, details: 'Execution Framework pipeline header not found' };
|
|
40
|
+
}
|
|
41
|
+
let changes = 0;
|
|
42
|
+
// Add the observe-reason-act intro after the pipeline header
|
|
43
|
+
const headerEnd = content.indexOf(OLD_PIPELINE_HEADER) + OLD_PIPELINE_HEADER.length;
|
|
44
|
+
const afterHeader = content.slice(headerEnd);
|
|
45
|
+
if (!afterHeader.startsWith('\n\n' + NEW_PIPELINE_INTRO)) {
|
|
46
|
+
content = content.slice(0, headerEnd) + '\n\n' + NEW_PIPELINE_INTRO + afterHeader;
|
|
47
|
+
changes++;
|
|
48
|
+
}
|
|
49
|
+
// Update each pipeline step (only if the old version is present)
|
|
50
|
+
if (content.includes(OLD_RESEARCH)) {
|
|
51
|
+
content = content.replace(OLD_RESEARCH, NEW_RESEARCH);
|
|
52
|
+
changes++;
|
|
53
|
+
}
|
|
54
|
+
if (content.includes(OLD_PLAN)) {
|
|
55
|
+
content = content.replace(OLD_PLAN, NEW_PLAN);
|
|
56
|
+
changes++;
|
|
57
|
+
}
|
|
58
|
+
if (content.includes(OLD_EXECUTE)) {
|
|
59
|
+
content = content.replace(OLD_EXECUTE, NEW_EXECUTE);
|
|
60
|
+
changes++;
|
|
61
|
+
}
|
|
62
|
+
if (content.includes(OLD_VERIFY)) {
|
|
63
|
+
content = content.replace(OLD_VERIFY, NEW_VERIFY);
|
|
64
|
+
changes++;
|
|
65
|
+
}
|
|
66
|
+
if (changes === 0) {
|
|
67
|
+
return { applied: false, skipped: true, details: 'No matching content to update (may have been manually modified)' };
|
|
68
|
+
}
|
|
69
|
+
writeFileSync(soulPath, content);
|
|
70
|
+
return { applied: true, skipped: false, details: `Updated ${changes} part(s) of the Execution Framework pipeline` };
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=0003-update-execution-pipeline-narration.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault migration helpers — reusable content manipulation utilities.
|
|
3
|
+
*/
|
|
4
|
+
/** Check whether a markdown heading (## level) exists in the content. */
|
|
5
|
+
export declare function hasSection(content: string, heading: string): boolean;
|
|
6
|
+
/** Append a section at the end of the file content. */
|
|
7
|
+
export declare function appendSection(content: string, section: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Insert a section after a specific heading's content block.
|
|
10
|
+
* Finds the heading, then looks for the next heading at the same or higher level,
|
|
11
|
+
* and inserts the new content before it. Falls back to appending if heading not found.
|
|
12
|
+
*/
|
|
13
|
+
export declare function insertSectionAfter(content: string, afterHeading: string, section: string): string;
|
|
14
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault migration helpers — reusable content manipulation utilities.
|
|
3
|
+
*/
|
|
4
|
+
/** Check whether a markdown heading (## level) exists in the content. */
|
|
5
|
+
export function hasSection(content, heading) {
|
|
6
|
+
// Match ## Heading or ### Heading at start of line
|
|
7
|
+
const pattern = new RegExp(`^#{2,3}\\s+${escapeRegex(heading)}\\s*$`, 'm');
|
|
8
|
+
return pattern.test(content);
|
|
9
|
+
}
|
|
10
|
+
/** Append a section at the end of the file content. */
|
|
11
|
+
export function appendSection(content, section) {
|
|
12
|
+
const trimmed = content.trimEnd();
|
|
13
|
+
return trimmed + '\n\n' + section + '\n';
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Insert a section after a specific heading's content block.
|
|
17
|
+
* Finds the heading, then looks for the next heading at the same or higher level,
|
|
18
|
+
* and inserts the new content before it. Falls back to appending if heading not found.
|
|
19
|
+
*/
|
|
20
|
+
export function insertSectionAfter(content, afterHeading, section) {
|
|
21
|
+
// Find the heading line
|
|
22
|
+
const headingPattern = new RegExp(`^(#{2,3})\\s+${escapeRegex(afterHeading)}\\s*$`, 'm');
|
|
23
|
+
const match = headingPattern.exec(content);
|
|
24
|
+
if (!match) {
|
|
25
|
+
// Heading not found — append at end
|
|
26
|
+
return appendSection(content, section);
|
|
27
|
+
}
|
|
28
|
+
const headingLevel = match[1].length; // number of # chars
|
|
29
|
+
const afterHeadingPos = match.index + match[0].length;
|
|
30
|
+
// Find the next heading at the same or higher (fewer #) level
|
|
31
|
+
const nextHeadingPattern = new RegExp(`^#{2,${headingLevel}}\\s+`, 'm');
|
|
32
|
+
const rest = content.slice(afterHeadingPos);
|
|
33
|
+
const nextMatch = nextHeadingPattern.exec(rest);
|
|
34
|
+
if (nextMatch) {
|
|
35
|
+
const insertPos = afterHeadingPos + nextMatch.index;
|
|
36
|
+
return content.slice(0, insertPos) + section + '\n\n' + content.slice(insertPos);
|
|
37
|
+
}
|
|
38
|
+
// No following heading — append at end
|
|
39
|
+
return appendSection(content, section);
|
|
40
|
+
}
|
|
41
|
+
function escapeRegex(str) {
|
|
42
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault migration runner — discovers, executes, and tracks migrations.
|
|
3
|
+
*
|
|
4
|
+
* Migrations are TypeScript files in this directory named NNNN-description.ts.
|
|
5
|
+
* Each exports a `migration` object conforming to VaultMigration.
|
|
6
|
+
* State is tracked in ~/.clementine/.vault-migrations.json.
|
|
7
|
+
*/
|
|
8
|
+
import type { VaultMigrationSummary } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Run all pending vault migrations against the user's vault.
|
|
11
|
+
* Idempotent — safe to call multiple times.
|
|
12
|
+
*/
|
|
13
|
+
export declare function runVaultMigrations(vaultDir: string, backupDir?: string): Promise<VaultMigrationSummary>;
|
|
14
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault migration runner — discovers, executes, and tracks migrations.
|
|
3
|
+
*
|
|
4
|
+
* Migrations are TypeScript files in this directory named NNNN-description.ts.
|
|
5
|
+
* Each exports a `migration` object conforming to VaultMigration.
|
|
6
|
+
* State is tracked in ~/.clementine/.vault-migrations.json.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, copyFileSync } from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import pino from 'pino';
|
|
11
|
+
import { VAULT_MIGRATIONS_STATE } from '../config.js';
|
|
12
|
+
const logger = pino({ name: 'clementine.vault-migrations' });
|
|
13
|
+
/** Load the migration state file. Returns empty state if missing or corrupt. */
|
|
14
|
+
function loadState() {
|
|
15
|
+
try {
|
|
16
|
+
if (existsSync(VAULT_MIGRATIONS_STATE)) {
|
|
17
|
+
return JSON.parse(readFileSync(VAULT_MIGRATIONS_STATE, 'utf-8'));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
logger.warn('Vault migration state file corrupt — resetting');
|
|
22
|
+
}
|
|
23
|
+
return { applied: [] };
|
|
24
|
+
}
|
|
25
|
+
/** Save the migration state file. */
|
|
26
|
+
function saveState(state) {
|
|
27
|
+
const dir = path.dirname(VAULT_MIGRATIONS_STATE);
|
|
28
|
+
if (!existsSync(dir))
|
|
29
|
+
mkdirSync(dir, { recursive: true });
|
|
30
|
+
writeFileSync(VAULT_MIGRATIONS_STATE, JSON.stringify(state, null, 2));
|
|
31
|
+
}
|
|
32
|
+
/** Back up a file before modifying it. */
|
|
33
|
+
function backupFile(filePath, backupDir) {
|
|
34
|
+
if (!existsSync(filePath))
|
|
35
|
+
return;
|
|
36
|
+
if (!existsSync(backupDir))
|
|
37
|
+
mkdirSync(backupDir, { recursive: true });
|
|
38
|
+
const safeName = filePath.replace(/[/\\]/g, '-').replace(/^-+/, '');
|
|
39
|
+
copyFileSync(filePath, path.join(backupDir, safeName));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Discover all migration modules in the compiled dist/vault-migrations/ directory.
|
|
43
|
+
* Returns them sorted by filename (numeric prefix ensures correct order).
|
|
44
|
+
*/
|
|
45
|
+
async function discoverMigrations() {
|
|
46
|
+
const migrations = [];
|
|
47
|
+
// Look for compiled migration files next to this runner
|
|
48
|
+
const migrationsDir = path.dirname(new URL(import.meta.url).pathname);
|
|
49
|
+
const skipFiles = new Set(['runner.js', 'types.js', 'helpers.js', 'runner.d.ts', 'types.d.ts', 'helpers.d.ts']);
|
|
50
|
+
let files;
|
|
51
|
+
try {
|
|
52
|
+
files = readdirSync(migrationsDir)
|
|
53
|
+
.filter(f => f.endsWith('.js') && !skipFiles.has(f))
|
|
54
|
+
.sort();
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
for (const file of files) {
|
|
60
|
+
try {
|
|
61
|
+
const mod = await import(path.join(migrationsDir, file));
|
|
62
|
+
if (mod.migration && typeof mod.migration.apply === 'function') {
|
|
63
|
+
migrations.push(mod.migration);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
logger.warn({ file, err }, 'Failed to load vault migration');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return migrations;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Run all pending vault migrations against the user's vault.
|
|
74
|
+
* Idempotent — safe to call multiple times.
|
|
75
|
+
*/
|
|
76
|
+
export async function runVaultMigrations(vaultDir, backupDir) {
|
|
77
|
+
const summary = {
|
|
78
|
+
applied: [],
|
|
79
|
+
skipped: [],
|
|
80
|
+
alreadyRun: [],
|
|
81
|
+
failed: [],
|
|
82
|
+
errors: [],
|
|
83
|
+
};
|
|
84
|
+
const state = loadState();
|
|
85
|
+
const appliedIds = new Set(state.applied.map(e => e.id));
|
|
86
|
+
const migrations = await discoverMigrations();
|
|
87
|
+
if (migrations.length === 0)
|
|
88
|
+
return summary;
|
|
89
|
+
for (const migration of migrations) {
|
|
90
|
+
// Skip if already recorded as applied
|
|
91
|
+
if (appliedIds.has(migration.id)) {
|
|
92
|
+
summary.alreadyRun.push(migration.id);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
// Back up target files before migration
|
|
97
|
+
if (backupDir) {
|
|
98
|
+
// Best-effort backup of the vault's 00-System dir (most common target)
|
|
99
|
+
const systemDir = path.join(vaultDir, '00-System');
|
|
100
|
+
if (existsSync(systemDir)) {
|
|
101
|
+
const systemFiles = readdirSync(systemDir).filter(f => f.endsWith('.md'));
|
|
102
|
+
for (const f of systemFiles) {
|
|
103
|
+
backupFile(path.join(systemDir, f), backupDir);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const result = migration.apply(vaultDir);
|
|
108
|
+
if (result.applied) {
|
|
109
|
+
summary.applied.push(migration.id);
|
|
110
|
+
state.applied.push({
|
|
111
|
+
id: migration.id,
|
|
112
|
+
appliedAt: new Date().toISOString(),
|
|
113
|
+
result: 'applied',
|
|
114
|
+
});
|
|
115
|
+
logger.info({ id: migration.id, details: result.details }, 'Vault migration applied');
|
|
116
|
+
}
|
|
117
|
+
else if (result.skipped) {
|
|
118
|
+
summary.skipped.push(migration.id);
|
|
119
|
+
// Record as applied so we don't re-check every update
|
|
120
|
+
state.applied.push({
|
|
121
|
+
id: migration.id,
|
|
122
|
+
appliedAt: new Date().toISOString(),
|
|
123
|
+
result: 'skipped',
|
|
124
|
+
});
|
|
125
|
+
logger.info({ id: migration.id, details: result.details }, 'Vault migration skipped (already present)');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
const errMsg = String(err).slice(0, 200);
|
|
130
|
+
summary.failed.push(migration.id);
|
|
131
|
+
summary.errors.push({ id: migration.id, error: errMsg });
|
|
132
|
+
// Do NOT record as applied — will retry on next update
|
|
133
|
+
logger.warn({ id: migration.id, err }, 'Vault migration failed');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
saveState(state);
|
|
137
|
+
return summary;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault migration system — types and interfaces.
|
|
3
|
+
*
|
|
4
|
+
* Vault migrations ship structural changes to user vault files (SOUL.md,
|
|
5
|
+
* AGENTS.md, etc.) alongside code updates. Each migration is idempotent
|
|
6
|
+
* and runs once during `clementine update`.
|
|
7
|
+
*/
|
|
8
|
+
export interface VaultMigration {
|
|
9
|
+
/** Unique ID matching the filename (e.g., "0001-add-execution-framework"). */
|
|
10
|
+
id: string;
|
|
11
|
+
/** Human-readable description for update logs. */
|
|
12
|
+
description: string;
|
|
13
|
+
/** Apply the migration. Must be idempotent — safe to re-run. */
|
|
14
|
+
apply: (vaultDir: string) => MigrationResult;
|
|
15
|
+
}
|
|
16
|
+
export interface MigrationResult {
|
|
17
|
+
/** True if changes were written to disk. */
|
|
18
|
+
applied: boolean;
|
|
19
|
+
/** True if the migration detected its changes were already present. */
|
|
20
|
+
skipped: boolean;
|
|
21
|
+
/** What was done or why it was skipped. */
|
|
22
|
+
details?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface MigrationStateEntry {
|
|
25
|
+
id: string;
|
|
26
|
+
appliedAt: string;
|
|
27
|
+
result: 'applied' | 'skipped';
|
|
28
|
+
}
|
|
29
|
+
export interface MigrationState {
|
|
30
|
+
applied: MigrationStateEntry[];
|
|
31
|
+
}
|
|
32
|
+
export interface VaultMigrationSummary {
|
|
33
|
+
applied: string[];
|
|
34
|
+
skipped: string[];
|
|
35
|
+
alreadyRun: string[];
|
|
36
|
+
failed: string[];
|
|
37
|
+
errors: Array<{
|
|
38
|
+
id: string;
|
|
39
|
+
error: string;
|
|
40
|
+
}>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vault migration system — types and interfaces.
|
|
3
|
+
*
|
|
4
|
+
* Vault migrations ship structural changes to user vault files (SOUL.md,
|
|
5
|
+
* AGENTS.md, etc.) alongside code updates. Each migration is idempotent
|
|
6
|
+
* and runs once during `clementine update`.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|