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.
- package/CHANGELOG.md +24 -6
- package/CLAUDE.md +56 -15
- package/README.md +5 -6
- package/bin/prjct +59 -42
- package/bin/prjct.ts +60 -0
- package/core/__tests__/agentic/memory-system.test.ts +18 -3
- package/core/__tests__/agentic/plan-mode.test.ts +55 -26
- package/core/__tests__/agentic/prompt-builder.test.ts +6 -6
- package/core/__tests__/utils/project-commands.test.ts +72 -0
- package/core/agentic/agent-router.ts +3 -12
- package/core/agentic/command-executor.ts +372 -3
- package/core/agentic/context-builder.ts +7 -27
- package/core/agentic/ground-truth.ts +604 -5
- package/core/agentic/index.ts +180 -0
- package/core/agentic/loop-detector.ts +418 -4
- package/core/agentic/memory-system.ts +857 -3
- package/core/agentic/plan-mode.ts +491 -4
- package/core/agentic/prompt-builder.ts +44 -65
- package/core/agentic/services.ts +13 -5
- package/core/agentic/skill-loader.ts +112 -0
- package/core/agentic/smart-context.ts +37 -122
- package/core/agentic/template-loader.ts +79 -122
- package/core/agentic/tool-registry.ts +5 -11
- package/core/agents/index.ts +1 -1
- package/core/agents/performance.ts +4 -2
- package/core/bus/bus.ts +262 -0
- package/core/bus/index.ts +3 -313
- package/core/commands/analysis.ts +5 -5
- package/core/commands/analytics.ts +11 -11
- package/core/commands/base.ts +33 -209
- package/core/commands/cleanup.ts +148 -0
- package/core/commands/command-data.ts +346 -0
- package/core/commands/commands.ts +216 -0
- package/core/commands/design.ts +83 -0
- package/core/commands/index.ts +13 -207
- package/core/commands/maintenance.ts +52 -473
- package/core/commands/planning.ts +3 -3
- package/core/commands/register.ts +104 -0
- package/core/commands/registry.ts +441 -0
- package/core/commands/setup.ts +25 -9
- package/core/commands/shipping.ts +48 -11
- package/core/commands/snapshots.ts +299 -0
- package/core/commands/workflow.ts +2 -2
- package/core/constants/index.ts +254 -4
- package/core/domain/agent-loader.ts +5 -6
- package/core/domain/task-stack.ts +555 -4
- package/core/errors.ts +127 -1
- package/core/events/events.ts +87 -0
- package/core/events/index.ts +4 -138
- package/core/index.ts +15 -23
- package/core/infrastructure/agent-detector.ts +126 -201
- package/core/infrastructure/author-detector.ts +99 -171
- package/core/infrastructure/command-installer.ts +476 -4
- package/core/infrastructure/config-manager.ts +41 -37
- package/core/infrastructure/path-manager.ts +59 -9
- package/core/infrastructure/permission-manager.ts +286 -0
- package/core/integrations/notion/client.ts +323 -0
- package/core/integrations/notion/index.ts +43 -0
- package/core/integrations/notion/setup.ts +230 -0
- package/core/integrations/notion/sync.ts +311 -0
- package/core/integrations/notion/templates.ts +234 -0
- package/core/outcomes/analyzer.ts +7 -41
- package/core/outcomes/index.ts +1 -1
- package/core/outcomes/recorder.ts +1 -1
- package/core/plugin/builtin/notion.ts +178 -0
- package/core/{plugins → plugin/builtin}/webhook.ts +6 -22
- package/core/plugin/loader.ts +5 -5
- package/core/plugin/registry.ts +2 -2
- package/core/schemas/ideas.ts +85 -54
- package/core/schemas/index.ts +14 -33
- package/core/schemas/permissions.ts +177 -0
- package/core/schemas/project.ts +39 -12
- package/core/schemas/roadmap.ts +94 -59
- package/core/schemas/schemas.ts +39 -0
- package/core/schemas/shipped.ts +87 -60
- package/core/schemas/state.ts +110 -70
- package/core/server/index.ts +21 -0
- package/core/server/routes.ts +165 -0
- package/core/server/server.ts +136 -0
- package/core/server/sse.ts +135 -0
- package/core/services/agent-service.ts +170 -0
- package/core/services/breakdown-service.ts +126 -0
- package/core/services/index.ts +21 -0
- package/core/services/memory-service.ts +108 -0
- package/core/services/project-service.ts +146 -0
- package/core/services/skill-service.ts +253 -0
- package/core/session/compaction.ts +257 -0
- package/core/session/index.ts +20 -8
- package/core/{infrastructure/session-manager/migration.ts → session/log-migration.ts} +9 -9
- package/core/{infrastructure/session-manager/session-manager.ts → session/session-log-manager.ts} +27 -26
- package/core/session/{session-manager.ts → task-session-manager.ts} +7 -4
- package/core/session/utils.ts +1 -1
- package/core/storage/ideas-storage.ts +10 -26
- package/core/storage/index.ts +14 -162
- package/core/storage/queue-storage.ts +13 -11
- package/core/storage/shipped-storage.ts +4 -17
- package/core/storage/state-storage.ts +35 -43
- package/core/storage/storage-manager.ts +42 -52
- package/core/storage/storage.ts +160 -0
- package/core/sync/auth-config.ts +1 -8
- package/core/sync/index.ts +17 -10
- package/core/sync/oauth-handler.ts +1 -6
- package/core/sync/sync-client.ts +6 -34
- package/core/sync/sync-manager.ts +11 -40
- package/core/types/agentic.ts +577 -0
- package/core/types/agents.ts +145 -0
- package/core/types/bus.ts +82 -0
- package/core/types/commands.ts +366 -0
- package/core/types/config.ts +70 -0
- package/core/types/core.ts +96 -0
- package/core/types/domain.ts +71 -0
- package/core/types/events.ts +42 -0
- package/core/types/fs.ts +56 -0
- package/core/types/index.ts +396 -500
- package/core/types/infrastructure.ts +196 -0
- package/core/types/integrations.ts +57 -0
- package/core/{agentic/memory-system/types.ts → types/memory.ts} +33 -8
- package/core/{outcomes/types.ts → types/outcomes.ts} +53 -8
- package/core/types/plugin.ts +25 -0
- package/core/types/server.ts +54 -0
- package/core/types/services.ts +65 -0
- package/core/types/session.ts +135 -0
- package/core/types/storage.ts +148 -0
- package/core/types/sync.ts +121 -0
- package/core/types/task.ts +72 -0
- package/core/types/template.ts +24 -0
- package/core/types/utils.ts +90 -0
- package/core/utils/cache.ts +195 -0
- package/core/utils/collection-filters.ts +245 -0
- package/core/utils/date-helper.ts +1 -5
- package/core/utils/file-helper.ts +20 -10
- package/core/utils/jsonl-helper.ts +5 -8
- package/core/utils/markdown-builder.ts +277 -0
- package/core/utils/project-commands.ts +132 -0
- package/core/utils/runtime.ts +119 -0
- package/dist/bin/prjct.mjs +12568 -0
- package/package.json +13 -8
- package/scripts/build.js +106 -0
- package/scripts/postinstall.js +50 -8
- package/templates/agentic/subagent-generation.md +1 -1
- package/templates/commands/init.md +43 -0
- package/templates/commands/notion-setup.md +191 -0
- package/templates/commands/serve.md +118 -0
- package/templates/commands/ship.md +13 -2
- package/templates/commands/skill.md +110 -0
- package/templates/commands/sync.md +1 -1
- package/templates/commands/test.md +23 -4
- package/templates/mcp-config.json +28 -0
- package/templates/permissions/default.jsonc +60 -0
- package/templates/permissions/permissive.jsonc +49 -0
- package/templates/permissions/strict.jsonc +62 -0
- package/templates/skills/code-review.md +47 -0
- package/templates/skills/debug.md +61 -0
- package/templates/skills/refactor.md +47 -0
- package/templates/subagents/domain/devops.md +1 -1
- package/templates/subagents/domain/testing.md +6 -10
- package/templates/subagents/workflow/prjct-shipper.md +16 -7
- package/templates/tools/bash.txt +22 -0
- package/templates/tools/edit.txt +18 -0
- package/templates/tools/glob.txt +19 -0
- package/templates/tools/grep.txt +21 -0
- package/templates/tools/read.txt +14 -0
- package/templates/tools/task.txt +20 -0
- package/templates/tools/webfetch.txt +16 -0
- package/templates/tools/websearch.txt +18 -0
- package/templates/tools/write.txt +17 -0
- package/core/agentic/command-executor/command-executor.ts +0 -312
- package/core/agentic/command-executor/index.ts +0 -16
- package/core/agentic/command-executor/status-signal.ts +0 -38
- package/core/agentic/command-executor/types.ts +0 -79
- package/core/agentic/ground-truth/index.ts +0 -76
- package/core/agentic/ground-truth/types.ts +0 -33
- package/core/agentic/ground-truth/utils.ts +0 -48
- package/core/agentic/ground-truth/verifiers/analyze.ts +0 -54
- package/core/agentic/ground-truth/verifiers/done.ts +0 -75
- package/core/agentic/ground-truth/verifiers/feature.ts +0 -70
- package/core/agentic/ground-truth/verifiers/index.ts +0 -37
- package/core/agentic/ground-truth/verifiers/init.ts +0 -52
- package/core/agentic/ground-truth/verifiers/now.ts +0 -57
- package/core/agentic/ground-truth/verifiers/ship.ts +0 -85
- package/core/agentic/ground-truth/verifiers/spec.ts +0 -45
- package/core/agentic/ground-truth/verifiers/sync.ts +0 -47
- package/core/agentic/ground-truth/verifiers.ts +0 -6
- package/core/agentic/loop-detector/error-analysis.ts +0 -97
- package/core/agentic/loop-detector/hallucination.ts +0 -71
- package/core/agentic/loop-detector/index.ts +0 -41
- package/core/agentic/loop-detector/loop-detector.ts +0 -222
- package/core/agentic/loop-detector/types.ts +0 -66
- package/core/agentic/memory-system/history.ts +0 -53
- package/core/agentic/memory-system/index.ts +0 -192
- package/core/agentic/memory-system/patterns.ts +0 -156
- package/core/agentic/memory-system/semantic-memories.ts +0 -278
- package/core/agentic/memory-system/session.ts +0 -21
- package/core/agentic/plan-mode/approval.ts +0 -57
- package/core/agentic/plan-mode/constants.ts +0 -44
- package/core/agentic/plan-mode/index.ts +0 -28
- package/core/agentic/plan-mode/plan-mode.ts +0 -407
- package/core/agentic/plan-mode/types.ts +0 -193
- package/core/agents/types.ts +0 -126
- package/core/command-registry/categories.ts +0 -23
- package/core/command-registry/commands.ts +0 -15
- package/core/command-registry/core-commands.ts +0 -344
- package/core/command-registry/index.ts +0 -158
- package/core/command-registry/optional-commands.ts +0 -163
- package/core/command-registry/setup-commands.ts +0 -83
- package/core/command-registry/types.ts +0 -59
- package/core/command-registry.ts +0 -9
- package/core/commands/types.ts +0 -185
- package/core/commands.ts +0 -11
- package/core/constants/formats.ts +0 -187
- package/core/context-sync.ts +0 -18
- package/core/data/index.ts +0 -27
- package/core/data/md-base-manager.ts +0 -203
- package/core/data/md-ideas-manager.ts +0 -155
- package/core/data/md-queue-manager.ts +0 -180
- package/core/data/md-shipped-manager.ts +0 -90
- package/core/data/md-state-manager.ts +0 -137
- package/core/domain/task-stack/index.ts +0 -19
- package/core/domain/task-stack/parser.ts +0 -86
- package/core/domain/task-stack/storage.ts +0 -123
- package/core/domain/task-stack/task-stack.ts +0 -340
- package/core/domain/task-stack/types.ts +0 -51
- package/core/infrastructure/command-installer/command-installer.ts +0 -327
- package/core/infrastructure/command-installer/global-config.ts +0 -136
- package/core/infrastructure/command-installer/index.ts +0 -25
- package/core/infrastructure/command-installer/types.ts +0 -41
- package/core/infrastructure/session-manager/index.ts +0 -23
- package/core/infrastructure/session-manager/types.ts +0 -45
- package/core/infrastructure/session-manager.ts +0 -8
- package/core/serializers/ideas-serializer.ts +0 -187
- package/core/serializers/index.ts +0 -36
- package/core/serializers/queue-serializer.ts +0 -210
- package/core/serializers/shipped-serializer.ts +0 -108
- package/core/serializers/state-serializer.ts +0 -136
- package/core/session/types.ts +0 -29
- /package/core/infrastructure/{agents/claude-agent.ts → claude-agent.ts} +0 -0
package/core/schemas/shipped.ts
CHANGED
|
@@ -2,80 +2,107 @@
|
|
|
2
2
|
* Shipped Schema
|
|
3
3
|
*
|
|
4
4
|
* Defines the structure for shipped.json - completed/shipped items.
|
|
5
|
+
* Uses Zod for runtime validation and TypeScript type inference.
|
|
5
6
|
* ZERO DATA LOSS - captures ALL fields from MD files.
|
|
7
|
+
*
|
|
8
|
+
* @version 2.0.0
|
|
6
9
|
*/
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
export type CheckStatus = 'pass' | 'warning' | 'fail' | 'skipped'
|
|
10
|
-
export type AgentType = 'fe' | 'be' | 'fe+be' | 'devops' | 'ai' | string
|
|
11
|
+
import { z } from 'zod'
|
|
11
12
|
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
minutes: number
|
|
16
|
-
totalMinutes: number
|
|
17
|
-
}
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Zod Schemas - Source of Truth
|
|
15
|
+
// =============================================================================
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
linesAdded?: number | null
|
|
23
|
-
linesRemoved?: number | null
|
|
24
|
-
commits?: number | null
|
|
25
|
-
}
|
|
17
|
+
export const ShipTypeSchema = z.enum(['feature', 'fix', 'improvement', 'refactor'])
|
|
18
|
+
export const CheckStatusSchema = z.enum(['pass', 'warning', 'fail', 'skipped'])
|
|
19
|
+
export const ChangeTypeSchema = z.enum(['added', 'changed', 'fixed', 'removed'])
|
|
26
20
|
|
|
27
|
-
export
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
export const DurationSchema = z.object({
|
|
22
|
+
hours: z.number(),
|
|
23
|
+
minutes: z.number(),
|
|
24
|
+
totalMinutes: z.number(),
|
|
25
|
+
})
|
|
31
26
|
|
|
32
|
-
export
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
27
|
+
export const CodeMetricsSchema = z.object({
|
|
28
|
+
filesChanged: z.number().nullable().optional(),
|
|
29
|
+
linesAdded: z.number().nullable().optional(),
|
|
30
|
+
linesRemoved: z.number().nullable().optional(),
|
|
31
|
+
commits: z.number().nullable().optional(),
|
|
32
|
+
})
|
|
38
33
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
branch?: string // "main"
|
|
44
|
-
}
|
|
34
|
+
export const ShipChangeSchema = z.object({
|
|
35
|
+
description: z.string(),
|
|
36
|
+
type: ChangeTypeSchema.optional(),
|
|
37
|
+
})
|
|
45
38
|
|
|
46
|
-
export
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
agent?: AgentType // "fe+be", "be", "fe"
|
|
53
|
-
// Full description (narrative text, not just bullet points)
|
|
54
|
-
description?: string // "CRITICAL: Multi-tenant isolation hardening..."
|
|
55
|
-
// Changelog from bullet points
|
|
56
|
-
changes: ShipChange[]
|
|
57
|
-
// Code snippets if any
|
|
58
|
-
codeSnippets?: string[] // TypeScript/code examples from MD
|
|
59
|
-
// Git commit info
|
|
60
|
-
commit?: CommitInfo
|
|
61
|
-
// Enriched fields from MD
|
|
62
|
-
codeMetrics?: CodeMetrics
|
|
63
|
-
qualityMetrics?: QualityMetrics
|
|
64
|
-
quantitativeImpact?: string // "81% (1,079 → 204 lines)"
|
|
65
|
-
duration?: Duration // parsed from "13h 38m"
|
|
66
|
-
tasksCompleted?: number | null
|
|
67
|
-
shippedAt: string // ISO8601
|
|
68
|
-
featureId?: string
|
|
69
|
-
}
|
|
39
|
+
export const QualityMetricsSchema = z.object({
|
|
40
|
+
lintStatus: CheckStatusSchema.nullable().optional(),
|
|
41
|
+
lintDetails: z.string().optional(),
|
|
42
|
+
testStatus: CheckStatusSchema.nullable().optional(),
|
|
43
|
+
testDetails: z.string().optional(),
|
|
44
|
+
})
|
|
70
45
|
|
|
71
|
-
export
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
46
|
+
export const CommitInfoSchema = z.object({
|
|
47
|
+
hash: z.string().optional(),
|
|
48
|
+
message: z.string().optional(),
|
|
49
|
+
branch: z.string().optional(),
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
export const ShippedItemSchema = z.object({
|
|
53
|
+
id: z.string(), // ship_xxxxxxxx
|
|
54
|
+
name: z.string(),
|
|
55
|
+
version: z.string().nullable().optional(),
|
|
56
|
+
type: ShipTypeSchema,
|
|
57
|
+
agent: z.string().optional(), // "fe+be", "be", "fe"
|
|
58
|
+
description: z.string().optional(),
|
|
59
|
+
changes: z.array(ShipChangeSchema),
|
|
60
|
+
codeSnippets: z.array(z.string()).optional(),
|
|
61
|
+
commit: CommitInfoSchema.optional(),
|
|
62
|
+
codeMetrics: CodeMetricsSchema.optional(),
|
|
63
|
+
qualityMetrics: QualityMetricsSchema.optional(),
|
|
64
|
+
quantitativeImpact: z.string().optional(),
|
|
65
|
+
duration: DurationSchema.optional(),
|
|
66
|
+
tasksCompleted: z.number().nullable().optional(),
|
|
67
|
+
shippedAt: z.string(), // ISO8601
|
|
68
|
+
featureId: z.string().optional(),
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
export const ShippedJsonSchema = z.object({
|
|
72
|
+
items: z.array(ShippedItemSchema),
|
|
73
|
+
lastUpdated: z.string(),
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
// =============================================================================
|
|
77
|
+
// Inferred Types - Backward Compatible
|
|
78
|
+
// =============================================================================
|
|
79
|
+
|
|
80
|
+
export type ShipType = z.infer<typeof ShipTypeSchema>
|
|
81
|
+
export type CheckStatus = z.infer<typeof CheckStatusSchema>
|
|
82
|
+
export type AgentType = 'fe' | 'be' | 'fe+be' | 'devops' | 'ai' | string
|
|
83
|
+
export type Duration = z.infer<typeof DurationSchema>
|
|
84
|
+
export type CodeMetrics = z.infer<typeof CodeMetricsSchema>
|
|
85
|
+
export type ShipChange = z.infer<typeof ShipChangeSchema>
|
|
86
|
+
export type QualityMetrics = z.infer<typeof QualityMetricsSchema>
|
|
87
|
+
export type CommitInfo = z.infer<typeof CommitInfoSchema>
|
|
88
|
+
export type ShippedItemSchema = z.infer<typeof ShippedItemSchema>
|
|
89
|
+
export type ShippedJson = z.infer<typeof ShippedJsonSchema>
|
|
75
90
|
|
|
76
91
|
// Legacy type for backwards compatibility
|
|
77
92
|
export type ShippedSchema = ShippedItemSchema[]
|
|
78
93
|
|
|
94
|
+
// =============================================================================
|
|
95
|
+
// Validation Helpers
|
|
96
|
+
// =============================================================================
|
|
97
|
+
|
|
98
|
+
/** Parse and validate shipped.json content */
|
|
99
|
+
export const parseShipped = (data: unknown): ShippedJson => ShippedJsonSchema.parse(data)
|
|
100
|
+
export const safeParseShipped = (data: unknown) => ShippedJsonSchema.safeParse(data)
|
|
101
|
+
|
|
102
|
+
// =============================================================================
|
|
103
|
+
// Defaults
|
|
104
|
+
// =============================================================================
|
|
105
|
+
|
|
79
106
|
export const DEFAULT_SHIPPED: ShippedJson = {
|
|
80
107
|
items: [],
|
|
81
108
|
lastUpdated: ''
|
package/core/schemas/state.ts
CHANGED
|
@@ -4,91 +4,131 @@
|
|
|
4
4
|
* Defines the structure for state.json - current task state.
|
|
5
5
|
* Queue is now separate in queue.json.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* Uses Zod for runtime validation and TypeScript type inference.
|
|
8
|
+
* @version 2.0.0
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
export type TaskType = 'feature' | 'bug' | 'improvement' | 'chore'
|
|
12
|
-
export type TaskSection = 'active' | 'backlog' | 'previously_active'
|
|
11
|
+
import { z } from 'zod'
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
startedAt: string // ISO8601
|
|
18
|
-
sessionId: string // sess_xxxxxxxx
|
|
19
|
-
featureId?: string // feat_xxxxxxxx
|
|
20
|
-
}
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Zod Schemas - Source of Truth
|
|
15
|
+
// =============================================================================
|
|
21
16
|
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
pausedAt: string // ISO8601
|
|
28
|
-
pauseReason?: string // Optional reason for pausing
|
|
29
|
-
}
|
|
17
|
+
export const PrioritySchema = z.enum(['low', 'medium', 'high', 'critical'])
|
|
18
|
+
export const TaskTypeSchema = z.enum(['feature', 'bug', 'improvement', 'chore'])
|
|
19
|
+
export const TaskSectionSchema = z.enum(['active', 'backlog', 'previously_active'])
|
|
20
|
+
export const TaskStatusSchema = z.enum(['pending', 'in_progress', 'completed', 'blocked', 'paused'])
|
|
21
|
+
export const ActivityTypeSchema = z.enum(['task_completed', 'feature_shipped', 'idea_captured', 'session_started'])
|
|
30
22
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
23
|
+
export const CurrentTaskSchema = z.object({
|
|
24
|
+
id: z.string(), // task_xxxxxxxx
|
|
25
|
+
description: z.string(),
|
|
26
|
+
startedAt: z.string(), // ISO8601
|
|
27
|
+
sessionId: z.string(), // sess_xxxxxxxx
|
|
28
|
+
featureId: z.string().optional(), // feat_xxxxxxxx
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
export const PreviousTaskSchema = z.object({
|
|
32
|
+
id: z.string(),
|
|
33
|
+
description: z.string(),
|
|
34
|
+
status: z.literal('paused'),
|
|
35
|
+
startedAt: z.string(), // ISO8601
|
|
36
|
+
pausedAt: z.string(), // ISO8601
|
|
37
|
+
pauseReason: z.string().optional(),
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
export const StateJsonSchema = z.object({
|
|
41
|
+
currentTask: CurrentTaskSchema.nullable(),
|
|
42
|
+
previousTask: PreviousTaskSchema.nullable().optional(),
|
|
43
|
+
lastUpdated: z.string(),
|
|
44
|
+
})
|
|
37
45
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
section: TaskSection // based on MD section
|
|
46
|
+
export const QueueTaskSchema = z.object({
|
|
47
|
+
id: z.string(), // task_xxxxxxxx
|
|
48
|
+
description: z.string(),
|
|
49
|
+
priority: PrioritySchema,
|
|
50
|
+
type: TaskTypeSchema, // detect from emoji 🐛=bug
|
|
51
|
+
featureId: z.string().optional(),
|
|
52
|
+
originFeature: z.string().optional(),
|
|
53
|
+
completed: z.boolean(),
|
|
54
|
+
completedAt: z.string().optional(),
|
|
55
|
+
createdAt: z.string(), // ISO8601
|
|
56
|
+
section: TaskSectionSchema,
|
|
50
57
|
// Additional fields for ZERO DATA LOSS
|
|
51
|
-
agent
|
|
52
|
-
groupName
|
|
53
|
-
groupId
|
|
54
|
-
}
|
|
58
|
+
agent: z.string().optional(), // "fe", "be", "fe + be"
|
|
59
|
+
groupName: z.string().optional(), // "Sales Reports", "Stock Audits"
|
|
60
|
+
groupId: z.string().optional(), // For grouping related tasks
|
|
61
|
+
})
|
|
55
62
|
|
|
56
|
-
export
|
|
57
|
-
tasks:
|
|
58
|
-
lastUpdated: string
|
|
59
|
-
}
|
|
63
|
+
export const QueueJsonSchema = z.object({
|
|
64
|
+
tasks: z.array(QueueTaskSchema),
|
|
65
|
+
lastUpdated: z.string(),
|
|
66
|
+
})
|
|
60
67
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
export const StatsSchema = z.object({
|
|
69
|
+
tasksToday: z.number(),
|
|
70
|
+
tasksThisWeek: z.number(),
|
|
71
|
+
streak: z.number(),
|
|
72
|
+
velocity: z.string(),
|
|
73
|
+
avgDuration: z.string(),
|
|
74
|
+
})
|
|
64
75
|
|
|
65
|
-
export
|
|
76
|
+
export const RecentActivitySchema = z.object({
|
|
77
|
+
type: ActivityTypeSchema,
|
|
78
|
+
description: z.string(),
|
|
79
|
+
timestamp: z.string(), // ISO8601
|
|
80
|
+
duration: z.string().optional(),
|
|
81
|
+
})
|
|
66
82
|
|
|
67
|
-
export
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
83
|
+
export const StateSchemaFull = z.object({
|
|
84
|
+
projectId: z.string(),
|
|
85
|
+
currentTask: CurrentTaskSchema.nullable(),
|
|
86
|
+
queue: z.array(QueueTaskSchema),
|
|
87
|
+
stats: StatsSchema,
|
|
88
|
+
recentActivity: z.array(RecentActivitySchema),
|
|
89
|
+
lastSync: z.string(), // ISO8601
|
|
90
|
+
})
|
|
74
91
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
timestamp: string // ISO8601
|
|
79
|
-
duration?: string
|
|
80
|
-
}
|
|
92
|
+
// =============================================================================
|
|
93
|
+
// Inferred Types - Backward Compatible
|
|
94
|
+
// =============================================================================
|
|
81
95
|
|
|
82
|
-
export
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
export type Priority = z.infer<typeof PrioritySchema>
|
|
97
|
+
export type TaskType = z.infer<typeof TaskTypeSchema>
|
|
98
|
+
export type TaskSection = z.infer<typeof TaskSectionSchema>
|
|
99
|
+
export type TaskStatus = z.infer<typeof TaskStatusSchema>
|
|
100
|
+
export type ActivityType = z.infer<typeof ActivityTypeSchema>
|
|
101
|
+
|
|
102
|
+
export type CurrentTask = z.infer<typeof CurrentTaskSchema>
|
|
103
|
+
export type PreviousTask = z.infer<typeof PreviousTaskSchema>
|
|
104
|
+
export type StateJson = z.infer<typeof StateJsonSchema>
|
|
105
|
+
export type QueueTask = z.infer<typeof QueueTaskSchema>
|
|
106
|
+
export type QueueJson = z.infer<typeof QueueJsonSchema>
|
|
107
|
+
export type Stats = z.infer<typeof StatsSchema>
|
|
108
|
+
export type RecentActivity = z.infer<typeof RecentActivitySchema>
|
|
109
|
+
export type StateSchema = z.infer<typeof StateSchemaFull>
|
|
110
|
+
|
|
111
|
+
// Legacy alias
|
|
112
|
+
export type QueuedTask = QueueTask
|
|
113
|
+
|
|
114
|
+
// =============================================================================
|
|
115
|
+
// Validation Helpers
|
|
116
|
+
// =============================================================================
|
|
90
117
|
|
|
118
|
+
/** Parse and validate state.json content */
|
|
119
|
+
export const parseState = (data: unknown): StateJson => StateJsonSchema.parse(data)
|
|
120
|
+
|
|
121
|
+
/** Parse and validate queue.json content */
|
|
122
|
+
export const parseQueue = (data: unknown): QueueJson => QueueJsonSchema.parse(data)
|
|
123
|
+
|
|
124
|
+
/** Safe parse with error result */
|
|
125
|
+
export const safeParseState = (data: unknown) => StateJsonSchema.safeParse(data)
|
|
126
|
+
export const safeParseQueue = (data: unknown) => QueueJsonSchema.safeParse(data)
|
|
127
|
+
|
|
128
|
+
// =============================================================================
|
|
91
129
|
// Defaults
|
|
130
|
+
// =============================================================================
|
|
131
|
+
|
|
92
132
|
export const DEFAULT_STATE: StateJson = {
|
|
93
133
|
currentTask: null,
|
|
94
134
|
lastUpdated: ''
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Module
|
|
3
|
+
*
|
|
4
|
+
* HTTP server for prjct-cli web dashboard and API.
|
|
5
|
+
*
|
|
6
|
+
* @module core/server
|
|
7
|
+
* @version 1.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export { createServer, startServer, DEFAULT_PORT } from './server'
|
|
11
|
+
export { createRoutes } from './routes'
|
|
12
|
+
export { createSSEManager, SSE_EVENTS } from './sse'
|
|
13
|
+
|
|
14
|
+
// Re-export types from canonical location
|
|
15
|
+
export type {
|
|
16
|
+
ServerConfig,
|
|
17
|
+
ServerInstance,
|
|
18
|
+
SSEClient,
|
|
19
|
+
SSEManager,
|
|
20
|
+
SSEEventType,
|
|
21
|
+
} from '../types'
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REST API Routes for prjct-cli
|
|
3
|
+
*
|
|
4
|
+
* Provides endpoints for reading and managing project state.
|
|
5
|
+
*
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Hono } from 'hono'
|
|
10
|
+
import fs from 'fs/promises'
|
|
11
|
+
import path from 'path'
|
|
12
|
+
import * as jsonc from 'jsonc-parser'
|
|
13
|
+
|
|
14
|
+
// Storage paths relative to project data directory
|
|
15
|
+
const STORAGE_PATHS = {
|
|
16
|
+
state: 'storage/state.json',
|
|
17
|
+
queue: 'storage/queue.json',
|
|
18
|
+
ideas: 'storage/ideas.json',
|
|
19
|
+
shipped: 'storage/shipped.json',
|
|
20
|
+
roadmap: 'planning/roadmap.json',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Read JSON file with JSONC support
|
|
25
|
+
*/
|
|
26
|
+
async function readJsonFile<T>(filePath: string): Promise<T | null> {
|
|
27
|
+
try {
|
|
28
|
+
const content = await fs.readFile(filePath, 'utf-8')
|
|
29
|
+
const errors: jsonc.ParseError[] = []
|
|
30
|
+
const result = jsonc.parse(content, errors)
|
|
31
|
+
return errors.length > 0 ? null : result
|
|
32
|
+
} catch {
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Write JSON file
|
|
39
|
+
*/
|
|
40
|
+
async function writeJsonFile(filePath: string, data: unknown): Promise<boolean> {
|
|
41
|
+
try {
|
|
42
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
|
43
|
+
await fs.writeFile(filePath, JSON.stringify(data, null, 2) + '\n', 'utf-8')
|
|
44
|
+
return true
|
|
45
|
+
} catch {
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get global project path
|
|
52
|
+
*/
|
|
53
|
+
function getProjectDataPath(projectId: string): string {
|
|
54
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '~'
|
|
55
|
+
return path.join(homeDir, '.prjct-cli', 'projects', projectId)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Create API routes for a project
|
|
60
|
+
*/
|
|
61
|
+
export function createRoutes(projectId: string, _projectPath: string): Hono {
|
|
62
|
+
const api = new Hono()
|
|
63
|
+
const dataPath = getProjectDataPath(projectId)
|
|
64
|
+
|
|
65
|
+
// GET /state - Current task state
|
|
66
|
+
api.get('/state', async (c) => {
|
|
67
|
+
const data = await readJsonFile(path.join(dataPath, STORAGE_PATHS.state))
|
|
68
|
+
if (!data) {
|
|
69
|
+
return c.json({ currentTask: null, lastUpdated: '' })
|
|
70
|
+
}
|
|
71
|
+
return c.json(data)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// GET /queue - Task queue
|
|
75
|
+
api.get('/queue', async (c) => {
|
|
76
|
+
const data = await readJsonFile(path.join(dataPath, STORAGE_PATHS.queue))
|
|
77
|
+
if (!data) {
|
|
78
|
+
return c.json({ tasks: [], lastUpdated: '' })
|
|
79
|
+
}
|
|
80
|
+
return c.json(data)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
// GET /ideas - Ideas backlog
|
|
84
|
+
api.get('/ideas', async (c) => {
|
|
85
|
+
const data = await readJsonFile(path.join(dataPath, STORAGE_PATHS.ideas))
|
|
86
|
+
if (!data) {
|
|
87
|
+
return c.json({ ideas: [], lastUpdated: '' })
|
|
88
|
+
}
|
|
89
|
+
return c.json(data)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
// GET /roadmap - Feature roadmap
|
|
93
|
+
api.get('/roadmap', async (c) => {
|
|
94
|
+
const data = await readJsonFile(path.join(dataPath, STORAGE_PATHS.roadmap))
|
|
95
|
+
if (!data) {
|
|
96
|
+
return c.json({ features: [], backlog: [], lastUpdated: '' })
|
|
97
|
+
}
|
|
98
|
+
return c.json(data)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
// GET /shipped - Shipped items
|
|
102
|
+
api.get('/shipped', async (c) => {
|
|
103
|
+
const data = await readJsonFile(path.join(dataPath, STORAGE_PATHS.shipped))
|
|
104
|
+
if (!data) {
|
|
105
|
+
return c.json({ items: [], lastUpdated: '' })
|
|
106
|
+
}
|
|
107
|
+
return c.json(data)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
// GET /dashboard - Combined dashboard data
|
|
111
|
+
api.get('/dashboard', async (c) => {
|
|
112
|
+
const [state, queue, ideas, roadmap, shipped] = await Promise.all([
|
|
113
|
+
readJsonFile(path.join(dataPath, STORAGE_PATHS.state)),
|
|
114
|
+
readJsonFile(path.join(dataPath, STORAGE_PATHS.queue)),
|
|
115
|
+
readJsonFile(path.join(dataPath, STORAGE_PATHS.ideas)),
|
|
116
|
+
readJsonFile(path.join(dataPath, STORAGE_PATHS.roadmap)),
|
|
117
|
+
readJsonFile(path.join(dataPath, STORAGE_PATHS.shipped)),
|
|
118
|
+
])
|
|
119
|
+
|
|
120
|
+
return c.json({
|
|
121
|
+
projectId,
|
|
122
|
+
state: state || { currentTask: null, lastUpdated: '' },
|
|
123
|
+
queue: queue || { tasks: [], lastUpdated: '' },
|
|
124
|
+
ideas: ideas || { ideas: [], lastUpdated: '' },
|
|
125
|
+
roadmap: roadmap || { features: [], backlog: [], lastUpdated: '' },
|
|
126
|
+
shipped: shipped || { items: [], lastUpdated: '' },
|
|
127
|
+
timestamp: new Date().toISOString(),
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
// POST /state - Update state (for future use)
|
|
132
|
+
api.post('/state', async (c) => {
|
|
133
|
+
try {
|
|
134
|
+
const body = await c.req.json()
|
|
135
|
+
const filePath = path.join(dataPath, STORAGE_PATHS.state)
|
|
136
|
+
const success = await writeJsonFile(filePath, body)
|
|
137
|
+
if (success) {
|
|
138
|
+
return c.json({ success: true })
|
|
139
|
+
}
|
|
140
|
+
return c.json({ success: false, error: 'Failed to write' }, 500)
|
|
141
|
+
} catch (e) {
|
|
142
|
+
return c.json({ success: false, error: String(e) }, 400)
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// GET /context - Read context markdown files
|
|
147
|
+
api.get('/context/:name', async (c) => {
|
|
148
|
+
const name = c.req.param('name')
|
|
149
|
+
const allowedFiles = ['now', 'next', 'ideas', 'shipped']
|
|
150
|
+
|
|
151
|
+
if (!allowedFiles.includes(name)) {
|
|
152
|
+
return c.json({ error: 'Invalid context file' }, 400)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
const filePath = path.join(dataPath, 'context', `${name}.md`)
|
|
157
|
+
const content = await fs.readFile(filePath, 'utf-8')
|
|
158
|
+
return c.text(content, 200, { 'Content-Type': 'text/markdown' })
|
|
159
|
+
} catch {
|
|
160
|
+
return c.text('', 200, { 'Content-Type': 'text/markdown' })
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
return api
|
|
165
|
+
}
|