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 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 date = idea.addedAt.split('T')[0]
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} _(${date})_${tags}`)
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 date = idea.addedAt.split('T')[0]
62
+ const rel = toRelative(idea.addedAt)
63
63
  const feat = idea.convertedTo ? ` \u2192 ${idea.convertedTo}` : ''
64
- lines.push(`- \u2713 ${idea.text}${feat} _(${date})_`)
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 date = idea.addedAt.split('T')[0]
74
- lines.push(`- ${idea.text} _(${date})_`)
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 date = new Date(ship.shippedAt).toLocaleDateString('en-US', {
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} - ${date}`)
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')
@@ -7,7 +7,7 @@
7
7
  * @see PRJ-113
8
8
  */
9
9
 
10
- import type { ContextSources, SourceInfo, SourceType } from '../types/citations'
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
+ }
@@ -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 date = idea.addedAt.split("T")[0];
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} _(${date})_${tags}`);
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 date = idea.addedAt.split("T")[0];
10738
+ const rel = toRelative(idea.addedAt);
10732
10739
  const feat = idea.convertedTo ? ` \u2192 ${idea.convertedTo}` : "";
10733
- lines.push(`- \u2713 ${idea.text}${feat} _(${date})_`);
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 date = idea.addedAt.split("T")[0];
10741
- lines.push(`- ${idea.text} _(${date})_`);
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 date = new Date(ship.shippedAt).toLocaleDateString("en-US", {
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} - ${date}`);
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.6.12",
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.6.12",
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)