edsger 0.54.0 → 0.55.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.
Files changed (142) hide show
  1. package/README.md +20 -0
  2. package/dist/api/financing.d.ts +47 -0
  3. package/dist/api/financing.js +37 -0
  4. package/dist/api/issues/approval-checker.d.ts +11 -9
  5. package/dist/api/issues/approval-checker.js +30 -41
  6. package/dist/api/issues/status-updater.d.ts +47 -20
  7. package/dist/api/issues/status-updater.js +114 -46
  8. package/dist/api/issues/update-issue.d.ts +5 -0
  9. package/dist/api/issues/update-issue.js +6 -0
  10. package/dist/commands/agent-workflow/processor.js +5 -1
  11. package/dist/commands/checklists/index.d.ts +5 -2
  12. package/dist/commands/checklists/index.js +73 -12
  13. package/dist/commands/checklists/tools.d.ts +14 -7
  14. package/dist/commands/checklists/tools.js +15 -208
  15. package/dist/commands/financing-deck/index.d.ts +8 -0
  16. package/dist/commands/financing-deck/index.js +66 -0
  17. package/dist/commands/find-architecture/index.d.ts +13 -0
  18. package/dist/commands/find-architecture/index.js +41 -0
  19. package/dist/commands/issue-analysis/index.d.ts +5 -0
  20. package/dist/commands/issue-analysis/index.js +9 -0
  21. package/dist/commands/sync-github-issues/index.d.ts +11 -0
  22. package/dist/commands/sync-github-issues/index.js +42 -0
  23. package/dist/commands/sync-sentry-issues/index.d.ts +14 -0
  24. package/dist/commands/sync-sentry-issues/index.js +73 -0
  25. package/dist/commands/technical-design/index.d.ts +5 -0
  26. package/dist/commands/technical-design/index.js +9 -0
  27. package/dist/commands/test-cases-analysis/index.d.ts +5 -0
  28. package/dist/commands/test-cases-analysis/index.js +9 -0
  29. package/dist/commands/user-stories-analysis/index.d.ts +5 -0
  30. package/dist/commands/user-stories-analysis/index.js +9 -0
  31. package/dist/commands/workflow/executors/phase-executor.js +6 -4
  32. package/dist/commands/workflow/phase-orchestrator.js +0 -1
  33. package/dist/config/issue-status.d.ts +18 -45
  34. package/dist/config/issue-status.js +21 -107
  35. package/dist/index.js +176 -4
  36. package/dist/phases/app-store-generation/agent.js +2 -1
  37. package/dist/phases/app-store-generation/index.js +11 -3
  38. package/dist/phases/branch-planning/index.js +0 -1
  39. package/dist/phases/bug-fixing/analyzer.js +0 -1
  40. package/dist/phases/bug-fixing/mcp-server.d.ts +18 -1
  41. package/dist/phases/bug-fixing/mcp-server.js +19 -76
  42. package/dist/phases/chat-processor/product-tools.d.ts +5 -8
  43. package/dist/phases/chat-processor/product-tools.js +6 -512
  44. package/dist/phases/chat-processor/tools.d.ts +5 -9
  45. package/dist/phases/chat-processor/tools.js +6 -704
  46. package/dist/phases/code-implementation/index.js +0 -1
  47. package/dist/phases/code-implementation-verification/agent.js +6 -1
  48. package/dist/phases/code-refine/index.js +0 -1
  49. package/dist/phases/code-refine/refine-iteration.js +2 -1
  50. package/dist/phases/code-review/index.js +0 -1
  51. package/dist/phases/code-testing/analyzer.js +0 -1
  52. package/dist/phases/financing-deck/agent.d.ts +1 -0
  53. package/dist/phases/financing-deck/agent.js +96 -0
  54. package/dist/phases/financing-deck/context.d.ts +13 -0
  55. package/dist/phases/financing-deck/context.js +69 -0
  56. package/dist/phases/financing-deck/index.d.ts +15 -0
  57. package/dist/phases/financing-deck/index.js +89 -0
  58. package/dist/phases/financing-deck/prompts.d.ts +2 -0
  59. package/dist/phases/financing-deck/prompts.js +94 -0
  60. package/dist/phases/find-architecture/index.d.ts +44 -0
  61. package/dist/phases/find-architecture/index.js +248 -0
  62. package/dist/phases/find-architecture/prompts.d.ts +31 -0
  63. package/dist/phases/find-architecture/prompts.js +128 -0
  64. package/dist/phases/find-architecture/state.d.ts +21 -0
  65. package/dist/phases/find-architecture/state.js +17 -0
  66. package/dist/phases/find-architecture/types.d.ts +55 -0
  67. package/dist/phases/find-architecture/types.js +69 -0
  68. package/dist/phases/find-bugs/index.js +13 -4
  69. package/dist/phases/find-features/index.js +10 -5
  70. package/dist/phases/find-smells/index.js +10 -3
  71. package/dist/phases/functional-testing/analyzer.js +27 -17
  72. package/dist/phases/functional-testing/http-fallback.d.ts +1 -1
  73. package/dist/phases/functional-testing/http-fallback.js +32 -16
  74. package/dist/phases/functional-testing/mcp-server.d.ts +9 -1
  75. package/dist/phases/functional-testing/mcp-server.js +13 -132
  76. package/dist/phases/growth-analysis/agent.js +2 -2
  77. package/dist/phases/growth-analysis/index.js +9 -3
  78. package/dist/phases/intelligence-analysis/agent.js +2 -2
  79. package/dist/phases/intelligence-analysis/index.js +9 -2
  80. package/dist/phases/issue-analysis/agent.d.ts +9 -1
  81. package/dist/phases/issue-analysis/agent.js +68 -27
  82. package/dist/phases/issue-analysis/context.d.ts +5 -9
  83. package/dist/phases/issue-analysis/context.js +31 -76
  84. package/dist/phases/issue-analysis/index.js +32 -84
  85. package/dist/phases/issue-analysis/outcome.d.ts +3 -33
  86. package/dist/phases/issue-analysis/outcome.js +15 -253
  87. package/dist/phases/issue-analysis/prompts.d.ts +3 -5
  88. package/dist/phases/issue-analysis/prompts.js +45 -158
  89. package/dist/phases/issue-analysis-verification/agent.d.ts +4 -4
  90. package/dist/phases/issue-analysis-verification/agent.js +5 -5
  91. package/dist/phases/issue-analysis-verification/index.d.ts +4 -2
  92. package/dist/phases/issue-analysis-verification/index.js +9 -22
  93. package/dist/phases/issue-analysis-verification/prompts.d.ts +1 -2
  94. package/dist/phases/issue-analysis-verification/prompts.js +21 -46
  95. package/dist/phases/output-contracts.js +66 -78
  96. package/dist/phases/pr-execution/index.js +2 -2
  97. package/dist/phases/pr-resolve/index.js +2 -8
  98. package/dist/phases/pr-splitting/index.js +2 -2
  99. package/dist/phases/release-sync/index.js +52 -43
  100. package/dist/phases/run-sheet/index.js +2 -1
  101. package/dist/phases/smoke-test/agent.js +2 -1
  102. package/dist/phases/smoke-test/index.js +4 -1
  103. package/dist/phases/sync-github-issues/index.d.ts +41 -0
  104. package/dist/phases/sync-github-issues/index.js +187 -0
  105. package/dist/phases/sync-github-issues/state.d.ts +26 -0
  106. package/dist/phases/sync-github-issues/state.js +18 -0
  107. package/dist/phases/sync-github-issues/types.d.ts +35 -0
  108. package/dist/phases/sync-github-issues/types.js +6 -0
  109. package/dist/phases/sync-sentry-issues/index.d.ts +29 -0
  110. package/dist/phases/sync-sentry-issues/index.js +153 -0
  111. package/dist/phases/sync-sentry-issues/sentry-client.d.ts +66 -0
  112. package/dist/phases/sync-sentry-issues/sentry-client.js +221 -0
  113. package/dist/phases/sync-sentry-issues/state.d.ts +23 -0
  114. package/dist/phases/sync-sentry-issues/state.js +18 -0
  115. package/dist/phases/sync-sentry-issues/types.d.ts +46 -0
  116. package/dist/phases/sync-sentry-issues/types.js +6 -0
  117. package/dist/phases/sync-shared/mcp.d.ts +81 -0
  118. package/dist/phases/sync-shared/mcp.js +111 -0
  119. package/dist/phases/technical-design/index.js +0 -1
  120. package/dist/phases/test-cases-analysis/agent.js +2 -1
  121. package/dist/phases/test-cases-analysis/index.js +0 -1
  122. package/dist/phases/user-stories-analysis/agent.js +2 -1
  123. package/dist/phases/user-stories-analysis/index.js +0 -1
  124. package/dist/services/coaching/coaching-agent.js +29 -4
  125. package/dist/services/feedbacks.d.ts +1 -1
  126. package/dist/skills/phase/issue-analysis/SKILL.md +48 -92
  127. package/dist/skills/phase/issue-analysis-verification/SKILL.md +46 -31
  128. package/dist/tools/bootstrap.d.ts +45 -0
  129. package/dist/tools/bootstrap.js +50 -0
  130. package/dist/types/external-sources.d.ts +22 -0
  131. package/dist/types/external-sources.js +23 -0
  132. package/dist/types/index.d.ts +5 -10
  133. package/dist/types/issues.d.ts +2 -0
  134. package/dist/types/llm-responses.d.ts +1 -14
  135. package/dist/utils/formatters.js +1 -7
  136. package/dist/utils/issue-phase-cli.d.ts +26 -0
  137. package/dist/utils/issue-phase-cli.js +44 -0
  138. package/dist/workspace/workspace-manager.d.ts +10 -0
  139. package/dist/workspace/workspace-manager.js +22 -1
  140. package/package.json +6 -2
  141. package/vitest.config.ts +4 -0
  142. package/.env.local +0 -12
@@ -29,6 +29,12 @@ export async function updateIssue(issueId, updates, verbose) {
29
29
  export async function updateTechnicalDesign(issueId, technicalDesign, verbose) {
30
30
  return updateIssue(issueId, { technical_design: technicalDesign }, verbose);
31
31
  }
32
+ /**
33
+ * Update execution plan for an issue
34
+ */
35
+ export async function updateExecutionPlan(issueId, executionPlan, verbose) {
36
+ return updateIssue(issueId, { execution_plan: executionPlan }, verbose);
37
+ }
32
38
  /**
33
39
  * Normalize phase name from pipeline format (hyphens) to workflow format (underscores)
34
40
  * e.g., 'issue-analysis' -> 'issue_analysis'
@@ -15,7 +15,7 @@ import { getGitHubConfig } from '../../api/github.js';
15
15
  import { WorkerTimeoutError } from '../../errors/index.js';
16
16
  import { sendHeartbeat, shouldProcess } from '../../system/session-manager.js';
17
17
  import { logError, logInfo, logSuccess, logWarning, } from '../../utils/logger.js';
18
- import { cloneIssueRepo } from '../../workspace/workspace-manager.js';
18
+ import { cleanupIssueRepo, cloneIssueRepo, getIssueRepoPath, } from '../../workspace/workspace-manager.js';
19
19
  import { calculateStats, createCompletedState, createFailedState, createInitialState, createProcessingState, updateIssueState, } from '../workflow/core/state-manager.js';
20
20
  /**
21
21
  * Maximum allowed concurrency (hard cap).
@@ -411,6 +411,10 @@ export class AgentWorkflowProcessor {
411
411
  logSuccess(`Issue completed: ${issueName}`);
412
412
  // Notify chat worker that issue workflow is done
413
413
  this.notifyChatWorker({ type: 'event:issue_done', issueId });
414
+ // Clean up the per-issue clone now that the workflow is finished.
415
+ // Failures intentionally leave the workspace so the user (or a retry)
416
+ // can inspect the partial state.
417
+ cleanupIssueRepo(getIssueRepoPath(this.options.workspaceRoot, issueId));
414
418
  }
415
419
  else {
416
420
  this.processedIssues = updateIssueState(this.processedIssues, issueId, (currentState) => createFailedState(issueId, currentState));
@@ -4,10 +4,13 @@
4
4
  */
5
5
  import { type CliOptions } from '../../types/index.js';
6
6
  /**
7
- * Run AI-powered checklist sync for a product based on local code analysis.
7
+ * Run AI-powered checklist sync. Scope is either a product (analyse the
8
+ * product's codebase) or a team (analyse team standards docs, generate
9
+ * org-wide checklists).
8
10
  */
9
11
  export declare function runChecklists(options: CliOptions & {
10
- checklistsProductId: string;
12
+ checklistsProductId?: string;
13
+ checklistsTeamId?: string;
11
14
  checklistsDir?: string;
12
15
  checklistsPrompt?: string;
13
16
  }): Promise<void>;
@@ -20,7 +20,11 @@ function logAssistantContent(content) {
20
20
  }
21
21
  }
22
22
  }
23
- const SYSTEM_PROMPT = `You are an expert software quality engineer. Your job is to analyse the code and documentation in the current working directory and manage quality checklists for the product.
23
+ // Two SYSTEM_PROMPTs because team-level sync has a different mental model:
24
+ // the directory is reference material (org standards / process docs / shared
25
+ // templates), not necessarily a product's own codebase. Telling the LLM
26
+ // "scan the code" when there's no code wastes turns.
27
+ const PRODUCT_SYSTEM_PROMPT = `You are an expert software quality engineer. Your job is to analyse the code and documentation in the current working directory and manage quality checklists for the product.
24
28
 
25
29
  ## Workflow
26
30
 
@@ -45,38 +49,95 @@ const SYSTEM_PROMPT = `You are an expert software quality engineer. Your job is
45
49
  - If the codebase is small, a few focused checklists are better than many sparse ones.
46
50
  - When creating multiple checklists, assign incrementing sort_order values (0, 1, 2, …) so they display in a meaningful order.
47
51
  `;
52
+ const TEAM_SYSTEM_PROMPT = `You are an expert software quality engineer. Your job is to analyse the reference material in the current working directory (team standards, engineering guidelines, process docs, compliance requirements, shared templates, etc.) and manage TEAM-LEVEL quality checklists.
53
+
54
+ Team checklists apply to every product owned by the team, so they should capture **organisation-wide** quality bars — not the specifics of any single codebase.
55
+
56
+ ## Workflow
57
+
58
+ 1. **Explore** the directory — read every relevant doc to understand the team's engineering standards, review process, security baseline, release rules, and other shared expectations. The directory is reference material, not necessarily product source code.
59
+ 2. **Query existing team checklists** using \`list_checklists\` so you know what already exists.
60
+ 3. **Decide what to change** — compare the standards documented in the directory against existing checklists:
61
+ - **Create** team checklists for standards that are not yet enforced (e.g., security baseline, release readiness, accessibility minimums, code-review etiquette).
62
+ - **Update** checklists whose items have drifted from the documented standards.
63
+ - **Delete** checklists that no longer reflect team policy.
64
+ - **Add / update / remove items** within checklists as needed.
65
+ 4. **Execute the changes** using the provided tools.
66
+ 5. **Summarise** what you did at the end.
67
+
68
+ ## Guidelines
69
+
70
+ - Stay generic across products — a team checklist will apply to every product in the team, so do NOT bake in product-specific tech-stack assumptions.
71
+ - Focus on actionable, verifiable checklist items — things a reviewer can check yes/no.
72
+ - Assign the correct **role** to each checklist (developer, qa_engineer, technical_lead, etc.).
73
+ - Assign relevant **phases** (code_implementation, code_review, technical_design, functional_testing, etc.).
74
+ - Keep item titles concise (< 80 chars). Use the description for details.
75
+ - Prefer boolean item_type for most items.
76
+ - Do not create duplicate checklists — update existing ones instead.
77
+ - When creating multiple checklists, assign incrementing sort_order values (0, 1, 2, …) so they display in a meaningful order.
78
+ `;
48
79
  /**
49
- * Run AI-powered checklist sync for a product based on local code analysis.
80
+ * Run AI-powered checklist sync. Scope is either a product (analyse the
81
+ * product's codebase) or a team (analyse team standards docs, generate
82
+ * org-wide checklists).
50
83
  */
51
84
  export async function runChecklists(options) {
52
85
  const productId = options.checklistsProductId;
86
+ const teamId = options.checklistsTeamId;
53
87
  const directory = options.checklistsDir || process.cwd();
54
88
  const userPrompt = options.checklistsPrompt;
89
+ if (!productId && !teamId) {
90
+ throw new Error('checklists sync requires either a product ID or a team ID.');
91
+ }
92
+ if (productId && teamId) {
93
+ throw new Error('checklists sync received both a product ID and a team ID; choose one.');
94
+ }
95
+ const isTeamScope = !productId;
55
96
  if (!isLoggedIn()) {
56
97
  throw new Error('You must be logged in to run checklists sync.\n' +
57
98
  'Run `edsger login` first.');
58
99
  }
59
100
  // Validate configuration (ensures .edsgerrc and env are loaded)
60
101
  validateConfiguration(options);
61
- // Register CLI session for log persistence
102
+ // Register CLI session for log persistence. We pass productId only when
103
+ // present so existing per-product session indexing still works.
62
104
  await registerSession({ command: 'checklists', productId });
63
- logInfo(`Starting checklist sync for product: ${productId}`);
105
+ if (isTeamScope) {
106
+ logInfo(`Starting checklist sync for team: ${teamId}`);
107
+ }
108
+ else {
109
+ logInfo(`Starting checklist sync for product: ${productId}`);
110
+ }
64
111
  logInfo(`Analysing directory: ${directory}`);
65
112
  if (userPrompt) {
66
113
  logInfo(`User instructions: ${userPrompt}`);
67
114
  }
68
- const mcpServer = createChecklistsMcpServer(productId);
69
- const promptParts = [
70
- `Analyse the codebase in the current working directory and synchronise the product's quality checklists.`,
71
- `Product ID: ${productId}`,
72
- `Directory: ${directory}`,
73
- '',
74
- 'Start by exploring the project structure and reading key files, then query existing checklists, and finally create/update/delete as needed.',
75
- ];
115
+ const mcpServer = isTeamScope
116
+ ? createChecklistsMcpServer({ kind: 'team', teamId: teamId })
117
+ : createChecklistsMcpServer({
118
+ kind: 'product',
119
+ productId: productId,
120
+ });
121
+ const promptParts = isTeamScope
122
+ ? [
123
+ `Analyse the reference material in the current working directory and synchronise the TEAM-LEVEL quality checklists.`,
124
+ `Team ID: ${teamId}`,
125
+ `Directory: ${directory}`,
126
+ '',
127
+ 'Start by exploring the directory and reading every relevant standards / process / guideline document, then query existing team checklists, and finally create/update/delete as needed. Remember: team checklists apply to every product in the team, so keep them generic.',
128
+ ]
129
+ : [
130
+ `Analyse the codebase in the current working directory and synchronise the product's quality checklists.`,
131
+ `Product ID: ${productId}`,
132
+ `Directory: ${directory}`,
133
+ '',
134
+ 'Start by exploring the project structure and reading key files, then query existing checklists, and finally create/update/delete as needed.',
135
+ ];
76
136
  if (userPrompt) {
77
137
  promptParts.push('', '## Additional Instructions from User', '', userPrompt);
78
138
  }
79
139
  const prompt = promptParts.join('\n');
140
+ const SYSTEM_PROMPT = isTeamScope ? TEAM_SYSTEM_PROMPT : PRODUCT_SYSTEM_PROMPT;
80
141
  try {
81
142
  for await (const message of query({
82
143
  prompt,
@@ -1,10 +1,17 @@
1
1
  /**
2
- * Checklist MCP tools for the Claude Agent SDK.
2
+ * Checklists MCP server CLI entry point.
3
3
  *
4
- * Provides all checklist & checklist-item CRUD operations so the AI agent
5
- * can query, create, update, and delete checklists based on code analysis.
4
+ * Tool implementations live in `edsger-tools`. This shim adapts the CLI's
5
+ * `callMcpEndpoint` transport into `ToolDeps` and threads the scope id
6
+ * (productId or teamId) through `deps.context` so the CLI can run AI
7
+ * sync against either a product or a team.
6
8
  */
7
- /**
8
- * Create an in-process MCP server with checklist management tools.
9
- */
10
- export declare function createChecklistsMcpServer(productId: string): import("@anthropic-ai/claude-agent-sdk").McpSdkServerConfigWithInstance;
9
+ import type { McpSdkServerConfigWithInstance } from '@anthropic-ai/claude-agent-sdk';
10
+ export type ChecklistScope = {
11
+ kind: 'product';
12
+ productId: string;
13
+ } | {
14
+ kind: 'team';
15
+ teamId: string;
16
+ };
17
+ export declare function createChecklistsMcpServer(scope: ChecklistScope | string): McpSdkServerConfigWithInstance;
@@ -1,212 +1,19 @@
1
1
  /**
2
- * Checklist MCP tools for the Claude Agent SDK.
2
+ * Checklists MCP server CLI entry point.
3
3
  *
4
- * Provides all checklist & checklist-item CRUD operations so the AI agent
5
- * can query, create, update, and delete checklists based on code analysis.
4
+ * Tool implementations live in `edsger-tools`. This shim adapts the CLI's
5
+ * `callMcpEndpoint` transport into `ToolDeps` and threads the scope id
6
+ * (productId or teamId) through `deps.context` so the CLI can run AI
7
+ * sync against either a product or a team.
6
8
  */
7
- import { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk';
8
- import { z } from 'zod';
9
- import { callMcpEndpoint } from '../../api/mcp-client.js';
10
- /**
11
- * Create an in-process MCP server with checklist management tools.
12
- */
13
- export function createChecklistsMcpServer(productId) {
14
- return createSdkMcpServer({
15
- name: 'edsger-checklists',
16
- version: '1.0.0',
17
- tools: [
18
- // ── Query tools ─────────────────────────────────────────────
19
- tool('list_checklists', 'List all product-level checklists. Optionally filter by role or phase. Returns checklists with their items.', {
20
- role: z
21
- .string()
22
- .optional()
23
- .describe('Filter by role: product_manager, developer, qa_engineer, technical_lead, ux_designer, devops_engineer, security_engineer'),
24
- phase: z
25
- .string()
26
- .optional()
27
- .describe('Filter by phase (e.g., code_implementation, code_review, technical_design)'),
28
- }, async (args) => {
29
- const params = { product_id: productId };
30
- if (args.role) {
31
- params.role = args.role;
32
- }
33
- if (args.phase) {
34
- params.phase = args.phase;
35
- }
36
- const result = await callMcpEndpoint('checklists/list', params);
37
- return {
38
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
39
- };
40
- }),
41
- // ── Checklist CRUD ──────────────────────────────────────────
42
- tool('create_checklist', 'Create a new product-level checklist. A checklist belongs to a role and applies to one or more phases. You can include items inline.', {
43
- name: z.string().describe('Checklist name'),
44
- description: z.string().optional().describe('Checklist description'),
45
- role: z
46
- .string()
47
- .describe('Role: product_manager, developer, qa_engineer, technical_lead, ux_designer, devops_engineer, security_engineer'),
48
- phases: z
49
- .array(z.string())
50
- .describe('Array of phases this checklist applies to (e.g., ["code_implementation", "code_review"])'),
51
- sort_order: z
52
- .number()
53
- .optional()
54
- .describe('Display order (0-based). Assign incrementing values when creating multiple checklists.'),
55
- items: z
56
- .array(z.object({
57
- title: z.string().describe('Item title'),
58
- description: z.string().optional().describe('Item description'),
59
- item_type: z
60
- .enum(['boolean', 'text', 'number', 'select'])
61
- .optional()
62
- .describe('Item type (default: boolean)'),
63
- is_required: z
64
- .boolean()
65
- .optional()
66
- .describe('Whether this item is required (default: true)'),
67
- }))
68
- .optional()
69
- .describe('Items to create with the checklist'),
70
- }, async (args) => {
71
- const result = await callMcpEndpoint('checklists/create', {
72
- product_id: productId,
73
- name: args.name,
74
- description: args.description || null,
75
- role: args.role,
76
- phases: args.phases,
77
- is_active: true,
78
- sort_order: args.sort_order ?? 0,
79
- items: args.items,
80
- });
81
- return {
82
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
83
- };
84
- }),
85
- tool('update_checklist', 'Update an existing checklist. Only provide fields you want to change.', {
86
- checklist_id: z.string().describe('Checklist ID to update'),
87
- name: z.string().optional().describe('New name'),
88
- description: z.string().optional().describe('New description'),
89
- role: z.string().optional().describe('New role'),
90
- phases: z.array(z.string()).optional().describe('New phases array'),
91
- is_active: z
92
- .boolean()
93
- .optional()
94
- .describe('Whether the checklist is active'),
95
- }, async (args) => {
96
- const params = {
97
- checklist_id: args.checklist_id,
98
- };
99
- if (args.name !== undefined) {
100
- params.name = args.name;
101
- }
102
- if (args.description !== undefined) {
103
- params.description = args.description;
104
- }
105
- if (args.role !== undefined) {
106
- params.role = args.role;
107
- }
108
- if (args.phases !== undefined) {
109
- params.phases = args.phases;
110
- }
111
- if (args.is_active !== undefined) {
112
- params.is_active = args.is_active;
113
- }
114
- const result = await callMcpEndpoint('checklists/update', params);
115
- return {
116
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
117
- };
118
- }),
119
- tool('delete_checklist', 'Delete a checklist and all its items. Use with caution.', {
120
- checklist_id: z.string().describe('Checklist ID to delete'),
121
- }, async (args) => {
122
- const result = await callMcpEndpoint('checklists/delete', {
123
- checklist_id: args.checklist_id,
124
- });
125
- return {
126
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
127
- };
128
- }),
129
- // ── Checklist Items CRUD ────────────────────────────────────
130
- tool('create_checklist_items', 'Add one or more items to an existing checklist.', {
131
- checklist_id: z.string().describe('Checklist ID to add items to'),
132
- items: z.array(z.object({
133
- title: z.string().describe('Item title'),
134
- description: z.string().optional().describe('Item description'),
135
- item_type: z
136
- .enum(['boolean', 'text', 'number', 'select'])
137
- .optional()
138
- .describe('Item type (default: boolean)'),
139
- is_required: z
140
- .boolean()
141
- .optional()
142
- .describe('Whether this item is required (default: true)'),
143
- sort_order: z.number().optional().describe('Sort order'),
144
- config: z
145
- .record(z.string(), z.unknown())
146
- .optional()
147
- .describe('Additional config (e.g., options for select type)'),
148
- })),
149
- }, async (args) => {
150
- const result = await callMcpEndpoint('checklist_items/create', {
151
- checklist_id: args.checklist_id,
152
- items: args.items,
153
- });
154
- return {
155
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
156
- };
157
- }),
158
- tool('update_checklist_item', 'Update an existing checklist item. Only provide fields you want to change.', {
159
- item_id: z.string().describe('Item ID to update'),
160
- title: z.string().optional().describe('New title'),
161
- description: z.string().optional().describe('New description'),
162
- item_type: z
163
- .enum(['boolean', 'text', 'number', 'select'])
164
- .optional()
165
- .describe('New item type'),
166
- is_required: z
167
- .boolean()
168
- .optional()
169
- .describe('Whether this item is required'),
170
- sort_order: z.number().optional().describe('New sort order'),
171
- config: z
172
- .record(z.string(), z.unknown())
173
- .optional()
174
- .describe('New config'),
175
- }, async (args) => {
176
- const params = { item_id: args.item_id };
177
- if (args.title !== undefined) {
178
- params.title = args.title;
179
- }
180
- if (args.description !== undefined) {
181
- params.description = args.description;
182
- }
183
- if (args.item_type !== undefined) {
184
- params.item_type = args.item_type;
185
- }
186
- if (args.is_required !== undefined) {
187
- params.is_required = args.is_required;
188
- }
189
- if (args.sort_order !== undefined) {
190
- params.sort_order = args.sort_order;
191
- }
192
- if (args.config !== undefined) {
193
- params.config = args.config;
194
- }
195
- const result = await callMcpEndpoint('checklist_items/update', params);
196
- return {
197
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
198
- };
199
- }),
200
- tool('delete_checklist_item', 'Delete a single checklist item.', {
201
- item_id: z.string().describe('Item ID to delete'),
202
- }, async (args) => {
203
- const result = await callMcpEndpoint('checklist_items/delete', {
204
- item_id: args.item_id,
205
- });
206
- return {
207
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
208
- };
209
- }),
210
- ],
211
- });
9
+ import { createChecklistsMcpServer as createChecklistsMcpServerCore } from 'edsger-tools';
10
+ import { getToolDeps } from '../../tools/bootstrap.js';
11
+ export function createChecklistsMcpServer(scope) {
12
+ // Backwards compat: if a bare string is passed, treat it as productId.
13
+ const ctx = typeof scope === 'string'
14
+ ? { productId: scope }
15
+ : scope.kind === 'product'
16
+ ? { productId: scope.productId }
17
+ : { teamId: scope.teamId };
18
+ return createChecklistsMcpServerCore(getToolDeps(false, ctx));
212
19
  }
@@ -0,0 +1,8 @@
1
+ import { type CliOptions } from '../../types/index.js';
2
+ /**
3
+ * Run AI-powered financing pitch deck draft for a product.
4
+ * Reads the founder's self-reported financial data + product issues +
5
+ * user feedback, then writes an 11-slide pitch deck to
6
+ * financing_ai_analyses for the desktop / web UI to render.
7
+ */
8
+ export declare const runFinancingDeck: (options: CliOptions) => Promise<void>;
@@ -0,0 +1,66 @@
1
+ import { generateFinancingDeck, } from '../../phases/financing-deck/index.js';
2
+ import { deregisterSession, registerSession, } from '../../system/session-manager.js';
3
+ import { logError, logInfo, logSuccess } from '../../utils/logger.js';
4
+ import { validateConfiguration } from '../../utils/validation.js';
5
+ const VALID_STAGES = [
6
+ 'pre_seed',
7
+ 'seed',
8
+ 'series_a',
9
+ 'series_b',
10
+ 'series_c',
11
+ 'growth',
12
+ ];
13
+ function isFinancingStage(value) {
14
+ return VALID_STAGES.includes(value);
15
+ }
16
+ /**
17
+ * Run AI-powered financing pitch deck draft for a product.
18
+ * Reads the founder's self-reported financial data + product issues +
19
+ * user feedback, then writes an 11-slide pitch deck to
20
+ * financing_ai_analyses for the desktop / web UI to render.
21
+ */
22
+ export const runFinancingDeck = async (options) => {
23
+ const productId = options.financingDeck;
24
+ if (!productId) {
25
+ throw new Error('Product ID is required for financing-deck');
26
+ }
27
+ const targetStage = options.financingTargetStage;
28
+ if (!targetStage) {
29
+ throw new Error('Target stage is required (--target-stage). One of: pre_seed, seed, series_a, series_b, series_c, growth.');
30
+ }
31
+ if (!isFinancingStage(targetStage)) {
32
+ throw new Error(`Invalid target stage "${targetStage}". Expected one of: ${VALID_STAGES.join(', ')}`);
33
+ }
34
+ // validateConfiguration is required before any phase runs (parity with
35
+ // other commands).
36
+ validateConfiguration(options);
37
+ await registerSession({ command: 'financing-deck', productId });
38
+ logInfo(`Starting financing deck draft for product: ${productId} (target ${targetStage})`);
39
+ try {
40
+ const result = await generateFinancingDeck({
41
+ productId,
42
+ targetStage,
43
+ verbose: options.verbose,
44
+ });
45
+ if (result.status === 'success') {
46
+ logSuccess('Financing deck draft completed.');
47
+ logInfo(` Slides: ${result.slideCount}`);
48
+ logInfo(` Red flags: ${result.redFlagCount}`);
49
+ if (result.analysisId) {
50
+ logInfo(` Saved analysis id: ${result.analysisId}`);
51
+ }
52
+ logInfo('\nView the draft in the Financing tab of your product dashboard.');
53
+ }
54
+ else {
55
+ logError(`Financing deck failed: ${result.summary}`);
56
+ process.exitCode = 1;
57
+ }
58
+ }
59
+ catch (error) {
60
+ logError(`Financing deck failed: ${error instanceof Error ? error.message : String(error)}`);
61
+ process.exitCode = 1;
62
+ }
63
+ finally {
64
+ await deregisterSession();
65
+ }
66
+ };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * CLI command: edsger find-architecture <productId>
3
+ * Audits the product's repository for architectural concerns (layering,
4
+ * coupling, cycles, missing/duplicated abstractions, responsibility creep)
5
+ * and files each new finding as an issue.
6
+ */
7
+ export interface FindArchitectureCliOptions {
8
+ full?: boolean;
9
+ branch?: string;
10
+ maxFiles?: number;
11
+ verbose?: boolean;
12
+ }
13
+ export declare function runFindArchitecture(productId: string, options: FindArchitectureCliOptions): Promise<void>;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * CLI command: edsger find-architecture <productId>
3
+ * Audits the product's repository for architectural concerns (layering,
4
+ * coupling, cycles, missing/duplicated abstractions, responsibility creep)
5
+ * and files each new finding as an issue.
6
+ */
7
+ import { getGitHubConfigByProduct } from '../../api/github.js';
8
+ import { scanForArchitecture } from '../../phases/find-architecture/index.js';
9
+ import { logError, logInfo, logSuccess } from '../../utils/logger.js';
10
+ export async function runFindArchitecture(productId, options) {
11
+ const { full, branch, maxFiles, verbose } = options;
12
+ logInfo(`Starting architecture scan for product ${productId}`);
13
+ const githubConfig = await getGitHubConfigByProduct(productId, verbose);
14
+ if (!githubConfig.configured ||
15
+ !githubConfig.token ||
16
+ !githubConfig.owner ||
17
+ !githubConfig.repo) {
18
+ logError(`GitHub not configured for product ${productId}: ${githubConfig.message || 'No installation found'}`);
19
+ process.exit(1);
20
+ }
21
+ const result = await scanForArchitecture({
22
+ productId,
23
+ githubToken: githubConfig.token,
24
+ owner: githubConfig.owner,
25
+ repo: githubConfig.repo,
26
+ full,
27
+ branch,
28
+ maxFiles,
29
+ verbose,
30
+ });
31
+ if (result.status === 'success') {
32
+ logSuccess(result.message);
33
+ if (result.summary) {
34
+ logInfo(result.summary);
35
+ }
36
+ }
37
+ else {
38
+ logError(result.message);
39
+ process.exit(1);
40
+ }
41
+ }
@@ -0,0 +1,5 @@
1
+ export interface IssueAnalysisCliOptions {
2
+ issueId: string;
3
+ verbose?: boolean;
4
+ }
5
+ export declare const runIssueAnalysisCommand: (options: IssueAnalysisCliOptions) => Promise<void>;
@@ -0,0 +1,9 @@
1
+ import { analyseIssue } from '../../phases/issue-analysis/index.js';
2
+ import { runIssuePhaseCli } from '../../utils/issue-phase-cli.js';
3
+ export const runIssueAnalysisCommand = (options) => runIssuePhaseCli({
4
+ command: 'issue-analysis',
5
+ description: 'Issue analysis',
6
+ issueId: options.issueId,
7
+ verbose: options.verbose,
8
+ execute: analyseIssue,
9
+ });
@@ -0,0 +1,11 @@
1
+ /**
2
+ * CLI command: `edsger sync-github-issues <productId>`
3
+ *
4
+ * Mirrors the connected GitHub repo's issues into the product's local issues
5
+ * list. New issues are inserted, updated descriptions flow through, and
6
+ * issues that disappeared remotely are flagged source_state='deleted'.
7
+ */
8
+ export interface SyncGithubIssuesCliOptions {
9
+ verbose?: boolean;
10
+ }
11
+ export declare function runSyncGithubIssues(productId: string, options?: SyncGithubIssuesCliOptions): Promise<void>;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * CLI command: `edsger sync-github-issues <productId>`
3
+ *
4
+ * Mirrors the connected GitHub repo's issues into the product's local issues
5
+ * list. New issues are inserted, updated descriptions flow through, and
6
+ * issues that disappeared remotely are flagged source_state='deleted'.
7
+ */
8
+ import { getGitHubConfigByProduct } from '../../api/github.js';
9
+ import { syncGithubIssues } from '../../phases/sync-github-issues/index.js';
10
+ import { logError, logInfo, logSuccess } from '../../utils/logger.js';
11
+ export async function runSyncGithubIssues(productId, options = {}) {
12
+ const { verbose } = options;
13
+ logInfo(`Starting GitHub issue sync for product ${productId}`);
14
+ const githubConfig = await getGitHubConfigByProduct(productId, verbose);
15
+ if (!githubConfig.configured ||
16
+ !githubConfig.token ||
17
+ !githubConfig.owner ||
18
+ !githubConfig.repo) {
19
+ logError(`GitHub not configured for product ${productId}: ${githubConfig.message || 'No installation found'}`);
20
+ process.exit(1);
21
+ }
22
+ const result = await syncGithubIssues({
23
+ productId,
24
+ githubToken: githubConfig.token,
25
+ owner: githubConfig.owner,
26
+ repo: githubConfig.repo,
27
+ verbose,
28
+ });
29
+ if (result.status === 'success') {
30
+ logSuccess(`GitHub sync completed: ${result.message}`);
31
+ if (result.repository) {
32
+ logInfo(`Repository: ${result.repository}`);
33
+ }
34
+ if (result.fetchedCount !== undefined) {
35
+ logInfo(`Fetched ${result.fetchedCount} · created ${result.createdCount ?? 0} · updated ${result.updatedCount ?? 0} · refreshed ${result.refreshedCount ?? 0} · deleted ${result.deletedCount ?? 0}`);
36
+ }
37
+ }
38
+ else {
39
+ logError(`GitHub sync failed: ${result.message}`);
40
+ process.exit(1);
41
+ }
42
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * CLI command: `edsger sync-sentry-issues <productId>`
3
+ *
4
+ * Reads Sentry credentials from process.env (populated by `edsger config
5
+ * set` via ~/.edsger/env.json or by real environment variables). For an
6
+ * MVP we intentionally don't put per-product Sentry config in the
7
+ * database — the auth token is user-scoped, and org/project rarely
8
+ * change. If the friction shows up, follow up by adding columns on the
9
+ * products table and a settings UI.
10
+ */
11
+ export interface SyncSentryIssuesCliOptions {
12
+ verbose?: boolean;
13
+ }
14
+ export declare function runSyncSentryIssues(productId: string, options?: SyncSentryIssuesCliOptions): Promise<void>;