prjct-cli 0.31.0 → 0.33.5
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 +118 -0
- package/CLAUDE.md +41 -0
- package/core/__tests__/agentic/memory-system.test.ts +2 -2
- package/core/__tests__/types/fs.test.ts +125 -0
- package/core/agentic/agent-router.ts +16 -4
- package/core/agentic/chain-of-thought.ts +4 -12
- package/core/agentic/command-executor.ts +10 -11
- package/core/agentic/context-builder.ts +24 -10
- package/core/agentic/ground-truth.ts +139 -55
- package/core/agentic/prompt-builder.ts +20 -7
- package/core/agentic/smart-context.ts +1 -1
- package/core/agentic/template-loader.ts +1 -1
- package/core/agentic/tool-registry.ts +4 -2
- package/core/bus/bus.ts +1 -1
- package/core/commands/cleanup.ts +24 -8
- package/core/commands/planning.ts +4 -2
- package/core/commands/setup.ts +4 -4
- package/core/commands/shipping.ts +34 -8
- package/core/commands/snapshots.ts +27 -13
- package/core/context/generator.ts +9 -5
- package/core/domain/agent-generator.ts +1 -1
- package/core/domain/agent-loader.ts +1 -1
- package/core/domain/analyzer.ts +76 -31
- package/core/domain/context-estimator.ts +1 -1
- package/core/domain/snapshot-manager.ts +55 -21
- package/core/domain/task-stack.ts +16 -7
- package/core/infrastructure/author-detector.ts +1 -1
- package/core/infrastructure/claude-agent.ts +12 -8
- package/core/infrastructure/command-installer.ts +42 -21
- package/core/infrastructure/editors-config.ts +1 -1
- package/core/infrastructure/path-manager.ts +27 -2
- package/core/infrastructure/permission-manager.ts +1 -1
- package/core/infrastructure/setup.ts +31 -13
- package/core/infrastructure/update-checker.ts +5 -5
- package/core/integrations/jira/client.ts +91 -30
- package/core/integrations/jira/index.ts +29 -5
- package/core/integrations/jira/mcp-adapter.ts +451 -0
- package/core/integrations/linear/client.ts +23 -3
- package/core/plugin/loader.ts +16 -6
- package/core/plugin/registry.ts +16 -6
- package/core/server/routes-extended.ts +13 -6
- package/core/server/routes.ts +15 -5
- package/core/server/sse.ts +4 -3
- package/core/services/agent-service.ts +4 -2
- package/core/services/memory-service.ts +16 -5
- package/core/services/project-service.ts +11 -2
- package/core/services/skill-service.ts +4 -3
- package/core/session/compaction.ts +4 -5
- package/core/session/metrics.ts +11 -4
- package/core/session/task-session-manager.ts +27 -9
- package/core/storage/storage-manager.ts +12 -5
- package/core/storage/storage.ts +26 -10
- package/core/sync/auth-config.ts +2 -2
- package/core/sync/oauth-handler.ts +1 -1
- package/core/sync/sync-client.ts +4 -2
- package/core/sync/sync-manager.ts +1 -1
- package/core/types/agentic.ts +8 -18
- package/core/types/config.ts +1 -1
- package/core/types/index.ts +3 -2
- package/core/types/integrations.ts +4 -48
- package/core/types/storage.ts +0 -8
- package/core/types/task.ts +0 -4
- package/core/utils/file-helper.ts +10 -4
- package/core/utils/jsonl-helper.ts +4 -4
- package/core/utils/keychain.ts +130 -0
- package/core/utils/logger.ts +27 -25
- package/core/utils/runtime.ts +1 -1
- package/core/utils/session-helper.ts +4 -4
- package/core/utils/version.ts +1 -1
- package/dist/bin/prjct.mjs +1 -1
- package/package.json +1 -1
- package/packages/shared/src/utils.ts +1 -1
- package/templates/commands/enrich.md +601 -195
- package/templates/commands/github.md +231 -0
- package/templates/commands/init.md +45 -26
- package/templates/commands/jira.md +161 -261
- package/templates/commands/linear.md +159 -177
- package/templates/commands/monday.md +196 -0
- package/templates/commands/setup.md +4 -1
- package/templates/mcp-config.json +42 -39
- package/core/integrations/notion/client.ts +0 -413
- package/core/integrations/notion/index.ts +0 -46
- package/core/integrations/notion/setup.ts +0 -235
- package/core/integrations/notion/sync.ts +0 -818
- package/core/integrations/notion/templates.ts +0 -246
- package/core/plugin/builtin/notion.ts +0 -178
- package/templates/skills/notion-push.md +0 -116
- package/templates/skills/notion-setup.md +0 -199
- package/templates/skills/notion-sync.md +0 -290
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,123 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.33.5] - 2026-01-13
|
|
4
|
+
|
|
5
|
+
### Fix: Type Safety Improvements (PRJ-54)
|
|
6
|
+
|
|
7
|
+
Remove unsafe `as unknown` type casts with proper TypeScript interfaces.
|
|
8
|
+
|
|
9
|
+
**Changes:**
|
|
10
|
+
- `GroundTruthContext` now uses `ContextPaths` directly
|
|
11
|
+
- `chain-of-thought.ts` uses `Pick<ProjectContext, ...>` type alias
|
|
12
|
+
- `command-executor.ts` uses `PromptContext` instead of `Record<string, unknown>`
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## [0.33.4] - 2026-01-13
|
|
17
|
+
|
|
18
|
+
### Refactor: Error Type Differentiation Phase 3 (PRJ-61)
|
|
19
|
+
|
|
20
|
+
**Final phase** - Complete error differentiation across all 116 remaining catch blocks in 52 files.
|
|
21
|
+
|
|
22
|
+
**Pattern Applied:**
|
|
23
|
+
- `isNotFoundError()` for expected ENOENT errors
|
|
24
|
+
- `instanceof SyntaxError` for JSON parse errors
|
|
25
|
+
- `_error` capture for intentional catch-all blocks (network, git, etc.)
|
|
26
|
+
- Unexpected errors propagate with `throw error`
|
|
27
|
+
|
|
28
|
+
**Key Files Fixed:**
|
|
29
|
+
- `core/storage/storage.ts` - Storage read/exists operations
|
|
30
|
+
- `core/commands/shipping.ts` - Ship workflow error handling
|
|
31
|
+
- `core/session/task-session-manager.ts` - Session management
|
|
32
|
+
- `core/commands/cleanup.ts` - Cleanup operations
|
|
33
|
+
- `core/agentic/context-builder.ts` - Context building
|
|
34
|
+
- Plus 47 more files
|
|
35
|
+
|
|
36
|
+
**Stats:**
|
|
37
|
+
- Catches fixed this phase: 116
|
|
38
|
+
- Total fixed (Phase 1+2+3): 185
|
|
39
|
+
- Remaining: 0 empty catches
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## [0.33.3] - 2026-01-13
|
|
44
|
+
|
|
45
|
+
### Refactor: Error Type Differentiation Phase 2 (PRJ-60)
|
|
46
|
+
|
|
47
|
+
**Continuation of PRJ-51** - Differentiate error types in 3 more files (14 catch blocks):
|
|
48
|
+
|
|
49
|
+
**Files Modified:**
|
|
50
|
+
- `core/domain/snapshot-manager.ts` - 6 catches (fs.access, fs.readFile, fs.unlink, JSON.parse)
|
|
51
|
+
- `core/server/routes-extended.ts` - 2 catches (readJsonFile, writeJsonFile helpers)
|
|
52
|
+
- `core/infrastructure/setup.ts` - 6 catches (migration, settings parsing, status line)
|
|
53
|
+
|
|
54
|
+
**Pattern Applied:**
|
|
55
|
+
- ENOENT errors → handled gracefully (expected for missing files)
|
|
56
|
+
- SyntaxError → handled gracefully (expected for malformed JSON)
|
|
57
|
+
- Other errors → propagated or logged (unexpected)
|
|
58
|
+
|
|
59
|
+
**Stats:**
|
|
60
|
+
- Catches fixed: 14
|
|
61
|
+
- Total fixed (Phase 1+2): 69
|
|
62
|
+
- Remaining: ~211 catches in 63 files
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## [0.33.2] - 2026-01-13
|
|
67
|
+
|
|
68
|
+
### Refactor: Error Type Differentiation (PRJ-51)
|
|
69
|
+
|
|
70
|
+
**Problem:** 280 catch blocks across 69 files used empty `catch {}` which swallowed all errors without differentiating between expected (ENOENT) and unexpected errors.
|
|
71
|
+
|
|
72
|
+
**Solution:** Phase 1 implementation - differentiate error types in 3 priority files (55 catch blocks):
|
|
73
|
+
|
|
74
|
+
**Pattern Applied:**
|
|
75
|
+
```typescript
|
|
76
|
+
// Before
|
|
77
|
+
} catch { return null }
|
|
78
|
+
|
|
79
|
+
// After
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (isNotFoundError(error)) return null // Expected: file doesn't exist
|
|
82
|
+
if (error instanceof SyntaxError) return null // Expected: invalid JSON
|
|
83
|
+
throw error // Unexpected: propagate
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Files Modified:**
|
|
88
|
+
- `core/agentic/ground-truth.ts` - 21 catches (verification functions)
|
|
89
|
+
- `core/domain/analyzer.ts` - 18 catches (codebase analysis)
|
|
90
|
+
- `core/infrastructure/command-installer.ts` - 16 catches (command management)
|
|
91
|
+
|
|
92
|
+
**Tests Added:**
|
|
93
|
+
- `core/__tests__/types/fs.test.ts` - 15 new tests for error utilities
|
|
94
|
+
|
|
95
|
+
**Stats:**
|
|
96
|
+
- Tests: 137 → 152 (+15)
|
|
97
|
+
- Catches fixed: 55
|
|
98
|
+
- Files: 4 (3 refactored + 1 test)
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## [0.33.1] - 2026-01-13
|
|
103
|
+
|
|
104
|
+
### Refactor: Code Quality Improvements
|
|
105
|
+
|
|
106
|
+
**PRJ-58: Consolidate hardcoded paths to pathManager**
|
|
107
|
+
- Added `getClaudeDir()`, `getClaudeCommandsDir()`, `getClaudeSettingsPath()` to pathManager
|
|
108
|
+
- Refactored 6 files to use centralized path methods instead of `os.homedir()` concatenation
|
|
109
|
+
- Files: `compaction.ts`, `generator.ts`, `routes-extended.ts`, `routes.ts`, `auth-config.ts`, `setup.ts`
|
|
110
|
+
|
|
111
|
+
**PRJ-57: Simplify logger level detection**
|
|
112
|
+
- Use `Set` for truthy values instead of multiple OR conditions
|
|
113
|
+
- Remove redundant `'prjct'` equality check (covered by `includes`)
|
|
114
|
+
- Use nullish coalescing (`??`) instead of ternary
|
|
115
|
+
- Pre-compute level name to avoid runtime lookup
|
|
116
|
+
- Add `createLogMethod()` factory to reduce repetition
|
|
117
|
+
- File: `core/utils/logger.ts`
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
3
121
|
## [0.30.3] - 2026-01-13
|
|
4
122
|
|
|
5
123
|
### Fix: Enrichment Not Enabled by Default
|
package/CLAUDE.md
CHANGED
|
@@ -91,6 +91,7 @@ User Action → Storage (JSON) → Context (MD) → Sync Events
|
|
|
91
91
|
|
|
92
92
|
## COMMANDS
|
|
93
93
|
|
|
94
|
+
### Core Workflow
|
|
94
95
|
| Trigger | Purpose |
|
|
95
96
|
|---------|---------|
|
|
96
97
|
| `p. init` | Initialize project with deep analysis |
|
|
@@ -102,11 +103,51 @@ User Action → Storage (JSON) → Context (MD) → Sync Events
|
|
|
102
103
|
| `p. resume` | Resume paused task |
|
|
103
104
|
| `p. bug <desc>` | Report bug with auto-priority |
|
|
104
105
|
|
|
106
|
+
### Issue Tracker Integrations
|
|
107
|
+
| Trigger | Purpose |
|
|
108
|
+
|---------|---------|
|
|
109
|
+
| `p. linear` | Linear issues (OAuth via MCP) |
|
|
110
|
+
| `p. jira` | JIRA issues (OAuth/SSO via MCP) |
|
|
111
|
+
| `p. github` | GitHub Issues (token via MCP) |
|
|
112
|
+
| `p. monday` | Monday.com boards (OAuth via MCP) |
|
|
113
|
+
| `p. enrich <ID>` | **AI-powered ticket enrichment** |
|
|
114
|
+
|
|
115
|
+
### Ticket Enrichment (`p. enrich`)
|
|
116
|
+
|
|
117
|
+
Transform vague PM tickets into technical PRDs:
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
PM creates: "Add user auth"
|
|
121
|
+
↓
|
|
122
|
+
p. enrich PRJ-59
|
|
123
|
+
↓
|
|
124
|
+
Architect analyzes codebase:
|
|
125
|
+
- Similar implementations found
|
|
126
|
+
- 5 files affected
|
|
127
|
+
- OAuth2 approach recommended
|
|
128
|
+
- 8 story points (not PM's guess of 2)
|
|
129
|
+
↓
|
|
130
|
+
Publishes PRD to tracker:
|
|
131
|
+
- Technical approach
|
|
132
|
+
- Acceptance criteria
|
|
133
|
+
- LLM-ready prompt (for any AI tool)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Subcommands:**
|
|
137
|
+
- `p. enrich <ID>` - Enrich specific ticket
|
|
138
|
+
- `p. enrich setup` - Configure team preferences (estimation, output)
|
|
139
|
+
- `p. enrich batch` - Enrich all assigned tickets (backlog grooming)
|
|
140
|
+
|
|
105
141
|
### Workflow
|
|
106
142
|
```
|
|
107
143
|
p. sync → p. task "description" → [work] → p. done → p. ship
|
|
108
144
|
```
|
|
109
145
|
|
|
146
|
+
### With Issue Tracker
|
|
147
|
+
```
|
|
148
|
+
p. linear → p. enrich PRJ-59 → p. linear start PRJ-59 → [work] → p. done → p. ship
|
|
149
|
+
```
|
|
150
|
+
|
|
110
151
|
---
|
|
111
152
|
|
|
112
153
|
## INTELLIGENT BEHAVIOR
|
|
@@ -253,7 +253,7 @@ describe('MemorySystem P3.3', () => {
|
|
|
253
253
|
try {
|
|
254
254
|
const testPath = pathManager.getGlobalProjectPath(TEST_PROJECT_ID)
|
|
255
255
|
await fs.rm(testPath, { recursive: true, force: true })
|
|
256
|
-
} catch {
|
|
256
|
+
} catch (_error) {
|
|
257
257
|
// Ignore cleanup errors
|
|
258
258
|
}
|
|
259
259
|
})
|
|
@@ -261,7 +261,7 @@ describe('MemorySystem P3.3', () => {
|
|
|
261
261
|
afterAll(async () => {
|
|
262
262
|
try {
|
|
263
263
|
await fs.rm(TEST_GLOBAL_BASE_DIR, { recursive: true, force: true })
|
|
264
|
-
} catch {
|
|
264
|
+
} catch (_error) {
|
|
265
265
|
// Ignore cleanup errors
|
|
266
266
|
}
|
|
267
267
|
})
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FS Types Tests
|
|
3
|
+
* Tests for file system error utilities
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect } from 'bun:test'
|
|
7
|
+
import {
|
|
8
|
+
isNotFoundError,
|
|
9
|
+
isPermissionError,
|
|
10
|
+
isDirNotEmptyError,
|
|
11
|
+
isFileExistsError,
|
|
12
|
+
isNodeError,
|
|
13
|
+
} from '../../types/fs'
|
|
14
|
+
|
|
15
|
+
describe('FS Error Utilities', () => {
|
|
16
|
+
describe('isNotFoundError', () => {
|
|
17
|
+
it('should return true for ENOENT error', () => {
|
|
18
|
+
const error = new Error('File not found') as NodeJS.ErrnoException
|
|
19
|
+
error.code = 'ENOENT'
|
|
20
|
+
expect(isNotFoundError(error)).toBe(true)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should return false for other error codes', () => {
|
|
24
|
+
const error = new Error('Permission denied') as NodeJS.ErrnoException
|
|
25
|
+
error.code = 'EACCES'
|
|
26
|
+
expect(isNotFoundError(error)).toBe(false)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('should return false for errors without code', () => {
|
|
30
|
+
const error = new Error('Generic error')
|
|
31
|
+
expect(isNotFoundError(error)).toBe(false)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should return false for non-error values', () => {
|
|
35
|
+
expect(isNotFoundError(null)).toBe(false)
|
|
36
|
+
expect(isNotFoundError(undefined)).toBe(false)
|
|
37
|
+
expect(isNotFoundError('string')).toBe(false)
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
describe('isPermissionError', () => {
|
|
42
|
+
it('should return true for EACCES error', () => {
|
|
43
|
+
const error = new Error('Permission denied') as NodeJS.ErrnoException
|
|
44
|
+
error.code = 'EACCES'
|
|
45
|
+
expect(isPermissionError(error)).toBe(true)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('should return true for EPERM error', () => {
|
|
49
|
+
const error = new Error('Operation not permitted') as NodeJS.ErrnoException
|
|
50
|
+
error.code = 'EPERM'
|
|
51
|
+
expect(isPermissionError(error)).toBe(true)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('should return false for other error codes', () => {
|
|
55
|
+
const error = new Error('File not found') as NodeJS.ErrnoException
|
|
56
|
+
error.code = 'ENOENT'
|
|
57
|
+
expect(isPermissionError(error)).toBe(false)
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
describe('isDirNotEmptyError', () => {
|
|
62
|
+
it('should return true for ENOTEMPTY error', () => {
|
|
63
|
+
const error = new Error('Directory not empty') as NodeJS.ErrnoException
|
|
64
|
+
error.code = 'ENOTEMPTY'
|
|
65
|
+
expect(isDirNotEmptyError(error)).toBe(true)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('should return false for other error codes', () => {
|
|
69
|
+
const error = new Error('File not found') as NodeJS.ErrnoException
|
|
70
|
+
error.code = 'ENOENT'
|
|
71
|
+
expect(isDirNotEmptyError(error)).toBe(false)
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
describe('isFileExistsError', () => {
|
|
76
|
+
it('should return true for EEXIST error', () => {
|
|
77
|
+
const error = new Error('File exists') as NodeJS.ErrnoException
|
|
78
|
+
error.code = 'EEXIST'
|
|
79
|
+
expect(isFileExistsError(error)).toBe(true)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('should return false for other error codes', () => {
|
|
83
|
+
const error = new Error('File not found') as NodeJS.ErrnoException
|
|
84
|
+
error.code = 'ENOENT'
|
|
85
|
+
expect(isFileExistsError(error)).toBe(false)
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
describe('isNodeError', () => {
|
|
90
|
+
it('should return true for Error with code property', () => {
|
|
91
|
+
const error = new Error('File not found') as NodeJS.ErrnoException
|
|
92
|
+
error.code = 'ENOENT'
|
|
93
|
+
expect(isNodeError(error)).toBe(true)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('should return false for Error without code property', () => {
|
|
97
|
+
const error = new Error('Generic error')
|
|
98
|
+
expect(isNodeError(error)).toBe(false)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('should return false for non-Error values', () => {
|
|
102
|
+
expect(isNodeError(null)).toBe(false)
|
|
103
|
+
expect(isNodeError({ code: 'ENOENT' })).toBe(false) // Not an Error instance
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
describe('SyntaxError handling pattern', () => {
|
|
108
|
+
it('should differentiate SyntaxError from fs errors', () => {
|
|
109
|
+
const syntaxError = new SyntaxError('Unexpected token')
|
|
110
|
+
const fsError = new Error('File not found') as NodeJS.ErrnoException
|
|
111
|
+
fsError.code = 'ENOENT'
|
|
112
|
+
|
|
113
|
+
// Pattern used in code
|
|
114
|
+
const handleError = (error: unknown): string => {
|
|
115
|
+
if (isNotFoundError(error)) return 'not-found'
|
|
116
|
+
if (error instanceof SyntaxError) return 'parse-error'
|
|
117
|
+
return 'other'
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
expect(handleError(fsError)).toBe('not-found')
|
|
121
|
+
expect(handleError(syntaxError)).toBe('parse-error')
|
|
122
|
+
expect(handleError(new Error('Other'))).toBe('other')
|
|
123
|
+
})
|
|
124
|
+
})
|
|
125
|
+
})
|
|
@@ -15,6 +15,7 @@ import fs from 'fs/promises'
|
|
|
15
15
|
import path from 'path'
|
|
16
16
|
import configManager from '../infrastructure/config-manager'
|
|
17
17
|
import pathManager from '../infrastructure/path-manager'
|
|
18
|
+
import { isNotFoundError } from '../types/fs'
|
|
18
19
|
import type { Agent, AssignmentContext } from '../types'
|
|
19
20
|
|
|
20
21
|
// Re-export types for convenience
|
|
@@ -57,7 +58,11 @@ class AgentRouter {
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
return agents
|
|
60
|
-
} catch {
|
|
61
|
+
} catch (error) {
|
|
62
|
+
// Agents directory doesn't exist yet - expected for new projects
|
|
63
|
+
if (!isNotFoundError(error)) {
|
|
64
|
+
console.error(`Agent loading error: ${(error as Error).message}`)
|
|
65
|
+
}
|
|
61
66
|
return []
|
|
62
67
|
}
|
|
63
68
|
}
|
|
@@ -80,7 +85,11 @@ class AgentRouter {
|
|
|
80
85
|
const filePath = path.join(this.agentsPath, `${name}.md`)
|
|
81
86
|
const content = await fs.readFile(filePath, 'utf-8')
|
|
82
87
|
return { name, content }
|
|
83
|
-
} catch {
|
|
88
|
+
} catch (error) {
|
|
89
|
+
// Agent file doesn't exist - expected
|
|
90
|
+
if (!isNotFoundError(error)) {
|
|
91
|
+
console.error(`Agent load error: ${(error as Error).message}`)
|
|
92
|
+
}
|
|
84
93
|
return null
|
|
85
94
|
}
|
|
86
95
|
}
|
|
@@ -130,8 +139,11 @@ class AgentRouter {
|
|
|
130
139
|
}) + '\n'
|
|
131
140
|
|
|
132
141
|
await fs.appendFile(logPath, entry)
|
|
133
|
-
} catch {
|
|
134
|
-
//
|
|
142
|
+
} catch (error) {
|
|
143
|
+
// Non-critical - log unexpected errors but don't fail
|
|
144
|
+
if (!isNotFoundError(error)) {
|
|
145
|
+
console.error(`Agent usage log error: ${(error as Error).message}`)
|
|
146
|
+
}
|
|
135
147
|
}
|
|
136
148
|
}
|
|
137
149
|
}
|
|
@@ -6,19 +6,11 @@
|
|
|
6
6
|
* @version 1.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
projectId?: string | null
|
|
11
|
-
projectPath: string
|
|
12
|
-
params: Record<string, unknown>
|
|
13
|
-
}
|
|
9
|
+
import type { ProjectContext, ContextState } from '../types'
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
shipped?: string | null
|
|
19
|
-
analysis?: string | null
|
|
20
|
-
[key: string]: unknown
|
|
21
|
-
}
|
|
11
|
+
// Type aliases for compatibility with ProjectContext from contextBuilder.build()
|
|
12
|
+
type Context = Pick<ProjectContext, 'projectId' | 'projectPath' | 'params'>
|
|
13
|
+
type State = ContextState
|
|
22
14
|
|
|
23
15
|
interface ReasoningStep {
|
|
24
16
|
step: string
|
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
SimpleExecutionResult,
|
|
25
25
|
ExecutionToolsFn,
|
|
26
26
|
ApprovalContext,
|
|
27
|
+
PromptContext,
|
|
27
28
|
} from '../types'
|
|
28
29
|
|
|
29
30
|
// =============================================================================
|
|
@@ -42,7 +43,7 @@ export function signalStart(commandName: string): void {
|
|
|
42
43
|
fs.mkdirSync(dir, { recursive: true })
|
|
43
44
|
}
|
|
44
45
|
fs.writeFileSync(RUNNING_FILE, `/p:${commandName}`)
|
|
45
|
-
} catch {
|
|
46
|
+
} catch (_error) {
|
|
46
47
|
// Silently ignore - status line is optional
|
|
47
48
|
}
|
|
48
49
|
}
|
|
@@ -55,7 +56,7 @@ export function signalEnd(): void {
|
|
|
55
56
|
if (fs.existsSync(RUNNING_FILE)) {
|
|
56
57
|
fs.unlinkSync(RUNNING_FILE)
|
|
57
58
|
}
|
|
58
|
-
} catch {
|
|
59
|
+
} catch (_error) {
|
|
59
60
|
// Silently ignore - status line is optional
|
|
60
61
|
}
|
|
61
62
|
}
|
|
@@ -132,7 +133,7 @@ export class CommandExecutor {
|
|
|
132
133
|
const preState = await contextBuilder.loadStateForCommand(metadataContext, commandName)
|
|
133
134
|
groundTruthResult = await groundTruth.verify(
|
|
134
135
|
commandName,
|
|
135
|
-
metadataContext
|
|
136
|
+
metadataContext,
|
|
136
137
|
preState
|
|
137
138
|
)
|
|
138
139
|
|
|
@@ -148,8 +149,8 @@ export class CommandExecutor {
|
|
|
148
149
|
const reasoningState = await contextBuilder.loadStateForCommand(metadataContext, commandName)
|
|
149
150
|
reasoning = await chainOfThought.reason(
|
|
150
151
|
commandName,
|
|
151
|
-
metadataContext
|
|
152
|
-
reasoningState
|
|
152
|
+
metadataContext,
|
|
153
|
+
reasoningState
|
|
153
154
|
)
|
|
154
155
|
|
|
155
156
|
// If reasoning shows critical issues, warn but continue
|
|
@@ -160,11 +161,9 @@ export class CommandExecutor {
|
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
// 3. AGENTIC: Claude decides agent assignment via templates
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
context = {
|
|
167
|
-
...context,
|
|
164
|
+
// Build context with agent routing info for Claude delegation
|
|
165
|
+
const context: PromptContext = {
|
|
166
|
+
...metadataContext,
|
|
168
167
|
agentsPath: path.join(os.homedir(), '.prjct-cli', 'projects', metadataContext.projectId || '', 'agents'),
|
|
169
168
|
agentRoutingPath: path.join(__dirname, '..', '..', 'templates', 'agentic', 'agent-routing.md'),
|
|
170
169
|
agenticDelegation: true,
|
|
@@ -205,7 +204,7 @@ export class CommandExecutor {
|
|
|
205
204
|
// Agent is null - Claude assigns via Task tool using agent-routing.md
|
|
206
205
|
const prompt = promptBuilder.build(
|
|
207
206
|
template,
|
|
208
|
-
context
|
|
207
|
+
context,
|
|
209
208
|
state,
|
|
210
209
|
null,
|
|
211
210
|
learnedPatterns,
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import fs from 'fs/promises'
|
|
10
10
|
import pathManager from '../infrastructure/path-manager'
|
|
11
11
|
import configManager from '../infrastructure/config-manager'
|
|
12
|
+
import { isNotFoundError } from '../types/fs'
|
|
12
13
|
import type { ContextPaths, ProjectContext, ContextState } from '../types'
|
|
13
14
|
|
|
14
15
|
// Re-export types for convenience
|
|
@@ -113,10 +114,14 @@ class ContextBuilder {
|
|
|
113
114
|
this._cache.delete(filePath)
|
|
114
115
|
this._mtimes.delete(filePath)
|
|
115
116
|
}
|
|
116
|
-
} catch {
|
|
117
|
-
// File doesn't exist - invalidate cache
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
} catch (error) {
|
|
118
|
+
// File doesn't exist or access error - invalidate cache
|
|
119
|
+
if (isNotFoundError(error)) {
|
|
120
|
+
this._cache.delete(filePath)
|
|
121
|
+
this._mtimes.delete(filePath)
|
|
122
|
+
} else {
|
|
123
|
+
throw error
|
|
124
|
+
}
|
|
120
125
|
}
|
|
121
126
|
}
|
|
122
127
|
}
|
|
@@ -137,8 +142,11 @@ class ContextBuilder {
|
|
|
137
142
|
try {
|
|
138
143
|
const [content, stat] = await Promise.all([fs.readFile(filePath, 'utf-8'), fs.stat(filePath)])
|
|
139
144
|
return { key, filePath, content, mtime: stat.mtimeMs }
|
|
140
|
-
} catch {
|
|
141
|
-
|
|
145
|
+
} catch (error) {
|
|
146
|
+
if (isNotFoundError(error)) {
|
|
147
|
+
return { key, filePath, content: null, mtime: null }
|
|
148
|
+
}
|
|
149
|
+
throw error
|
|
142
150
|
}
|
|
143
151
|
})
|
|
144
152
|
|
|
@@ -227,8 +235,11 @@ class ContextBuilder {
|
|
|
227
235
|
try {
|
|
228
236
|
const content = await fs.readFile(filePath, 'utf-8')
|
|
229
237
|
return { filePath, content }
|
|
230
|
-
} catch {
|
|
231
|
-
|
|
238
|
+
} catch (error) {
|
|
239
|
+
if (isNotFoundError(error)) {
|
|
240
|
+
return { filePath, content: null }
|
|
241
|
+
}
|
|
242
|
+
throw error
|
|
232
243
|
}
|
|
233
244
|
})
|
|
234
245
|
|
|
@@ -264,8 +275,11 @@ class ContextBuilder {
|
|
|
264
275
|
try {
|
|
265
276
|
await fs.access(filePath)
|
|
266
277
|
return true
|
|
267
|
-
} catch {
|
|
268
|
-
|
|
278
|
+
} catch (error) {
|
|
279
|
+
if (isNotFoundError(error)) {
|
|
280
|
+
return false
|
|
281
|
+
}
|
|
282
|
+
throw error
|
|
269
283
|
}
|
|
270
284
|
}
|
|
271
285
|
|