prjct-cli 1.9.0 → 1.11.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 +114 -1
- package/core/__tests__/agentic/prompt-assembly.test.ts +298 -0
- package/core/__tests__/agentic/prompt-builder.test.ts +2 -2
- package/core/__tests__/agentic/token-budget.test.ts +294 -0
- package/core/__tests__/storage/analysis-storage.test.ts +277 -0
- package/core/agentic/anti-hallucination.ts +124 -0
- package/core/agentic/environment-block.ts +102 -0
- package/core/agentic/injection-validator.ts +16 -0
- package/core/agentic/prompt-builder.ts +339 -167
- package/core/agentic/token-budget.ts +226 -0
- package/core/commands/analysis.ts +117 -2
- package/core/commands/command-data.ts +29 -0
- package/core/commands/commands.ts +14 -0
- package/core/commands/register.ts +2 -0
- package/core/index.ts +2 -0
- package/core/schemas/analysis.ts +69 -25
- package/core/services/context-selector.ts +8 -2
- package/core/services/sync-service.ts +35 -0
- package/core/storage/analysis-storage.ts +328 -0
- package/core/storage/index.ts +2 -0
- package/dist/bin/prjct.mjs +1357 -664
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,119 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.11.0] - 2026-02-09
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- implement sealable analysis with commit-hash signature (PRJ-263) (#153)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## [1.11.0] - 2026-02-08
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
- **Sealable Analysis**: 3-state lifecycle (draft/verified/sealed) with SHA-256 commit-hash signatures (PRJ-263)
|
|
14
|
+
- **Dual Storage**: Re-sync creates drafts without destroying sealed analysis — only sealed feeds task context
|
|
15
|
+
- **Staleness Detection**: Warns when HEAD moves past the sealed commit hash
|
|
16
|
+
- **Seal & Verify Commands**: `prjct seal` locks draft analysis, `prjct verify` checks integrity
|
|
17
|
+
|
|
18
|
+
### Implementation Details
|
|
19
|
+
New `analysis-storage.ts` extends StorageManager with dual storage (draft + sealed). Analysis schema rewritten as Zod schemas with runtime validation. Sync service writes drafts in parallel with existing writes. Canonical JSON representation ensures deterministic SHA-256 signatures.
|
|
20
|
+
|
|
21
|
+
Key changes:
|
|
22
|
+
- `core/schemas/analysis.ts` — Full rewrite: plain interfaces → Zod schemas with `AnalysisStatusSchema`, `AnalysisItemSchema`
|
|
23
|
+
- `core/storage/analysis-storage.ts` — New: dual storage, sealing, verification, staleness detection
|
|
24
|
+
- `core/services/sync-service.ts` — Added `saveDraftAnalysis()` to parallel writes
|
|
25
|
+
- `core/commands/analysis.ts` — Added `seal()` and `verify()` command methods
|
|
26
|
+
- `core/commands/register.ts`, `core/index.ts` — Registered new commands
|
|
27
|
+
|
|
28
|
+
### Test Plan
|
|
29
|
+
|
|
30
|
+
#### For QA
|
|
31
|
+
1. Run `prjct sync` — verify draft analysis is created in storage
|
|
32
|
+
2. Run `prjct seal` — verify analysis is locked with SHA-256 signature
|
|
33
|
+
3. Run `prjct verify` — verify signature matches
|
|
34
|
+
4. Run `prjct sync` again — verify sealed analysis is preserved, new draft created
|
|
35
|
+
5. Make a commit, run `prjct status` — verify staleness detection warns about diverged commits
|
|
36
|
+
|
|
37
|
+
#### For Users
|
|
38
|
+
- **What changed:** Analysis results can now be locked (sealed) so re-syncing doesn't overwrite verified context
|
|
39
|
+
- **How to use:** Run `prjct seal` after reviewing sync results, `prjct verify` to check integrity
|
|
40
|
+
- **Breaking changes:** None — old analysis files parse with `status: 'draft'` default
|
|
41
|
+
|
|
42
|
+
## [1.10.0] - 2026-02-08
|
|
43
|
+
|
|
44
|
+
### Features
|
|
45
|
+
|
|
46
|
+
- redesign prompt assembly with correct section ordering + anti-hallucination (PRJ-301) (#152)
|
|
47
|
+
- add coordinated global token budget (PRJ-266) (#151)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
## [1.12.0] - 2026-02-07
|
|
51
|
+
|
|
52
|
+
### Features
|
|
53
|
+
- **Prompt Assembly Redesign**: Correct section ordering based on research of 25+ system prompts (PRJ-301)
|
|
54
|
+
- **Environment Block**: Structured `<env>` block with project, git, platform, runtime, and model metadata
|
|
55
|
+
- **Anti-Hallucination Block**: Explicit availability/unavailability grounding injected BEFORE task context
|
|
56
|
+
- **Token Efficiency Directive**: Conciseness rules appended to every prompt
|
|
57
|
+
|
|
58
|
+
### Implementation Details
|
|
59
|
+
Redesigned `prompt-builder.ts` section ordering to follow research-backed pattern:
|
|
60
|
+
Identity → Environment → Ground Truth → Capabilities → Constraints → Task Context → Task → Output Schema → Efficiency
|
|
61
|
+
|
|
62
|
+
Key changes:
|
|
63
|
+
- New `environment-block.ts`: Generates `<env>` XML block with auto-detected runtime, platform, and normalized names
|
|
64
|
+
- New `anti-hallucination.ts`: Generates constraints block from sealed analysis (available tech, absent domains, grounding rules)
|
|
65
|
+
- Moved template content (task instructions) to section 7 — LLM knows identity, env, and rules before reading task
|
|
66
|
+
- Anti-hallucination block placed at section 5 (before task context), replacing old `RULES (CRITICAL)` at the end
|
|
67
|
+
- Added `buildEfficiencyDirective()` with conciseness rules (max 4 lines, no preamble/postamble)
|
|
68
|
+
- Exported `PROMPT_SECTION_ORDER` constant and `SectionPriority` type for budget trimming
|
|
69
|
+
- Kept `buildCriticalRules()` as fallback when project context unavailable
|
|
70
|
+
|
|
71
|
+
### Learnings
|
|
72
|
+
- Zod `.default()` only applies during `.parse()` — raw object construction skips defaults, use `??` fallback
|
|
73
|
+
- Renaming prompt section headers breaks existing test assertions — always update test matchers
|
|
74
|
+
- Template position matters: placing task instructions after constraints improves LLM grounding
|
|
75
|
+
|
|
76
|
+
### Test Plan
|
|
77
|
+
|
|
78
|
+
#### For QA
|
|
79
|
+
1. Run `bun test` — all 719 tests pass (0 failures)
|
|
80
|
+
2. Run `bun run build` — build succeeds
|
|
81
|
+
3. Verify `<env>` block appears in generated prompts before constraints
|
|
82
|
+
4. Verify `CONSTRAINTS (Read Before Acting)` appears before template content
|
|
83
|
+
5. Verify `OUTPUT RULES` section appears at end of prompt
|
|
84
|
+
6. Check `AVAILABLE` and `NOT PRESENT` lists reflect project tech stack
|
|
85
|
+
7. Run `prjct sync` — prompt assembly still works end-to-end
|
|
86
|
+
|
|
87
|
+
#### For Users
|
|
88
|
+
Prompts sent to AI models are now structured with research-backed section ordering, reducing hallucinations and improving response conciseness. No user action required — improvements are automatic.
|
|
89
|
+
|
|
90
|
+
## [1.11.0] - 2026-02-07
|
|
91
|
+
|
|
92
|
+
### Features
|
|
93
|
+
- **Token Budget Coordinator**: Centralized token budget management across all context-loading components (PRJ-266)
|
|
94
|
+
|
|
95
|
+
### Implementation Details
|
|
96
|
+
Created `TokenBudgetCoordinator` class that manages the global token budget based on model context windows. Key features:
|
|
97
|
+
- Model context window registry (Claude 200K, Gemini 1M) with automatic budget calculation
|
|
98
|
+
- Input/output budget split: 65% input, 35% reserved for output
|
|
99
|
+
- Priority-based allocation: state (P1) > injection context (P2) > file content (P3)
|
|
100
|
+
- Request/record API for usage tracking with overflow detection
|
|
101
|
+
- Integrated into `injection-validator.ts`, `prompt-builder.ts`, and `context-selector.ts`
|
|
102
|
+
- Backward compatible: falls back to existing defaults when no coordinator is set
|
|
103
|
+
|
|
104
|
+
### Test Plan
|
|
105
|
+
|
|
106
|
+
#### For QA
|
|
107
|
+
1. Create coordinator with `'sonnet'` → input budget = 130K, output reserve = 70K
|
|
108
|
+
2. Create with `'2.5-pro'` (Gemini) → input budget = 650K (5x Claude)
|
|
109
|
+
3. Request tokens up to allocation limit → verify grants are capped
|
|
110
|
+
4. Exhaust a category budget → verify subsequent requests return 0
|
|
111
|
+
5. Verify `budgetsFromCoordinator()` uses coordinator's injection allocation
|
|
112
|
+
6. Run full test suite → all 705 tests pass
|
|
113
|
+
|
|
114
|
+
#### For Users
|
|
115
|
+
Token budgets are now centrally coordinated based on the model's context window. Larger models get proportionally larger budgets automatically. No breaking changes.
|
|
116
|
+
|
|
3
117
|
## [1.9.0] - 2026-02-07
|
|
4
118
|
|
|
5
119
|
### Features
|
|
@@ -11,7 +125,6 @@
|
|
|
11
125
|
|
|
12
126
|
- replace keyword domain detection with LLM semantic classification (PRJ-299) (#148)
|
|
13
127
|
|
|
14
|
-
|
|
15
128
|
## [1.10.0] - 2026-02-07
|
|
16
129
|
|
|
17
130
|
### Features
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Assembly Tests (PRJ-301)
|
|
3
|
+
*
|
|
4
|
+
* Tests for the redesigned prompt assembly:
|
|
5
|
+
* - Section ordering (Identity → Env → Ground Truth → ... → Efficiency)
|
|
6
|
+
* - Environment block generation
|
|
7
|
+
* - Anti-hallucination block generation
|
|
8
|
+
* - Token efficiency directive
|
|
9
|
+
* - Budget trimming with priorities
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { beforeEach, describe, expect, it } from 'bun:test'
|
|
13
|
+
import {
|
|
14
|
+
buildAntiHallucinationBlock,
|
|
15
|
+
type ProjectGroundTruth,
|
|
16
|
+
} from '../../agentic/anti-hallucination'
|
|
17
|
+
import { buildEnvironmentBlock, type EnvironmentBlockInput } from '../../agentic/environment-block'
|
|
18
|
+
import promptBuilder, { PROMPT_SECTION_ORDER } from '../../agentic/prompt-builder'
|
|
19
|
+
|
|
20
|
+
// =============================================================================
|
|
21
|
+
// Environment Block
|
|
22
|
+
// =============================================================================
|
|
23
|
+
|
|
24
|
+
describe('Environment Block (PRJ-301)', () => {
|
|
25
|
+
it('should generate <env> block with all fields', () => {
|
|
26
|
+
const input: EnvironmentBlockInput = {
|
|
27
|
+
projectName: 'my-app',
|
|
28
|
+
projectPath: '/home/user/my-app',
|
|
29
|
+
isGitRepo: true,
|
|
30
|
+
gitBranch: 'feature/login',
|
|
31
|
+
platform: 'darwin',
|
|
32
|
+
runtime: 'bun',
|
|
33
|
+
date: '2026-02-07',
|
|
34
|
+
model: 'opus',
|
|
35
|
+
provider: 'claude',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const block = buildEnvironmentBlock(input)
|
|
39
|
+
|
|
40
|
+
expect(block).toContain('<env>')
|
|
41
|
+
expect(block).toContain('</env>')
|
|
42
|
+
expect(block).toContain('project: my-app')
|
|
43
|
+
expect(block).toContain('path: /home/user/my-app')
|
|
44
|
+
expect(block).toContain('git: true')
|
|
45
|
+
expect(block).toContain('branch: feature/login')
|
|
46
|
+
expect(block).toContain('platform: macOS')
|
|
47
|
+
expect(block).toContain('runtime: bun')
|
|
48
|
+
expect(block).toContain('date: 2026-02-07')
|
|
49
|
+
expect(block).toContain('model: opus')
|
|
50
|
+
expect(block).toContain('provider: claude')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('should omit undefined fields', () => {
|
|
54
|
+
const input: EnvironmentBlockInput = {
|
|
55
|
+
projectName: 'my-app',
|
|
56
|
+
projectPath: '/test',
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const block = buildEnvironmentBlock(input)
|
|
60
|
+
|
|
61
|
+
expect(block).toContain('project: my-app')
|
|
62
|
+
expect(block).toContain('path: /test')
|
|
63
|
+
expect(block).not.toContain('model:')
|
|
64
|
+
expect(block).not.toContain('provider:')
|
|
65
|
+
expect(block).not.toContain('branch:')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('should normalize platform names', () => {
|
|
69
|
+
expect(
|
|
70
|
+
buildEnvironmentBlock({ projectName: 'x', projectPath: '/x', platform: 'darwin' })
|
|
71
|
+
).toContain('platform: macOS')
|
|
72
|
+
expect(
|
|
73
|
+
buildEnvironmentBlock({ projectName: 'x', projectPath: '/x', platform: 'linux' })
|
|
74
|
+
).toContain('platform: Linux')
|
|
75
|
+
expect(
|
|
76
|
+
buildEnvironmentBlock({ projectName: 'x', projectPath: '/x', platform: 'win32' })
|
|
77
|
+
).toContain('platform: Windows')
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('should auto-detect runtime and date when not provided', () => {
|
|
81
|
+
const block = buildEnvironmentBlock({ projectName: 'x', projectPath: '/x' })
|
|
82
|
+
|
|
83
|
+
// Should have a runtime (bun or node)
|
|
84
|
+
expect(block).toMatch(/runtime: (bun|node)/)
|
|
85
|
+
// Should have a date in YYYY-MM-DD format
|
|
86
|
+
expect(block).toMatch(/date: \d{4}-\d{2}-\d{2}/)
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
// =============================================================================
|
|
91
|
+
// Anti-Hallucination Block
|
|
92
|
+
// =============================================================================
|
|
93
|
+
|
|
94
|
+
describe('Anti-Hallucination Block (PRJ-301)', () => {
|
|
95
|
+
it('should generate constraints block with availability', () => {
|
|
96
|
+
const truth: ProjectGroundTruth = {
|
|
97
|
+
projectPath: '/home/user/my-app',
|
|
98
|
+
language: 'TypeScript',
|
|
99
|
+
framework: 'Hono',
|
|
100
|
+
techStack: ['Hono', 'Zod', 'Vitest'],
|
|
101
|
+
domains: {
|
|
102
|
+
hasFrontend: false,
|
|
103
|
+
hasBackend: true,
|
|
104
|
+
hasDatabase: false,
|
|
105
|
+
hasTesting: true,
|
|
106
|
+
hasDocker: false,
|
|
107
|
+
},
|
|
108
|
+
fileCount: 292,
|
|
109
|
+
availableAgents: ['backend', 'testing'],
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const block = buildAntiHallucinationBlock(truth)
|
|
113
|
+
|
|
114
|
+
// Section header
|
|
115
|
+
expect(block).toContain('CONSTRAINTS (Read Before Acting)')
|
|
116
|
+
|
|
117
|
+
// Availability
|
|
118
|
+
expect(block).toContain('AVAILABLE in this project: TypeScript, Hono, Zod, Vitest')
|
|
119
|
+
|
|
120
|
+
// Unavailability (no frontend, no database, no docker)
|
|
121
|
+
expect(block).toContain('NOT PRESENT:')
|
|
122
|
+
expect(block).toContain('Frontend (UI/components)')
|
|
123
|
+
expect(block).toContain('Database (SQL/ORM)')
|
|
124
|
+
expect(block).toContain('Docker/containers')
|
|
125
|
+
|
|
126
|
+
// Should NOT list present domains as absent
|
|
127
|
+
expect(block).not.toContain('NOT PRESENT: Backend')
|
|
128
|
+
expect(block).not.toContain('NOT PRESENT: Testing')
|
|
129
|
+
|
|
130
|
+
// Agents
|
|
131
|
+
expect(block).toContain('AGENTS: backend, testing')
|
|
132
|
+
|
|
133
|
+
// Grounding rules
|
|
134
|
+
expect(block).toContain('SCOPE: Only files in `/home/user/my-app` are accessible.')
|
|
135
|
+
expect(block).toContain('Do NOT infer or guess paths')
|
|
136
|
+
expect(block).toContain('NEVER assume a library is available')
|
|
137
|
+
expect(block).toContain('trust this section')
|
|
138
|
+
|
|
139
|
+
// File count
|
|
140
|
+
expect(block).toContain('292 files in project')
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('should handle minimal input', () => {
|
|
144
|
+
const truth: ProjectGroundTruth = {
|
|
145
|
+
projectPath: '/test',
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const block = buildAntiHallucinationBlock(truth)
|
|
149
|
+
|
|
150
|
+
expect(block).toContain('CONSTRAINTS')
|
|
151
|
+
expect(block).toContain('SCOPE: Only files in `/test` are accessible.')
|
|
152
|
+
// Should not have AVAILABLE or NOT PRESENT lines
|
|
153
|
+
expect(block).not.toContain('AVAILABLE in this project:')
|
|
154
|
+
expect(block).not.toContain('NOT PRESENT:')
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
it('should not duplicate framework in techStack listing', () => {
|
|
158
|
+
const truth: ProjectGroundTruth = {
|
|
159
|
+
projectPath: '/test',
|
|
160
|
+
language: 'TypeScript',
|
|
161
|
+
framework: 'Next.js',
|
|
162
|
+
techStack: ['Next.js', 'React', 'Tailwind'],
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const block = buildAntiHallucinationBlock(truth)
|
|
166
|
+
|
|
167
|
+
// Next.js should appear once (from framework), not duplicated from techStack
|
|
168
|
+
const matches = block.match(/Next\.js/g)
|
|
169
|
+
expect(matches?.length).toBe(1)
|
|
170
|
+
})
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
// =============================================================================
|
|
174
|
+
// Section Ordering
|
|
175
|
+
// =============================================================================
|
|
176
|
+
|
|
177
|
+
describe('Prompt Section Ordering (PRJ-301)', () => {
|
|
178
|
+
let builder: typeof promptBuilder
|
|
179
|
+
|
|
180
|
+
beforeEach(() => {
|
|
181
|
+
builder = promptBuilder
|
|
182
|
+
builder.resetContext()
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('should define correct section order constant', () => {
|
|
186
|
+
expect(PROMPT_SECTION_ORDER).toEqual([
|
|
187
|
+
'identity',
|
|
188
|
+
'environment',
|
|
189
|
+
'ground_truth',
|
|
190
|
+
'capabilities',
|
|
191
|
+
'constraints',
|
|
192
|
+
'task_context',
|
|
193
|
+
'task',
|
|
194
|
+
'output_schema',
|
|
195
|
+
'efficiency',
|
|
196
|
+
])
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
it('should place environment block before constraints', async () => {
|
|
200
|
+
const template = {
|
|
201
|
+
frontmatter: { description: 'Test', 'allowed-tools': ['Read'] },
|
|
202
|
+
content: '## Instructions\nDo the thing',
|
|
203
|
+
}
|
|
204
|
+
const context = { projectPath: '/test', files: ['a.js'] }
|
|
205
|
+
|
|
206
|
+
const prompt = await builder.build(template, context, {})
|
|
207
|
+
|
|
208
|
+
const envPos = prompt.indexOf('<env>')
|
|
209
|
+
const constraintsPos = prompt.indexOf('CONSTRAINTS')
|
|
210
|
+
expect(envPos).toBeGreaterThan(-1)
|
|
211
|
+
expect(constraintsPos).toBeGreaterThan(-1)
|
|
212
|
+
expect(envPos).toBeLessThan(constraintsPos)
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
it('should place constraints before task template content', async () => {
|
|
216
|
+
const template = {
|
|
217
|
+
frontmatter: { description: 'Test' },
|
|
218
|
+
content: '## UNIQUE_TEMPLATE_MARKER\nFollow these steps',
|
|
219
|
+
}
|
|
220
|
+
const context = { projectPath: '/test', files: ['a.js'] }
|
|
221
|
+
|
|
222
|
+
const prompt = await builder.build(template, context, {})
|
|
223
|
+
|
|
224
|
+
const constraintsPos = prompt.indexOf('CONSTRAINTS')
|
|
225
|
+
const templatePos = prompt.indexOf('UNIQUE_TEMPLATE_MARKER')
|
|
226
|
+
expect(constraintsPos).toBeGreaterThan(-1)
|
|
227
|
+
expect(templatePos).toBeGreaterThan(-1)
|
|
228
|
+
expect(constraintsPos).toBeLessThan(templatePos)
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
it('should place identity (TASK:) at the beginning', async () => {
|
|
232
|
+
const template = {
|
|
233
|
+
frontmatter: { description: 'My Task' },
|
|
234
|
+
content: '## Flow\nStep 1',
|
|
235
|
+
}
|
|
236
|
+
const context = { projectPath: '/test' }
|
|
237
|
+
|
|
238
|
+
const prompt = await builder.build(template, context, {})
|
|
239
|
+
|
|
240
|
+
const taskPos = prompt.indexOf('TASK: My Task')
|
|
241
|
+
expect(taskPos).toBeLessThan(50)
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it('should place efficiency directive at the end', async () => {
|
|
245
|
+
const template = {
|
|
246
|
+
frontmatter: { description: 'Test' },
|
|
247
|
+
content: '## Flow\nStep 1',
|
|
248
|
+
}
|
|
249
|
+
const context = { projectPath: '/test' }
|
|
250
|
+
|
|
251
|
+
const prompt = await builder.build(template, context, {})
|
|
252
|
+
|
|
253
|
+
const efficiencyPos = prompt.indexOf('OUTPUT RULES')
|
|
254
|
+
const executePos = prompt.indexOf('EXECUTE:')
|
|
255
|
+
expect(efficiencyPos).toBeGreaterThan(-1)
|
|
256
|
+
expect(executePos).toBeGreaterThan(-1)
|
|
257
|
+
// Should be in the last ~300 chars of the prompt
|
|
258
|
+
expect(prompt.length - executePos).toBeLessThan(300)
|
|
259
|
+
})
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
// =============================================================================
|
|
263
|
+
// Token Efficiency Directive
|
|
264
|
+
// =============================================================================
|
|
265
|
+
|
|
266
|
+
describe('Token Efficiency Directive (PRJ-301)', () => {
|
|
267
|
+
let builder: typeof promptBuilder
|
|
268
|
+
|
|
269
|
+
beforeEach(() => {
|
|
270
|
+
builder = promptBuilder
|
|
271
|
+
builder.resetContext()
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
it('should include efficiency rules in every prompt', async () => {
|
|
275
|
+
const template = {
|
|
276
|
+
frontmatter: { description: 'Test' },
|
|
277
|
+
content: '## Flow\nStep 1',
|
|
278
|
+
}
|
|
279
|
+
const context = { projectPath: '/test' }
|
|
280
|
+
|
|
281
|
+
const prompt = await builder.build(template, context, {})
|
|
282
|
+
|
|
283
|
+
expect(prompt).toContain('OUTPUT RULES')
|
|
284
|
+
expect(prompt).toContain('Be concise')
|
|
285
|
+
expect(prompt).toContain('No preamble')
|
|
286
|
+
expect(prompt).toContain('No postamble')
|
|
287
|
+
expect(prompt).toContain('EXECUTE:')
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
it('should build efficiency directive as standalone method', () => {
|
|
291
|
+
const directive = builder.buildEfficiencyDirective()
|
|
292
|
+
|
|
293
|
+
expect(directive).toContain('Maximum 4 lines')
|
|
294
|
+
expect(directive).toContain('No preamble')
|
|
295
|
+
expect(directive).toContain('Prefer structured output')
|
|
296
|
+
expect(directive).toContain('EXECUTE:')
|
|
297
|
+
})
|
|
298
|
+
})
|
|
@@ -107,7 +107,7 @@ describe('PromptBuilder', () => {
|
|
|
107
107
|
|
|
108
108
|
const prompt = await builder.build(template, context, state)
|
|
109
109
|
|
|
110
|
-
expect(prompt).toContain('
|
|
110
|
+
expect(prompt).toContain('STACK')
|
|
111
111
|
expect(prompt).toContain('Node.js')
|
|
112
112
|
})
|
|
113
113
|
|
|
@@ -187,7 +187,7 @@ describe('PromptBuilder', () => {
|
|
|
187
187
|
expect(prompt).toContain('TASK:')
|
|
188
188
|
expect(prompt).toContain('TOOLS:')
|
|
189
189
|
expect(prompt).toContain('Flow')
|
|
190
|
-
expect(prompt).toContain('
|
|
190
|
+
expect(prompt).toContain('CONSTRAINTS (Read Before Acting)')
|
|
191
191
|
expect(prompt).toContain('## FILES:')
|
|
192
192
|
})
|
|
193
193
|
|