@damper/cli 0.6.5 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/services/claude.js +3 -2
- package/dist/services/context-bootstrap.d.ts +10 -0
- package/dist/services/context-bootstrap.js +23 -19
- package/dist/services/damper-api.d.ts +21 -0
- package/dist/services/damper-api.js +15 -1
- package/dist/templates/CLAUDE_APPEND.md.js +11 -1
- package/dist/templates/TASK_CONTEXT.md.d.ts +3 -2
- package/dist/templates/TASK_CONTEXT.md.js +14 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { statusCommand } from './commands/status.js';
|
|
|
5
5
|
import { cleanupCommand } from './commands/cleanup.js';
|
|
6
6
|
import { setupCommand } from './commands/setup.js';
|
|
7
7
|
import { releaseCommand } from './commands/release.js';
|
|
8
|
-
const VERSION = '0.6.
|
|
8
|
+
const VERSION = '0.6.7';
|
|
9
9
|
function showHelp() {
|
|
10
10
|
console.log(`
|
|
11
11
|
${pc.bold('@damper/cli')} - Agent orchestration for Damper tasks
|
package/dist/services/claude.js
CHANGED
|
@@ -103,15 +103,16 @@ export async function launchClaude(options) {
|
|
|
103
103
|
console.log(pc.dim(' (removes worktree and branch)'));
|
|
104
104
|
console.log();
|
|
105
105
|
if (yolo) {
|
|
106
|
-
console.log(pc.yellow('Mode: YOLO (auto-
|
|
106
|
+
console.log(pc.yellow('Mode: YOLO (plan then auto-execute)'));
|
|
107
107
|
}
|
|
108
108
|
else {
|
|
109
109
|
console.log(pc.cyan('Mode: Plan (will ask for approval)'));
|
|
110
110
|
}
|
|
111
111
|
console.log();
|
|
112
112
|
// Build prompt - context is in TASK_CONTEXT.md, MCP is in .claude/settings.json
|
|
113
|
+
// Always enter plan mode first. In yolo mode, execute without waiting for approval.
|
|
113
114
|
const planInstruction = yolo
|
|
114
|
-
? ''
|
|
115
|
+
? ' After reading TASK_CONTEXT.md, use the EnterPlanMode tool to create an implementation plan, then execute it without waiting for user approval.'
|
|
115
116
|
: ' After reading TASK_CONTEXT.md, use the EnterPlanMode tool to create an implementation plan for user approval before making any code changes.';
|
|
116
117
|
const initialPrompt = `IMPORTANT: Start by reading TASK_CONTEXT.md completely. It contains the task description, implementation plan, critical rules, and architecture context.${planInstruction} Task #${taskId}: ${taskTitle}`;
|
|
117
118
|
console.log(pc.dim(`Launching Claude in ${cwd}...`));
|
|
@@ -9,6 +9,16 @@ export interface BootstrapResult {
|
|
|
9
9
|
taskContextPath: string;
|
|
10
10
|
claudeMdUpdated: boolean;
|
|
11
11
|
}
|
|
12
|
+
export interface SectionBlockIndex {
|
|
13
|
+
section: string;
|
|
14
|
+
blocks: Array<{
|
|
15
|
+
id: string;
|
|
16
|
+
heading: string | null;
|
|
17
|
+
level: number;
|
|
18
|
+
charCount: number;
|
|
19
|
+
}>;
|
|
20
|
+
totalChars: number;
|
|
21
|
+
}
|
|
12
22
|
/**
|
|
13
23
|
* Fetch all relevant context from Damper and write local files
|
|
14
24
|
*/
|
|
@@ -6,6 +6,24 @@ import { generateClaudeAppend } from '../templates/CLAUDE_APPEND.md.js';
|
|
|
6
6
|
const TASK_CONTEXT_FILE = 'TASK_CONTEXT.md';
|
|
7
7
|
const CLAUDE_MD_FILE = 'CLAUDE.md';
|
|
8
8
|
const TASK_SECTION_MARKER = '## Current Task:';
|
|
9
|
+
/**
|
|
10
|
+
* Fetch block indices for relevant sections.
|
|
11
|
+
* Only fetches the headings/structure - no content.
|
|
12
|
+
* The agent will use get_section_block_content to load what it needs.
|
|
13
|
+
*/
|
|
14
|
+
async function fetchBlockIndices(api, relevantSections) {
|
|
15
|
+
const indices = [];
|
|
16
|
+
for (const sectionName of relevantSections) {
|
|
17
|
+
try {
|
|
18
|
+
const blockIndex = await api.getSectionBlocks(sectionName);
|
|
19
|
+
indices.push(blockIndex);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
console.log(pc.dim(` Could not fetch blocks for: ${sectionName}`));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return indices;
|
|
26
|
+
}
|
|
9
27
|
/**
|
|
10
28
|
* Fetch all relevant context from Damper and write local files
|
|
11
29
|
*/
|
|
@@ -15,26 +33,12 @@ export async function bootstrapContext(options) {
|
|
|
15
33
|
const task = await api.getTask(taskId);
|
|
16
34
|
console.log(pc.dim('Fetching project context...'));
|
|
17
35
|
const context = await api.getProjectContext(taskId);
|
|
18
|
-
// Fetch
|
|
19
|
-
const sections = [];
|
|
36
|
+
// Fetch block indices (not content) for relevant sections
|
|
20
37
|
const relevantSections = context.relevantSections || [];
|
|
38
|
+
let blockIndices = [];
|
|
21
39
|
if (relevantSections.length > 0) {
|
|
22
|
-
console.log(pc.dim(`Fetching ${relevantSections.length} relevant
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
const result = await api.getContextSection(sectionName);
|
|
26
|
-
// Handle both single section and glob pattern responses
|
|
27
|
-
if ('pattern' in result && result.sections) {
|
|
28
|
-
sections.push(...result.sections);
|
|
29
|
-
}
|
|
30
|
-
else if ('section' in result && 'content' in result) {
|
|
31
|
-
sections.push(result);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
catch (err) {
|
|
35
|
-
console.log(pc.dim(` Could not fetch section: ${sectionName}`));
|
|
36
|
-
}
|
|
37
|
-
}
|
|
40
|
+
console.log(pc.dim(`Fetching block indices for ${relevantSections.length} relevant sections...`));
|
|
41
|
+
blockIndices = await fetchBlockIndices(api, relevantSections);
|
|
38
42
|
}
|
|
39
43
|
// Fetch templates
|
|
40
44
|
console.log(pc.dim('Fetching templates...'));
|
|
@@ -51,7 +55,7 @@ export async function bootstrapContext(options) {
|
|
|
51
55
|
const taskContext = generateTaskContext({
|
|
52
56
|
task,
|
|
53
57
|
criticalRules: context.criticalRules || [],
|
|
54
|
-
|
|
58
|
+
blockIndices,
|
|
55
59
|
templates,
|
|
56
60
|
modules,
|
|
57
61
|
damperInstructions: instructions.content,
|
|
@@ -131,6 +131,27 @@ export declare class DamperApi {
|
|
|
131
131
|
}>;
|
|
132
132
|
isEmpty: boolean;
|
|
133
133
|
}>;
|
|
134
|
+
getSectionBlocks(section: string): Promise<{
|
|
135
|
+
section: string;
|
|
136
|
+
blocks: Array<{
|
|
137
|
+
id: string;
|
|
138
|
+
heading: string | null;
|
|
139
|
+
level: number;
|
|
140
|
+
charCount: number;
|
|
141
|
+
}>;
|
|
142
|
+
totalChars: number;
|
|
143
|
+
}>;
|
|
144
|
+
getSectionBlockContent(section: string, blockIds: string[]): Promise<{
|
|
145
|
+
section: string;
|
|
146
|
+
blocks: Array<{
|
|
147
|
+
id: string;
|
|
148
|
+
heading: string | null;
|
|
149
|
+
level: number;
|
|
150
|
+
content: string;
|
|
151
|
+
charCount: number;
|
|
152
|
+
}>;
|
|
153
|
+
totalChars: number;
|
|
154
|
+
}>;
|
|
134
155
|
listTemplates(): Promise<{
|
|
135
156
|
templates: Array<{
|
|
136
157
|
name: string;
|
|
@@ -69,6 +69,16 @@ export class DamperApi {
|
|
|
69
69
|
async listContextSections() {
|
|
70
70
|
return this.request('GET', '/api/agent/context');
|
|
71
71
|
}
|
|
72
|
+
// Context Blocks
|
|
73
|
+
async getSectionBlocks(section) {
|
|
74
|
+
const encodedSection = encodeURIComponent(section);
|
|
75
|
+
return this.request('GET', `/api/agent/context/${encodedSection}/blocks`);
|
|
76
|
+
}
|
|
77
|
+
async getSectionBlockContent(section, blockIds) {
|
|
78
|
+
const encodedSection = encodeURIComponent(section);
|
|
79
|
+
const encodedBlockIds = blockIds.map(id => encodeURIComponent(id)).join(',');
|
|
80
|
+
return this.request('GET', `/api/agent/context/${encodedSection}/blocks/${encodedBlockIds}`);
|
|
81
|
+
}
|
|
72
82
|
// Templates
|
|
73
83
|
async listTemplates() {
|
|
74
84
|
return this.request('GET', '/api/agent/templates');
|
|
@@ -95,7 +105,10 @@ This project uses Damper MCP for task tracking. **You MUST follow this workflow.
|
|
|
95
105
|
|
|
96
106
|
### At Session Start (MANDATORY)
|
|
97
107
|
1. \`get_project_context\` - **READ THIS FIRST.** Contains architecture, conventions, and critical project info.
|
|
98
|
-
2.
|
|
108
|
+
2. Load relevant architecture context using blocks (token-efficient):
|
|
109
|
+
- If TASK_CONTEXT.md has an "Available Architecture Context" section, use \`get_section_block_content(section, blockIds)\` to load only the blocks relevant to your task
|
|
110
|
+
- Otherwise, use \`get_section_blocks(section)\` to see what's available, then fetch specific blocks
|
|
111
|
+
- Only fall back to \`get_context_section\` if you need an entire section
|
|
99
112
|
3. \`list_tasks\` - Check for existing tasks to work on
|
|
100
113
|
4. If working on a task: \`start_task\` to lock it
|
|
101
114
|
|
|
@@ -104,6 +117,7 @@ This project uses Damper MCP for task tracking. **You MUST follow this workflow.
|
|
|
104
117
|
- \`add_note\` for decisions: "Decision: chose X because Y"
|
|
105
118
|
- \`update_subtask\` to mark subtask progress
|
|
106
119
|
- **Follow patterns from project context** - Don't reinvent; use existing conventions
|
|
120
|
+
- When you need architecture context mid-task, use \`get_section_block_content\` to load specific blocks rather than full sections
|
|
107
121
|
|
|
108
122
|
### Feedback & Changelog Integration
|
|
109
123
|
- \`link_feedback_to_task\` - Link user feedback IDs to your task (helps track what customer requests led to the feature)
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export function generateClaudeAppend(options) {
|
|
2
2
|
const { taskId, taskTitle, yolo } = options;
|
|
3
3
|
const planSection = yolo
|
|
4
|
-
?
|
|
4
|
+
? `
|
|
5
|
+
**MANDATORY: Plan First, Then Execute**
|
|
6
|
+
Before making ANY code changes, you MUST enter plan mode using the EnterPlanMode tool.
|
|
7
|
+
Read TASK_CONTEXT.md first, then create a plan. Once the plan is ready, execute it without waiting for user approval.
|
|
8
|
+
`
|
|
5
9
|
: `
|
|
6
10
|
**MANDATORY: Plan Mode**
|
|
7
11
|
Before making ANY code changes, you MUST enter plan mode using the EnterPlanMode tool.
|
|
@@ -13,6 +17,12 @@ Read TASK_CONTEXT.md first, then create a plan for user approval. Do NOT write c
|
|
|
13
17
|
**IMPORTANT**: Read TASK_CONTEXT.md for full task details and architecture context.
|
|
14
18
|
If you feel you've lost context, re-read that file.
|
|
15
19
|
${planSection}
|
|
20
|
+
**NEVER commit these files** (they are generated by the CLI and gitignored):
|
|
21
|
+
- \`CLAUDE.md\` changes (this task section is temporary)
|
|
22
|
+
- \`TASK_CONTEXT.md\`
|
|
23
|
+
- \`.mcp.json\`
|
|
24
|
+
- \`.claude/settings.local.json\`
|
|
25
|
+
|
|
16
26
|
**Your responsibilities (via Damper MCP):**
|
|
17
27
|
1. Use \`add_commit\` after each git commit
|
|
18
28
|
2. Use \`add_note\` for important decisions
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { TaskDetail,
|
|
1
|
+
import type { TaskDetail, Module } from '../services/damper-api.js';
|
|
2
|
+
import type { SectionBlockIndex } from '../services/context-bootstrap.js';
|
|
2
3
|
interface TaskContextOptions {
|
|
3
4
|
task: TaskDetail;
|
|
4
5
|
criticalRules: string[];
|
|
5
|
-
|
|
6
|
+
blockIndices: SectionBlockIndex[];
|
|
6
7
|
templates: Array<{
|
|
7
8
|
name: string;
|
|
8
9
|
description?: string | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export function generateTaskContext(options) {
|
|
2
|
-
const { task, criticalRules,
|
|
2
|
+
const { task, criticalRules, blockIndices, templates, modules, damperInstructions } = options;
|
|
3
3
|
const typeIcon = task.type === 'bug' ? 'Bug' : task.type === 'feature' ? 'Feature' : task.type === 'improvement' ? 'Improvement' : 'Task';
|
|
4
4
|
const lines = [];
|
|
5
5
|
// Header
|
|
@@ -80,14 +80,21 @@ export function generateTaskContext(options) {
|
|
|
80
80
|
}
|
|
81
81
|
lines.push('');
|
|
82
82
|
}
|
|
83
|
-
// Project Context
|
|
84
|
-
if (
|
|
85
|
-
lines.push('##
|
|
83
|
+
// Project Context Block Index (load-on-demand)
|
|
84
|
+
if (blockIndices.length > 0) {
|
|
85
|
+
lines.push('## Available Architecture Context');
|
|
86
86
|
lines.push('');
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
lines.push('**BEFORE starting work**, load the blocks relevant to your task using the MCP tool:');
|
|
88
|
+
lines.push('`get_section_block_content(section, blockIds)` — pass the section name and an array of block IDs from the list below.');
|
|
89
|
+
lines.push('Only load what you need to keep token usage low.');
|
|
90
|
+
lines.push('');
|
|
91
|
+
for (const index of blockIndices) {
|
|
92
|
+
lines.push(`### ${index.section} (${index.totalChars} chars)`);
|
|
89
93
|
lines.push('');
|
|
90
|
-
|
|
94
|
+
for (const block of index.blocks) {
|
|
95
|
+
const heading = block.heading ? block.heading.replace(/^#+\s*/, '') : '(intro)';
|
|
96
|
+
lines.push(`- \`${block.id}\`: ${heading} (${block.charCount} chars)`);
|
|
97
|
+
}
|
|
91
98
|
lines.push('');
|
|
92
99
|
}
|
|
93
100
|
}
|