forgepm 0.7.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 (97) hide show
  1. package/dist/bin/forgepm.d.ts +2 -0
  2. package/dist/bin/forgepm.js +4 -0
  3. package/dist/bin/forgepm.js.map +1 -0
  4. package/dist/src/backends/base.d.ts +23 -0
  5. package/dist/src/backends/base.js +2 -0
  6. package/dist/src/backends/base.js.map +1 -0
  7. package/dist/src/backends/http-utils.d.ts +6 -0
  8. package/dist/src/backends/http-utils.js +36 -0
  9. package/dist/src/backends/http-utils.js.map +1 -0
  10. package/dist/src/backends/jira.d.ts +16 -0
  11. package/dist/src/backends/jira.js +117 -0
  12. package/dist/src/backends/jira.js.map +1 -0
  13. package/dist/src/backends/linear.d.ts +11 -0
  14. package/dist/src/backends/linear.js +85 -0
  15. package/dist/src/backends/linear.js.map +1 -0
  16. package/dist/src/cli/archaeology.d.ts +38 -0
  17. package/dist/src/cli/archaeology.js +182 -0
  18. package/dist/src/cli/archaeology.js.map +1 -0
  19. package/dist/src/cli/index.d.ts +1 -0
  20. package/dist/src/cli/index.js +351 -0
  21. package/dist/src/cli/index.js.map +1 -0
  22. package/dist/src/core/event-bus.d.ts +17 -0
  23. package/dist/src/core/event-bus.js +33 -0
  24. package/dist/src/core/event-bus.js.map +1 -0
  25. package/dist/src/core/event-plugins.d.ts +6 -0
  26. package/dist/src/core/event-plugins.js +2 -0
  27. package/dist/src/core/event-plugins.js.map +1 -0
  28. package/dist/src/core/forge-ops.d.ts +42 -0
  29. package/dist/src/core/forge-ops.js +101 -0
  30. package/dist/src/core/forge-ops.js.map +1 -0
  31. package/dist/src/core/forge.d.ts +44 -0
  32. package/dist/src/core/forge.js +86 -0
  33. package/dist/src/core/forge.js.map +1 -0
  34. package/dist/src/core/schema.d.ts +8 -0
  35. package/dist/src/core/schema.js +139 -0
  36. package/dist/src/core/schema.js.map +1 -0
  37. package/dist/src/core/store.d.ts +24 -0
  38. package/dist/src/core/store.js +155 -0
  39. package/dist/src/core/store.js.map +1 -0
  40. package/dist/src/core/types.d.ts +91 -0
  41. package/dist/src/core/types.js +19 -0
  42. package/dist/src/core/types.js.map +1 -0
  43. package/dist/src/core/version.d.ts +1 -0
  44. package/dist/src/core/version.js +20 -0
  45. package/dist/src/core/version.js.map +1 -0
  46. package/dist/src/github/pull.d.ts +13 -0
  47. package/dist/src/github/pull.js +51 -0
  48. package/dist/src/github/pull.js.map +1 -0
  49. package/dist/src/github/push.d.ts +20 -0
  50. package/dist/src/github/push.js +118 -0
  51. package/dist/src/github/push.js.map +1 -0
  52. package/dist/src/github/setup.d.ts +10 -0
  53. package/dist/src/github/setup.js +112 -0
  54. package/dist/src/github/setup.js.map +1 -0
  55. package/dist/src/github/slack.d.ts +12 -0
  56. package/dist/src/github/slack.js +33 -0
  57. package/dist/src/github/slack.js.map +1 -0
  58. package/dist/src/index.d.ts +14 -0
  59. package/dist/src/index.js +9 -0
  60. package/dist/src/index.js.map +1 -0
  61. package/dist/src/mcp/server.d.ts +5 -0
  62. package/dist/src/mcp/server.js +69 -0
  63. package/dist/src/mcp/server.js.map +1 -0
  64. package/dist/src/mcp/tool-handlers.d.ts +19 -0
  65. package/dist/src/mcp/tool-handlers.js +123 -0
  66. package/dist/src/mcp/tool-handlers.js.map +1 -0
  67. package/dist/src/pm/calibration.d.ts +13 -0
  68. package/dist/src/pm/calibration.js +56 -0
  69. package/dist/src/pm/calibration.js.map +1 -0
  70. package/dist/src/pm/callsheet.d.ts +66 -0
  71. package/dist/src/pm/callsheet.js +91 -0
  72. package/dist/src/pm/callsheet.js.map +1 -0
  73. package/dist/src/pm/drift-detector.d.ts +38 -0
  74. package/dist/src/pm/drift-detector.js +111 -0
  75. package/dist/src/pm/drift-detector.js.map +1 -0
  76. package/dist/src/pm/evm.d.ts +31 -0
  77. package/dist/src/pm/evm.js +58 -0
  78. package/dist/src/pm/evm.js.map +1 -0
  79. package/dist/src/pm/pdca.d.ts +27 -0
  80. package/dist/src/pm/pdca.js +83 -0
  81. package/dist/src/pm/pdca.js.map +1 -0
  82. package/dist/src/pm/recall.d.ts +23 -0
  83. package/dist/src/pm/recall.js +126 -0
  84. package/dist/src/pm/recall.js.map +1 -0
  85. package/dist/src/pm/retrospective.d.ts +35 -0
  86. package/dist/src/pm/retrospective.js +104 -0
  87. package/dist/src/pm/retrospective.js.map +1 -0
  88. package/dist/src/pm/sessions.d.ts +36 -0
  89. package/dist/src/pm/sessions.js +91 -0
  90. package/dist/src/pm/sessions.js.map +1 -0
  91. package/dist/src/pm/tolerances.d.ts +21 -0
  92. package/dist/src/pm/tolerances.js +54 -0
  93. package/dist/src/pm/tolerances.js.map +1 -0
  94. package/dist/src/utils/validation.d.ts +2 -0
  95. package/dist/src/utils/validation.js +8 -0
  96. package/dist/src/utils/validation.js.map +1 -0
  97. package/package.json +55 -0
@@ -0,0 +1,51 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execFileAsync = promisify(execFile);
4
+ import { validateGitHubName } from '../utils/validation.js';
5
+ export class GitHubPullSync {
6
+ owner;
7
+ repo;
8
+ constructor(owner, repo) {
9
+ this.owner = owner;
10
+ this.repo = repo;
11
+ validateGitHubName(owner, repo);
12
+ }
13
+ async pull(store, bus) {
14
+ const result = { totalFetched: 0, tasksClosed: 0, errors: [] };
15
+ let issues;
16
+ try {
17
+ const { stdout } = await execFileAsync('gh', [
18
+ 'issue', 'list',
19
+ '--repo', `${this.owner}/${this.repo}`,
20
+ '--label', 'forge:tracked',
21
+ '--state', 'all',
22
+ '--json', 'number,state,labels,title',
23
+ '--limit', '200',
24
+ ]);
25
+ issues = JSON.parse(stdout);
26
+ }
27
+ catch (err) {
28
+ result.errors.push(`Failed to fetch issues: ${err instanceof Error ? err.message : String(err)}`);
29
+ return result;
30
+ }
31
+ result.totalFetched = issues.length;
32
+ // Get all local tasks with github_issue_number
33
+ const localTasks = store.query('SELECT id, status, github_issue_number FROM tasks WHERE github_issue_number IS NOT NULL AND github_issue_number > 0');
34
+ const localByIssue = new Map(localTasks.map(t => [t.github_issue_number, t]));
35
+ for (const issue of issues) {
36
+ const localTask = localByIssue.get(issue.number);
37
+ if (!localTask)
38
+ continue; // Issue not tracked locally
39
+ // Conflict policy: SQLite wins — only process unidirectional events
40
+ // If GitHub issue is closed but local task is not done/blocked, mark it done
41
+ if (issue.state === 'closed' && localTask.status !== 'done' && localTask.status !== 'blocked') {
42
+ store.run('UPDATE tasks SET status = ?, updated_at = datetime("now") WHERE id = ?', ['done', localTask.id]);
43
+ bus.publish({ type: 'pull.task_closed', taskId: localTask.id, issueNumber: issue.number });
44
+ result.tasksClosed++;
45
+ }
46
+ }
47
+ bus.publish({ type: 'pull.completed', synced: result.tasksClosed });
48
+ return result;
49
+ }
50
+ }
51
+ //# sourceMappingURL=pull.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.js","sourceRoot":"","sources":["../../../src/github/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAItC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAe1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,MAAM,OAAO,cAAc;IAEf;IACA;IAFV,YACU,KAAa,EACb,IAAY;QADZ,UAAK,GAAL,KAAK,CAAQ;QACb,SAAI,GAAJ,IAAI,CAAQ;QAEpB,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAmB,EAAE,GAAa;QAC3C,MAAM,MAAM,GAAe,EAAE,YAAY,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAE3E,IAAI,MAAqB,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE;gBAC3C,OAAO,EAAE,MAAM;gBACf,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE;gBACtC,SAAS,EAAE,eAAe;gBAC1B,SAAS,EAAE,KAAK;gBAChB,QAAQ,EAAE,2BAA2B;gBACrC,SAAS,EAAE,KAAK;aACjB,CAAC,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAkB,CAAC;QAC/C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClG,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC;QAEpC,+CAA+C;QAC/C,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAC5B,qHAAqH,CACtH,CAAC;QAEF,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAE9E,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACjD,IAAI,CAAC,SAAS;gBAAE,SAAS,CAAC,4BAA4B;YAEtD,oEAAoE;YACpE,6EAA6E;YAC7E,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,SAAS,CAAC,MAAM,KAAK,MAAM,IAAI,SAAS,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC9F,KAAK,CAAC,GAAG,CAAC,wEAAwE,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC5G,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;gBAC3F,MAAM,CAAC,WAAW,EAAE,CAAC;YACvB,CAAC;QACH,CAAC;QAED,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;QACpE,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ import type { OverlayStore } from '../core/store.js';
2
+ interface PushTask {
3
+ id: string;
4
+ title: string;
5
+ status: string;
6
+ complexity: number;
7
+ github_issue_number?: number;
8
+ }
9
+ export declare class GitHubPushSync {
10
+ private owner;
11
+ private repo;
12
+ private projectNumber;
13
+ constructor(owner: string, repo: string, projectNumber: number);
14
+ pushTask(task: PushTask): Promise<number>;
15
+ closeTask(issueNumber: number): Promise<void>;
16
+ updateProjectField(_itemId: string, _fieldId: string, _value: string | number): Promise<void>;
17
+ processSyncOutbox(store: OverlayStore): Promise<number>;
18
+ private statusToLabel;
19
+ }
20
+ export {};
@@ -0,0 +1,118 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execFileAsync = promisify(execFile);
4
+ import { validateGitHubName } from '../utils/validation.js';
5
+ export class GitHubPushSync {
6
+ owner;
7
+ repo;
8
+ projectNumber;
9
+ constructor(owner, repo, projectNumber) {
10
+ this.owner = owner;
11
+ this.repo = repo;
12
+ this.projectNumber = projectNumber;
13
+ validateGitHubName(owner, repo);
14
+ }
15
+ async pushTask(task) {
16
+ const repoFlag = `${this.owner}/${this.repo}`;
17
+ if (!task.github_issue_number) {
18
+ // Create new issue
19
+ const { stdout } = await execFileAsync('gh', [
20
+ 'issue',
21
+ 'create',
22
+ '--repo',
23
+ repoFlag,
24
+ '--title',
25
+ task.title,
26
+ '--body',
27
+ `ForgePM task \`${task.id}\`\nStatus: ${task.status}\nComplexity: ${task.complexity}`,
28
+ '--label',
29
+ 'forge:tracked',
30
+ ]);
31
+ // gh issue create outputs the issue URL on stdout
32
+ const match = stdout.trim().match(/\/issues\/(\d+)/);
33
+ if (!match)
34
+ throw new Error(`Failed to parse issue URL from gh output: ${stdout.trim()}`);
35
+ return parseInt(match[1], 10);
36
+ }
37
+ else {
38
+ // Update existing issue — update title and labels via gh issue edit
39
+ const statusLabel = this.statusToLabel(task.status);
40
+ const editArgs = [
41
+ 'issue',
42
+ 'edit',
43
+ String(task.github_issue_number),
44
+ '--repo',
45
+ repoFlag,
46
+ '--title',
47
+ task.title,
48
+ '--body',
49
+ `ForgePM task \`${task.id}\`\nStatus: ${task.status}\nComplexity: ${task.complexity}`,
50
+ ];
51
+ if (statusLabel) {
52
+ editArgs.push('--add-label', statusLabel);
53
+ }
54
+ await execFileAsync('gh', editArgs);
55
+ return task.github_issue_number;
56
+ }
57
+ }
58
+ async closeTask(issueNumber) {
59
+ await execFileAsync('gh', [
60
+ 'issue',
61
+ 'close',
62
+ String(issueNumber),
63
+ '--repo',
64
+ `${this.owner}/${this.repo}`,
65
+ ]);
66
+ }
67
+ // TODO v0.2: implement full Projects V2 field updates using item IDs + field IDs
68
+ // For MVP, label-based updates are used in pushTask instead.
69
+ async updateProjectField(_itemId, _fieldId, _value) {
70
+ // Placeholder — Projects V2 field updates require resolving item node IDs
71
+ // and field node IDs via GraphQL, which is out of scope for MVP.
72
+ return;
73
+ }
74
+ async processSyncOutbox(store) {
75
+ const pending = store.query(`SELECT id, entity_type, entity_id, operation, payload
76
+ FROM sync_outbox
77
+ WHERE synced_at IS NULL
78
+ ORDER BY id ASC`);
79
+ let synced = 0;
80
+ for (const row of pending) {
81
+ try {
82
+ const payload = JSON.parse(row.payload);
83
+ if (row.entity_type === 'task') {
84
+ if (row.operation === 'upsert') {
85
+ await this.pushTask({
86
+ id: row.entity_id,
87
+ title: payload['title'] ?? row.entity_id,
88
+ status: payload['status'] ?? 'backlog',
89
+ complexity: payload['complexity'] ?? 1,
90
+ github_issue_number: payload['github_issue_number'],
91
+ });
92
+ }
93
+ else if (row.operation === 'close') {
94
+ const issueNumber = payload['github_issue_number'];
95
+ if (issueNumber) {
96
+ await this.closeTask(issueNumber);
97
+ }
98
+ }
99
+ }
100
+ store.run(`UPDATE sync_outbox SET synced_at = datetime('now') WHERE id = ?`, [row.id]);
101
+ synced++;
102
+ }
103
+ catch (err) {
104
+ console.error(`[push] Failed to sync outbox item ${row.id}:`, err);
105
+ }
106
+ }
107
+ return synced;
108
+ }
109
+ statusToLabel(status) {
110
+ const map = {
111
+ in_progress: 'forge:tracked',
112
+ done: 'forge:tracked',
113
+ blocked: 'forge:breach',
114
+ };
115
+ return map[status] ?? null;
116
+ }
117
+ }
118
+ //# sourceMappingURL=push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push.js","sourceRoot":"","sources":["../../../src/github/push.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface GitHubSetupResult {
2
+ projectNumber: number;
3
+ fieldsCreated: string[];
4
+ labelsCreated: string[];
5
+ }
6
+ export declare function setupGitHubProject(owner: string, repo: string): Promise<GitHubSetupResult>;
7
+ export declare function detectGitHubRemote(): Promise<{
8
+ owner: string;
9
+ repo: string;
10
+ } | null>;
@@ -0,0 +1,112 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execFileAsync = promisify(execFile);
4
+ const CUSTOM_FIELDS = [
5
+ { name: 'Agent', type: 'SINGLE_SELECT', options: ['pm', 'dev-1', 'dev-2', 'qa'] },
6
+ { name: 'Complexity', type: 'NUMBER' },
7
+ { name: 'SPI', type: 'NUMBER' },
8
+ { name: 'CPI', type: 'NUMBER' },
9
+ { name: 'TokenBudget', type: 'NUMBER' },
10
+ { name: 'TokensSpent', type: 'NUMBER' },
11
+ {
12
+ name: 'PDCAPhase',
13
+ type: 'SINGLE_SELECT',
14
+ options: ['plan', 'do', 'check', 'act', 'done'],
15
+ },
16
+ ];
17
+ const LABELS = [
18
+ { name: 'agent:pm', color: '0075ca' },
19
+ { name: 'agent:dev-1', color: '00b4d8' },
20
+ { name: 'agent:dev-2', color: '48cae4' },
21
+ { name: 'agent:qa', color: '90e0ef' },
22
+ { name: 'forge:tracked', color: '2ea44f' },
23
+ { name: 'forge:breach', color: 'd93f0b' },
24
+ { name: 'forge:escalated', color: 'e4e669' },
25
+ { name: 'priority:high', color: 'b60205' },
26
+ { name: 'priority:medium', color: 'fbca04' },
27
+ { name: 'priority:low', color: '0e8a16' },
28
+ ];
29
+ import { validateGitHubName } from '../utils/validation.js';
30
+ export async function setupGitHubProject(owner, repo) {
31
+ validateGitHubName(owner, repo);
32
+ // 1. Create GitHub Project V2
33
+ const { stdout: createOut } = await execFileAsync('gh', [
34
+ 'project',
35
+ 'create',
36
+ '--owner',
37
+ owner,
38
+ '--title',
39
+ `ForgePM: ${repo}`,
40
+ '--format',
41
+ 'json',
42
+ ]);
43
+ const projectData = JSON.parse(createOut);
44
+ const projectNumber = projectData.number;
45
+ // 2. Create custom fields
46
+ const fieldsCreated = [];
47
+ for (const field of CUSTOM_FIELDS) {
48
+ try {
49
+ const args = [
50
+ 'project',
51
+ 'field-create',
52
+ String(projectNumber),
53
+ '--owner',
54
+ owner,
55
+ '--name',
56
+ field.name,
57
+ '--data-type',
58
+ field.type,
59
+ ];
60
+ if (field.options && field.options.length > 0) {
61
+ args.push('--single-select-options', field.options.join(','));
62
+ }
63
+ await execFileAsync('gh', args);
64
+ fieldsCreated.push(field.name);
65
+ }
66
+ catch (err) {
67
+ console.error(`[setup] Failed to create field ${field.name}:`, err);
68
+ }
69
+ }
70
+ // 3. Create labels
71
+ const labelsCreated = [];
72
+ for (const label of LABELS) {
73
+ try {
74
+ await execFileAsync('gh', [
75
+ 'label',
76
+ 'create',
77
+ label.name,
78
+ '--repo',
79
+ `${owner}/${repo}`,
80
+ '--color',
81
+ label.color,
82
+ '--force',
83
+ ]);
84
+ labelsCreated.push(label.name);
85
+ }
86
+ catch (err) {
87
+ console.error(`[setup] Failed to create label ${label.name}:`, err);
88
+ }
89
+ }
90
+ return { projectNumber, fieldsCreated, labelsCreated };
91
+ }
92
+ export async function detectGitHubRemote() {
93
+ try {
94
+ const { stdout } = await execFileAsync('git', ['remote', 'get-url', 'origin']);
95
+ const url = stdout.trim();
96
+ // SSH: git@github.com:owner/repo.git
97
+ const sshMatch = url.match(/^git@github\.com:([^/]+)\/([^.]+?)(?:\.git)?$/);
98
+ if (sshMatch) {
99
+ return { owner: sshMatch[1], repo: sshMatch[2] };
100
+ }
101
+ // HTTPS: https://github.com/owner/repo.git
102
+ const httpsMatch = url.match(/^https:\/\/github\.com\/([^/]+)\/([^.]+?)(?:\.git)?$/);
103
+ if (httpsMatch) {
104
+ return { owner: httpsMatch[1], repo: httpsMatch[2] };
105
+ }
106
+ return null;
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ }
112
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/github/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface SlackMessage {
2
+ text: string;
3
+ blocks?: unknown[];
4
+ }
5
+ export declare function postToSlack(webhookUrl: string, message: SlackMessage): Promise<boolean>;
6
+ export declare function formatBreachAlert(taskId: string, dimension: string, actual: number, limit: number): SlackMessage;
7
+ export declare function formatSessionSummary(summary: {
8
+ goal: string;
9
+ tasksCompleted: number;
10
+ tokensSpent: number;
11
+ velocityPoints: number;
12
+ }): SlackMessage;
@@ -0,0 +1,33 @@
1
+ export async function postToSlack(webhookUrl, message) {
2
+ try {
3
+ const response = await fetch(webhookUrl, {
4
+ method: 'POST',
5
+ headers: { 'Content-Type': 'application/json' },
6
+ body: JSON.stringify(message),
7
+ });
8
+ if (!response.ok) {
9
+ console.error(`[slack] POST failed: ${response.status} ${response.statusText}`);
10
+ return false;
11
+ }
12
+ return true;
13
+ }
14
+ catch (err) {
15
+ console.error('[slack] POST error:', err);
16
+ return false;
17
+ }
18
+ }
19
+ export function formatBreachAlert(taskId, dimension, actual, limit) {
20
+ const text = `🚨 *Tolerance Breach* — task \`${taskId}\`\n` +
21
+ ` Dimension: *${dimension}*\n` +
22
+ ` Actual: ${actual} | Limit: ${limit}`;
23
+ return { text };
24
+ }
25
+ export function formatSessionSummary(summary) {
26
+ const text = `✅ *Session Complete*\n` +
27
+ ` Goal: ${summary.goal}\n` +
28
+ ` Tasks completed: ${summary.tasksCompleted}\n` +
29
+ ` Tokens spent: ${summary.tokensSpent}\n` +
30
+ ` Velocity points: ${summary.velocityPoints}`;
31
+ return { text };
32
+ }
33
+ //# sourceMappingURL=slack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.js","sourceRoot":"","sources":["../../../src/github/slack.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAkB,EAAE,OAAqB;IACzE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE;YACvC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;SAC9B,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,wBAAwB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YAChF,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,MAAc,EACd,SAAiB,EACjB,MAAc,EACd,KAAa;IAEb,MAAM,IAAI,GACR,kCAAkC,MAAM,MAAM;QAC9C,iBAAiB,SAAS,KAAK;QAC/B,aAAa,MAAM,eAAe,KAAK,EAAE,CAAC;IAC5C,OAAO,EAAE,IAAI,EAAE,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAKpC;IACC,MAAM,IAAI,GACR,wBAAwB;QACxB,WAAW,OAAO,CAAC,IAAI,IAAI;QAC3B,sBAAsB,OAAO,CAAC,cAAc,IAAI;QAChD,mBAAmB,OAAO,CAAC,WAAW,IAAI;QAC1C,sBAAsB,OAAO,CAAC,cAAc,EAAE,CAAC;IACjD,OAAO,EAAE,IAAI,EAAE,CAAC;AAClB,CAAC"}
@@ -0,0 +1,14 @@
1
+ export { createForge } from './core/forge.js';
2
+ export type { ForgeInstance } from './core/forge.js';
3
+ export { startMcpServer, createMcpServer } from './mcp/server.js';
4
+ export type { ForgeConfig, DomainEvent, Result, ModelTier, TaskStatus, PdcaPhase, ToleranceStatus, EvmHealth, TolerancePreset, } from './core/types.js';
5
+ export { DEFAULT_CONFIG, getModelTier } from './core/types.js';
6
+ export type { CallSheet, InternalMetrics } from './pm/callsheet.js';
7
+ export type { Session, SessionSummary } from './pm/sessions.js';
8
+ export { RecallEngine } from './pm/recall.js';
9
+ export type { RecallResult, RecallParams } from './pm/recall.js';
10
+ export type { EventPlugin } from './core/event-plugins.js';
11
+ export { fetchWithRetry, HttpError } from './backends/http-utils.js';
12
+ export type { BackendAdapter, TaskData, ExternalUpdate } from './backends/base.js';
13
+ export { LinearBackend } from './backends/linear.js';
14
+ export { JiraBackend } from './backends/jira.js';
@@ -0,0 +1,9 @@
1
+ // Public API — re-exports for consumers of the forgepm package
2
+ export { createForge } from './core/forge.js';
3
+ export { startMcpServer, createMcpServer } from './mcp/server.js';
4
+ export { DEFAULT_CONFIG, getModelTier } from './core/types.js';
5
+ export { RecallEngine } from './pm/recall.js';
6
+ export { fetchWithRetry, HttpError } from './backends/http-utils.js';
7
+ export { LinearBackend } from './backends/linear.js';
8
+ export { JiraBackend } from './backends/jira.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAE/D,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAclE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAK/D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { type ForgeInstance } from '../core/forge.js';
3
+ import type { ForgeConfig } from '../core/types.js';
4
+ export declare function createMcpServer(forge: ForgeInstance): McpServer;
5
+ export declare function startMcpServer(dbPath: string, config?: Partial<ForgeConfig>): Promise<McpServer>;
@@ -0,0 +1,69 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { z } from 'zod';
4
+ import { createForge } from '../core/forge.js';
5
+ import { VERSION } from '../core/version.js';
6
+ import { handleStatus, handleStart, handleDone, handleSession, handleEscalate, handleCreate, handleDecompose, handleRecall, handleRetro } from './tool-handlers.js';
7
+ function registerTools(server, forge) {
8
+ server.tool('forge_status', 'Get project status, progress, and next recommended action', {
9
+ include_internal: z.boolean().optional().describe('Include SPI/CPI metrics for agent use'),
10
+ }, async ({ include_internal }) => handleStatus(forge, include_internal));
11
+ server.tool('forge_start', 'Start a PDCA cycle on a task, initialising EVM baseline and model-tier selection', {
12
+ task_id: z.string().describe('The task ID to start (e.g. TASK-001)'),
13
+ complexity: z.number().int().min(1).max(10).optional().describe('Override complexity score 1-10'),
14
+ }, async ({ task_id, complexity }) => handleStart(forge, task_id, complexity));
15
+ server.tool('forge_done', 'Mark a task complete, record actual tokens, update EVM metrics', {
16
+ task_id: z.string().describe('The task ID to complete'),
17
+ actual_tokens: z.number().int().positive().optional().describe('Total tokens used (legacy). Prefer input_tokens + output_tokens.'),
18
+ input_tokens: z.number().int().nonnegative().optional().describe('Input tokens from LLM response usage field'),
19
+ output_tokens: z.number().int().nonnegative().optional().describe('Output tokens from LLM response usage field'),
20
+ notes: z.string().optional().describe('Optional completion notes'),
21
+ }, async ({ task_id, actual_tokens, input_tokens, output_tokens, notes }) => handleDone(forge, task_id, actual_tokens, input_tokens, output_tokens, notes));
22
+ server.tool('forge_session', 'Manage work sessions: start, end, or get current status', {
23
+ action: z.enum(['start', 'end', 'status']).describe('"start" | "end" | "status"'),
24
+ goal: z.string().optional().describe('Session goal (required for action=start)'),
25
+ token_budget: z.number().int().positive().optional().describe('Token budget for this session'),
26
+ }, async ({ action, goal, token_budget }) => handleSession(forge, action, goal, token_budget));
27
+ server.tool('forge_escalate', 'Report a tolerance breach or blocking issue, get exception report with options', {
28
+ task_id: z.string().describe('The task ID that encountered the issue'),
29
+ reason: z.string().describe('Description of what went wrong'),
30
+ failure_type: z.enum(['reasoning', 'prompt', 'task_definition', 'unknown']).optional().describe('Type of failure for PDCA routing'),
31
+ }, async ({ task_id, reason, failure_type }) => handleEscalate(forge, task_id, reason, failure_type));
32
+ server.tool('forge_create', 'Create a task, story, or epic in the project backlog', {
33
+ type: z.enum(['task', 'story', 'epic']).describe('"task" | "story" | "epic"'),
34
+ title: z.string().describe('Title of the item'),
35
+ complexity: z.number().int().min(1).max(10).optional().describe('Complexity 1-10 (tasks only, default 3)'),
36
+ why: z.string().optional().describe('Rationale / user value'),
37
+ story_id: z.string().optional().describe('Parent story ID for tasks'),
38
+ depends_on: z.array(z.string()).optional().describe('List of dependency task IDs'),
39
+ }, async ({ type, title, complexity, why, story_id, depends_on }) => handleCreate(forge, type, title, complexity, why, story_id, depends_on));
40
+ server.tool('forge_recall', 'Search project knowledge: tasks, sessions, failure patterns, lessons learned', {
41
+ query: z.string().min(1).describe('Free-text search query'),
42
+ entity_types: z.array(z.enum(['task', 'story', 'epic', 'session', 'pdca', 'lesson'])).optional().describe('Filter by entity type. Default: all'),
43
+ status_filter: z.string().optional().describe('Filter by task status (e.g. "done", "blocked"). Applies to tasks only.'),
44
+ limit: z.number().int().min(1).max(50).optional().describe('Max results (default 10)'),
45
+ include_failures: z.boolean().optional().describe('Include PDCA failure patterns'),
46
+ }, async ({ query, entity_types, status_filter, limit, include_failures }) => handleRecall(forge, query, entity_types, status_filter, limit, include_failures));
47
+ server.tool('forge_retro', 'Generate a retrospective report for a session: progress, EVM, lessons, recommendations', {
48
+ session_id: z.string().optional().describe('Session ID. Omit for most recent session.'),
49
+ format: z.enum(['json', 'markdown']).optional().describe('Output format (default: json)'),
50
+ }, async ({ session_id, format }) => handleRetro(forge, session_id, format));
51
+ server.tool('forge_decompose', 'Decompose a feature description into tasks — returns hints for agent to create sub-tasks', {
52
+ description: z.string().describe('Feature or work item description'),
53
+ max_complexity: z.number().int().min(1).max(10).optional().describe('Max complexity per task (default 5)'),
54
+ max_tasks: z.number().int().positive().optional().describe('Maximum number of tasks to create (default 5)'),
55
+ }, async ({ description, max_complexity, max_tasks }) => handleDecompose(forge, description, max_complexity, max_tasks));
56
+ }
57
+ export function createMcpServer(forge) {
58
+ const server = new McpServer({ name: 'forgepm', version: VERSION });
59
+ registerTools(server, forge);
60
+ return server;
61
+ }
62
+ export async function startMcpServer(dbPath, config) {
63
+ const forge = await createForge(dbPath, config);
64
+ const server = createMcpServer(forge);
65
+ const transport = new StdioServerTransport();
66
+ await server.connect(transport);
67
+ return server;
68
+ }
69
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { ForgeInstance } from '../core/forge.js';
2
+ import type { FailureType } from '../pm/pdca.js';
3
+ export interface ToolResult {
4
+ [key: string]: unknown;
5
+ content: Array<{
6
+ type: 'text';
7
+ text: string;
8
+ }>;
9
+ isError?: boolean;
10
+ }
11
+ export declare function handleStatus(forge: ForgeInstance, includeInternal?: boolean): ToolResult;
12
+ export declare function handleStart(forge: ForgeInstance, taskId: string, complexity?: number): ToolResult;
13
+ export declare function handleDone(forge: ForgeInstance, taskId: string, actualTokens?: number, inputTokens?: number, outputTokens?: number, notes?: string): ToolResult;
14
+ export declare function handleSession(forge: ForgeInstance, action: string, goal?: string, tokenBudget?: number): ToolResult;
15
+ export declare function handleEscalate(forge: ForgeInstance, taskId: string, reason: string, failureType?: FailureType): ToolResult;
16
+ export declare function handleCreate(forge: ForgeInstance, type: string, title: string, complexity?: number, why?: string, storyId?: string, dependsOn?: string[]): ToolResult;
17
+ export declare function handleRecall(forge: ForgeInstance, query: string, entityTypes?: string[], statusFilter?: string, limit?: number, includeFailures?: boolean): ToolResult;
18
+ export declare function handleRetro(forge: ForgeInstance, sessionId?: string, format?: string): ToolResult;
19
+ export declare function handleDecompose(_forge: ForgeInstance, description: string, maxComplexity?: number, _maxTasks?: number): ToolResult;