prjct-cli 1.6.7 → 1.6.9
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 +106 -5
- package/README.md +46 -0
- package/core/agentic/chain-of-thought.ts +3 -1
- package/core/agentic/ground-truth.ts +12 -5
- package/core/agentic/index.ts +14 -2
- package/core/agentic/memory-system.ts +86 -23
- package/core/agentic/services.ts +1 -1
- package/core/agentic/template-executor.ts +4 -4
- package/core/agentic/template-loader.ts +2 -8
- package/core/ai-tools/registry.ts +2 -9
- package/core/bus/bus.ts +0 -1
- package/core/bus/index.ts +1 -1
- package/core/cli/start.ts +0 -2
- package/core/commands/base.ts +2 -2
- package/core/commands/planning.ts +4 -6
- package/core/constants/index.ts +19 -0
- package/core/context/generator.ts +0 -2
- package/core/context-tools/files-tool.ts +0 -6
- package/core/context-tools/imports-tool.ts +0 -6
- package/core/context-tools/recent-tool.ts +0 -6
- package/core/context-tools/signatures-tool.ts +0 -6
- package/core/context-tools/summary-tool.ts +0 -6
- package/core/context-tools/token-counter.ts +0 -13
- package/core/infrastructure/agent-detector.ts +2 -15
- package/core/infrastructure/ai-provider.ts +0 -29
- package/core/infrastructure/author-detector.ts +0 -14
- package/core/infrastructure/config-manager.ts +1 -1
- package/core/infrastructure/path-manager.ts +3 -17
- package/core/infrastructure/setup.ts +0 -3
- package/core/integrations/jira/client.ts +3 -77
- package/core/plugin/hooks.ts +0 -2
- package/core/plugin/index.ts +0 -13
- package/core/plugin/loader.ts +0 -2
- package/core/plugin/registry.ts +0 -2
- package/core/server/server.ts +2 -4
- package/core/server/sse.ts +115 -59
- package/core/services/agent-service.ts +1 -1
- package/core/services/context-generator.ts +23 -48
- package/core/services/diff-generator.ts +18 -55
- package/core/services/hooks-service.ts +0 -1
- package/core/services/memory-service.ts +1 -1
- package/core/services/project-service.ts +1 -1
- package/core/services/stack-detector.ts +4 -20
- package/core/services/sync-service.ts +36 -107
- package/core/services/sync-verifier.ts +17 -37
- package/core/services/watch-service.ts +1 -1
- package/core/storage/index.ts +1 -1
- package/core/storage/storage.ts +0 -2
- package/core/types/citations.ts +22 -0
- package/core/types/commands.ts +10 -0
- package/core/types/diff.ts +41 -0
- package/core/types/errors.ts +111 -0
- package/core/types/index.ts +80 -0
- package/core/types/infrastructure.ts +14 -0
- package/core/types/jira.ts +51 -0
- package/core/types/logger.ts +17 -0
- package/core/types/output.ts +47 -0
- package/core/types/project-sync.ts +109 -0
- package/core/types/server.ts +28 -10
- package/core/types/services.ts +14 -0
- package/core/types/stack.ts +19 -0
- package/core/types/sync-verifier.ts +33 -0
- package/core/types/workflow.ts +23 -0
- package/core/utils/animations.ts +0 -18
- package/core/utils/cache.ts +0 -6
- package/core/utils/citations.ts +2 -16
- package/core/utils/collection-filters.ts +0 -24
- package/core/utils/date-helper.ts +0 -20
- package/core/utils/error-messages.ts +5 -139
- package/core/utils/file-helper.ts +0 -26
- package/core/utils/help.ts +0 -9
- package/core/utils/jsonl-helper.ts +0 -21
- package/core/utils/logger.ts +3 -11
- package/core/utils/markdown-builder.ts +0 -3
- package/core/utils/next-steps.ts +0 -2
- package/core/utils/output.ts +6 -45
- package/core/utils/runtime.ts +0 -11
- package/core/utils/session-helper.ts +0 -12
- package/core/utils/version.ts +0 -12
- package/core/workflow/workflow-preferences.ts +18 -31
- package/dist/bin/prjct.mjs +319 -351
- package/dist/core/infrastructure/command-installer.js +1 -26
- package/dist/core/infrastructure/setup.js +1 -28
- package/dist/core/utils/version.js +0 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,106 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.6.9] - 2026-02-07
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
- resolve SSE zombie connections and infinite promise leak (PRJ-286) (#134)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## [1.6.11] - 2026-02-07
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
- **Fix SSE zombie connections and infinite promise leak (PRJ-286)**: Replaced infinite `await new Promise(() => {})` with AbortController-based mechanism that resolves on client removal. Added max client lifetime (1 hour) with per-client TTL timeout. Added periodic reaper (every 5 min) that scans for and removes zombie entries from the clients Map. Consolidated duplicate cleanup paths into single idempotent `removeClient(id)` function. Added `shutdown()` to SSEManager for clean server stop. All timers use `unref()` to avoid blocking process exit.
|
|
14
|
+
|
|
15
|
+
### Implementation Details
|
|
16
|
+
Replaced the infinite pending promise in `streamSSE` callback with an `AbortController` whose signal resolves the await when the client is removed. Internal client state (`heartbeatInterval`, `ttlTimeout`, `abortController`) is tracked in an `InternalClient` wrapper separate from the public `SSEClient` type. The public `SSEClient` interface gained only `connectedAt` for staleness detection.
|
|
17
|
+
|
|
18
|
+
### Learnings
|
|
19
|
+
- AbortController integrates cleanly with Hono's `streamSSE` — the async callback needs to await *something*, and a signal-based promise is the right primitive.
|
|
20
|
+
- Timer `unref()` has different shapes between Bun (number) and Node (Timeout object) — use `typeof` check before calling.
|
|
21
|
+
- Idempotent cleanup functions eliminate race conditions between heartbeat failure and stream abort handlers.
|
|
22
|
+
|
|
23
|
+
### Test Plan
|
|
24
|
+
|
|
25
|
+
#### For QA
|
|
26
|
+
1. Start prjct server, connect SSE client to `/api/events` — verify `connected` event
|
|
27
|
+
2. Disconnect client gracefully — verify `clients.size === 0`
|
|
28
|
+
3. Kill client process (ungraceful) — verify heartbeat cleanup within 30s
|
|
29
|
+
4. Connect client, wait >1 hour — verify TTL auto-disconnect
|
|
30
|
+
5. Connect 5+ clients, kill all — verify reaper cleans all within 5 min
|
|
31
|
+
6. Call `server.stop()` — verify all clients disconnected and reaper stopped
|
|
32
|
+
|
|
33
|
+
#### For Users
|
|
34
|
+
**What changed:** SSE connections now clean up reliably on disconnect, have a 1-hour max lifetime, and a background reaper removes zombie connections every 5 minutes.
|
|
35
|
+
**Breaking changes:** `SSEManager` interface now includes `shutdown()`. `SSEClient` now includes `connectedAt`.
|
|
36
|
+
|
|
37
|
+
## [1.6.10] - 2026-02-07
|
|
38
|
+
|
|
39
|
+
### Documentation
|
|
40
|
+
- **Document all environment variables (PRJ-90)**: Added comprehensive environment variable documentation to README.md covering all 13 env vars used by prjct-cli. Organized into Configuration, JIRA Integration, and Agent Detection categories with defaults, descriptions, and usage examples. Added inline comments at all `process.env` read sites in 6 source files.
|
|
41
|
+
|
|
42
|
+
### Test Plan
|
|
43
|
+
|
|
44
|
+
#### For QA
|
|
45
|
+
1. `bun run build` — should succeed
|
|
46
|
+
2. `bun run lint` — no errors
|
|
47
|
+
3. Verify README.md renders correctly on GitHub (env vars tables)
|
|
48
|
+
|
|
49
|
+
#### For Users
|
|
50
|
+
**What changed:** New "Environment Variables" section in README.md with full documentation of all configurable env vars.
|
|
51
|
+
**Breaking changes:** None.
|
|
52
|
+
|
|
53
|
+
## [1.6.8] - 2026-02-07
|
|
54
|
+
|
|
55
|
+
### Refactoring
|
|
56
|
+
|
|
57
|
+
- standardize export patterns to ESM (PRJ-99) (#132)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
## [1.6.9] - 2026-02-07
|
|
61
|
+
|
|
62
|
+
### Refactor
|
|
63
|
+
- **Standardize export patterns to ESM (PRJ-99)**: Removed redundant `export default { ... }` CJS-compat patterns from 33 files across `core/`. Updated 19 import sites to use namespace imports (`import * as X`). Cleaned 3 barrel re-exports in `agentic/index.ts`, `bus/index.ts`, and `storage/index.ts`. 3 function-collection modules (chain-of-thought, ground-truth, template-loader) retain proper singleton defaults for test mocking compatibility. Net reduction of 274 lines.
|
|
64
|
+
|
|
65
|
+
### Implementation Details
|
|
66
|
+
Removed the redundant pattern where files had both named exports (`export function X`) and a CJS-compat default export object (`export default { X, Y, Z }`). All 33 cleaned files already had proper named exports, making the default objects unnecessary. Import sites referencing removed defaults were converted to `import * as X from` namespace imports, which preserves the `X.method()` usage pattern.
|
|
67
|
+
|
|
68
|
+
### Learnings
|
|
69
|
+
- Bun enforces read-only properties on ESM namespace objects (`import * as X`) — direct property assignment for test mocking fails at runtime
|
|
70
|
+
- Function-collection modules that need test mocking should export a named singleton object as default, consistent with class-instance modules like `pathManager`, `loopDetector`
|
|
71
|
+
- Barrel file (`index.ts`) re-exports of `default` must be updated when removing default exports from source modules
|
|
72
|
+
|
|
73
|
+
### Test Plan
|
|
74
|
+
|
|
75
|
+
#### For QA
|
|
76
|
+
1. Run `bun run build` — should complete with no errors
|
|
77
|
+
2. Run `bun run test` — all 416 tests should pass (1 pre-existing timeout flake in DependencyValidator)
|
|
78
|
+
3. Run `bun run lint` — no lint errors
|
|
79
|
+
4. Run `npx tsc -p core/tsconfig.json --noEmit` — no type errors
|
|
80
|
+
5. Verify `prjct sync --yes` still works end-to-end
|
|
81
|
+
|
|
82
|
+
#### For Users
|
|
83
|
+
**What changed:** Internal refactor only — no API or CLI behavior changes.
|
|
84
|
+
**How to use:** No user action needed.
|
|
85
|
+
**Breaking changes:** None.
|
|
86
|
+
|
|
87
|
+
## [1.6.8] - 2026-02-07
|
|
88
|
+
|
|
89
|
+
### Documentation
|
|
90
|
+
- **Add JSDoc to CachedStore class methods (PRJ-91)**: Enhanced all 12 public/protected methods on the `CachedStore<T>` base class with comprehensive JSDoc including `@param`, `@returns`, `@throws`, `@example`, and `@typeParam` annotations. Improved class-level documentation with usage example and cross-references to subclasses.
|
|
91
|
+
|
|
92
|
+
### Test Plan
|
|
93
|
+
|
|
94
|
+
#### For QA
|
|
95
|
+
1. Build (`bun run build`) — should succeed
|
|
96
|
+
2. Typecheck (`npx tsc -p core/tsconfig.json --noEmit`) — should pass
|
|
97
|
+
3. Verify JSDoc renders in IDE hover tooltips for CachedStore methods
|
|
98
|
+
|
|
99
|
+
#### For Users
|
|
100
|
+
**What changed:** Better IDE documentation for CachedStore internals.
|
|
101
|
+
**Breaking changes:** None
|
|
102
|
+
|
|
103
|
+
|
|
3
104
|
## [1.6.7] - 2026-02-07
|
|
4
105
|
|
|
5
106
|
### Bug Fixes
|
|
@@ -787,7 +888,7 @@ Added visual workflow status template showing:
|
|
|
787
888
|
- add automatic npm publication and update detection system
|
|
788
889
|
- publish prjct-cli to npm registry
|
|
789
890
|
- remove bun and homebrew installation methods
|
|
790
|
-
- add natural language interface with
|
|
891
|
+
- add natural language interface with multi-language support
|
|
791
892
|
- add interactive workflow system with capability detection and installation
|
|
792
893
|
- release v0.3.0 with interactive editor selection and codebase analysis
|
|
793
894
|
- add project management workflows for analyzing, tracking, and fixing tasks
|
|
@@ -810,7 +911,7 @@ Added visual workflow status template showing:
|
|
|
810
911
|
- make Linear/JIRA templates explicitly ignore MCP tools
|
|
811
912
|
- remove MCP inheritance from Linear/JIRA templates
|
|
812
913
|
- standardize confirmation pattern across all commands (#85)
|
|
813
|
-
- LLM
|
|
914
|
+
- LLM must handle the prompts, not the CLI - PRJ-149 (#84)
|
|
814
915
|
- Claude over-plans simple commands like p. sync - PRJ-148 (#83)
|
|
815
916
|
- implement silent memory application - PRJ-103 (#69)
|
|
816
917
|
- ignore tar warning in release workflow - PRJ-147
|
|
@@ -1436,14 +1537,14 @@ Implemented hierarchical agent resolution allowing AGENTS.md files at any direct
|
|
|
1436
1537
|
|
|
1437
1538
|
### Bug Fixes
|
|
1438
1539
|
|
|
1439
|
-
- LLM
|
|
1540
|
+
- LLM must handle the prompts, not the CLI - PRJ-149 (#84)
|
|
1440
1541
|
|
|
1441
1542
|
|
|
1442
1543
|
## [0.55.3] - 2026-01-30
|
|
1443
1544
|
|
|
1444
1545
|
### Fixed
|
|
1445
1546
|
|
|
1446
|
-
- **LLM
|
|
1547
|
+
- **LLM must handle the prompts, not the CLI** (PRJ-149)
|
|
1447
1548
|
- Added `--json` flag to `prjct sync` for non-interactive mode
|
|
1448
1549
|
- CLI now detects non-TTY mode and outputs structured JSON instead of interactive prompts
|
|
1449
1550
|
- Updated `sync.md` template so LLM uses AskUserQuestion for confirmation
|
|
@@ -1653,7 +1754,7 @@ Implemented hierarchical agent resolution allowing AGENTS.md files at any direct
|
|
|
1653
1754
|
### Added
|
|
1654
1755
|
|
|
1655
1756
|
- **Workflow hooks via natural language** (PRJ-137)
|
|
1656
|
-
- Configure hooks with `p. workflow "
|
|
1757
|
+
- Configure hooks with `p. workflow "before ship run the tests"`
|
|
1657
1758
|
- Supports before/after hooks for task, done, ship, sync commands
|
|
1658
1759
|
- Three scopes: permanent (persisted), session, one-time
|
|
1659
1760
|
- Uses existing memory system for storage
|
package/README.md
CHANGED
|
@@ -132,6 +132,52 @@ prjct --version # Show version + provider status
|
|
|
132
132
|
prjct --help # Show help
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
+
## Environment Variables
|
|
136
|
+
|
|
137
|
+
### Configuration
|
|
138
|
+
|
|
139
|
+
| Variable | Default | Description |
|
|
140
|
+
|----------|---------|-------------|
|
|
141
|
+
| `PRJCT_CLI_HOME` | `~/.prjct-cli` | Override global storage location. Useful for tests or sandboxed environments. |
|
|
142
|
+
| `PRJCT_DEBUG` | _(unset)_ | Enable debug logging. Values: `1`, `true`, or a log level (`error`, `warn`, `info`, `debug`). |
|
|
143
|
+
| `DEBUG` | _(unset)_ | Fallback debug flag (used if `PRJCT_DEBUG` is not set). Values: `1`, `true`, or `prjct`. |
|
|
144
|
+
| `CI` | _(unset)_ | Set automatically in CI environments. Skips interactive prompts. |
|
|
145
|
+
|
|
146
|
+
### JIRA Integration
|
|
147
|
+
|
|
148
|
+
| Variable | Default | Description |
|
|
149
|
+
|----------|---------|-------------|
|
|
150
|
+
| `JIRA_BASE_URL` | _(none)_ | JIRA instance URL (e.g., `https://myorg.atlassian.net`). |
|
|
151
|
+
| `JIRA_EMAIL` | _(none)_ | Email for JIRA API authentication. |
|
|
152
|
+
| `JIRA_API_TOKEN` | _(none)_ | API token for JIRA authentication. Generate at [Atlassian API tokens](https://id.atlassian.com/manage-profile/security/api-tokens). |
|
|
153
|
+
|
|
154
|
+
### Agent Detection (Auto-set)
|
|
155
|
+
|
|
156
|
+
These are typically set by the AI agent runtime, not by users:
|
|
157
|
+
|
|
158
|
+
| Variable | Description |
|
|
159
|
+
|----------|-------------|
|
|
160
|
+
| `CLAUDE_AGENT` | Set when running inside Claude Code. |
|
|
161
|
+
| `ANTHROPIC_CLAUDE` | Alternative Claude environment indicator. |
|
|
162
|
+
| `MCP_AVAILABLE` | Set when MCP (Model Context Protocol) is available. |
|
|
163
|
+
| `HOME` / `USERPROFILE` | Standard OS home directory (used for path resolution). |
|
|
164
|
+
|
|
165
|
+
### Usage Examples
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# Enable debug logging
|
|
169
|
+
PRJCT_DEBUG=1 prjct sync
|
|
170
|
+
|
|
171
|
+
# Use a custom storage location
|
|
172
|
+
PRJCT_CLI_HOME=/tmp/prjct-test prjct init
|
|
173
|
+
|
|
174
|
+
# Configure JIRA integration via env vars
|
|
175
|
+
export JIRA_BASE_URL=https://myorg.atlassian.net
|
|
176
|
+
export JIRA_EMAIL=you@example.com
|
|
177
|
+
export JIRA_API_TOKEN=your-api-token
|
|
178
|
+
prjct jira setup
|
|
179
|
+
```
|
|
180
|
+
|
|
135
181
|
## Requirements
|
|
136
182
|
|
|
137
183
|
- Node.js 18+ or Bun 1.0+
|
|
@@ -229,4 +229,6 @@ function formatPlan(result: ReasoningResult): string {
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
export { requiresReasoning, reason, formatPlan, REASONING_REQUIRED_COMMANDS }
|
|
232
|
-
|
|
232
|
+
|
|
233
|
+
const chainOfThought = { requiresReasoning, reason, formatPlan, REASONING_REQUIRED_COMMANDS }
|
|
234
|
+
export default chainOfThought
|
|
@@ -686,14 +686,21 @@ export function requiresVerification(commandName: string): boolean {
|
|
|
686
686
|
return ['done', 'ship', 'feature', 'spec', 'now', 'init', 'sync', 'analyze'].includes(commandName)
|
|
687
687
|
}
|
|
688
688
|
|
|
689
|
-
|
|
690
|
-
// Default Export
|
|
691
|
-
// =============================================================================
|
|
692
|
-
|
|
693
|
-
export default {
|
|
689
|
+
const groundTruth = {
|
|
694
690
|
verify,
|
|
695
691
|
prepareCommand,
|
|
696
692
|
requiresVerification,
|
|
697
693
|
verifiers,
|
|
698
694
|
formatWarnings,
|
|
695
|
+
formatDuration,
|
|
696
|
+
escapeRegex,
|
|
697
|
+
verifyDone,
|
|
698
|
+
verifyShip,
|
|
699
|
+
verifyFeature,
|
|
700
|
+
verifyNow,
|
|
701
|
+
verifyInit,
|
|
702
|
+
verifySync,
|
|
703
|
+
verifyAnalyze,
|
|
704
|
+
verifySpec,
|
|
699
705
|
}
|
|
706
|
+
export default groundTruth
|
package/core/agentic/index.ts
CHANGED
|
@@ -104,7 +104,13 @@ export type {
|
|
|
104
104
|
export { default as AgentRouter } from './agent-router'
|
|
105
105
|
// ============ Utilities ============
|
|
106
106
|
// Chain of thought, services
|
|
107
|
-
export {
|
|
107
|
+
export {
|
|
108
|
+
default as chainOfThought,
|
|
109
|
+
formatPlan,
|
|
110
|
+
REASONING_REQUIRED_COMMANDS,
|
|
111
|
+
reason,
|
|
112
|
+
requiresReasoning,
|
|
113
|
+
} from './chain-of-thought'
|
|
108
114
|
// ============ Execution ============
|
|
109
115
|
// Command execution, loop detection
|
|
110
116
|
export {
|
|
@@ -174,7 +180,13 @@ export { default as promptBuilder } from './prompt-builder'
|
|
|
174
180
|
export { default as services } from './services'
|
|
175
181
|
export { default as smartContext } from './smart-context'
|
|
176
182
|
export { default as templateExecutor, TemplateExecutor } from './template-executor'
|
|
177
|
-
export {
|
|
183
|
+
export {
|
|
184
|
+
clearCache,
|
|
185
|
+
default as templateLoader,
|
|
186
|
+
getAllowedTools,
|
|
187
|
+
load,
|
|
188
|
+
parseFrontmatter,
|
|
189
|
+
} from './template-loader'
|
|
178
190
|
// ============ Tools ============
|
|
179
191
|
// Tool and template management
|
|
180
192
|
export { default as toolRegistry } from './tool-registry'
|
|
@@ -65,17 +65,26 @@ import { calculateConfidence, MEMORY_TAGS } from '../types/memory'
|
|
|
65
65
|
// =============================================================================
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
*
|
|
68
|
+
* Abstract base class for project-scoped, disk-backed stores with in-memory caching.
|
|
69
69
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
70
|
+
* Provides lazy loading, automatic directory creation on save, and project-scoped
|
|
71
|
+
* cache invalidation. Subclasses only need to define the filename, default data
|
|
72
|
+
* structure, and optionally a subdirectory or post-load normalization hook.
|
|
73
73
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* -
|
|
77
|
-
*
|
|
78
|
-
*
|
|
74
|
+
* Extended by {@link PatternStore} and {@link SemanticMemories}.
|
|
75
|
+
*
|
|
76
|
+
* @typeParam T - The shape of the stored data (e.g., `Patterns`, `MemoryDatabase`)
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* class MyStore extends CachedStore<MyData> {
|
|
81
|
+
* protected getFilename() { return 'my-data.json' }
|
|
82
|
+
* protected getDefault() { return { items: [] } }
|
|
83
|
+
* }
|
|
84
|
+
*
|
|
85
|
+
* const store = new MyStore()
|
|
86
|
+
* const data = await store.load('project-id')
|
|
87
|
+
* ```
|
|
79
88
|
*/
|
|
80
89
|
export abstract class CachedStore<T> {
|
|
81
90
|
private _data: T | null = null
|
|
@@ -83,24 +92,33 @@ export abstract class CachedStore<T> {
|
|
|
83
92
|
private _projectId: string | null = null
|
|
84
93
|
|
|
85
94
|
/**
|
|
86
|
-
*
|
|
95
|
+
* Return the filename for this store (e.g., `'patterns.json'`).
|
|
96
|
+
* @returns The JSON filename used for disk persistence
|
|
87
97
|
*/
|
|
88
98
|
protected abstract getFilename(): string
|
|
89
99
|
|
|
90
100
|
/**
|
|
91
|
-
*
|
|
101
|
+
* Return the default data structure when the file does not exist on disk.
|
|
102
|
+
* @returns A fresh default instance of `T`
|
|
92
103
|
*/
|
|
93
104
|
protected abstract getDefault(): T
|
|
94
105
|
|
|
95
106
|
/**
|
|
96
|
-
* Optional
|
|
107
|
+
* Optional subdirectory within the project's `memory/` folder.
|
|
108
|
+
* Override to nest the store file under a subfolder.
|
|
109
|
+
*
|
|
110
|
+
* @returns Subdirectory name, or `null` to store directly in `memory/`
|
|
97
111
|
*/
|
|
98
112
|
protected getSubdirectory(): string | null {
|
|
99
113
|
return null
|
|
100
114
|
}
|
|
101
115
|
|
|
102
116
|
/**
|
|
103
|
-
*
|
|
117
|
+
* Build the full filesystem path for this store's JSON file.
|
|
118
|
+
*
|
|
119
|
+
* @param projectId - The project identifier used for path resolution
|
|
120
|
+
* @returns Absolute path to the store file
|
|
121
|
+
* (e.g., `~/.prjct-cli/projects/{id}/memory/patterns.json`)
|
|
104
122
|
*/
|
|
105
123
|
protected getPath(projectId: string): string {
|
|
106
124
|
const basePath = path.join(pathManager.getGlobalProjectPath(projectId), 'memory')
|
|
@@ -114,8 +132,20 @@ export abstract class CachedStore<T> {
|
|
|
114
132
|
}
|
|
115
133
|
|
|
116
134
|
/**
|
|
117
|
-
* Load data from disk
|
|
118
|
-
*
|
|
135
|
+
* Load data from disk with project-scoped caching.
|
|
136
|
+
*
|
|
137
|
+
* Returns cached data immediately if already loaded for the same project.
|
|
138
|
+
* Otherwise reads from disk, falling back to {@link getDefault} when the
|
|
139
|
+
* file does not exist. Calls {@link afterLoad} after a successful disk read.
|
|
140
|
+
*
|
|
141
|
+
* @param projectId - The project identifier
|
|
142
|
+
* @returns The loaded (or cached) data
|
|
143
|
+
* @throws {Error} If the file read fails for reasons other than ENOENT
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* const patterns = await patternStore.load('my-project-id')
|
|
148
|
+
* ```
|
|
119
149
|
*/
|
|
120
150
|
async load(projectId: string): Promise<T> {
|
|
121
151
|
// Return cached if same project and loaded
|
|
@@ -146,15 +176,25 @@ export abstract class CachedStore<T> {
|
|
|
146
176
|
}
|
|
147
177
|
|
|
148
178
|
/**
|
|
149
|
-
* Hook for subclasses to normalize data after loading
|
|
150
|
-
*
|
|
179
|
+
* Hook for subclasses to normalize or migrate data after loading from disk.
|
|
180
|
+
*
|
|
181
|
+
* Called once per disk read (not on cache hits). Override to ensure
|
|
182
|
+
* structural invariants — e.g., adding missing index keys.
|
|
183
|
+
*
|
|
184
|
+
* @param _data - The freshly loaded data to normalize (mutate in place)
|
|
151
185
|
*/
|
|
152
186
|
protected afterLoad(_data: T): void {
|
|
153
187
|
// Override in subclass if needed
|
|
154
188
|
}
|
|
155
189
|
|
|
156
190
|
/**
|
|
157
|
-
*
|
|
191
|
+
* Persist the current in-memory data to disk.
|
|
192
|
+
*
|
|
193
|
+
* Creates parent directories automatically if they don't exist.
|
|
194
|
+
* No-op if no data has been loaded yet.
|
|
195
|
+
*
|
|
196
|
+
* @param projectId - The project identifier for path resolution
|
|
197
|
+
* @throws {Error} If the file write fails
|
|
158
198
|
*/
|
|
159
199
|
async save(projectId: string): Promise<void> {
|
|
160
200
|
if (!this._data) return
|
|
@@ -165,21 +205,39 @@ export abstract class CachedStore<T> {
|
|
|
165
205
|
}
|
|
166
206
|
|
|
167
207
|
/**
|
|
168
|
-
*
|
|
208
|
+
* Access the cached data without triggering a disk read.
|
|
209
|
+
*
|
|
210
|
+
* @returns The cached data, or `null` if nothing has been loaded
|
|
169
211
|
*/
|
|
170
212
|
protected getData(): T | null {
|
|
171
213
|
return this._data
|
|
172
214
|
}
|
|
173
215
|
|
|
174
216
|
/**
|
|
175
|
-
*
|
|
217
|
+
* Replace the in-memory data directly. Does not persist to disk —
|
|
218
|
+
* call {@link save} afterwards if persistence is needed.
|
|
219
|
+
*
|
|
220
|
+
* @param data - The new data to cache
|
|
176
221
|
*/
|
|
177
222
|
protected setData(data: T): void {
|
|
178
223
|
this._data = data
|
|
179
224
|
}
|
|
180
225
|
|
|
181
226
|
/**
|
|
182
|
-
*
|
|
227
|
+
* Atomically load, transform, and save data in one operation.
|
|
228
|
+
*
|
|
229
|
+
* @param projectId - The project identifier
|
|
230
|
+
* @param updater - Pure function that receives current data and returns updated data
|
|
231
|
+
* @returns The updated data after saving
|
|
232
|
+
* @throws {Error} If load or save fails
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* await store.update('my-project', (data) => ({
|
|
237
|
+
* ...data,
|
|
238
|
+
* count: data.count + 1,
|
|
239
|
+
* }))
|
|
240
|
+
* ```
|
|
183
241
|
*/
|
|
184
242
|
async update(projectId: string, updater: (data: T) => T): Promise<T> {
|
|
185
243
|
const data = await this.load(projectId)
|
|
@@ -190,7 +248,11 @@ export abstract class CachedStore<T> {
|
|
|
190
248
|
}
|
|
191
249
|
|
|
192
250
|
/**
|
|
193
|
-
* Check
|
|
251
|
+
* Check whether data has been loaded into the cache.
|
|
252
|
+
*
|
|
253
|
+
* @param projectId - If provided, checks that data is loaded for this specific project.
|
|
254
|
+
* If omitted, returns `true` if any project's data is cached.
|
|
255
|
+
* @returns `true` if data is loaded (and matches the project, when specified)
|
|
194
256
|
*/
|
|
195
257
|
isLoaded(projectId?: string): boolean {
|
|
196
258
|
if (projectId) {
|
|
@@ -200,7 +262,8 @@ export abstract class CachedStore<T> {
|
|
|
200
262
|
}
|
|
201
263
|
|
|
202
264
|
/**
|
|
203
|
-
*
|
|
265
|
+
* Clear the in-memory cache, forcing a fresh disk read on the next {@link load} call.
|
|
266
|
+
* Does not delete or modify the file on disk.
|
|
204
267
|
*/
|
|
205
268
|
reset(): void {
|
|
206
269
|
this._data = null
|
package/core/agentic/services.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* import { services } from './services'
|
|
13
13
|
*
|
|
14
14
|
* // Instead of:
|
|
15
|
-
* import templateLoader from './template-loader'
|
|
15
|
+
* import * as templateLoader from './template-loader'
|
|
16
16
|
* import contextBuilder from './context-builder'
|
|
17
17
|
* // ... 12 more imports
|
|
18
18
|
*
|
|
@@ -208,11 +208,11 @@ You are executing a prjct command as ${context.agentName}. Follow the template-f
|
|
|
208
208
|
b) What technologies exist in this project
|
|
209
209
|
c) What agents are available in ${context.paths.agentsDir}
|
|
210
210
|
|
|
211
|
-
- **
|
|
212
|
-
(
|
|
211
|
+
- **IMPORTANT**: The agents in ${context.paths.agentsDir} are already project-specific
|
|
212
|
+
(they were generated during p. sync with the actual project technologies)
|
|
213
213
|
|
|
214
|
-
-
|
|
215
|
-
-
|
|
214
|
+
- ALWAYS use the specialist if one exists for the domain
|
|
215
|
+
- Only use the generalist if there is NO agent for that domain
|
|
216
216
|
|
|
217
217
|
- Check if task should be fragmented (read: ${context.paths.taskFragmentation})
|
|
218
218
|
- If agents loaded, check their skills and load from ${context.paths.skillsDir}
|
|
@@ -105,11 +105,5 @@ export function clearCache(): void {
|
|
|
105
105
|
cacheOrder.length = 0
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
export default {
|
|
111
|
-
load,
|
|
112
|
-
parseFrontmatter,
|
|
113
|
-
getAllowedTools,
|
|
114
|
-
clearCache,
|
|
115
|
-
}
|
|
108
|
+
const templateLoader = { load, parseFrontmatter, getAllowedTools, clearCache }
|
|
109
|
+
export default templateLoader
|
|
@@ -13,19 +13,12 @@ import { exec } from 'node:child_process'
|
|
|
13
13
|
import os from 'node:os'
|
|
14
14
|
import path from 'node:path'
|
|
15
15
|
import { promisify } from 'node:util'
|
|
16
|
+
import type { AIToolConfig } from '../types'
|
|
16
17
|
import { fileExists } from '../utils/fs-helpers'
|
|
17
18
|
|
|
18
19
|
const execAsync = promisify(exec)
|
|
19
20
|
|
|
20
|
-
export
|
|
21
|
-
id: string
|
|
22
|
-
name: string
|
|
23
|
-
outputFile: string
|
|
24
|
-
outputPath: 'repo' | 'global' // 'repo' = project root, 'global' = ~/.prjct-cli/projects/{id}/context/
|
|
25
|
-
maxTokens: number
|
|
26
|
-
format: 'detailed' | 'concise' | 'minimal' | 'json'
|
|
27
|
-
description: string
|
|
28
|
-
}
|
|
21
|
+
export type { AIToolConfig } from '../types'
|
|
29
22
|
|
|
30
23
|
/**
|
|
31
24
|
* Supported AI tools registry
|
package/core/bus/bus.ts
CHANGED
package/core/bus/index.ts
CHANGED
package/core/cli/start.ts
CHANGED
package/core/commands/base.ts
CHANGED
|
@@ -20,9 +20,9 @@ import type {
|
|
|
20
20
|
CommandResult,
|
|
21
21
|
ProjectContext,
|
|
22
22
|
} from '../types'
|
|
23
|
-
import dateHelper from '../utils/date-helper'
|
|
23
|
+
import * as dateHelper from '../utils/date-helper'
|
|
24
24
|
import * as fileHelper from '../utils/file-helper'
|
|
25
|
-
import jsonlHelper from '../utils/jsonl-helper'
|
|
25
|
+
import * as jsonlHelper from '../utils/jsonl-helper'
|
|
26
26
|
import out from '../utils/output'
|
|
27
27
|
|
|
28
28
|
/**
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import path from 'node:path'
|
|
7
|
-
import authorDetector from '../infrastructure/author-detector'
|
|
7
|
+
import * as authorDetector from '../infrastructure/author-detector'
|
|
8
8
|
import commandInstaller from '../infrastructure/command-installer'
|
|
9
9
|
import { generateUUID } from '../schemas'
|
|
10
10
|
import type { Priority, TaskSection, TaskType } from '../schemas/state'
|
|
11
11
|
import { ideasStorage, queueStorage } from '../storage'
|
|
12
|
-
import type { CommandResult, ProjectContext } from '../types'
|
|
12
|
+
import type { CommandResult, InitOptions, ProjectContext } from '../types'
|
|
13
13
|
import { getErrorMessage } from '../types/fs'
|
|
14
14
|
import { showNextSteps } from '../utils/next-steps'
|
|
15
15
|
import { OnboardingWizard } from '../wizard'
|
|
@@ -34,10 +34,7 @@ async function getAnalysisCommands(): Promise<import('./analysis').AnalysisComma
|
|
|
34
34
|
return _analysisCommands
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export
|
|
38
|
-
yes?: boolean // Skip interactive wizard, use defaults
|
|
39
|
-
idea?: string | null // Initial idea for architect mode
|
|
40
|
-
}
|
|
37
|
+
export type { InitOptions } from '../types'
|
|
41
38
|
|
|
42
39
|
export class PlanningCommands extends PrjctCommandsBase {
|
|
43
40
|
/**
|
|
@@ -71,6 +68,7 @@ export class PlanningCommands extends PrjctCommandsBase {
|
|
|
71
68
|
|
|
72
69
|
// Determine if we should run interactive wizard
|
|
73
70
|
const isTTY = process.stdout.isTTY && process.stdin.isTTY
|
|
71
|
+
// CI: Skip interactive prompts in CI environments
|
|
74
72
|
const skipWizard = opts.yes || !isTTY || process.env.CI === 'true'
|
|
75
73
|
|
|
76
74
|
// Run wizard if interactive
|
package/core/constants/index.ts
CHANGED
|
@@ -323,6 +323,25 @@ export const EVENT_LIMITS = {
|
|
|
323
323
|
HISTORY_MAX: 100,
|
|
324
324
|
} as const
|
|
325
325
|
|
|
326
|
+
// =============================================================================
|
|
327
|
+
// Workflow Help Strings (user-facing, no magic strings)
|
|
328
|
+
// =============================================================================
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Example commands shown in workflow preferences help.
|
|
332
|
+
* Keeps UI copy in English and centralized.
|
|
333
|
+
*/
|
|
334
|
+
export const WORKFLOW_HELP = {
|
|
335
|
+
/** Message when no workflow preferences are configured */
|
|
336
|
+
NO_PREFERENCES: 'No workflow preferences configured.',
|
|
337
|
+
/** Example: set a before-ship hook to run tests */
|
|
338
|
+
SET_EXAMPLE: 'p. workflow before ship run the tests',
|
|
339
|
+
/** Example: modify workflow to run npm test */
|
|
340
|
+
MODIFY_EXAMPLE: 'p. workflow before ship run npm test',
|
|
341
|
+
/** Example: remove the ship hook */
|
|
342
|
+
REMOVE_EXAMPLE: 'p. workflow remove the ship hook',
|
|
343
|
+
} as const
|
|
344
|
+
|
|
326
345
|
// =============================================================================
|
|
327
346
|
// Combined Exports
|
|
328
347
|
// =============================================================================
|
|
@@ -575,9 +575,3 @@ function isTestFile(filePath: string): boolean {
|
|
|
575
575
|
lower.endsWith('_test.py')
|
|
576
576
|
)
|
|
577
577
|
}
|
|
578
|
-
|
|
579
|
-
// =============================================================================
|
|
580
|
-
// Exports
|
|
581
|
-
// =============================================================================
|
|
582
|
-
|
|
583
|
-
export default { findRelevantFiles }
|
|
@@ -395,9 +395,3 @@ async function buildDependencyTree(
|
|
|
395
395
|
|
|
396
396
|
return node
|
|
397
397
|
}
|
|
398
|
-
|
|
399
|
-
// =============================================================================
|
|
400
|
-
// Exports
|
|
401
|
-
// =============================================================================
|
|
402
|
-
|
|
403
|
-
export default { analyzeImports }
|
|
@@ -299,9 +299,3 @@ function shouldIgnore(filePath: string): boolean {
|
|
|
299
299
|
|
|
300
300
|
return false
|
|
301
301
|
}
|
|
302
|
-
|
|
303
|
-
// =============================================================================
|
|
304
|
-
// Exports
|
|
305
|
-
// =============================================================================
|
|
306
|
-
|
|
307
|
-
export default { getRecentFiles }
|