@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 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.5';
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
@@ -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-accepting edits)'));
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 full content of relevant sections
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 context sections...`));
23
- for (const sectionName of relevantSections) {
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
- sections,
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. \`get_context_section\` - Fetch full content for sections relevant to your task
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, ContextSection, Module } from '../services/damper-api.js';
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
- sections: ContextSection[];
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, sections, templates, modules, damperInstructions } = options;
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 Sections
84
- if (sections.length > 0) {
85
- lines.push('## Relevant Architecture');
83
+ // Project Context Block Index (load-on-demand)
84
+ if (blockIndices.length > 0) {
85
+ lines.push('## Available Architecture Context');
86
86
  lines.push('');
87
- for (const section of sections) {
88
- lines.push(`### ${section.section}`);
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
- lines.push(section.content);
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damper/cli",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "description": "CLI tool for orchestrating Damper task workflows with Claude Code",
5
5
  "author": "Damper <hello@usedamper.com>",
6
6
  "repository": {