prjct-cli 1.6.12 → 1.7.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 +58 -1
- package/core/__tests__/utils/date-helper.test.ts +44 -0
- package/core/services/diff-generator.ts +1 -7
- package/core/services/sync-service.ts +0 -2
- package/core/storage/ideas-storage.ts +7 -7
- package/core/storage/shipped-storage.ts +3 -6
- package/core/storage/state-storage.ts +3 -3
- package/core/utils/citations.ts +1 -1
- package/core/utils/date-helper.ts +10 -0
- package/dist/bin/prjct.mjs +20 -15
- package/package.json +2 -1
- package/templates/agentic/context-filtering.md +0 -35
- package/templates/agentic/skill-integration.md +0 -59
- package/templates/agentic/subagent-generation.md +0 -54
- package/templates/analysis/bug-severity.md +0 -74
- package/templates/analysis/complexity.md +0 -54
- package/templates/analysis/health.md +0 -66
- package/templates/analysis/intent.md +0 -66
- package/templates/analysis/task-breakdown.md +0 -53
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,69 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.7.0] - 2026-02-07
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- use relative timestamps to reduce token waste (PRJ-274) (#139)
|
|
8
|
+
- use relative timestamps to reduce token waste (PRJ-274)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## [1.6.16] - 2026-02-07
|
|
12
|
+
|
|
13
|
+
### Improvement
|
|
14
|
+
- **Use relative timestamps to reduce token waste (PRJ-274)**: Added `toRelative()` function using `date-fns` `formatDistanceToNowStrict`. Replaced raw ISO-8601 timestamps in Markdown context files (`now.md`, `ideas.md`, `shipped.md`) with human-readable relative time ("5 minutes ago", "3 days ago"). JSON storage retains full ISO timestamps — no data loss.
|
|
15
|
+
|
|
16
|
+
### Implementation Details
|
|
17
|
+
Added `date-fns` as a dependency and created a thin `toRelative(date)` wrapper around `formatDistanceToNowStrict` in `core/utils/date-helper.ts`. Updated `toMarkdown()` in `state-storage.ts` (Started/Paused fields), `ideas-storage.ts` (all 3 sections: pending, converted, archived), and `shipped-storage.ts` (ship date per entry). 6 new unit tests added covering minutes, hours, days, months, Date objects, and ISO string inputs.
|
|
18
|
+
|
|
19
|
+
### Learnings
|
|
20
|
+
- `date-fns` `formatDistanceToNowStrict` gives exact units ("5 minutes ago" not "about 5 minutes ago") — better for token efficiency
|
|
21
|
+
- Tests need `setSystemTime()` from `bun:test` since `formatDistanceToNowStrict` uses system clock internally
|
|
22
|
+
|
|
23
|
+
### Test Plan
|
|
24
|
+
|
|
25
|
+
#### For QA
|
|
26
|
+
1. Run `bun test core/__tests__/utils/date-helper.test.ts` — verify all 55 tests pass (6 new for `toRelative`)
|
|
27
|
+
2. Run `bun run build` — verify build succeeds
|
|
28
|
+
3. Run `prjct sync` — verify `context/now.md` shows relative timestamps instead of raw ISO
|
|
29
|
+
4. Check `ideas.md` and `shipped.md` for relative date format
|
|
30
|
+
|
|
31
|
+
#### For Users
|
|
32
|
+
**What changed:** Timestamps in context files now show "5 minutes ago", "3 days ago" instead of raw ISO-8601 strings.
|
|
33
|
+
**How to use:** No action needed — automatic.
|
|
34
|
+
**Breaking changes:** None.
|
|
35
|
+
|
|
36
|
+
## [1.6.15] - 2026-02-07
|
|
37
|
+
|
|
38
|
+
### Refactor
|
|
39
|
+
- **Remove unused templates and dead code (PRJ-293)**: Deleted 8 unused template files from `templates/analysis/` (5) and `templates/agentic/` (3) that were never referenced by any code or other templates. Also removed unused type imports flagged by biome's `noUnusedImports` rule from `diff-generator.ts`, `sync-service.ts`, and `citations.ts`. Total: -471 lines removed.
|
|
40
|
+
|
|
41
|
+
### Implementation Details
|
|
42
|
+
Audited all 135 templates by cross-referencing with code that loads them. Carefully distinguished between templates loaded dynamically via `readdir` (checklists, skills — kept) and templates with zero references (analysis prompts, agentic scaffolding — deleted). Unused imports were types imported for re-export where the `export type` statement imports independently from the source module, making the `import type` line redundant.
|
|
43
|
+
|
|
44
|
+
### Learnings
|
|
45
|
+
- Dynamic template loading via `readdir` (in `prompt-builder.ts` and `skill-service.ts`) means simple grep searches can't identify all references — must trace runtime loading patterns to distinguish truly unused templates from dynamically loaded ones
|
|
46
|
+
- TypeScript `export type { X } from 'module'` is a standalone declaration that imports independently — a separate `import type { X }` is only needed if `X` is used in the file body
|
|
47
|
+
|
|
48
|
+
### Test Plan
|
|
49
|
+
|
|
50
|
+
#### For QA
|
|
51
|
+
1. Run `bun run build` — verify build succeeds with no errors
|
|
52
|
+
2. Run `bun run lint` — verify zero biome warnings (especially `noUnusedImports`)
|
|
53
|
+
3. Run `prjct sync` — verify sync still works (deleted templates were unused by sync)
|
|
54
|
+
4. Verify `templates/checklists/*.md` and `templates/skills/*.md` are untouched (dynamically loaded)
|
|
55
|
+
|
|
56
|
+
#### For Users
|
|
57
|
+
**What changed:** Removed 8 unused internal template files and cleaned up dead imports. No user-facing behavior changes.
|
|
58
|
+
**How to use:** No action needed — this is an internal cleanup.
|
|
59
|
+
**Breaking changes:** None.
|
|
60
|
+
|
|
3
61
|
## [1.6.12] - 2026-02-07
|
|
4
62
|
|
|
5
63
|
### Bug Fixes
|
|
6
64
|
|
|
7
65
|
- replace sync I/O in imports-tool hot path (PRJ-290) (#137)
|
|
8
66
|
|
|
9
|
-
|
|
10
67
|
## [1.6.14] - 2026-02-07
|
|
11
68
|
|
|
12
69
|
### Bug Fixes
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
isToday,
|
|
22
22
|
isWithinLastDays,
|
|
23
23
|
parseDate,
|
|
24
|
+
toRelative,
|
|
24
25
|
} from '../../utils/date-helper'
|
|
25
26
|
|
|
26
27
|
describe('DateHelper', () => {
|
|
@@ -402,4 +403,47 @@ describe('DateHelper', () => {
|
|
|
402
403
|
expect(original.getMinutes()).toBe(30)
|
|
403
404
|
})
|
|
404
405
|
})
|
|
406
|
+
|
|
407
|
+
describe('toRelative', () => {
|
|
408
|
+
it('should show minutes for dates within 1 hour', () => {
|
|
409
|
+
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
410
|
+
const fiveMinAgo = '2025-10-15T11:55:00.000Z'
|
|
411
|
+
expect(toRelative(fiveMinAgo)).toBe('5 minutes ago')
|
|
412
|
+
setSystemTime()
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
it('should show hours for dates within 24 hours', () => {
|
|
416
|
+
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
417
|
+
const threeHoursAgo = '2025-10-15T09:00:00.000Z'
|
|
418
|
+
expect(toRelative(threeHoursAgo)).toBe('3 hours ago')
|
|
419
|
+
setSystemTime()
|
|
420
|
+
})
|
|
421
|
+
|
|
422
|
+
it('should show days for dates within 7 days', () => {
|
|
423
|
+
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
424
|
+
const twoDaysAgo = '2025-10-13T12:00:00.000Z'
|
|
425
|
+
expect(toRelative(twoDaysAgo)).toBe('2 days ago')
|
|
426
|
+
setSystemTime()
|
|
427
|
+
})
|
|
428
|
+
|
|
429
|
+
it('should show months for dates older than 30 days', () => {
|
|
430
|
+
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
431
|
+
const twoMonthsAgo = '2025-08-15T12:00:00.000Z'
|
|
432
|
+
expect(toRelative(twoMonthsAgo)).toBe('2 months ago')
|
|
433
|
+
setSystemTime()
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
it('should accept Date objects', () => {
|
|
437
|
+
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
438
|
+
const date = new Date('2025-10-15T11:00:00.000Z')
|
|
439
|
+
expect(toRelative(date)).toBe('1 hour ago')
|
|
440
|
+
setSystemTime()
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
it('should accept ISO string timestamps', () => {
|
|
444
|
+
setSystemTime(new Date('2025-10-15T12:00:00.000Z'))
|
|
445
|
+
expect(toRelative('2025-10-14T12:00:00.000Z')).toBe('1 day ago')
|
|
446
|
+
setSystemTime()
|
|
447
|
+
})
|
|
448
|
+
})
|
|
405
449
|
})
|
|
@@ -9,13 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import chalk from 'chalk'
|
|
12
|
-
import type {
|
|
13
|
-
DiffOptions,
|
|
14
|
-
DiffSection,
|
|
15
|
-
ParsedMarkdownSection,
|
|
16
|
-
PreservedInfo,
|
|
17
|
-
SyncDiff,
|
|
18
|
-
} from '../types'
|
|
12
|
+
import type { DiffOptions, ParsedMarkdownSection, SyncDiff } from '../types'
|
|
19
13
|
|
|
20
14
|
export type {
|
|
21
15
|
DiffOptions,
|
|
@@ -33,7 +33,6 @@ import configManager from '../infrastructure/config-manager'
|
|
|
33
33
|
import pathManager from '../infrastructure/path-manager'
|
|
34
34
|
import { metricsStorage } from '../storage/metrics-storage'
|
|
35
35
|
import type {
|
|
36
|
-
AIToolResult,
|
|
37
36
|
GitData,
|
|
38
37
|
ProjectCommands,
|
|
39
38
|
ProjectStats,
|
|
@@ -48,7 +47,6 @@ import { type ContextSources, defaultSources, type SourceInfo } from '../utils/c
|
|
|
48
47
|
import * as dateHelper from '../utils/date-helper'
|
|
49
48
|
import log from '../utils/logger'
|
|
50
49
|
import { ContextFileGenerator } from './context-generator'
|
|
51
|
-
import type { SyncDiff } from './diff-generator'
|
|
52
50
|
import { localStateGenerator } from './local-state-generator'
|
|
53
51
|
import { skillInstaller } from './skill-installer'
|
|
54
52
|
import { StackDetector } from './stack-detector'
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { generateUUID } from '../schemas'
|
|
9
9
|
import type { Idea, IdeaPriority, IdeaStatus, IdeasJson } from '../types'
|
|
10
|
-
import { getTimestamp } from '../utils/date-helper'
|
|
10
|
+
import { getTimestamp, toRelative } from '../utils/date-helper'
|
|
11
11
|
import { StorageManager } from './storage-manager'
|
|
12
12
|
|
|
13
13
|
class IdeasStorage extends StorageManager<IdeasJson> {
|
|
@@ -45,10 +45,10 @@ class IdeasStorage extends StorageManager<IdeasJson> {
|
|
|
45
45
|
lines.push('## Brain Dump')
|
|
46
46
|
if (pending.length > 0) {
|
|
47
47
|
pending.forEach((idea) => {
|
|
48
|
-
const
|
|
48
|
+
const rel = toRelative(idea.addedAt)
|
|
49
49
|
const tags = idea.tags.length > 0 ? ` ${idea.tags.map((t) => `#${t}`).join(' ')}` : ''
|
|
50
50
|
const priority = idea.priority !== 'medium' ? ` [${idea.priority.toUpperCase()}]` : ''
|
|
51
|
-
lines.push(`- ${idea.text}${priority} _(${
|
|
51
|
+
lines.push(`- ${idea.text}${priority} _(${rel})_${tags}`)
|
|
52
52
|
})
|
|
53
53
|
} else {
|
|
54
54
|
lines.push('_No pending ideas_')
|
|
@@ -59,9 +59,9 @@ class IdeasStorage extends StorageManager<IdeasJson> {
|
|
|
59
59
|
if (converted.length > 0) {
|
|
60
60
|
lines.push('## Converted')
|
|
61
61
|
converted.forEach((idea) => {
|
|
62
|
-
const
|
|
62
|
+
const rel = toRelative(idea.addedAt)
|
|
63
63
|
const feat = idea.convertedTo ? ` \u2192 ${idea.convertedTo}` : ''
|
|
64
|
-
lines.push(`- \u2713 ${idea.text}${feat} _(${
|
|
64
|
+
lines.push(`- \u2713 ${idea.text}${feat} _(${rel})_`)
|
|
65
65
|
})
|
|
66
66
|
lines.push('')
|
|
67
67
|
}
|
|
@@ -70,8 +70,8 @@ class IdeasStorage extends StorageManager<IdeasJson> {
|
|
|
70
70
|
if (archived.length > 0) {
|
|
71
71
|
lines.push('## Archived')
|
|
72
72
|
archived.forEach((idea) => {
|
|
73
|
-
const
|
|
74
|
-
lines.push(`- ${idea.text} _(${
|
|
73
|
+
const rel = toRelative(idea.addedAt)
|
|
74
|
+
lines.push(`- ${idea.text} _(${rel})_`)
|
|
75
75
|
})
|
|
76
76
|
lines.push('')
|
|
77
77
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { generateUUID } from '../schemas'
|
|
9
9
|
import type { ShippedFeature, ShippedJson } from '../types'
|
|
10
|
-
import { getTimestamp } from '../utils/date-helper'
|
|
10
|
+
import { getTimestamp, toRelative } from '../utils/date-helper'
|
|
11
11
|
import { StorageManager } from './storage-manager'
|
|
12
12
|
|
|
13
13
|
class ShippedStorage extends StorageManager<ShippedJson> {
|
|
@@ -72,13 +72,10 @@ class ShippedStorage extends StorageManager<ShippedJson> {
|
|
|
72
72
|
.sort((a, b) => new Date(b.shippedAt).getTime() - new Date(a.shippedAt).getTime())
|
|
73
73
|
|
|
74
74
|
ships.forEach((ship) => {
|
|
75
|
-
const
|
|
76
|
-
month: 'short',
|
|
77
|
-
day: 'numeric',
|
|
78
|
-
})
|
|
75
|
+
const rel = toRelative(ship.shippedAt)
|
|
79
76
|
const version = ship.version ? ` v${ship.version}` : ''
|
|
80
77
|
const duration = ship.duration ? ` (${ship.duration})` : ''
|
|
81
|
-
lines.push(`- **${ship.name}**${version}${duration} - ${
|
|
78
|
+
lines.push(`- **${ship.name}**${version}${duration} - ${rel}`)
|
|
82
79
|
if (ship.description) {
|
|
83
80
|
lines.push(` _${ship.description}_`)
|
|
84
81
|
}
|
|
@@ -16,7 +16,7 @@ import type {
|
|
|
16
16
|
Subtask,
|
|
17
17
|
SubtaskSummary,
|
|
18
18
|
} from '../schemas/state'
|
|
19
|
-
import { getTimestamp } from '../utils/date-helper'
|
|
19
|
+
import { getTimestamp, toRelative } from '../utils/date-helper'
|
|
20
20
|
import { md } from '../utils/markdown-builder'
|
|
21
21
|
import { StorageManager } from './storage-manager'
|
|
22
22
|
|
|
@@ -52,7 +52,7 @@ class StateStorage extends StorageManager<StateJson> {
|
|
|
52
52
|
const task = data.currentTask!
|
|
53
53
|
m.bold(task.description)
|
|
54
54
|
.blank()
|
|
55
|
-
.raw(`Started: ${task.startedAt}`)
|
|
55
|
+
.raw(`Started: ${toRelative(task.startedAt)}`)
|
|
56
56
|
.raw(`Session: ${task.sessionId}`)
|
|
57
57
|
.maybe(task.featureId, (m, id) => m.raw(`Feature: ${id}`))
|
|
58
58
|
|
|
@@ -122,7 +122,7 @@ class StateStorage extends StorageManager<StateJson> {
|
|
|
122
122
|
m.hr()
|
|
123
123
|
.h2('Paused')
|
|
124
124
|
.bold(prev.description)
|
|
125
|
-
.raw(`Paused: ${prev.pausedAt}`)
|
|
125
|
+
.raw(`Paused: ${toRelative(prev.pausedAt)}`)
|
|
126
126
|
.maybe(prev.pauseReason, (m, reason) => m.raw(`Reason: ${reason}`))
|
|
127
127
|
.blank()
|
|
128
128
|
.italic('Use /p:resume to continue')
|
package/core/utils/citations.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @see PRJ-113
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { ContextSources, SourceInfo
|
|
10
|
+
import type { ContextSources, SourceInfo } from '../types/citations'
|
|
11
11
|
|
|
12
12
|
export type { ContextSources, SourceInfo, SourceType } from '../types/citations'
|
|
13
13
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - commands.ts (38+ inline date operations)
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { formatDistanceToNowStrict } from 'date-fns'
|
|
10
11
|
import type { DateComponents } from '../types'
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -164,3 +165,12 @@ export function getEndOfDay(date: Date): Date {
|
|
|
164
165
|
result.setHours(23, 59, 59, 999)
|
|
165
166
|
return result
|
|
166
167
|
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Convert a date/timestamp to a relative string (e.g. "5 minutes ago").
|
|
171
|
+
* Uses date-fns formatDistanceToNowStrict for accurate, token-friendly output.
|
|
172
|
+
*/
|
|
173
|
+
export function toRelative(date: string | Date): string {
|
|
174
|
+
const d = typeof date === 'string' ? new Date(date) : date
|
|
175
|
+
return formatDistanceToNowStrict(d, { addSuffix: true })
|
|
176
|
+
}
|
package/dist/bin/prjct.mjs
CHANGED
|
@@ -667,8 +667,10 @@ __export(date_helper_exports, {
|
|
|
667
667
|
getYearMonthDay: () => getYearMonthDay,
|
|
668
668
|
isToday: () => isToday,
|
|
669
669
|
isWithinLastDays: () => isWithinLastDays,
|
|
670
|
-
parseDate: () => parseDate
|
|
670
|
+
parseDate: () => parseDate,
|
|
671
|
+
toRelative: () => toRelative
|
|
671
672
|
});
|
|
673
|
+
import { formatDistanceToNowStrict } from "date-fns";
|
|
672
674
|
function formatDate(date) {
|
|
673
675
|
const year = date.getFullYear();
|
|
674
676
|
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
|
@@ -755,6 +757,10 @@ function getEndOfDay(date) {
|
|
|
755
757
|
result.setHours(23, 59, 59, 999);
|
|
756
758
|
return result;
|
|
757
759
|
}
|
|
760
|
+
function toRelative(date) {
|
|
761
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
762
|
+
return formatDistanceToNowStrict(d, { addSuffix: true });
|
|
763
|
+
}
|
|
758
764
|
var init_date_helper = __esm({
|
|
759
765
|
"core/utils/date-helper.ts"() {
|
|
760
766
|
"use strict";
|
|
@@ -774,6 +780,7 @@ var init_date_helper = __esm({
|
|
|
774
780
|
__name(calculateDuration, "calculateDuration");
|
|
775
781
|
__name(getStartOfDay, "getStartOfDay");
|
|
776
782
|
__name(getEndOfDay, "getEndOfDay");
|
|
783
|
+
__name(toRelative, "toRelative");
|
|
777
784
|
}
|
|
778
785
|
});
|
|
779
786
|
|
|
@@ -10716,10 +10723,10 @@ var init_ideas_storage = __esm({
|
|
|
10716
10723
|
lines.push("## Brain Dump");
|
|
10717
10724
|
if (pending.length > 0) {
|
|
10718
10725
|
pending.forEach((idea) => {
|
|
10719
|
-
const
|
|
10726
|
+
const rel = toRelative(idea.addedAt);
|
|
10720
10727
|
const tags = idea.tags.length > 0 ? ` ${idea.tags.map((t) => `#${t}`).join(" ")}` : "";
|
|
10721
10728
|
const priority = idea.priority !== "medium" ? ` [${idea.priority.toUpperCase()}]` : "";
|
|
10722
|
-
lines.push(`- ${idea.text}${priority} _(${
|
|
10729
|
+
lines.push(`- ${idea.text}${priority} _(${rel})_${tags}`);
|
|
10723
10730
|
});
|
|
10724
10731
|
} else {
|
|
10725
10732
|
lines.push("_No pending ideas_");
|
|
@@ -10728,17 +10735,17 @@ var init_ideas_storage = __esm({
|
|
|
10728
10735
|
if (converted.length > 0) {
|
|
10729
10736
|
lines.push("## Converted");
|
|
10730
10737
|
converted.forEach((idea) => {
|
|
10731
|
-
const
|
|
10738
|
+
const rel = toRelative(idea.addedAt);
|
|
10732
10739
|
const feat = idea.convertedTo ? ` \u2192 ${idea.convertedTo}` : "";
|
|
10733
|
-
lines.push(`- \u2713 ${idea.text}${feat} _(${
|
|
10740
|
+
lines.push(`- \u2713 ${idea.text}${feat} _(${rel})_`);
|
|
10734
10741
|
});
|
|
10735
10742
|
lines.push("");
|
|
10736
10743
|
}
|
|
10737
10744
|
if (archived.length > 0) {
|
|
10738
10745
|
lines.push("## Archived");
|
|
10739
10746
|
archived.forEach((idea) => {
|
|
10740
|
-
const
|
|
10741
|
-
lines.push(`- ${idea.text} _(${
|
|
10747
|
+
const rel = toRelative(idea.addedAt);
|
|
10748
|
+
lines.push(`- ${idea.text} _(${rel})_`);
|
|
10742
10749
|
});
|
|
10743
10750
|
lines.push("");
|
|
10744
10751
|
}
|
|
@@ -11466,13 +11473,10 @@ var init_shipped_storage = __esm({
|
|
|
11466
11473
|
lines.push("");
|
|
11467
11474
|
const ships = byMonth.get(month).sort((a, b) => new Date(b.shippedAt).getTime() - new Date(a.shippedAt).getTime());
|
|
11468
11475
|
ships.forEach((ship) => {
|
|
11469
|
-
const
|
|
11470
|
-
month: "short",
|
|
11471
|
-
day: "numeric"
|
|
11472
|
-
});
|
|
11476
|
+
const rel = toRelative(ship.shippedAt);
|
|
11473
11477
|
const version = ship.version ? ` v${ship.version}` : "";
|
|
11474
11478
|
const duration = ship.duration ? ` (${ship.duration})` : "";
|
|
11475
|
-
lines.push(`- **${ship.name}**${version}${duration} - ${
|
|
11479
|
+
lines.push(`- **${ship.name}**${version}${duration} - ${rel}`);
|
|
11476
11480
|
if (ship.description) {
|
|
11477
11481
|
lines.push(` _${ship.description}_`);
|
|
11478
11482
|
}
|
|
@@ -11848,7 +11852,7 @@ var init_state_storage = __esm({
|
|
|
11848
11852
|
toMarkdown(data) {
|
|
11849
11853
|
return md().h1("NOW").when(!!data.currentTask, (m) => {
|
|
11850
11854
|
const task = data.currentTask;
|
|
11851
|
-
m.bold(task.description).blank().raw(`Started: ${task.startedAt}`).raw(`Session: ${task.sessionId}`).maybe(task.featureId, (m2, id) => m2.raw(`Feature: ${id}`));
|
|
11855
|
+
m.bold(task.description).blank().raw(`Started: ${toRelative(task.startedAt)}`).raw(`Session: ${task.sessionId}`).maybe(task.featureId, (m2, id) => m2.raw(`Feature: ${id}`));
|
|
11852
11856
|
if (task.subtasks && task.subtasks.length > 0) {
|
|
11853
11857
|
m.blank().h2("Subtasks Progress").raw(
|
|
11854
11858
|
`**Progress**: ${task.subtaskProgress?.completed || 0}/${task.subtaskProgress?.total || 0} (${task.subtaskProgress?.percentage || 0}%)`
|
|
@@ -11883,7 +11887,7 @@ var init_state_storage = __esm({
|
|
|
11883
11887
|
}).when(!data.currentTask, (m) => {
|
|
11884
11888
|
m.italic("No active task. Use /p:work to start.");
|
|
11885
11889
|
}).maybe(data.previousTask, (m, prev) => {
|
|
11886
|
-
m.hr().h2("Paused").bold(prev.description).raw(`Paused: ${prev.pausedAt}`).maybe(prev.pauseReason, (m2, reason2) => m2.raw(`Reason: ${reason2}`)).blank().italic("Use /p:resume to continue");
|
|
11890
|
+
m.hr().h2("Paused").bold(prev.description).raw(`Paused: ${toRelative(prev.pausedAt)}`).maybe(prev.pauseReason, (m2, reason2) => m2.raw(`Reason: ${reason2}`)).blank().italic("Use /p:resume to continue");
|
|
11887
11891
|
}).blank().build();
|
|
11888
11892
|
}
|
|
11889
11893
|
// =========== Domain Methods ===========
|
|
@@ -28706,7 +28710,7 @@ var require_package = __commonJS({
|
|
|
28706
28710
|
"package.json"(exports, module) {
|
|
28707
28711
|
module.exports = {
|
|
28708
28712
|
name: "prjct-cli",
|
|
28709
|
-
version: "1.
|
|
28713
|
+
version: "1.7.0",
|
|
28710
28714
|
description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
|
|
28711
28715
|
main: "core/index.ts",
|
|
28712
28716
|
bin: {
|
|
@@ -28761,6 +28765,7 @@ var require_package = __commonJS({
|
|
|
28761
28765
|
"@linear/sdk": "^29.0.0",
|
|
28762
28766
|
chalk: "^4.1.2",
|
|
28763
28767
|
chokidar: "^5.0.0",
|
|
28768
|
+
"date-fns": "^4.1.0",
|
|
28764
28769
|
esbuild: "^0.25.0",
|
|
28765
28770
|
glob: "^13.0.1",
|
|
28766
28771
|
hono: "^4.11.3",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prjct-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
|
|
5
5
|
"main": "core/index.ts",
|
|
6
6
|
"bin": {
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"@linear/sdk": "^29.0.0",
|
|
56
56
|
"chalk": "^4.1.2",
|
|
57
57
|
"chokidar": "^5.0.0",
|
|
58
|
+
"date-fns": "^4.1.0",
|
|
58
59
|
"esbuild": "^0.25.0",
|
|
59
60
|
"glob": "^13.0.1",
|
|
60
61
|
"hono": "^4.11.3",
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
allowed-tools: [Glob, Read]
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Context Filtering
|
|
6
|
-
|
|
7
|
-
Determine relevant files for a task.
|
|
8
|
-
|
|
9
|
-
## Process
|
|
10
|
-
|
|
11
|
-
1. **Get real extensions**: Only include what EXISTS in project
|
|
12
|
-
2. **Identify directories**: Based on task, not assumptions
|
|
13
|
-
3. **Filter by task**: What files will be modified?
|
|
14
|
-
4. **Exclude non-relevant**: node_modules, .git, dist, build
|
|
15
|
-
|
|
16
|
-
## Output
|
|
17
|
-
|
|
18
|
-
```json
|
|
19
|
-
{
|
|
20
|
-
"include": {
|
|
21
|
-
"extensions": [".ts", ".tsx"],
|
|
22
|
-
"directories": ["src/", "lib/"]
|
|
23
|
-
},
|
|
24
|
-
"exclude": {
|
|
25
|
-
"directories": ["node_modules/", ".git/", "dist/"]
|
|
26
|
-
},
|
|
27
|
-
"reasoning": "why these patterns"
|
|
28
|
-
}
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Rules
|
|
32
|
-
|
|
33
|
-
- Use REAL extensions (not assumed)
|
|
34
|
-
- Task-specific filtering
|
|
35
|
-
- Efficient - focus on what matters
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# Skill Integration
|
|
2
|
-
|
|
3
|
-
Agents integrate with Claude Code skills from claude-plugins.dev.
|
|
4
|
-
|
|
5
|
-
## Agent → Skill Mapping
|
|
6
|
-
|
|
7
|
-
| Agent | Skill |
|
|
8
|
-
|-------|-------|
|
|
9
|
-
| frontend.md | frontend-design |
|
|
10
|
-
| uxui.md | frontend-design |
|
|
11
|
-
| backend.md | javascript-typescript |
|
|
12
|
-
| testing.md | developer-kit |
|
|
13
|
-
| devops.md | developer-kit |
|
|
14
|
-
| prjct-planner.md | feature-dev |
|
|
15
|
-
| prjct-shipper.md | code-review |
|
|
16
|
-
|
|
17
|
-
## Installation (during `p. sync`)
|
|
18
|
-
|
|
19
|
-
1. Check existing: `ls ~/.claude/skills/*.md`
|
|
20
|
-
2. Search: `https://claude-plugins.dev/skills?q={term}`
|
|
21
|
-
3. Prefer: @anthropics, high downloads
|
|
22
|
-
4. Write to: `~/.claude/skills/{name}.md`
|
|
23
|
-
5. Save mapping: `{globalPath}/config/skills.json`
|
|
24
|
-
|
|
25
|
-
## Agent Frontmatter
|
|
26
|
-
|
|
27
|
-
```yaml
|
|
28
|
-
---
|
|
29
|
-
name: frontend
|
|
30
|
-
description: "Frontend specialist. Use PROACTIVELY."
|
|
31
|
-
tools: Read, Write, Glob, Grep
|
|
32
|
-
skills: [frontend-design]
|
|
33
|
-
---
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Usage
|
|
37
|
-
|
|
38
|
-
**During `p. task`**:
|
|
39
|
-
- Load agent → invoke linked skills
|
|
40
|
-
|
|
41
|
-
**During `p. ship`**:
|
|
42
|
-
- Invoke code-review skill
|
|
43
|
-
|
|
44
|
-
## Key Skills
|
|
45
|
-
|
|
46
|
-
| Skill | Purpose |
|
|
47
|
-
|-------|---------|
|
|
48
|
-
| frontend-design | UI components, anti-AI-slop |
|
|
49
|
-
| javascript-typescript | Node.js, React patterns |
|
|
50
|
-
| python-development | Django, FastAPI patterns |
|
|
51
|
-
| feature-dev | Architecture, planning |
|
|
52
|
-
| code-review | PR review, security |
|
|
53
|
-
| developer-kit | Testing, DevOps |
|
|
54
|
-
|
|
55
|
-
## Troubleshooting
|
|
56
|
-
|
|
57
|
-
- Skill not invoking? Check agent `skills:` frontmatter
|
|
58
|
-
- Wrong skill? Re-run `p. sync`
|
|
59
|
-
- Manual invoke: `/frontend-design`
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# Sub-Agent Generation
|
|
2
|
-
|
|
3
|
-
Generate project-specific agents based on detected stack.
|
|
4
|
-
|
|
5
|
-
## Output Location
|
|
6
|
-
|
|
7
|
-
`{globalPath}/agents/` (NEVER local project)
|
|
8
|
-
|
|
9
|
-
## Agent Format
|
|
10
|
-
|
|
11
|
-
```markdown
|
|
12
|
-
---
|
|
13
|
-
name: agent-name
|
|
14
|
-
description: When to use. Include "Use PROACTIVELY" for auto-invoke.
|
|
15
|
-
tools: Read, Write, Glob, Grep, Bash
|
|
16
|
-
model: sonnet
|
|
17
|
-
skills: [skill-name]
|
|
18
|
-
---
|
|
19
|
-
Agent prompt...
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Required Workflow Agents
|
|
23
|
-
|
|
24
|
-
| Agent | Purpose | Skill |
|
|
25
|
-
|-------|---------|-------|
|
|
26
|
-
| prjct-workflow.md | Task lifecycle | - |
|
|
27
|
-
| prjct-planner.md | Feature planning | feature-dev |
|
|
28
|
-
| prjct-shipper.md | Git, deploy | code-review |
|
|
29
|
-
|
|
30
|
-
## Domain Agents (based on stack)
|
|
31
|
-
|
|
32
|
-
| If Detected | Generate | Skill |
|
|
33
|
-
|-------------|----------|-------|
|
|
34
|
-
| React, Vue, CSS | frontend.md | frontend-design |
|
|
35
|
-
| Node, Express, API | backend.md | javascript-typescript |
|
|
36
|
-
| PostgreSQL, MongoDB | database.md | - |
|
|
37
|
-
| Docker, CI/CD | devops.md | developer-kit |
|
|
38
|
-
| Jest, Pytest | testing.md | developer-kit |
|
|
39
|
-
| Any UI | uxui.md | frontend-design |
|
|
40
|
-
|
|
41
|
-
## Execution
|
|
42
|
-
|
|
43
|
-
1. Read `{globalPath}/analysis/repo-summary.md`
|
|
44
|
-
2. Create `{globalPath}/agents/` directory
|
|
45
|
-
3. Generate workflow agents (always)
|
|
46
|
-
4. Generate domain agents (based on analysis)
|
|
47
|
-
5. Add skills to frontmatter
|
|
48
|
-
6. Report generated agents
|
|
49
|
-
|
|
50
|
-
## Rules
|
|
51
|
-
|
|
52
|
-
- **ALWAYS** write to `{globalPath}/agents/`
|
|
53
|
-
- **NEVER** write to `.claude/` or `.prjct/`
|
|
54
|
-
- Adapt templates to project context
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: bug-severity
|
|
3
|
-
description: Assess bug severity from description
|
|
4
|
-
allowed-tools: [Read]
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Bug Severity Assessment
|
|
8
|
-
|
|
9
|
-
Analyze the bug description to determine its severity and priority.
|
|
10
|
-
|
|
11
|
-
## Input
|
|
12
|
-
- Bug: {{description}}
|
|
13
|
-
- Context (if available)
|
|
14
|
-
|
|
15
|
-
## Severity Levels
|
|
16
|
-
|
|
17
|
-
### CRITICAL
|
|
18
|
-
- System crash or data loss
|
|
19
|
-
- Security vulnerability
|
|
20
|
-
- Blocks all users
|
|
21
|
-
- Production is down
|
|
22
|
-
|
|
23
|
-
### HIGH
|
|
24
|
-
- Major feature broken
|
|
25
|
-
- Significant user impact
|
|
26
|
-
- Workaround difficult
|
|
27
|
-
- Affects many users
|
|
28
|
-
|
|
29
|
-
### MEDIUM
|
|
30
|
-
- Feature partially broken
|
|
31
|
-
- Workaround exists
|
|
32
|
-
- Limited user impact
|
|
33
|
-
- Non-essential functionality
|
|
34
|
-
|
|
35
|
-
### LOW
|
|
36
|
-
- Minor inconvenience
|
|
37
|
-
- Cosmetic issue
|
|
38
|
-
- Edge case only
|
|
39
|
-
- Easy workaround
|
|
40
|
-
|
|
41
|
-
## Analysis Steps
|
|
42
|
-
|
|
43
|
-
1. **Assess Impact**
|
|
44
|
-
- Who is affected?
|
|
45
|
-
- How many users?
|
|
46
|
-
- Is there data loss risk?
|
|
47
|
-
|
|
48
|
-
2. **Check Urgency**
|
|
49
|
-
- Is production affected?
|
|
50
|
-
- Is there a deadline?
|
|
51
|
-
- Are users blocked?
|
|
52
|
-
|
|
53
|
-
3. **Evaluate Workaround**
|
|
54
|
-
- Can users continue working?
|
|
55
|
-
- How hard is the workaround?
|
|
56
|
-
|
|
57
|
-
## Output Format
|
|
58
|
-
|
|
59
|
-
Return JSON:
|
|
60
|
-
```json
|
|
61
|
-
{
|
|
62
|
-
"severity": "critical|high|medium|low",
|
|
63
|
-
"priority": 1-4,
|
|
64
|
-
"reasoning": "<brief explanation>",
|
|
65
|
-
"suggestedAction": "<what to do next>"
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Guidelines
|
|
70
|
-
|
|
71
|
-
- Err on the side of higher severity if unsure
|
|
72
|
-
- Security issues are always CRITICAL
|
|
73
|
-
- Data loss is always CRITICAL
|
|
74
|
-
- User-reported = add weight
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: complexity-analysis
|
|
3
|
-
description: Analyze task complexity semantically
|
|
4
|
-
allowed-tools: [Read]
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Task Complexity Analysis
|
|
8
|
-
|
|
9
|
-
Analyze the given task description and determine its complexity level.
|
|
10
|
-
|
|
11
|
-
## Input
|
|
12
|
-
- Task: {{task}}
|
|
13
|
-
- Project context (if available)
|
|
14
|
-
|
|
15
|
-
## Analysis Steps
|
|
16
|
-
|
|
17
|
-
1. **Understand the Task**
|
|
18
|
-
- What is being asked?
|
|
19
|
-
- What systems/files are affected?
|
|
20
|
-
- Are there dependencies?
|
|
21
|
-
|
|
22
|
-
2. **Evaluate Scope**
|
|
23
|
-
- Single file change → LOW
|
|
24
|
-
- Multiple files, same module → MEDIUM
|
|
25
|
-
- Cross-module or architectural → HIGH
|
|
26
|
-
|
|
27
|
-
3. **Assess Risk**
|
|
28
|
-
- Read-only or additive → LOW risk
|
|
29
|
-
- Modifying existing logic → MEDIUM risk
|
|
30
|
-
- Refactoring or migration → HIGH risk
|
|
31
|
-
|
|
32
|
-
4. **Consider Dependencies**
|
|
33
|
-
- No external deps → LOW
|
|
34
|
-
- Some integration → MEDIUM
|
|
35
|
-
- Multiple systems → HIGH
|
|
36
|
-
|
|
37
|
-
## Output Format
|
|
38
|
-
|
|
39
|
-
Return JSON:
|
|
40
|
-
```json
|
|
41
|
-
{
|
|
42
|
-
"complexity": "low|medium|high",
|
|
43
|
-
"type": "feature|bugfix|refactor|testing|docs|chore",
|
|
44
|
-
"estimatedHours": <number>,
|
|
45
|
-
"reasoning": "<brief explanation>"
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Guidelines
|
|
50
|
-
|
|
51
|
-
- Be realistic, not optimistic
|
|
52
|
-
- Consider testing time in estimates
|
|
53
|
-
- If unsure, lean toward higher complexity
|
|
54
|
-
- Don't use keyword matching - analyze semantically
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: health-score
|
|
3
|
-
description: Calculate project health score
|
|
4
|
-
allowed-tools: [Read]
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Project Health Score
|
|
8
|
-
|
|
9
|
-
Evaluate the project's health based on activity metrics.
|
|
10
|
-
|
|
11
|
-
## Input
|
|
12
|
-
- Active task: {{hasActiveTask}}
|
|
13
|
-
- Queue size: {{queueSize}}
|
|
14
|
-
- Recent ships: {{recentShips}}
|
|
15
|
-
- Ideas count: {{ideasCount}}
|
|
16
|
-
- Days since last ship: {{daysSinceShip}}
|
|
17
|
-
|
|
18
|
-
## Health Factors
|
|
19
|
-
|
|
20
|
-
### Momentum (40%)
|
|
21
|
-
- Active task = good
|
|
22
|
-
- Regular shipping = good
|
|
23
|
-
- Long gaps = concerning
|
|
24
|
-
|
|
25
|
-
### Focus (30%)
|
|
26
|
-
- Queue < 10 = focused
|
|
27
|
-
- Queue 10-20 = busy
|
|
28
|
-
- Queue > 20 = overloaded
|
|
29
|
-
|
|
30
|
-
### Progress (20%)
|
|
31
|
-
- Ships this week > 0 = active
|
|
32
|
-
- Ships this month > 2 = productive
|
|
33
|
-
- No ships in 7+ days = stalled
|
|
34
|
-
|
|
35
|
-
### Planning (10%)
|
|
36
|
-
- Ideas captured = thinking ahead
|
|
37
|
-
- Too many ideas = unfocused
|
|
38
|
-
|
|
39
|
-
## Score Calculation
|
|
40
|
-
|
|
41
|
-
Evaluate each factor and combine:
|
|
42
|
-
|
|
43
|
-
| Score | Label | Meaning |
|
|
44
|
-
|-------|-------|---------|
|
|
45
|
-
| 80-100 | Excellent | High momentum, focused, shipping |
|
|
46
|
-
| 60-79 | Good | Active, some room to improve |
|
|
47
|
-
| 40-59 | Fair | Slowing down, needs attention |
|
|
48
|
-
| 0-39 | Low | Stalled, intervention needed |
|
|
49
|
-
|
|
50
|
-
## Output Format
|
|
51
|
-
|
|
52
|
-
Return JSON:
|
|
53
|
-
```json
|
|
54
|
-
{
|
|
55
|
-
"score": <0-100>,
|
|
56
|
-
"label": "Excellent|Good|Fair|Low",
|
|
57
|
-
"momentum": "<assessment>",
|
|
58
|
-
"suggestions": ["<action 1>", "<action 2>"]
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## Guidelines
|
|
63
|
-
|
|
64
|
-
- Be encouraging but honest
|
|
65
|
-
- Suggest specific actions
|
|
66
|
-
- Focus on momentum, not perfection
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: intent-detection
|
|
3
|
-
description: Detect user intent from natural language
|
|
4
|
-
allowed-tools: []
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Intent Detection
|
|
8
|
-
|
|
9
|
-
Analyze user input to determine their intent and map to appropriate action.
|
|
10
|
-
|
|
11
|
-
## Input
|
|
12
|
-
- User message: {{message}}
|
|
13
|
-
|
|
14
|
-
## Intent Categories
|
|
15
|
-
|
|
16
|
-
### Work Intents
|
|
17
|
-
- **start_task**: User wants to begin working on something
|
|
18
|
-
- **complete_task**: User finished current work
|
|
19
|
-
- **ship**: User wants to release/deploy
|
|
20
|
-
- **pause**: User needs to pause current work
|
|
21
|
-
|
|
22
|
-
### Planning Intents
|
|
23
|
-
- **add_feature**: User has a new feature idea
|
|
24
|
-
- **add_idea**: Quick thought to capture
|
|
25
|
-
- **add_bug**: Report a problem
|
|
26
|
-
- **view_queue**: See what's next
|
|
27
|
-
|
|
28
|
-
### Status Intents
|
|
29
|
-
- **check_progress**: View metrics/status
|
|
30
|
-
- **get_recap**: Project overview
|
|
31
|
-
- **get_help**: Need guidance
|
|
32
|
-
|
|
33
|
-
### System Intents
|
|
34
|
-
- **sync**: Update project state
|
|
35
|
-
- **analyze**: Analyze codebase
|
|
36
|
-
- **cleanup**: Clean up files
|
|
37
|
-
|
|
38
|
-
## Analysis
|
|
39
|
-
|
|
40
|
-
Look for semantic meaning, not keywords:
|
|
41
|
-
- "I'm done" → complete_task
|
|
42
|
-
- "Let's ship this" → ship
|
|
43
|
-
- "Quick thought..." → add_idea
|
|
44
|
-
- "What should I do?" → get_help OR view_queue
|
|
45
|
-
|
|
46
|
-
## Output Format
|
|
47
|
-
|
|
48
|
-
Return JSON:
|
|
49
|
-
```json
|
|
50
|
-
{
|
|
51
|
-
"intent": "<intent_name>",
|
|
52
|
-
"confidence": <0.0-1.0>,
|
|
53
|
-
"parameters": {
|
|
54
|
-
"task": "<extracted task if any>",
|
|
55
|
-
"feature": "<extracted feature if any>"
|
|
56
|
-
},
|
|
57
|
-
"suggestedCommand": "/p:<command>"
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Guidelines
|
|
62
|
-
|
|
63
|
-
- Use semantic understanding, not regex
|
|
64
|
-
- Extract relevant parameters
|
|
65
|
-
- High confidence (>0.8) for clear intents
|
|
66
|
-
- Ask for clarification if < 0.5
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: task-breakdown
|
|
3
|
-
description: Break down a feature into actionable tasks
|
|
4
|
-
allowed-tools: [Read, Glob, Grep]
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Feature Task Breakdown
|
|
8
|
-
|
|
9
|
-
Analyze the feature description and break it into concrete, actionable tasks.
|
|
10
|
-
|
|
11
|
-
## Input
|
|
12
|
-
- Feature: {{feature}}
|
|
13
|
-
- Project path: {{projectPath}}
|
|
14
|
-
|
|
15
|
-
## Analysis Steps
|
|
16
|
-
|
|
17
|
-
1. **Understand the Feature**
|
|
18
|
-
- Read related code if paths are obvious
|
|
19
|
-
- Identify affected systems
|
|
20
|
-
- Note existing patterns to follow
|
|
21
|
-
|
|
22
|
-
2. **Identify Components**
|
|
23
|
-
- What new files/modules are needed?
|
|
24
|
-
- What existing code needs modification?
|
|
25
|
-
- What tests are required?
|
|
26
|
-
|
|
27
|
-
3. **Order by Dependencies**
|
|
28
|
-
- Foundation tasks first (models, types, interfaces)
|
|
29
|
-
- Core logic second
|
|
30
|
-
- Integration third
|
|
31
|
-
- Tests and polish last
|
|
32
|
-
|
|
33
|
-
4. **Size Each Task**
|
|
34
|
-
- Each task should be 20-60 minutes
|
|
35
|
-
- If larger, break down further
|
|
36
|
-
- If smaller, combine with related task
|
|
37
|
-
|
|
38
|
-
## Output Format
|
|
39
|
-
|
|
40
|
-
Return a numbered task list:
|
|
41
|
-
```
|
|
42
|
-
1. [20m] Task description - specific action
|
|
43
|
-
2. [30m] Another task - what exactly to do
|
|
44
|
-
3. [45m] Final task - clear deliverable
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Guidelines
|
|
48
|
-
|
|
49
|
-
- Tasks must be specific and actionable
|
|
50
|
-
- Include time estimates in brackets
|
|
51
|
-
- Order matters - dependencies first
|
|
52
|
-
- Don't assume - if unsure, read code first
|
|
53
|
-
- Match project patterns (read existing code)
|