@damper/mcp 0.8.3 β†’ 0.8.5

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.
@@ -4,6 +4,11 @@
4
4
  * Extracted for testability - these pure functions format API responses
5
5
  * into user-friendly text output.
6
6
  */
7
+ export interface SelfAssessment {
8
+ missingContext?: string[];
9
+ toolIssues?: string[];
10
+ processGaps?: string[];
11
+ }
7
12
  export interface StartTaskResult {
8
13
  id: string;
9
14
  status: string;
@@ -39,11 +44,16 @@ export interface AbandonTaskResult {
39
44
  * Format start_task response
40
45
  */
41
46
  export declare function formatStartTaskResponse(result: StartTaskResult): string;
47
+ /**
48
+ * Format self-assessment follow-up actions.
49
+ * Guides the agent to propose improvements to the user with rationale.
50
+ */
51
+ export declare function formatSelfAssessmentActions(assessment: SelfAssessment): string;
42
52
  /**
43
53
  * Format complete_task response
44
54
  */
45
- export declare function formatCompleteTaskResponse(result: CompleteTaskResult): string;
55
+ export declare function formatCompleteTaskResponse(result: CompleteTaskResult, assessment?: SelfAssessment): string;
46
56
  /**
47
57
  * Format abandon_task response
48
58
  */
49
- export declare function formatAbandonTaskResponse(result: AbandonTaskResult, hasSummary: boolean): string;
59
+ export declare function formatAbandonTaskResponse(result: AbandonTaskResult, hasSummary: boolean, assessment?: SelfAssessment): string;
@@ -52,18 +52,67 @@ export function formatStartTaskResponse(result) {
52
52
  lines.push('1. `add_note`: "Session started: <goal>"');
53
53
  lines.push('2. Work: use `add_commit` for commits, `add_note` for decisions');
54
54
  lines.push('3. `add_note`: "Session end: <summary>"');
55
- lines.push('4. `complete_task` (with `confirmations` if checklist exists) or `abandon_task`');
55
+ lines.push('4. `complete_task` (with `confirmations` and `selfAssessment`) or `abandon_task`');
56
+ return lines.join('\n');
57
+ }
58
+ /**
59
+ * Format self-assessment follow-up actions.
60
+ * Guides the agent to propose improvements to the user with rationale.
61
+ */
62
+ export function formatSelfAssessmentActions(assessment) {
63
+ const lines = [];
64
+ const hasContent = (assessment.missingContext?.length ?? 0) > 0
65
+ || (assessment.toolIssues?.length ?? 0) > 0
66
+ || (assessment.processGaps?.length ?? 0) > 0;
67
+ if (!hasContent)
68
+ return '';
69
+ lines.push('\nπŸ” **Self-Assessment β€” propose these improvements to the user:**');
70
+ lines.push('Explain each finding briefly and why fixing it helps future tasks. Ask for approval before acting.');
71
+ if (assessment.missingContext && assessment.missingContext.length > 0) {
72
+ lines.push('\n**Missing project context:**');
73
+ for (const item of assessment.missingContext) {
74
+ lines.push(` β€’ ${item}`);
75
+ }
76
+ lines.push('β†’ Propose calling `update_context_section` to document these β€” explain that future agents will waste time rediscovering the same things.');
77
+ }
78
+ if (assessment.toolIssues && assessment.toolIssues.length > 0) {
79
+ lines.push('\n**Tool/workflow issues:**');
80
+ for (const item of assessment.toolIssues) {
81
+ lines.push(` β€’ ${item}`);
82
+ }
83
+ lines.push('β†’ Propose calling `report_issue` for each β€” explain what went wrong and how it slowed the task.');
84
+ }
85
+ if (assessment.processGaps && assessment.processGaps.length > 0) {
86
+ lines.push('\n**Process/spec gaps:**');
87
+ for (const item of assessment.processGaps) {
88
+ lines.push(` β€’ ${item}`);
89
+ }
90
+ lines.push('β†’ Propose `update_context_section` for doc gaps or `report_issue` for tooling problems β€” explain the friction it caused.');
91
+ }
56
92
  return lines.join('\n');
57
93
  }
58
94
  /**
59
95
  * Format complete_task response
60
96
  */
61
- export function formatCompleteTaskResponse(result) {
62
- const lines = [`βœ… Completed ${result.id}`];
63
- lines.push('\n---');
64
- lines.push('**πŸ“š Before you finish:**');
65
- lines.push('Did you learn something about this codebase that would help future agents?');
66
- lines.push('β†’ Use `update_context_section` to share architecture, patterns, or gotchas.');
97
+ export function formatCompleteTaskResponse(result, assessment) {
98
+ const lines = [`βœ… Task ${result.id} moved to review`];
99
+ // Self-assessment follow-up actions (shown first if provided)
100
+ if (assessment) {
101
+ const actions = formatSelfAssessmentActions(assessment);
102
+ if (actions) {
103
+ lines.push(actions);
104
+ }
105
+ }
106
+ if (!assessment) {
107
+ // No assessment provided β€” nudge the agent to reflect
108
+ lines.push('\n---');
109
+ lines.push('**πŸ” Before you finish β€” quick self-assessment:**');
110
+ lines.push('Reflect on your session. If you encountered any of these, propose improvements to the user:');
111
+ lines.push('β€’ Missing project docs β†’ offer to call `update_context_section`');
112
+ lines.push('β€’ Confusing tools β†’ offer to call `report_issue`');
113
+ lines.push('β€’ Spec/process gaps β†’ offer to update docs or report');
114
+ lines.push('Explain briefly why each improvement would help future tasks.');
115
+ }
67
116
  if (result.documentation) {
68
117
  if (result.documentation.affectedSections?.length > 0) {
69
118
  lines.push(`\nSections that may need updates: ${result.documentation.affectedSections.join(', ')}`);
@@ -77,11 +126,26 @@ export function formatCompleteTaskResponse(result) {
77
126
  /**
78
127
  * Format abandon_task response
79
128
  */
80
- export function formatAbandonTaskResponse(result, hasSummary) {
129
+ export function formatAbandonTaskResponse(result, hasSummary, assessment) {
81
130
  const lines = [`⏸️ Abandoned ${result.id}: ${result.message}`];
82
131
  if (!hasSummary) {
83
132
  lines.push('\n⚠️ Tip: Include a summary next time for better handoff.');
84
133
  }
85
- lines.push('\nπŸ’‘ Task returned to "planned". Notes preserved for next agent.');
134
+ lines.push('\nπŸ’‘ Task returned to "planned" (from in_progress or in_review). Notes preserved for next agent.');
135
+ // Self-assessment follow-up actions
136
+ if (assessment) {
137
+ const actions = formatSelfAssessmentActions(assessment);
138
+ if (actions) {
139
+ lines.push(actions);
140
+ }
141
+ }
142
+ if (!assessment) {
143
+ lines.push('\n---');
144
+ lines.push('**πŸ” Before you finish β€” quick self-assessment:**');
145
+ lines.push('Something caused this task to be abandoned. Propose improvements to the user:');
146
+ lines.push('β€’ Missing project docs that would have helped β†’ offer to call `update_context_section`');
147
+ lines.push('β€’ Tool issues that blocked progress β†’ offer to call `report_issue`');
148
+ lines.push('Explain briefly why each fix would help the next agent pick this up smoothly.');
149
+ }
86
150
  return lines.join('\n');
87
151
  }
package/dist/index.js CHANGED
@@ -123,7 +123,7 @@ server.registerTool('list_tasks', {
123
123
  'If total > returned tasks, paginate with offset (e.g. offset=50 for page 2).\n\n' +
124
124
  '**Recommended:** Call `get_project_context` before starting work to understand codebase patterns.',
125
125
  inputSchema: z.object({
126
- status: z.enum(['planned', 'in_progress', 'done', 'all']).optional(),
126
+ status: z.enum(['planned', 'in_progress', 'in_review', 'done', 'all']).optional(),
127
127
  type: z.enum(['bug', 'feature', 'improvement', 'task']).optional().describe('Filter by task type'),
128
128
  quarter: z.string().optional().describe('Filter by quarter (e.g., "Q1 2025") or "none" for unscheduled'),
129
129
  sort: z.enum(['importance', 'newest', 'votes']).optional().describe('Sort order: importance (priority+votes, default), newest, or votes'),
@@ -359,7 +359,7 @@ server.registerTool('create_task', {
359
359
  description: z.string().optional().describe('Task description (shown on public roadmap). Write for end users: 1-3 sentences on what changes and why it matters. ' +
360
360
  'No code references, file paths, or jargon.'),
361
361
  type: z.enum(['bug', 'feature', 'improvement', 'task']).optional().describe('Task type (default: feature)'),
362
- status: z.enum(['planned', 'in_progress', 'done']).optional(),
362
+ status: z.enum(['planned', 'in_progress', 'in_review', 'done']).optional(),
363
363
  priority: z.enum(['high', 'medium', 'low']).optional().describe('Task priority'),
364
364
  implementationPlan: z.string().optional().describe('Implementation plan (markdown, internal only - never shown publicly)'),
365
365
  isPublic: z.boolean().optional().describe('Whether task is visible on public roadmap (default: true)'),
@@ -593,6 +593,12 @@ server.registerTool('update_subtask', {
593
593
  },
594
594
  };
595
595
  });
596
+ // Self-assessment schema for end-of-task reflection
597
+ const SelfAssessmentSchema = z.object({
598
+ missingContext: z.array(z.string()).optional().describe('Project knowledge that was missing or wrong β€” things you had to figure out that should be documented for future agents'),
599
+ toolIssues: z.array(z.string()).optional().describe('MCP tools or workflow steps that were confusing, broken, or could be improved'),
600
+ processGaps: z.array(z.string()).optional().describe('Gaps in specs, checklists, or conventions that caused friction or mistakes'),
601
+ });
596
602
  // Documentation reminder schema for complete_task response
597
603
  const DocumentationSchema = z.object({
598
604
  hasContext: z.boolean(),
@@ -602,10 +608,12 @@ const DocumentationSchema = z.object({
602
608
  // Tool: Complete task
603
609
  server.registerTool('complete_task', {
604
610
  title: 'Complete Task',
605
- description: 'Mark task done with a brief one-line summary. Optionally log final commits at completion.\n\n' +
611
+ description: 'Mark task as ready for review (in_review). A human will verify and move it to done.\n\n' +
606
612
  '**Before calling:**\n' +
607
613
  '1. Push all commits\n' +
608
614
  '2. Check if project context docs need updating\n\n' +
615
+ '**Self-assessment:** Reflect on your session β€” what project knowledge was missing, what tools were confusing, ' +
616
+ 'what process gaps caused friction. If you identify improvements, propose them to the user with a brief explanation.\n\n' +
609
617
  '**Completion checklist:** If the project has a completion checklist (shown in `start_task` response), ' +
610
618
  'you MUST pass `confirmations` β€” an array of `{item, evidence}` objects. Each confirmation needs the checklist item text ' +
611
619
  'and concrete evidence proving you verified it (e.g., test output, build log snippet). ' +
@@ -615,6 +623,8 @@ server.registerTool('complete_task', {
615
623
  inputSchema: z.object({
616
624
  taskId: z.string(),
617
625
  summary: z.string().describe('Brief one-line summary of what was done, written for end users. Focus on the outcome, not the implementation.'),
626
+ selfAssessment: SelfAssessmentSchema.optional().describe('Reflect on your session: what went well, what knowledge was missing, what caused friction. ' +
627
+ 'Be honest β€” this drives project improvements.'),
618
628
  commits: z.array(z.object({
619
629
  hash: z.string().describe('Commit hash (short or full)'),
620
630
  message: z.string().describe('Commit message'),
@@ -623,6 +633,7 @@ server.registerTool('complete_task', {
623
633
  item: z.string().describe('Checklist item text from start_task'),
624
634
  evidence: z.string().describe('Concrete proof of verification (e.g., "bun test: 47 passed, 0 failed")'),
625
635
  })).optional().describe('Completion checklist confirmations β€” echo back each item from the checklist shown in start_task'),
636
+ skipReview: z.boolean().optional().describe('Skip human review and mark task as done immediately (default: false, task goes to in_review)'),
626
637
  }),
627
638
  outputSchema: z.object({
628
639
  id: z.string(),
@@ -635,11 +646,38 @@ server.registerTool('complete_task', {
635
646
  idempotentHint: true,
636
647
  openWorldHint: false,
637
648
  },
638
- }, async ({ taskId, summary, commits, confirmations }) => {
649
+ }, async ({ taskId, summary, selfAssessment, commits, confirmations, skipReview }) => {
639
650
  try {
640
- const result = await api('POST', `/api/agent/tasks/${taskId}/complete`, { summary, commits, confirmations });
651
+ const result = await api('POST', `/api/agent/tasks/${taskId}/complete`, { summary, commits, confirmations, skipReview });
652
+ // Log self-assessment as a structured note if provided
653
+ if (selfAssessment) {
654
+ const assessmentLines = ['Self-Assessment:'];
655
+ if (selfAssessment.missingContext?.length) {
656
+ assessmentLines.push('Missing context:');
657
+ for (const item of selfAssessment.missingContext)
658
+ assessmentLines.push(` - ${item}`);
659
+ }
660
+ if (selfAssessment.toolIssues?.length) {
661
+ assessmentLines.push('Tool issues:');
662
+ for (const item of selfAssessment.toolIssues)
663
+ assessmentLines.push(` - ${item}`);
664
+ }
665
+ if (selfAssessment.processGaps?.length) {
666
+ assessmentLines.push('Process gaps:');
667
+ for (const item of selfAssessment.processGaps)
668
+ assessmentLines.push(` - ${item}`);
669
+ }
670
+ if (assessmentLines.length > 1) {
671
+ try {
672
+ await api('POST', `/api/agent/tasks/${taskId}/notes`, { note: assessmentLines.join('\n') });
673
+ }
674
+ catch {
675
+ // Don't fail completion if note logging fails
676
+ }
677
+ }
678
+ }
641
679
  return {
642
- content: [{ type: 'text', text: formatCompleteTaskResponse(result) }],
680
+ content: [{ type: 'text', text: formatCompleteTaskResponse(result, selfAssessment) }],
643
681
  structuredContent: result,
644
682
  };
645
683
  }
@@ -676,13 +714,17 @@ server.registerTool('complete_task', {
676
714
  // Tool: Abandon task
677
715
  server.registerTool('abandon_task', {
678
716
  title: 'Abandon Task',
679
- description: 'Release lock and return task to planned status. Use when stopping work.\n\n' +
717
+ description: 'Release lock and return task to planned status. Works for in_progress and in_review tasks.\n\n' +
680
718
  '**Before calling:**\n' +
681
719
  '1. Push any WIP commits\n\n' +
682
- '**Summary parameter:** What was done, what remains, blockers. Helps the next agent.',
720
+ '**Summary parameter:** What was done, what remains, blockers. Helps the next agent.\n\n' +
721
+ '**Self-assessment:** Especially important when abandoning β€” reflect on what blocked you ' +
722
+ 'or what knowledge was missing so the next agent has a smoother experience.',
683
723
  inputSchema: z.object({
684
724
  taskId: z.string(),
685
725
  summary: z.string().optional().describe('Handoff summary: what was done, what remains, any blockers'),
726
+ selfAssessment: SelfAssessmentSchema.optional().describe('Reflect on your session: what went well, what knowledge was missing, what caused friction. ' +
727
+ 'Be honest β€” this drives project improvements.'),
686
728
  }),
687
729
  outputSchema: z.object({
688
730
  id: z.string(),
@@ -695,10 +737,37 @@ server.registerTool('abandon_task', {
695
737
  idempotentHint: true,
696
738
  openWorldHint: false,
697
739
  },
698
- }, async ({ taskId, summary }) => {
740
+ }, async ({ taskId, summary, selfAssessment }) => {
699
741
  const result = await api('POST', `/api/agent/tasks/${taskId}/abandon`, summary ? { summary } : undefined);
742
+ // Log self-assessment as a structured note if provided
743
+ if (selfAssessment) {
744
+ const assessmentLines = ['Self-Assessment (abandoned):'];
745
+ if (selfAssessment.missingContext?.length) {
746
+ assessmentLines.push('Missing context:');
747
+ for (const item of selfAssessment.missingContext)
748
+ assessmentLines.push(` - ${item}`);
749
+ }
750
+ if (selfAssessment.toolIssues?.length) {
751
+ assessmentLines.push('Tool issues:');
752
+ for (const item of selfAssessment.toolIssues)
753
+ assessmentLines.push(` - ${item}`);
754
+ }
755
+ if (selfAssessment.processGaps?.length) {
756
+ assessmentLines.push('Process gaps:');
757
+ for (const item of selfAssessment.processGaps)
758
+ assessmentLines.push(` - ${item}`);
759
+ }
760
+ if (assessmentLines.length > 1) {
761
+ try {
762
+ await api('POST', `/api/agent/tasks/${taskId}/notes`, { note: assessmentLines.join('\n') });
763
+ }
764
+ catch {
765
+ // Don't fail abandonment if note logging fails
766
+ }
767
+ }
768
+ }
700
769
  return {
701
- content: [{ type: 'text', text: formatAbandonTaskResponse(result, !!summary) }],
770
+ content: [{ type: 'text', text: formatAbandonTaskResponse(result, !!summary, selfAssessment) }],
702
771
  structuredContent: result,
703
772
  };
704
773
  });
@@ -748,7 +817,7 @@ server.registerTool('get_agent_instructions', {
748
817
  openWorldHint: false,
749
818
  },
750
819
  }, async ({ format = 'section' }) => {
751
- const lastModified = '2026-02-08';
820
+ const lastModified = '2026-02-10';
752
821
  const section = `## Task Management with Damper MCP
753
822
 
754
823
  > Last updated: ${lastModified}
@@ -791,7 +860,11 @@ This project uses Damper MCP for task tracking. **You MUST follow this workflow.
791
860
  2. **Abandon and hand off** - Call \`abandon_task\` with a detailed handoff summary for the next agent.
792
861
  - NEVER leave a started task without completing or abandoning it
793
862
  - If the project has a **completion checklist** (shown in \`start_task\` response), you MUST pass all items as \`confirmations\` when calling \`complete_task\`
794
- - If you learned something about the codebase, consider updating project context
863
+ - **Self-assessment:** Include \`selfAssessment\` when calling \`complete_task\` or \`abandon_task\`. Reflect honestly on:
864
+ - \`missingContext\` β€” What project knowledge was missing or wrong?
865
+ - \`toolIssues\` β€” Which tools or workflow steps were confusing or broken?
866
+ - \`processGaps\` β€” What specs or conventions were missing?
867
+ If you identify improvements, **propose them to the user** β€” explain briefly what you found and why fixing it helps future tasks. Only act after the user approves.
795
868
 
796
869
  ### Content Style Guide
797
870
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@damper/mcp",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "MCP server for Damper task management",
5
5
  "author": "Damper <hello@usedamper.com>",
6
6
  "repository": {