prjct-cli 0.20.0 → 0.21.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 (236) hide show
  1. package/CHANGELOG.md +24 -6
  2. package/CLAUDE.md +56 -15
  3. package/README.md +5 -6
  4. package/bin/prjct +59 -42
  5. package/bin/prjct.ts +60 -0
  6. package/core/__tests__/agentic/memory-system.test.ts +18 -3
  7. package/core/__tests__/agentic/plan-mode.test.ts +55 -26
  8. package/core/__tests__/agentic/prompt-builder.test.ts +6 -6
  9. package/core/__tests__/utils/project-commands.test.ts +72 -0
  10. package/core/agentic/agent-router.ts +3 -12
  11. package/core/agentic/command-executor.ts +372 -3
  12. package/core/agentic/context-builder.ts +7 -27
  13. package/core/agentic/ground-truth.ts +604 -5
  14. package/core/agentic/index.ts +180 -0
  15. package/core/agentic/loop-detector.ts +418 -4
  16. package/core/agentic/memory-system.ts +857 -3
  17. package/core/agentic/plan-mode.ts +491 -4
  18. package/core/agentic/prompt-builder.ts +44 -65
  19. package/core/agentic/services.ts +13 -5
  20. package/core/agentic/skill-loader.ts +112 -0
  21. package/core/agentic/smart-context.ts +37 -122
  22. package/core/agentic/template-loader.ts +79 -122
  23. package/core/agentic/tool-registry.ts +5 -11
  24. package/core/agents/index.ts +1 -1
  25. package/core/agents/performance.ts +4 -2
  26. package/core/bus/bus.ts +262 -0
  27. package/core/bus/index.ts +3 -313
  28. package/core/commands/analysis.ts +5 -5
  29. package/core/commands/analytics.ts +11 -11
  30. package/core/commands/base.ts +33 -209
  31. package/core/commands/cleanup.ts +148 -0
  32. package/core/commands/command-data.ts +346 -0
  33. package/core/commands/commands.ts +216 -0
  34. package/core/commands/design.ts +83 -0
  35. package/core/commands/index.ts +13 -207
  36. package/core/commands/maintenance.ts +52 -473
  37. package/core/commands/planning.ts +3 -3
  38. package/core/commands/register.ts +104 -0
  39. package/core/commands/registry.ts +441 -0
  40. package/core/commands/setup.ts +25 -9
  41. package/core/commands/shipping.ts +48 -11
  42. package/core/commands/snapshots.ts +299 -0
  43. package/core/commands/workflow.ts +2 -2
  44. package/core/constants/index.ts +254 -4
  45. package/core/domain/agent-loader.ts +5 -6
  46. package/core/domain/task-stack.ts +555 -4
  47. package/core/errors.ts +127 -1
  48. package/core/events/events.ts +87 -0
  49. package/core/events/index.ts +4 -138
  50. package/core/index.ts +15 -23
  51. package/core/infrastructure/agent-detector.ts +126 -201
  52. package/core/infrastructure/author-detector.ts +99 -171
  53. package/core/infrastructure/command-installer.ts +476 -4
  54. package/core/infrastructure/config-manager.ts +41 -37
  55. package/core/infrastructure/path-manager.ts +59 -9
  56. package/core/infrastructure/permission-manager.ts +286 -0
  57. package/core/integrations/notion/client.ts +323 -0
  58. package/core/integrations/notion/index.ts +43 -0
  59. package/core/integrations/notion/setup.ts +230 -0
  60. package/core/integrations/notion/sync.ts +311 -0
  61. package/core/integrations/notion/templates.ts +234 -0
  62. package/core/outcomes/analyzer.ts +7 -41
  63. package/core/outcomes/index.ts +1 -1
  64. package/core/outcomes/recorder.ts +1 -1
  65. package/core/plugin/builtin/notion.ts +178 -0
  66. package/core/{plugins → plugin/builtin}/webhook.ts +6 -22
  67. package/core/plugin/loader.ts +5 -5
  68. package/core/plugin/registry.ts +2 -2
  69. package/core/schemas/ideas.ts +85 -54
  70. package/core/schemas/index.ts +14 -33
  71. package/core/schemas/permissions.ts +177 -0
  72. package/core/schemas/project.ts +39 -12
  73. package/core/schemas/roadmap.ts +94 -59
  74. package/core/schemas/schemas.ts +39 -0
  75. package/core/schemas/shipped.ts +87 -60
  76. package/core/schemas/state.ts +110 -70
  77. package/core/server/index.ts +21 -0
  78. package/core/server/routes.ts +165 -0
  79. package/core/server/server.ts +136 -0
  80. package/core/server/sse.ts +135 -0
  81. package/core/services/agent-service.ts +170 -0
  82. package/core/services/breakdown-service.ts +126 -0
  83. package/core/services/index.ts +21 -0
  84. package/core/services/memory-service.ts +108 -0
  85. package/core/services/project-service.ts +146 -0
  86. package/core/services/skill-service.ts +253 -0
  87. package/core/session/compaction.ts +257 -0
  88. package/core/session/index.ts +20 -8
  89. package/core/{infrastructure/session-manager/migration.ts → session/log-migration.ts} +9 -9
  90. package/core/{infrastructure/session-manager/session-manager.ts → session/session-log-manager.ts} +27 -26
  91. package/core/session/{session-manager.ts → task-session-manager.ts} +7 -4
  92. package/core/session/utils.ts +1 -1
  93. package/core/storage/ideas-storage.ts +10 -26
  94. package/core/storage/index.ts +14 -162
  95. package/core/storage/queue-storage.ts +13 -11
  96. package/core/storage/shipped-storage.ts +4 -17
  97. package/core/storage/state-storage.ts +35 -43
  98. package/core/storage/storage-manager.ts +42 -52
  99. package/core/storage/storage.ts +160 -0
  100. package/core/sync/auth-config.ts +1 -8
  101. package/core/sync/index.ts +17 -10
  102. package/core/sync/oauth-handler.ts +1 -6
  103. package/core/sync/sync-client.ts +6 -34
  104. package/core/sync/sync-manager.ts +11 -40
  105. package/core/types/agentic.ts +577 -0
  106. package/core/types/agents.ts +145 -0
  107. package/core/types/bus.ts +82 -0
  108. package/core/types/commands.ts +366 -0
  109. package/core/types/config.ts +70 -0
  110. package/core/types/core.ts +96 -0
  111. package/core/types/domain.ts +71 -0
  112. package/core/types/events.ts +42 -0
  113. package/core/types/fs.ts +56 -0
  114. package/core/types/index.ts +396 -500
  115. package/core/types/infrastructure.ts +196 -0
  116. package/core/types/integrations.ts +57 -0
  117. package/core/{agentic/memory-system/types.ts → types/memory.ts} +33 -8
  118. package/core/{outcomes/types.ts → types/outcomes.ts} +53 -8
  119. package/core/types/plugin.ts +25 -0
  120. package/core/types/server.ts +54 -0
  121. package/core/types/services.ts +65 -0
  122. package/core/types/session.ts +135 -0
  123. package/core/types/storage.ts +148 -0
  124. package/core/types/sync.ts +121 -0
  125. package/core/types/task.ts +72 -0
  126. package/core/types/template.ts +24 -0
  127. package/core/types/utils.ts +90 -0
  128. package/core/utils/cache.ts +195 -0
  129. package/core/utils/collection-filters.ts +245 -0
  130. package/core/utils/date-helper.ts +1 -5
  131. package/core/utils/file-helper.ts +20 -10
  132. package/core/utils/jsonl-helper.ts +5 -8
  133. package/core/utils/markdown-builder.ts +277 -0
  134. package/core/utils/project-commands.ts +132 -0
  135. package/core/utils/runtime.ts +119 -0
  136. package/dist/bin/prjct.mjs +12568 -0
  137. package/package.json +13 -8
  138. package/scripts/build.js +106 -0
  139. package/scripts/postinstall.js +50 -8
  140. package/templates/agentic/subagent-generation.md +1 -1
  141. package/templates/commands/init.md +43 -0
  142. package/templates/commands/notion-setup.md +191 -0
  143. package/templates/commands/serve.md +118 -0
  144. package/templates/commands/ship.md +13 -2
  145. package/templates/commands/skill.md +110 -0
  146. package/templates/commands/sync.md +1 -1
  147. package/templates/commands/test.md +23 -4
  148. package/templates/mcp-config.json +28 -0
  149. package/templates/permissions/default.jsonc +60 -0
  150. package/templates/permissions/permissive.jsonc +49 -0
  151. package/templates/permissions/strict.jsonc +62 -0
  152. package/templates/skills/code-review.md +47 -0
  153. package/templates/skills/debug.md +61 -0
  154. package/templates/skills/refactor.md +47 -0
  155. package/templates/subagents/domain/devops.md +1 -1
  156. package/templates/subagents/domain/testing.md +6 -10
  157. package/templates/subagents/workflow/prjct-shipper.md +16 -7
  158. package/templates/tools/bash.txt +22 -0
  159. package/templates/tools/edit.txt +18 -0
  160. package/templates/tools/glob.txt +19 -0
  161. package/templates/tools/grep.txt +21 -0
  162. package/templates/tools/read.txt +14 -0
  163. package/templates/tools/task.txt +20 -0
  164. package/templates/tools/webfetch.txt +16 -0
  165. package/templates/tools/websearch.txt +18 -0
  166. package/templates/tools/write.txt +17 -0
  167. package/core/agentic/command-executor/command-executor.ts +0 -312
  168. package/core/agentic/command-executor/index.ts +0 -16
  169. package/core/agentic/command-executor/status-signal.ts +0 -38
  170. package/core/agentic/command-executor/types.ts +0 -79
  171. package/core/agentic/ground-truth/index.ts +0 -76
  172. package/core/agentic/ground-truth/types.ts +0 -33
  173. package/core/agentic/ground-truth/utils.ts +0 -48
  174. package/core/agentic/ground-truth/verifiers/analyze.ts +0 -54
  175. package/core/agentic/ground-truth/verifiers/done.ts +0 -75
  176. package/core/agentic/ground-truth/verifiers/feature.ts +0 -70
  177. package/core/agentic/ground-truth/verifiers/index.ts +0 -37
  178. package/core/agentic/ground-truth/verifiers/init.ts +0 -52
  179. package/core/agentic/ground-truth/verifiers/now.ts +0 -57
  180. package/core/agentic/ground-truth/verifiers/ship.ts +0 -85
  181. package/core/agentic/ground-truth/verifiers/spec.ts +0 -45
  182. package/core/agentic/ground-truth/verifiers/sync.ts +0 -47
  183. package/core/agentic/ground-truth/verifiers.ts +0 -6
  184. package/core/agentic/loop-detector/error-analysis.ts +0 -97
  185. package/core/agentic/loop-detector/hallucination.ts +0 -71
  186. package/core/agentic/loop-detector/index.ts +0 -41
  187. package/core/agentic/loop-detector/loop-detector.ts +0 -222
  188. package/core/agentic/loop-detector/types.ts +0 -66
  189. package/core/agentic/memory-system/history.ts +0 -53
  190. package/core/agentic/memory-system/index.ts +0 -192
  191. package/core/agentic/memory-system/patterns.ts +0 -156
  192. package/core/agentic/memory-system/semantic-memories.ts +0 -278
  193. package/core/agentic/memory-system/session.ts +0 -21
  194. package/core/agentic/plan-mode/approval.ts +0 -57
  195. package/core/agentic/plan-mode/constants.ts +0 -44
  196. package/core/agentic/plan-mode/index.ts +0 -28
  197. package/core/agentic/plan-mode/plan-mode.ts +0 -407
  198. package/core/agentic/plan-mode/types.ts +0 -193
  199. package/core/agents/types.ts +0 -126
  200. package/core/command-registry/categories.ts +0 -23
  201. package/core/command-registry/commands.ts +0 -15
  202. package/core/command-registry/core-commands.ts +0 -344
  203. package/core/command-registry/index.ts +0 -158
  204. package/core/command-registry/optional-commands.ts +0 -163
  205. package/core/command-registry/setup-commands.ts +0 -83
  206. package/core/command-registry/types.ts +0 -59
  207. package/core/command-registry.ts +0 -9
  208. package/core/commands/types.ts +0 -185
  209. package/core/commands.ts +0 -11
  210. package/core/constants/formats.ts +0 -187
  211. package/core/context-sync.ts +0 -18
  212. package/core/data/index.ts +0 -27
  213. package/core/data/md-base-manager.ts +0 -203
  214. package/core/data/md-ideas-manager.ts +0 -155
  215. package/core/data/md-queue-manager.ts +0 -180
  216. package/core/data/md-shipped-manager.ts +0 -90
  217. package/core/data/md-state-manager.ts +0 -137
  218. package/core/domain/task-stack/index.ts +0 -19
  219. package/core/domain/task-stack/parser.ts +0 -86
  220. package/core/domain/task-stack/storage.ts +0 -123
  221. package/core/domain/task-stack/task-stack.ts +0 -340
  222. package/core/domain/task-stack/types.ts +0 -51
  223. package/core/infrastructure/command-installer/command-installer.ts +0 -327
  224. package/core/infrastructure/command-installer/global-config.ts +0 -136
  225. package/core/infrastructure/command-installer/index.ts +0 -25
  226. package/core/infrastructure/command-installer/types.ts +0 -41
  227. package/core/infrastructure/session-manager/index.ts +0 -23
  228. package/core/infrastructure/session-manager/types.ts +0 -45
  229. package/core/infrastructure/session-manager.ts +0 -8
  230. package/core/serializers/ideas-serializer.ts +0 -187
  231. package/core/serializers/index.ts +0 -36
  232. package/core/serializers/queue-serializer.ts +0 -210
  233. package/core/serializers/shipped-serializer.ts +0 -108
  234. package/core/serializers/state-serializer.ts +0 -136
  235. package/core/session/types.ts +0 -29
  236. /package/core/infrastructure/{agents/claude-agent.ts → claude-agent.ts} +0 -0
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Notion Database Templates
3
+ * Schemas for auto-creating prjct databases in Notion.
4
+ */
5
+
6
+ import type { NotionDatabaseSchema } from './client'
7
+
8
+ // =============================================================================
9
+ // Database Schemas
10
+ // =============================================================================
11
+
12
+ /**
13
+ * Shipped Features Database Schema
14
+ * Tracks shipped features with metrics
15
+ */
16
+ export const SHIPPED_DATABASE_SCHEMA: NotionDatabaseSchema = {
17
+ title: 'prjct: Shipped Features',
18
+ properties: {
19
+ Name: { type: 'title', title: {} },
20
+ Version: { type: 'rich_text', rich_text: {} },
21
+ Type: {
22
+ type: 'select',
23
+ select: {
24
+ options: [
25
+ { name: 'feature', color: 'blue' },
26
+ { name: 'fix', color: 'red' },
27
+ { name: 'improvement', color: 'green' },
28
+ { name: 'refactor', color: 'purple' },
29
+ ],
30
+ },
31
+ },
32
+ 'Shipped Date': { type: 'date', date: {} },
33
+ 'Lines Changed': { type: 'number', number: { format: 'number' } },
34
+ 'Files Changed': { type: 'number', number: { format: 'number' } },
35
+ Commits: { type: 'number', number: { format: 'number' } },
36
+ Duration: { type: 'rich_text', rich_text: {} },
37
+ Description: { type: 'rich_text', rich_text: {} },
38
+ Project: { type: 'rich_text', rich_text: {} },
39
+ },
40
+ }
41
+
42
+ /**
43
+ * Roadmap Database Schema
44
+ * Tracks feature roadmap and progress
45
+ */
46
+ export const ROADMAP_DATABASE_SCHEMA: NotionDatabaseSchema = {
47
+ title: 'prjct: Roadmap',
48
+ properties: {
49
+ Feature: { type: 'title', title: {} },
50
+ Status: {
51
+ type: 'status',
52
+ status: {
53
+ options: [
54
+ { name: 'Planned', color: 'gray' },
55
+ { name: 'Active', color: 'blue' },
56
+ { name: 'Completed', color: 'green' },
57
+ { name: 'Shipped', color: 'purple' },
58
+ ],
59
+ groups: [
60
+ { name: 'To Do', option_ids: [], color: 'gray' },
61
+ { name: 'In Progress', option_ids: [], color: 'blue' },
62
+ { name: 'Done', option_ids: [], color: 'green' },
63
+ ],
64
+ },
65
+ },
66
+ Priority: {
67
+ type: 'select',
68
+ select: {
69
+ options: [
70
+ { name: 'High', color: 'red' },
71
+ { name: 'Medium', color: 'yellow' },
72
+ { name: 'Low', color: 'gray' },
73
+ ],
74
+ },
75
+ },
76
+ Progress: { type: 'number', number: { format: 'percent' } },
77
+ Phase: { type: 'rich_text', rich_text: {} },
78
+ 'Target Date': { type: 'date', date: {} },
79
+ Description: { type: 'rich_text', rich_text: {} },
80
+ Tasks: { type: 'number', number: { format: 'number' } },
81
+ Project: { type: 'rich_text', rich_text: {} },
82
+ },
83
+ }
84
+
85
+ /**
86
+ * Ideas Database Schema
87
+ * Captures and tracks ideas
88
+ */
89
+ export const IDEAS_DATABASE_SCHEMA: NotionDatabaseSchema = {
90
+ title: 'prjct: Ideas',
91
+ properties: {
92
+ Idea: { type: 'title', title: {} },
93
+ Status: {
94
+ type: 'status',
95
+ status: {
96
+ options: [
97
+ { name: 'Pending', color: 'gray' },
98
+ { name: 'Converted', color: 'green' },
99
+ { name: 'Archived', color: 'default' },
100
+ ],
101
+ groups: [
102
+ { name: 'Not Started', option_ids: [], color: 'gray' },
103
+ { name: 'Done', option_ids: [], color: 'green' },
104
+ ],
105
+ },
106
+ },
107
+ Priority: {
108
+ type: 'select',
109
+ select: {
110
+ options: [
111
+ { name: 'high', color: 'red' },
112
+ { name: 'medium', color: 'yellow' },
113
+ { name: 'low', color: 'gray' },
114
+ ],
115
+ },
116
+ },
117
+ Tags: { type: 'multi_select', multi_select: { options: [] } },
118
+ Created: { type: 'date', date: {} },
119
+ 'Converted To': { type: 'rich_text', rich_text: {} },
120
+ Project: { type: 'rich_text', rich_text: {} },
121
+ },
122
+ }
123
+
124
+ /**
125
+ * Active Tasks Database Schema
126
+ * Tracks current task queue
127
+ */
128
+ export const TASKS_DATABASE_SCHEMA: NotionDatabaseSchema = {
129
+ title: 'prjct: Active Tasks',
130
+ properties: {
131
+ Task: { type: 'title', title: {} },
132
+ Priority: {
133
+ type: 'select',
134
+ select: {
135
+ options: [
136
+ { name: 'critical', color: 'red' },
137
+ { name: 'high', color: 'orange' },
138
+ { name: 'medium', color: 'yellow' },
139
+ { name: 'low', color: 'gray' },
140
+ ],
141
+ },
142
+ },
143
+ Type: {
144
+ type: 'select',
145
+ select: {
146
+ options: [
147
+ { name: 'feature', color: 'blue' },
148
+ { name: 'bug', color: 'red' },
149
+ { name: 'improvement', color: 'green' },
150
+ { name: 'chore', color: 'gray' },
151
+ ],
152
+ },
153
+ },
154
+ Section: {
155
+ type: 'select',
156
+ select: {
157
+ options: [
158
+ { name: 'active', color: 'blue' },
159
+ { name: 'backlog', color: 'gray' },
160
+ ],
161
+ },
162
+ },
163
+ Completed: { type: 'checkbox', checkbox: {} },
164
+ Agent: { type: 'rich_text', rich_text: {} },
165
+ Feature: { type: 'rich_text', rich_text: {} },
166
+ Created: { type: 'date', date: {} },
167
+ 'Completed At': { type: 'date', date: {} },
168
+ Project: { type: 'rich_text', rich_text: {} },
169
+ },
170
+ }
171
+
172
+ // =============================================================================
173
+ // Dashboard Template
174
+ // =============================================================================
175
+
176
+ /**
177
+ * Dashboard page content template
178
+ */
179
+ export function getDashboardContent(
180
+ projectName: string,
181
+ databases: {
182
+ shipped?: string
183
+ roadmap?: string
184
+ ideas?: string
185
+ tasks?: string
186
+ }
187
+ ): string {
188
+ const sections = []
189
+
190
+ sections.push(`# ${projectName} Dashboard`)
191
+ sections.push('')
192
+ sections.push('This dashboard is automatically synced by prjct-cli.')
193
+ sections.push('')
194
+
195
+ if (databases.shipped) {
196
+ sections.push('## Shipped Features')
197
+ sections.push(`View all shipped features and metrics.`)
198
+ sections.push('')
199
+ }
200
+
201
+ if (databases.roadmap) {
202
+ sections.push('## Roadmap')
203
+ sections.push(`Track feature progress and planning.`)
204
+ sections.push('')
205
+ }
206
+
207
+ if (databases.ideas) {
208
+ sections.push('## Ideas')
209
+ sections.push(`Captured ideas and their status.`)
210
+ sections.push('')
211
+ }
212
+
213
+ if (databases.tasks) {
214
+ sections.push('## Active Tasks')
215
+ sections.push(`Current task queue and completion status.`)
216
+ sections.push('')
217
+ }
218
+
219
+ sections.push('---')
220
+ sections.push('Powered by [prjct-cli](https://prjct.app)')
221
+
222
+ return sections.join('\n')
223
+ }
224
+
225
+ // =============================================================================
226
+ // All Schemas Export
227
+ // =============================================================================
228
+
229
+ export const ALL_DATABASE_SCHEMAS = {
230
+ shipped: SHIPPED_DATABASE_SCHEMA,
231
+ roadmap: ROADMAP_DATABASE_SCHEMA,
232
+ ideas: IDEAS_DATABASE_SCHEMA,
233
+ tasks: TASKS_DATABASE_SCHEMA,
234
+ } as const
@@ -6,47 +6,13 @@
6
6
  */
7
7
 
8
8
  import outcomeRecorder from './recorder'
9
- import type { Outcome, OutcomeSummary, QualityScore } from './types'
10
-
11
- /**
12
- * Pattern detected from outcomes.
13
- */
14
- export interface DetectedPattern {
15
- /** Pattern description */
16
- description: string
17
-
18
- /** Confidence level (0-1) */
19
- confidence: number
20
-
21
- /** Number of occurrences supporting this pattern */
22
- occurrences: number
23
-
24
- /** Suggested action based on pattern */
25
- suggestedAction?: string
26
- }
27
-
28
- /**
29
- * Agent performance metrics.
30
- */
31
- export interface AgentMetrics {
32
- /** Agent name */
33
- agent: string
34
-
35
- /** Number of tasks completed */
36
- tasksCompleted: number
37
-
38
- /** Success rate (0-100) */
39
- successRate: number
40
-
41
- /** Average quality score */
42
- avgQualityScore: number
43
-
44
- /** Estimate accuracy */
45
- estimateAccuracy: number
46
-
47
- /** Best task types for this agent */
48
- bestFor: string[]
49
- }
9
+ import type {
10
+ Outcome,
11
+ OutcomeSummary,
12
+ QualityScore,
13
+ DetectedPattern,
14
+ AgentMetrics,
15
+ } from '../types'
50
16
 
51
17
  /**
52
18
  * OutcomeAnalyzer - Extracts insights from outcomes.
@@ -31,4 +31,4 @@
31
31
 
32
32
  export { OutcomeRecorder, default as outcomeRecorder } from './recorder'
33
33
  export { OutcomeAnalyzer, default as outcomeAnalyzer } from './analyzer'
34
- export * from './types'
34
+ export * from '../types'
@@ -9,7 +9,7 @@ import path from 'path'
9
9
  import * as fileHelper from '../utils/file-helper'
10
10
  import pathManager from '../infrastructure/path-manager'
11
11
  import { generateUUID } from '../schemas'
12
- import type { Outcome, OutcomeInput, OutcomeFilter } from './types'
12
+ import type { Outcome, OutcomeInput, OutcomeFilter } from '../types'
13
13
 
14
14
  const OUTCOMES_DIR = 'outcomes'
15
15
  const OUTCOMES_FILE = 'outcomes.jsonl'
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Notion Plugin for prjct-cli
3
+ *
4
+ * Syncs prjct data to Notion databases on events.
5
+ * Activated when project has integrations.notion.enabled = true
6
+ *
7
+ * @version 1.0.0
8
+ *
9
+ * Configuration in GlobalConfig.integrations.notion:
10
+ * {
11
+ * "enabled": true,
12
+ * "databases": {
13
+ * "shipped": "notion-db-id",
14
+ * "ideas": "notion-db-id"
15
+ * },
16
+ * "syncOn": { "ship": true, "idea": true }
17
+ * }
18
+ */
19
+
20
+ import { HookPoints } from '../hooks'
21
+ import type { NotionIntegrationConfig } from '../../types/integrations'
22
+ import type { ShippedFeature, Idea } from '../../types/storage'
23
+ import { notionClient, syncShippedFeature, syncIdea } from '../../integrations/notion'
24
+
25
+ interface NotionPluginContext {
26
+ projectId: string
27
+ config: NotionIntegrationConfig
28
+ apiToken?: string
29
+ }
30
+
31
+ const plugin = {
32
+ name: 'notion',
33
+ version: '1.0.0',
34
+ description: 'Sync prjct data to Notion',
35
+
36
+ // Plugin state
37
+ enabled: false,
38
+ projectId: null as string | null,
39
+ config: null as NotionIntegrationConfig | null,
40
+
41
+ /**
42
+ * Activate plugin
43
+ */
44
+ async activate(context: NotionPluginContext): Promise<void> {
45
+ const { projectId, config, apiToken } = context
46
+
47
+ if (!config?.enabled) {
48
+ return
49
+ }
50
+
51
+ // Initialize Notion client
52
+ notionClient.initialize(config, apiToken || process.env.NOTION_TOKEN)
53
+
54
+ if (!notionClient.isReady()) {
55
+ console.warn('[notion] API token not configured, plugin disabled')
56
+ return
57
+ }
58
+
59
+ plugin.enabled = true
60
+ plugin.projectId = projectId
61
+ plugin.config = config
62
+ },
63
+
64
+ /**
65
+ * Deactivate plugin
66
+ */
67
+ async deactivate(): Promise<void> {
68
+ plugin.enabled = false
69
+ plugin.projectId = null
70
+ plugin.config = null
71
+ },
72
+
73
+ /**
74
+ * Hook handlers
75
+ */
76
+ hooks: {
77
+ /**
78
+ * Sync shipped feature to Notion after ship
79
+ */
80
+ [HookPoints.AFTER_FEATURE_SHIP]: async function (data: {
81
+ feature: ShippedFeature
82
+ projectId?: string
83
+ }): Promise<void> {
84
+ if (!plugin.enabled || !plugin.config || !plugin.projectId) return
85
+ if (!plugin.config.syncOn?.ship) return
86
+
87
+ try {
88
+ const result = await syncShippedFeature(
89
+ data.projectId || plugin.projectId,
90
+ data.feature,
91
+ plugin.config
92
+ )
93
+
94
+ if (result.success) {
95
+ console.log(`[notion] Synced: ${data.feature.name} (${result.action})`)
96
+ } else if (result.error) {
97
+ console.warn(`[notion] Sync failed: ${result.error}`)
98
+ }
99
+ } catch (error) {
100
+ // Graceful degradation - don't fail the ship
101
+ console.warn('[notion] Sync error:', (error as Error).message)
102
+ }
103
+ },
104
+
105
+ /**
106
+ * Sync idea to Notion after capture
107
+ */
108
+ [HookPoints.AFTER_IDEA_CAPTURE]: async function (data: {
109
+ idea: Idea
110
+ projectId?: string
111
+ }): Promise<void> {
112
+ if (!plugin.enabled || !plugin.config || !plugin.projectId) return
113
+ if (!plugin.config.syncOn?.idea) return
114
+
115
+ try {
116
+ const result = await syncIdea(
117
+ data.projectId || plugin.projectId,
118
+ data.idea,
119
+ plugin.config
120
+ )
121
+
122
+ if (result.success) {
123
+ console.log(`[notion] Synced idea: ${data.idea.text.slice(0, 30)}... (${result.action})`)
124
+ } else if (result.error) {
125
+ console.warn(`[notion] Sync failed: ${result.error}`)
126
+ }
127
+ } catch (error) {
128
+ // Graceful degradation - don't fail the idea capture
129
+ console.warn('[notion] Sync error:', (error as Error).message)
130
+ }
131
+ },
132
+
133
+ /**
134
+ * Sync task completion (optional)
135
+ */
136
+ [HookPoints.AFTER_TASK_COMPLETE]: async function (data: {
137
+ taskName?: string
138
+ projectId?: string
139
+ }): Promise<void> {
140
+ if (!plugin.enabled || !plugin.config || !plugin.projectId) return
141
+ if (!plugin.config.syncOn?.done) return
142
+
143
+ // Task sync is optional and less critical
144
+ // Could update task status in Notion if database exists
145
+ if (data.taskName) {
146
+ console.log(`[notion] Task completed: ${data.taskName}`)
147
+ }
148
+ },
149
+ },
150
+
151
+ /**
152
+ * Check if plugin is active
153
+ */
154
+ isActive(): boolean {
155
+ return plugin.enabled && plugin.config?.enabled === true
156
+ },
157
+
158
+ /**
159
+ * Get current sync status
160
+ */
161
+ getStatus(): {
162
+ enabled: boolean
163
+ databases: number
164
+ lastSync?: string
165
+ } {
166
+ const dbCount = plugin.config?.databases
167
+ ? Object.values(plugin.config.databases).filter(Boolean).length
168
+ : 0
169
+
170
+ return {
171
+ enabled: plugin.enabled,
172
+ databases: dbCount,
173
+ lastSync: plugin.config?.lastSyncAt,
174
+ }
175
+ },
176
+ }
177
+
178
+ export default plugin
@@ -18,25 +18,9 @@
18
18
  */
19
19
 
20
20
  import crypto from 'crypto'
21
- import { EventTypes } from '../bus'
22
- import { HookPoints } from '../plugin/hooks'
23
-
24
- interface WebhookConfig {
25
- url?: string
26
- events?: string[]
27
- secret?: string
28
- }
29
-
30
- interface PluginContext {
31
- config: WebhookConfig
32
- }
33
-
34
- interface WebhookPayload {
35
- event: string
36
- timestamp: string
37
- source: string
38
- data: unknown
39
- }
21
+ import { EventTypes } from '../../bus'
22
+ import { HookPoints } from '../hooks'
23
+ import type { WebhookConfig, WebhookPluginContext, WebhookPayload } from '../../types'
40
24
 
41
25
  const plugin = {
42
26
  name: 'webhook',
@@ -46,12 +30,12 @@ const plugin = {
46
30
  // Plugin state
47
31
  config: null as WebhookConfig | null,
48
32
  enabled: false,
49
- events: [] as string[],
33
+ enabledEvents: [] as string[],
50
34
 
51
35
  /**
52
36
  * Activate plugin
53
37
  */
54
- async activate({ config }: PluginContext): Promise<void> {
38
+ async activate({ config }: WebhookPluginContext): Promise<void> {
55
39
  plugin.config = config
56
40
 
57
41
  if (!config.url) {
@@ -60,7 +44,7 @@ const plugin = {
60
44
  }
61
45
 
62
46
  plugin.enabled = true
63
- plugin.events = config.events || [
47
+ plugin.enabledEvents = config.events || [
64
48
  EventTypes.SESSION_COMPLETED,
65
49
  EventTypes.FEATURE_SHIPPED,
66
50
  EventTypes.SNAPSHOT_CREATED
@@ -12,7 +12,7 @@
12
12
  import fs from 'fs/promises'
13
13
  import path from 'path'
14
14
  import { hookSystem } from './hooks'
15
- import { eventBus } from '../bus'
15
+ import { eventBus, type EventCallback } from '../bus'
16
16
  import pathManager from '../infrastructure/path-manager'
17
17
 
18
18
  type PluginSource = 'builtin' | 'global' | 'project'
@@ -23,7 +23,7 @@ interface Plugin {
23
23
  version?: string
24
24
  description?: string
25
25
  hooks?: Record<string, HookHandler>
26
- events?: Record<string, HookHandler>
26
+ events?: Record<string, EventCallback>
27
27
  commands?: Record<string, { handler: () => void; description?: string }>
28
28
  priority?: number
29
29
  activate?: (context: PluginContext) => Promise<void>
@@ -83,10 +83,10 @@ class PluginLoader {
83
83
  }
84
84
 
85
85
  /**
86
- * Load built-in plugins from core/plugins
86
+ * Load built-in plugins from core/plugin/builtin
87
87
  */
88
88
  async loadBuiltinPlugins(): Promise<void> {
89
- const builtinPath = path.join(__dirname, '..', 'plugins')
89
+ const builtinPath = path.join(__dirname, 'builtin')
90
90
 
91
91
  try {
92
92
  const files = await fs.readdir(builtinPath)
@@ -106,7 +106,7 @@ class PluginLoader {
106
106
  * Load global plugins from ~/.prjct-cli/plugins
107
107
  */
108
108
  async loadGlobalPlugins(): Promise<void> {
109
- const globalPath = path.join(pathManager.getGlobalStoragePath(), 'plugins')
109
+ const globalPath = path.join(pathManager.getGlobalBasePath(), 'plugins')
110
110
 
111
111
  try {
112
112
  const files = await fs.readdir(globalPath)
@@ -57,7 +57,7 @@ class PluginRegistry {
57
57
 
58
58
  // Global plugins
59
59
  await this.discoverFromPath(
60
- path.join(pathManager.getGlobalStoragePath(), 'plugins'),
60
+ path.join(pathManager.getGlobalBasePath(), 'plugins'),
61
61
  'global'
62
62
  )
63
63
  }
@@ -188,7 +188,7 @@ class PluginRegistry {
188
188
  * Install a plugin (copy to global plugins)
189
189
  */
190
190
  async install(sourcePath: string, name: string | null = null): Promise<void> {
191
- const globalPluginsPath = path.join(pathManager.getGlobalStoragePath(), 'plugins')
191
+ const globalPluginsPath = path.join(pathManager.getGlobalBasePath(), 'plugins')
192
192
  await fs.mkdir(globalPluginsPath, { recursive: true })
193
193
 
194
194
  const stat = await fs.stat(sourcePath)