prjct-cli 0.54.2 → 0.55.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 +34 -0
- package/core/agentic/prompt-builder.ts +38 -0
- package/core/infrastructure/command-installer.ts +114 -7
- package/dist/bin/prjct.mjs +93 -5
- package/dist/core/infrastructure/command-installer.js +68 -4
- package/dist/core/infrastructure/setup.js +58 -4
- package/package.json +1 -1
- package/templates/commands/git.md +53 -11
- package/templates/commands/merge.md +22 -2
- package/templates/commands/ship.md +28 -2
- package/templates/commands/task.md +30 -6
- package/templates/global/modules/CLAUDE-commands.md +70 -0
- package/templates/global/modules/CLAUDE-core.md +86 -0
- package/templates/global/modules/CLAUDE-git.md +50 -0
- package/templates/global/modules/CLAUDE-intelligence.md +92 -0
- package/templates/global/modules/CLAUDE-storage.md +50 -0
- package/templates/global/modules/module-config.json +36 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.55.0] - 2026-01-30
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- modular CLAUDE.md for reduced token usage - PRJ-94 (#86)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## [0.54.4] - 2026-01-30
|
|
11
|
+
|
|
12
|
+
### Improved
|
|
13
|
+
|
|
14
|
+
- **Modular CLAUDE.md for reduced token usage** (PRJ-94)
|
|
15
|
+
- Split global template into 5 modules: core, git, storage, commands, intelligence
|
|
16
|
+
- Added profile-based composition: minimal (84% reduction), standard (56%), full (23%)
|
|
17
|
+
- FAST commands (sync, next, dash) use minimal profile (~394 tokens)
|
|
18
|
+
- SMART commands (task, ship, bug) dynamically inject additional modules
|
|
19
|
+
- Target 40-60% token reduction achieved for simple commands
|
|
20
|
+
|
|
21
|
+
## [0.54.3] - 2026-01-30
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
- standardize confirmation pattern across all commands (#85)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## [0.54.3] - 2026-01-30
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Standardize confirmation pattern across all commands to use AskUserQuestion
|
|
33
|
+
- Updated `ship.md`, `merge.md`, `git.md`, `task.md` templates
|
|
34
|
+
- Replaces inconsistent "Proceed? (yes/no)" text prompts
|
|
35
|
+
- All confirmations now use consistent options: "Yes (Recommended)", "No, cancel"
|
|
36
|
+
|
|
3
37
|
## [0.54.2] - 2026-01-30
|
|
4
38
|
|
|
5
39
|
### Bug Fixes
|
|
@@ -26,6 +26,7 @@ import type {
|
|
|
26
26
|
ThinkBlock,
|
|
27
27
|
} from '../types'
|
|
28
28
|
import { isNotFoundError } from '../types/fs'
|
|
29
|
+
import { getPackageRoot } from '../utils/version'
|
|
29
30
|
|
|
30
31
|
// Re-export types for convenience
|
|
31
32
|
export type {
|
|
@@ -125,6 +126,31 @@ class PromptBuilder {
|
|
|
125
126
|
this._currentContext = context
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Load a specific CLAUDE module for SMART commands (PRJ-94)
|
|
131
|
+
* These modules extend the base global CLAUDE.md for complex operations
|
|
132
|
+
*/
|
|
133
|
+
loadModule(moduleName: string): string | null {
|
|
134
|
+
const modulePath = path.join(getPackageRoot(), 'templates/global/modules', moduleName)
|
|
135
|
+
return this.getTemplate(modulePath)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Get additional modules needed for SMART commands (PRJ-94)
|
|
140
|
+
* Returns array of module names that should be injected
|
|
141
|
+
*/
|
|
142
|
+
getModulesForCommand(commandName: string): string[] {
|
|
143
|
+
const smartCommands: Record<string, string[]> = {
|
|
144
|
+
task: ['CLAUDE-intelligence.md', 'CLAUDE-storage.md'],
|
|
145
|
+
ship: ['CLAUDE-intelligence.md', 'CLAUDE-storage.md'],
|
|
146
|
+
bug: ['CLAUDE-intelligence.md'],
|
|
147
|
+
done: ['CLAUDE-storage.md'],
|
|
148
|
+
work: ['CLAUDE-intelligence.md', 'CLAUDE-storage.md'],
|
|
149
|
+
spec: ['CLAUDE-intelligence.md'],
|
|
150
|
+
}
|
|
151
|
+
return smartCommands[commandName] || []
|
|
152
|
+
}
|
|
153
|
+
|
|
128
154
|
/**
|
|
129
155
|
* Load quality checklists from templates/checklists/
|
|
130
156
|
* Uses lazy loading with TTL cache.
|
|
@@ -561,6 +587,18 @@ class PromptBuilder {
|
|
|
561
587
|
// CRITICAL: Compressed rules
|
|
562
588
|
parts.push(this.buildCriticalRules())
|
|
563
589
|
|
|
590
|
+
// PRJ-94: Inject additional modules for SMART commands
|
|
591
|
+
const additionalModules = this.getModulesForCommand(commandName)
|
|
592
|
+
if (additionalModules.length > 0) {
|
|
593
|
+
for (const moduleName of additionalModules) {
|
|
594
|
+
const moduleContent = this.loadModule(moduleName)
|
|
595
|
+
if (moduleContent) {
|
|
596
|
+
parts.push('\n')
|
|
597
|
+
parts.push(moduleContent)
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
564
602
|
// P1.1: Learned Patterns
|
|
565
603
|
if (learnedPatterns && Object.keys(learnedPatterns).some((k) => learnedPatterns[k])) {
|
|
566
604
|
parts.push('\n## PROJECT DEFAULTS (apply automatically)\n')
|
|
@@ -25,6 +25,101 @@ import type {
|
|
|
25
25
|
import { isNotFoundError } from '../types/fs'
|
|
26
26
|
import { getPackageRoot } from '../utils/version'
|
|
27
27
|
|
|
28
|
+
// =============================================================================
|
|
29
|
+
// Module Types
|
|
30
|
+
// =============================================================================
|
|
31
|
+
|
|
32
|
+
interface ModuleProfile {
|
|
33
|
+
description: string
|
|
34
|
+
modules: string[]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface ModuleConfig {
|
|
38
|
+
description: string
|
|
39
|
+
version: string
|
|
40
|
+
profiles: Record<string, ModuleProfile>
|
|
41
|
+
default: string
|
|
42
|
+
commandProfiles: Record<string, string>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// =============================================================================
|
|
46
|
+
// Modular Template Composition (PRJ-94)
|
|
47
|
+
// =============================================================================
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Load module configuration
|
|
51
|
+
*/
|
|
52
|
+
async function loadModuleConfig(): Promise<ModuleConfig | null> {
|
|
53
|
+
try {
|
|
54
|
+
const configPath = path.join(getPackageRoot(), 'templates/global/modules/module-config.json')
|
|
55
|
+
const content = await fs.readFile(configPath, 'utf-8')
|
|
56
|
+
return JSON.parse(content) as ModuleConfig
|
|
57
|
+
} catch {
|
|
58
|
+
return null
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Compose global template from modules based on profile
|
|
64
|
+
* @param profile - Profile name ('full', 'standard', 'minimal') or null for default
|
|
65
|
+
* @returns Composed template content with markers
|
|
66
|
+
*/
|
|
67
|
+
export async function composeGlobalTemplate(profile?: string): Promise<string> {
|
|
68
|
+
const config = await loadModuleConfig()
|
|
69
|
+
const modulesDir = path.join(getPackageRoot(), 'templates/global/modules')
|
|
70
|
+
|
|
71
|
+
// Fallback to legacy template if config not found
|
|
72
|
+
if (!config) {
|
|
73
|
+
const legacyPath = path.join(getPackageRoot(), 'templates/global/CLAUDE.md')
|
|
74
|
+
return fs.readFile(legacyPath, 'utf-8')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const profileName = profile || config.default
|
|
78
|
+
const selectedProfile = config.profiles[profileName]
|
|
79
|
+
|
|
80
|
+
if (!selectedProfile) {
|
|
81
|
+
// Fallback to default profile
|
|
82
|
+
const defaultProfile = config.profiles[config.default]
|
|
83
|
+
if (!defaultProfile) {
|
|
84
|
+
const legacyPath = path.join(getPackageRoot(), 'templates/global/CLAUDE.md')
|
|
85
|
+
return fs.readFile(legacyPath, 'utf-8')
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const modules = (selectedProfile || config.profiles[config.default]).modules
|
|
90
|
+
|
|
91
|
+
// Load and compose modules
|
|
92
|
+
const parts: string[] = []
|
|
93
|
+
parts.push('<!-- prjct:start - DO NOT REMOVE THIS MARKER -->')
|
|
94
|
+
|
|
95
|
+
for (const moduleName of modules) {
|
|
96
|
+
try {
|
|
97
|
+
const modulePath = path.join(modulesDir, moduleName)
|
|
98
|
+
const content = await fs.readFile(modulePath, 'utf-8')
|
|
99
|
+
parts.push('')
|
|
100
|
+
parts.push(content)
|
|
101
|
+
} catch {
|
|
102
|
+
// Module not found, skip
|
|
103
|
+
console.warn(`Module not found: ${moduleName}`)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
parts.push('')
|
|
108
|
+
parts.push('<!-- prjct:end - DO NOT REMOVE THIS MARKER -->')
|
|
109
|
+
parts.push('')
|
|
110
|
+
|
|
111
|
+
return parts.join('\n')
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get recommended profile for a command
|
|
116
|
+
*/
|
|
117
|
+
export async function getProfileForCommand(command: string): Promise<string> {
|
|
118
|
+
const config = await loadModuleConfig()
|
|
119
|
+
if (!config) return 'standard'
|
|
120
|
+
return config.commandProfiles[command] || config.default
|
|
121
|
+
}
|
|
122
|
+
|
|
28
123
|
// =============================================================================
|
|
29
124
|
// Global Config
|
|
30
125
|
// =============================================================================
|
|
@@ -89,17 +184,29 @@ export async function installGlobalConfig(): Promise<GlobalConfigResult> {
|
|
|
89
184
|
activeProvider.contextFile
|
|
90
185
|
)
|
|
91
186
|
|
|
92
|
-
// Read template content
|
|
187
|
+
// Read template content - use modular composition (PRJ-94)
|
|
93
188
|
let templateContent = ''
|
|
94
189
|
try {
|
|
190
|
+
// First try provider-specific template
|
|
95
191
|
templateContent = await fs.readFile(templatePath, 'utf-8')
|
|
96
192
|
} catch (_error) {
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
193
|
+
// Use modular composition for Claude (PRJ-94)
|
|
194
|
+
if (providerName === 'claude') {
|
|
195
|
+
try {
|
|
196
|
+
templateContent = await composeGlobalTemplate('standard')
|
|
197
|
+
} catch {
|
|
198
|
+
// Final fallback to legacy template
|
|
199
|
+
const fallbackTemplatePath = path.join(getPackageRoot(), 'templates/global/CLAUDE.md')
|
|
200
|
+
templateContent = await fs.readFile(fallbackTemplatePath, 'utf-8')
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
// Fallback for other providers
|
|
204
|
+
const fallbackTemplatePath = path.join(getPackageRoot(), 'templates/global/CLAUDE.md')
|
|
205
|
+
templateContent = await fs.readFile(fallbackTemplatePath, 'utf-8')
|
|
206
|
+
// If it is Gemini, we should rename Claude to Gemini in the fallback content
|
|
207
|
+
if (providerName === 'gemini') {
|
|
208
|
+
templateContent = templateContent.replace(/Claude/g, 'Gemini')
|
|
209
|
+
}
|
|
103
210
|
}
|
|
104
211
|
}
|
|
105
212
|
|
package/dist/bin/prjct.mjs
CHANGED
|
@@ -5525,6 +5525,49 @@ var init_doctor_service = __esm({
|
|
|
5525
5525
|
import fs16 from "node:fs/promises";
|
|
5526
5526
|
import os5 from "node:os";
|
|
5527
5527
|
import path16 from "node:path";
|
|
5528
|
+
async function loadModuleConfig() {
|
|
5529
|
+
try {
|
|
5530
|
+
const configPath = path16.join(getPackageRoot(), "templates/global/modules/module-config.json");
|
|
5531
|
+
const content = await fs16.readFile(configPath, "utf-8");
|
|
5532
|
+
return JSON.parse(content);
|
|
5533
|
+
} catch {
|
|
5534
|
+
return null;
|
|
5535
|
+
}
|
|
5536
|
+
}
|
|
5537
|
+
async function composeGlobalTemplate(profile) {
|
|
5538
|
+
const config = await loadModuleConfig();
|
|
5539
|
+
const modulesDir = path16.join(getPackageRoot(), "templates/global/modules");
|
|
5540
|
+
if (!config) {
|
|
5541
|
+
const legacyPath = path16.join(getPackageRoot(), "templates/global/CLAUDE.md");
|
|
5542
|
+
return fs16.readFile(legacyPath, "utf-8");
|
|
5543
|
+
}
|
|
5544
|
+
const profileName = profile || config.default;
|
|
5545
|
+
const selectedProfile = config.profiles[profileName];
|
|
5546
|
+
if (!selectedProfile) {
|
|
5547
|
+
const defaultProfile = config.profiles[config.default];
|
|
5548
|
+
if (!defaultProfile) {
|
|
5549
|
+
const legacyPath = path16.join(getPackageRoot(), "templates/global/CLAUDE.md");
|
|
5550
|
+
return fs16.readFile(legacyPath, "utf-8");
|
|
5551
|
+
}
|
|
5552
|
+
}
|
|
5553
|
+
const modules = (selectedProfile || config.profiles[config.default]).modules;
|
|
5554
|
+
const parts = [];
|
|
5555
|
+
parts.push("<!-- prjct:start - DO NOT REMOVE THIS MARKER -->");
|
|
5556
|
+
for (const moduleName of modules) {
|
|
5557
|
+
try {
|
|
5558
|
+
const modulePath = path16.join(modulesDir, moduleName);
|
|
5559
|
+
const content = await fs16.readFile(modulePath, "utf-8");
|
|
5560
|
+
parts.push("");
|
|
5561
|
+
parts.push(content);
|
|
5562
|
+
} catch {
|
|
5563
|
+
console.warn(`Module not found: ${moduleName}`);
|
|
5564
|
+
}
|
|
5565
|
+
}
|
|
5566
|
+
parts.push("");
|
|
5567
|
+
parts.push("<!-- prjct:end - DO NOT REMOVE THIS MARKER -->");
|
|
5568
|
+
parts.push("");
|
|
5569
|
+
return parts.join("\n");
|
|
5570
|
+
}
|
|
5528
5571
|
async function installDocs() {
|
|
5529
5572
|
try {
|
|
5530
5573
|
const docsDir = path16.join(os5.homedir(), ".prjct-cli", "docs");
|
|
@@ -5569,10 +5612,19 @@ async function installGlobalConfig2() {
|
|
|
5569
5612
|
try {
|
|
5570
5613
|
templateContent = await fs16.readFile(templatePath, "utf-8");
|
|
5571
5614
|
} catch (_error) {
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5615
|
+
if (providerName === "claude") {
|
|
5616
|
+
try {
|
|
5617
|
+
templateContent = await composeGlobalTemplate("standard");
|
|
5618
|
+
} catch {
|
|
5619
|
+
const fallbackTemplatePath = path16.join(getPackageRoot(), "templates/global/CLAUDE.md");
|
|
5620
|
+
templateContent = await fs16.readFile(fallbackTemplatePath, "utf-8");
|
|
5621
|
+
}
|
|
5622
|
+
} else {
|
|
5623
|
+
const fallbackTemplatePath = path16.join(getPackageRoot(), "templates/global/CLAUDE.md");
|
|
5624
|
+
templateContent = await fs16.readFile(fallbackTemplatePath, "utf-8");
|
|
5625
|
+
if (providerName === "gemini") {
|
|
5626
|
+
templateContent = templateContent.replace(/Claude/g, "Gemini");
|
|
5627
|
+
}
|
|
5576
5628
|
}
|
|
5577
5629
|
}
|
|
5578
5630
|
let existingContent = "";
|
|
@@ -5655,6 +5707,8 @@ var init_command_installer = __esm({
|
|
|
5655
5707
|
"use strict";
|
|
5656
5708
|
init_fs();
|
|
5657
5709
|
init_version();
|
|
5710
|
+
__name(loadModuleConfig, "loadModuleConfig");
|
|
5711
|
+
__name(composeGlobalTemplate, "composeGlobalTemplate");
|
|
5658
5712
|
__name(installDocs, "installDocs");
|
|
5659
5713
|
__name(installGlobalConfig2, "installGlobalConfig");
|
|
5660
5714
|
CommandInstaller = class {
|
|
@@ -12510,6 +12564,7 @@ var init_prompt_builder = __esm({
|
|
|
12510
12564
|
init_outcomes2();
|
|
12511
12565
|
init_storage2();
|
|
12512
12566
|
init_fs();
|
|
12567
|
+
init_version();
|
|
12513
12568
|
PromptBuilder = class {
|
|
12514
12569
|
static {
|
|
12515
12570
|
__name(this, "PromptBuilder");
|
|
@@ -12572,6 +12627,29 @@ var init_prompt_builder = __esm({
|
|
|
12572
12627
|
setContext(context2) {
|
|
12573
12628
|
this._currentContext = context2;
|
|
12574
12629
|
}
|
|
12630
|
+
/**
|
|
12631
|
+
* Load a specific CLAUDE module for SMART commands (PRJ-94)
|
|
12632
|
+
* These modules extend the base global CLAUDE.md for complex operations
|
|
12633
|
+
*/
|
|
12634
|
+
loadModule(moduleName) {
|
|
12635
|
+
const modulePath = path25.join(getPackageRoot(), "templates/global/modules", moduleName);
|
|
12636
|
+
return this.getTemplate(modulePath);
|
|
12637
|
+
}
|
|
12638
|
+
/**
|
|
12639
|
+
* Get additional modules needed for SMART commands (PRJ-94)
|
|
12640
|
+
* Returns array of module names that should be injected
|
|
12641
|
+
*/
|
|
12642
|
+
getModulesForCommand(commandName) {
|
|
12643
|
+
const smartCommands = {
|
|
12644
|
+
task: ["CLAUDE-intelligence.md", "CLAUDE-storage.md"],
|
|
12645
|
+
ship: ["CLAUDE-intelligence.md", "CLAUDE-storage.md"],
|
|
12646
|
+
bug: ["CLAUDE-intelligence.md"],
|
|
12647
|
+
done: ["CLAUDE-storage.md"],
|
|
12648
|
+
work: ["CLAUDE-intelligence.md", "CLAUDE-storage.md"],
|
|
12649
|
+
spec: ["CLAUDE-intelligence.md"]
|
|
12650
|
+
};
|
|
12651
|
+
return smartCommands[commandName] || [];
|
|
12652
|
+
}
|
|
12575
12653
|
/**
|
|
12576
12654
|
* Load quality checklists from templates/checklists/
|
|
12577
12655
|
* Uses lazy loading with TTL cache.
|
|
@@ -12926,6 +13004,16 @@ Stack: ${stack}
|
|
|
12926
13004
|
}
|
|
12927
13005
|
}
|
|
12928
13006
|
parts.push(this.buildCriticalRules());
|
|
13007
|
+
const additionalModules = this.getModulesForCommand(commandName);
|
|
13008
|
+
if (additionalModules.length > 0) {
|
|
13009
|
+
for (const moduleName of additionalModules) {
|
|
13010
|
+
const moduleContent = this.loadModule(moduleName);
|
|
13011
|
+
if (moduleContent) {
|
|
13012
|
+
parts.push("\n");
|
|
13013
|
+
parts.push(moduleContent);
|
|
13014
|
+
}
|
|
13015
|
+
}
|
|
13016
|
+
}
|
|
12929
13017
|
if (learnedPatterns && Object.keys(learnedPatterns).some((k) => learnedPatterns[k])) {
|
|
12930
13018
|
parts.push("\n## PROJECT DEFAULTS (apply automatically)\n");
|
|
12931
13019
|
for (const [key, value] of Object.entries(learnedPatterns)) {
|
|
@@ -25073,7 +25161,7 @@ var require_package = __commonJS({
|
|
|
25073
25161
|
"package.json"(exports, module) {
|
|
25074
25162
|
module.exports = {
|
|
25075
25163
|
name: "prjct-cli",
|
|
25076
|
-
version: "0.
|
|
25164
|
+
version: "0.55.0",
|
|
25077
25165
|
description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
|
|
25078
25166
|
main: "core/index.ts",
|
|
25079
25167
|
bin: {
|
|
@@ -393,7 +393,9 @@ var init_ai_provider = __esm({
|
|
|
393
393
|
var command_installer_exports = {};
|
|
394
394
|
__export(command_installer_exports, {
|
|
395
395
|
CommandInstaller: () => CommandInstaller,
|
|
396
|
+
composeGlobalTemplate: () => composeGlobalTemplate,
|
|
396
397
|
default: () => command_installer_default,
|
|
398
|
+
getProfileForCommand: () => getProfileForCommand,
|
|
397
399
|
getProviderPaths: () => getProviderPaths,
|
|
398
400
|
installDocs: () => installDocs,
|
|
399
401
|
installGlobalConfig: () => installGlobalConfig,
|
|
@@ -459,6 +461,57 @@ var VERSION = getVersion();
|
|
|
459
461
|
var PACKAGE_ROOT = getPackageRoot();
|
|
460
462
|
|
|
461
463
|
// core/infrastructure/command-installer.ts
|
|
464
|
+
async function loadModuleConfig() {
|
|
465
|
+
try {
|
|
466
|
+
const configPath = import_node_path3.default.join(getPackageRoot(), "templates/global/modules/module-config.json");
|
|
467
|
+
const content = await import_promises.default.readFile(configPath, "utf-8");
|
|
468
|
+
return JSON.parse(content);
|
|
469
|
+
} catch {
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
__name(loadModuleConfig, "loadModuleConfig");
|
|
474
|
+
async function composeGlobalTemplate(profile) {
|
|
475
|
+
const config = await loadModuleConfig();
|
|
476
|
+
const modulesDir = import_node_path3.default.join(getPackageRoot(), "templates/global/modules");
|
|
477
|
+
if (!config) {
|
|
478
|
+
const legacyPath = import_node_path3.default.join(getPackageRoot(), "templates/global/CLAUDE.md");
|
|
479
|
+
return import_promises.default.readFile(legacyPath, "utf-8");
|
|
480
|
+
}
|
|
481
|
+
const profileName = profile || config.default;
|
|
482
|
+
const selectedProfile = config.profiles[profileName];
|
|
483
|
+
if (!selectedProfile) {
|
|
484
|
+
const defaultProfile = config.profiles[config.default];
|
|
485
|
+
if (!defaultProfile) {
|
|
486
|
+
const legacyPath = import_node_path3.default.join(getPackageRoot(), "templates/global/CLAUDE.md");
|
|
487
|
+
return import_promises.default.readFile(legacyPath, "utf-8");
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
const modules = (selectedProfile || config.profiles[config.default]).modules;
|
|
491
|
+
const parts = [];
|
|
492
|
+
parts.push("<!-- prjct:start - DO NOT REMOVE THIS MARKER -->");
|
|
493
|
+
for (const moduleName of modules) {
|
|
494
|
+
try {
|
|
495
|
+
const modulePath = import_node_path3.default.join(modulesDir, moduleName);
|
|
496
|
+
const content = await import_promises.default.readFile(modulePath, "utf-8");
|
|
497
|
+
parts.push("");
|
|
498
|
+
parts.push(content);
|
|
499
|
+
} catch {
|
|
500
|
+
console.warn(`Module not found: ${moduleName}`);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
parts.push("");
|
|
504
|
+
parts.push("<!-- prjct:end - DO NOT REMOVE THIS MARKER -->");
|
|
505
|
+
parts.push("");
|
|
506
|
+
return parts.join("\n");
|
|
507
|
+
}
|
|
508
|
+
__name(composeGlobalTemplate, "composeGlobalTemplate");
|
|
509
|
+
async function getProfileForCommand(command) {
|
|
510
|
+
const config = await loadModuleConfig();
|
|
511
|
+
if (!config) return "standard";
|
|
512
|
+
return config.commandProfiles[command] || config.default;
|
|
513
|
+
}
|
|
514
|
+
__name(getProfileForCommand, "getProfileForCommand");
|
|
462
515
|
async function installDocs() {
|
|
463
516
|
try {
|
|
464
517
|
const docsDir = import_node_path3.default.join(import_node_os2.default.homedir(), ".prjct-cli", "docs");
|
|
@@ -504,10 +557,19 @@ async function installGlobalConfig() {
|
|
|
504
557
|
try {
|
|
505
558
|
templateContent = await import_promises.default.readFile(templatePath, "utf-8");
|
|
506
559
|
} catch (_error) {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
560
|
+
if (providerName === "claude") {
|
|
561
|
+
try {
|
|
562
|
+
templateContent = await composeGlobalTemplate("standard");
|
|
563
|
+
} catch {
|
|
564
|
+
const fallbackTemplatePath = import_node_path3.default.join(getPackageRoot(), "templates/global/CLAUDE.md");
|
|
565
|
+
templateContent = await import_promises.default.readFile(fallbackTemplatePath, "utf-8");
|
|
566
|
+
}
|
|
567
|
+
} else {
|
|
568
|
+
const fallbackTemplatePath = import_node_path3.default.join(getPackageRoot(), "templates/global/CLAUDE.md");
|
|
569
|
+
templateContent = await import_promises.default.readFile(fallbackTemplatePath, "utf-8");
|
|
570
|
+
if (providerName === "gemini") {
|
|
571
|
+
templateContent = templateContent.replace(/Claude/g, "Gemini");
|
|
572
|
+
}
|
|
511
573
|
}
|
|
512
574
|
}
|
|
513
575
|
let existingContent = "";
|
|
@@ -919,6 +981,8 @@ var command_installer_default = commandInstaller;
|
|
|
919
981
|
// Annotate the CommonJS export names for ESM import in node:
|
|
920
982
|
0 && (module.exports = {
|
|
921
983
|
CommandInstaller,
|
|
984
|
+
composeGlobalTemplate,
|
|
985
|
+
getProfileForCommand,
|
|
922
986
|
getProviderPaths,
|
|
923
987
|
installDocs,
|
|
924
988
|
installGlobalConfig,
|
|
@@ -470,6 +470,51 @@ init_ai_provider();
|
|
|
470
470
|
var import_promises = __toESM(require("node:fs/promises"));
|
|
471
471
|
var import_node_os2 = __toESM(require("node:os"));
|
|
472
472
|
var import_node_path3 = __toESM(require("node:path"));
|
|
473
|
+
async function loadModuleConfig() {
|
|
474
|
+
try {
|
|
475
|
+
const configPath = import_node_path3.default.join(getPackageRoot(), "templates/global/modules/module-config.json");
|
|
476
|
+
const content = await import_promises.default.readFile(configPath, "utf-8");
|
|
477
|
+
return JSON.parse(content);
|
|
478
|
+
} catch {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
__name(loadModuleConfig, "loadModuleConfig");
|
|
483
|
+
async function composeGlobalTemplate(profile) {
|
|
484
|
+
const config = await loadModuleConfig();
|
|
485
|
+
const modulesDir = import_node_path3.default.join(getPackageRoot(), "templates/global/modules");
|
|
486
|
+
if (!config) {
|
|
487
|
+
const legacyPath = import_node_path3.default.join(getPackageRoot(), "templates/global/CLAUDE.md");
|
|
488
|
+
return import_promises.default.readFile(legacyPath, "utf-8");
|
|
489
|
+
}
|
|
490
|
+
const profileName = profile || config.default;
|
|
491
|
+
const selectedProfile = config.profiles[profileName];
|
|
492
|
+
if (!selectedProfile) {
|
|
493
|
+
const defaultProfile = config.profiles[config.default];
|
|
494
|
+
if (!defaultProfile) {
|
|
495
|
+
const legacyPath = import_node_path3.default.join(getPackageRoot(), "templates/global/CLAUDE.md");
|
|
496
|
+
return import_promises.default.readFile(legacyPath, "utf-8");
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
const modules = (selectedProfile || config.profiles[config.default]).modules;
|
|
500
|
+
const parts = [];
|
|
501
|
+
parts.push("<!-- prjct:start - DO NOT REMOVE THIS MARKER -->");
|
|
502
|
+
for (const moduleName of modules) {
|
|
503
|
+
try {
|
|
504
|
+
const modulePath = import_node_path3.default.join(modulesDir, moduleName);
|
|
505
|
+
const content = await import_promises.default.readFile(modulePath, "utf-8");
|
|
506
|
+
parts.push("");
|
|
507
|
+
parts.push(content);
|
|
508
|
+
} catch {
|
|
509
|
+
console.warn(`Module not found: ${moduleName}`);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
parts.push("");
|
|
513
|
+
parts.push("<!-- prjct:end - DO NOT REMOVE THIS MARKER -->");
|
|
514
|
+
parts.push("");
|
|
515
|
+
return parts.join("\n");
|
|
516
|
+
}
|
|
517
|
+
__name(composeGlobalTemplate, "composeGlobalTemplate");
|
|
473
518
|
async function installDocs() {
|
|
474
519
|
try {
|
|
475
520
|
const docsDir = import_node_path3.default.join(import_node_os2.default.homedir(), ".prjct-cli", "docs");
|
|
@@ -515,10 +560,19 @@ async function installGlobalConfig() {
|
|
|
515
560
|
try {
|
|
516
561
|
templateContent = await import_promises.default.readFile(templatePath, "utf-8");
|
|
517
562
|
} catch (_error) {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
563
|
+
if (providerName === "claude") {
|
|
564
|
+
try {
|
|
565
|
+
templateContent = await composeGlobalTemplate("standard");
|
|
566
|
+
} catch {
|
|
567
|
+
const fallbackTemplatePath = import_node_path3.default.join(getPackageRoot(), "templates/global/CLAUDE.md");
|
|
568
|
+
templateContent = await import_promises.default.readFile(fallbackTemplatePath, "utf-8");
|
|
569
|
+
}
|
|
570
|
+
} else {
|
|
571
|
+
const fallbackTemplatePath = import_node_path3.default.join(getPackageRoot(), "templates/global/CLAUDE.md");
|
|
572
|
+
templateContent = await import_promises.default.readFile(fallbackTemplatePath, "utf-8");
|
|
573
|
+
if (providerName === "gemini") {
|
|
574
|
+
templateContent = templateContent.replace(/Claude/g, "Gemini");
|
|
575
|
+
}
|
|
522
576
|
}
|
|
523
577
|
}
|
|
524
578
|
let existingContent = "";
|
package/package.json
CHANGED
|
@@ -91,9 +91,8 @@ ABORT.
|
|
|
91
91
|
git diff --stat
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
+
Show the user:
|
|
94
95
|
```
|
|
95
|
-
OUTPUT:
|
|
96
|
-
"""
|
|
97
96
|
## Commit Plan
|
|
98
97
|
|
|
99
98
|
Branch: {currentBranch}
|
|
@@ -101,13 +100,38 @@ Changes:
|
|
|
101
100
|
{git diff --stat output}
|
|
102
101
|
|
|
103
102
|
Will create commit with prjct footer.
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Then ask for confirmation:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
AskUserQuestion:
|
|
109
|
+
question: "Create this commit?"
|
|
110
|
+
header: "Commit"
|
|
111
|
+
options:
|
|
112
|
+
- label: "Yes, commit (Recommended)"
|
|
113
|
+
description: "Stage all changes and commit"
|
|
114
|
+
- label: "No, cancel"
|
|
115
|
+
description: "Abort commit"
|
|
116
|
+
- label: "Show full diff"
|
|
117
|
+
description: "See detailed changes"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Handle responses:**
|
|
106
121
|
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
**If "Show full diff":**
|
|
123
|
+
- Run `git diff` to show full changes
|
|
124
|
+
- Ask again with Yes/No options only
|
|
125
|
+
|
|
126
|
+
**If "No, cancel":**
|
|
127
|
+
```
|
|
128
|
+
OUTPUT: "✅ Commit cancelled"
|
|
129
|
+
STOP - Do not continue
|
|
109
130
|
```
|
|
110
131
|
|
|
132
|
+
**If "Yes, commit":**
|
|
133
|
+
CONTINUE to Step 3
|
|
134
|
+
|
|
111
135
|
### Step 3: Stage and Commit
|
|
112
136
|
|
|
113
137
|
```bash
|
|
@@ -159,20 +183,38 @@ ABORT.
|
|
|
159
183
|
git log origin/{currentBranch}..HEAD --oneline 2>/dev/null || git log --oneline -3
|
|
160
184
|
```
|
|
161
185
|
|
|
186
|
+
Show the user:
|
|
162
187
|
```
|
|
163
|
-
OUTPUT:
|
|
164
|
-
"""
|
|
165
188
|
## Push Plan
|
|
166
189
|
|
|
167
190
|
Branch: {currentBranch}
|
|
168
191
|
Commits to push:
|
|
169
192
|
{commits}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Then ask for confirmation:
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
AskUserQuestion:
|
|
199
|
+
question: "Push these commits?"
|
|
200
|
+
header: "Push"
|
|
201
|
+
options:
|
|
202
|
+
- label: "Yes, push (Recommended)"
|
|
203
|
+
description: "Push to remote origin"
|
|
204
|
+
- label: "No, cancel"
|
|
205
|
+
description: "Keep commits local"
|
|
206
|
+
```
|
|
170
207
|
|
|
171
|
-
|
|
172
|
-
"""
|
|
208
|
+
**Handle responses:**
|
|
173
209
|
|
|
174
|
-
|
|
210
|
+
**If "No, cancel":**
|
|
175
211
|
```
|
|
212
|
+
OUTPUT: "✅ Push cancelled"
|
|
213
|
+
STOP - Do not continue
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**If "Yes, push":**
|
|
217
|
+
CONTINUE to Step 3
|
|
176
218
|
|
|
177
219
|
### Step 3: Execute Push
|
|
178
220
|
|
|
@@ -79,11 +79,31 @@ Will do:
|
|
|
79
79
|
1. Merge PR with squash
|
|
80
80
|
2. Delete feature branch
|
|
81
81
|
3. Update local main
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then ask for confirmation:
|
|
82
85
|
|
|
83
|
-
|
|
86
|
+
```
|
|
87
|
+
AskUserQuestion:
|
|
88
|
+
question: "Merge this PR?"
|
|
89
|
+
header: "Merge"
|
|
90
|
+
options:
|
|
91
|
+
- label: "Yes, merge (Recommended)"
|
|
92
|
+
description: "Squash merge and delete branch"
|
|
93
|
+
- label: "No, cancel"
|
|
94
|
+
description: "Keep PR open"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Handle responses:**
|
|
98
|
+
|
|
99
|
+
**If "No, cancel":**
|
|
100
|
+
```
|
|
101
|
+
OUTPUT: "✅ Merge cancelled"
|
|
102
|
+
STOP - Do not continue
|
|
84
103
|
```
|
|
85
104
|
|
|
86
|
-
|
|
105
|
+
**If "Yes, merge":**
|
|
106
|
+
CONTINUE to Step 4
|
|
87
107
|
|
|
88
108
|
---
|
|
89
109
|
|
|
@@ -69,11 +69,37 @@ Will do:
|
|
|
69
69
|
4. Commit with prjct footer
|
|
70
70
|
5. Push branch
|
|
71
71
|
6. Create PR to main
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Then ask for confirmation:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
AskUserQuestion:
|
|
78
|
+
question: "Ready to ship these changes?"
|
|
79
|
+
header: "Ship"
|
|
80
|
+
options:
|
|
81
|
+
- label: "Yes, ship it (Recommended)"
|
|
82
|
+
description: "Run tests, bump version, create PR"
|
|
83
|
+
- label: "No, cancel"
|
|
84
|
+
description: "Abort ship operation"
|
|
85
|
+
- label: "Show full diff"
|
|
86
|
+
description: "See all file changes before deciding"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Handle responses:**
|
|
72
90
|
|
|
73
|
-
|
|
91
|
+
**If "Show full diff":**
|
|
92
|
+
- Run `git diff` to show full changes
|
|
93
|
+
- Ask again with Yes/No options only
|
|
94
|
+
|
|
95
|
+
**If "No, cancel":**
|
|
96
|
+
```
|
|
97
|
+
OUTPUT: "✅ Ship cancelled"
|
|
98
|
+
STOP - Do not continue
|
|
74
99
|
```
|
|
75
100
|
|
|
76
|
-
|
|
101
|
+
**If "Yes, ship it":**
|
|
102
|
+
CONTINUE to Step 3
|
|
77
103
|
|
|
78
104
|
---
|
|
79
105
|
|
|
@@ -123,9 +123,8 @@ ELSE:
|
|
|
123
123
|
|
|
124
124
|
**⛔ DO NOT create branches or modify state without user approval.**
|
|
125
125
|
|
|
126
|
+
Show the user:
|
|
126
127
|
```
|
|
127
|
-
OUTPUT:
|
|
128
|
-
"""
|
|
129
128
|
## Task Plan
|
|
130
129
|
|
|
131
130
|
Description: $ARGUMENTS
|
|
@@ -137,13 +136,38 @@ Will do:
|
|
|
137
136
|
2. Initialize task tracking in state.json
|
|
138
137
|
3. Break down into subtasks
|
|
139
138
|
4. {If Linear: Update issue status to In Progress}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Then ask for confirmation:
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
AskUserQuestion:
|
|
145
|
+
question: "Start this task?"
|
|
146
|
+
header: "Task"
|
|
147
|
+
options:
|
|
148
|
+
- label: "Yes, start task (Recommended)"
|
|
149
|
+
description: "Create branch and begin tracking"
|
|
150
|
+
- label: "No, cancel"
|
|
151
|
+
description: "Don't create task"
|
|
152
|
+
- label: "Modify plan"
|
|
153
|
+
description: "Change type, branch name, or subtasks"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Handle responses:**
|
|
140
157
|
|
|
141
|
-
|
|
142
|
-
""
|
|
158
|
+
**If "Modify plan":**
|
|
159
|
+
- Ask: "What would you like to change?"
|
|
160
|
+
- Update plan accordingly
|
|
161
|
+
- Ask again with Yes/No options only
|
|
143
162
|
|
|
144
|
-
|
|
145
|
-
DO NOT assume
|
|
163
|
+
**If "No, cancel":**
|
|
146
164
|
```
|
|
165
|
+
OUTPUT: "✅ Task creation cancelled"
|
|
166
|
+
STOP - Do not continue
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**If "Yes, start task":**
|
|
170
|
+
CONTINUE to Step B
|
|
147
171
|
|
|
148
172
|
### Step B: Explore Codebase
|
|
149
173
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
## FAST vs SMART COMMANDS (CRITICAL)
|
|
2
|
+
|
|
3
|
+
**Some commands just run a CLI. Others need intelligence. Know the difference.**
|
|
4
|
+
|
|
5
|
+
### FAST COMMANDS (Execute Immediately - NO planning, NO exploration)
|
|
6
|
+
|
|
7
|
+
| Command | Action | Time |
|
|
8
|
+
|---------|--------|------|
|
|
9
|
+
| `p. sync` | Run `prjct sync` | <5s |
|
|
10
|
+
| `p. next` | Run `prjct next` | <2s |
|
|
11
|
+
| `p. dash` | Run `prjct dash` | <2s |
|
|
12
|
+
| `p. pause` | Run `prjct pause` | <2s |
|
|
13
|
+
| `p. resume` | Run `prjct resume` | <2s |
|
|
14
|
+
|
|
15
|
+
**For these commands:**
|
|
16
|
+
```
|
|
17
|
+
1. Read template
|
|
18
|
+
2. Run the CLI command shown
|
|
19
|
+
3. Done
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**DO NOT:** explore codebase, create plans, ask questions, read project files
|
|
23
|
+
|
|
24
|
+
### SMART COMMANDS (Require intelligence)
|
|
25
|
+
|
|
26
|
+
| Command | Why it needs intelligence |
|
|
27
|
+
|---------|--------------------------|
|
|
28
|
+
| `p. task` | Must explore codebase, break down work |
|
|
29
|
+
| `p. ship` | Must validate changes, create PR |
|
|
30
|
+
| `p. bug` | Must classify severity, find affected files |
|
|
31
|
+
| `p. done` | Must verify completion, update state |
|
|
32
|
+
|
|
33
|
+
**For these commands:** Follow the full INTELLIGENT BEHAVIOR rules.
|
|
34
|
+
|
|
35
|
+
### Decision Rule
|
|
36
|
+
```
|
|
37
|
+
IF template just says "run CLI command":
|
|
38
|
+
→ Execute immediately, no planning
|
|
39
|
+
ELSE:
|
|
40
|
+
→ Use intelligent behavior (explore, ask, plan)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## CORE WORKFLOW
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
p. sync → p. task "description" → [work] → p. done → p. ship
|
|
49
|
+
│ │ │ │
|
|
50
|
+
│ └─ Creates branch, breaks down │ │
|
|
51
|
+
│ task, starts tracking │ │
|
|
52
|
+
│ │ │
|
|
53
|
+
└─ Analyzes project, generates agents │ │
|
|
54
|
+
│ │
|
|
55
|
+
Completes subtask ─────┘ │
|
|
56
|
+
│
|
|
57
|
+
Ships feature, PR, tag ───┘
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Quick Reference
|
|
61
|
+
|
|
62
|
+
| Trigger | What It Does |
|
|
63
|
+
|---------|--------------|
|
|
64
|
+
| `p. sync` | Analyze project, generate domain agents |
|
|
65
|
+
| `p. task <desc>` | Start task with auto-classification |
|
|
66
|
+
| `p. done` | Complete current subtask |
|
|
67
|
+
| `p. ship [name]` | Ship feature with PR + version bump |
|
|
68
|
+
| `p. pause` | Pause current task |
|
|
69
|
+
| `p. resume` | Resume paused task |
|
|
70
|
+
| `p. bug <desc>` | Report bug with auto-priority |
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# prjct-cli
|
|
2
|
+
|
|
3
|
+
**Context layer for AI agents** - Project context for Claude Code, Gemini CLI, and more.
|
|
4
|
+
|
|
5
|
+
## HOW TO USE PRJCT
|
|
6
|
+
|
|
7
|
+
When user types `p. <command>`, load the template from `templates/commands/{command}.md` and execute it.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
p. sync → templates/commands/sync.md
|
|
11
|
+
p. task X → templates/commands/task.md
|
|
12
|
+
p. done → templates/commands/done.md
|
|
13
|
+
p. ship X → templates/commands/ship.md
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## CRITICAL RULES
|
|
19
|
+
|
|
20
|
+
### 0. FOLLOW TEMPLATES STEP BY STEP (NON-NEGOTIABLE)
|
|
21
|
+
|
|
22
|
+
**Templates are MANDATORY WORKFLOWS, not suggestions.**
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
1. READ the template file COMPLETELY
|
|
26
|
+
2. FOLLOW each step IN ORDER
|
|
27
|
+
3. DO NOT skip steps - even "obvious" ones
|
|
28
|
+
4. STOP at any BLOCKING condition
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 1. Path Resolution (MOST IMPORTANT)
|
|
32
|
+
|
|
33
|
+
**ALL writes go to global storage**: `~/.prjct-cli/projects/{projectId}/`
|
|
34
|
+
|
|
35
|
+
- **NEVER** write to `.prjct/` (config only, read-only)
|
|
36
|
+
- **NEVER** write to `./` (current directory)
|
|
37
|
+
- **ALWAYS** resolve projectId first from `.prjct/prjct.config.json`
|
|
38
|
+
|
|
39
|
+
### 2. Before Any Command
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
1. Read .prjct/prjct.config.json → get projectId
|
|
43
|
+
2. Set globalPath = ~/.prjct-cli/projects/{projectId}
|
|
44
|
+
3. Execute command using globalPath for all writes
|
|
45
|
+
4. Log to {globalPath}/memory/events.jsonl
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 3. Timestamps & UUIDs
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Timestamp (NEVER hardcode)
|
|
52
|
+
bun -e "console.log(new Date().toISOString())" 2>/dev/null || node -e "console.log(new Date().toISOString())"
|
|
53
|
+
|
|
54
|
+
# UUID
|
|
55
|
+
bun -e "console.log(crypto.randomUUID())" 2>/dev/null || node -e "console.log(require('crypto').randomUUID())"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## OUTPUT FORMAT
|
|
61
|
+
|
|
62
|
+
Concise responses (< 4 lines):
|
|
63
|
+
```
|
|
64
|
+
[What was done]
|
|
65
|
+
|
|
66
|
+
[Key metrics]
|
|
67
|
+
Next: [suggested action]
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## CLEAN TERMINAL UX
|
|
73
|
+
|
|
74
|
+
**Tool calls MUST be user-friendly.**
|
|
75
|
+
|
|
76
|
+
1. **ALWAYS use clear descriptions** in Bash tool calls:
|
|
77
|
+
- GOOD: `description: "Building project"`
|
|
78
|
+
- BAD: `description: "bun run build 2>&1 | tail -5"`
|
|
79
|
+
|
|
80
|
+
2. **Hide implementation details** - Users don't need to see pipe chains, internal paths, JSON parsing
|
|
81
|
+
|
|
82
|
+
3. **Use action verbs**: "Building project", "Running tests", "Checking git status"
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
**Auto-managed by prjct-cli** | https://prjct.app
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
## GIT WORKFLOW RULES (CRITICAL)
|
|
2
|
+
|
|
3
|
+
**NEVER commit directly to main/master**
|
|
4
|
+
- Always create a feature branch first
|
|
5
|
+
- Always create a PR for review
|
|
6
|
+
- Direct pushes to main are FORBIDDEN
|
|
7
|
+
|
|
8
|
+
**NEVER push without a PR**
|
|
9
|
+
- All changes go through pull requests
|
|
10
|
+
- No exceptions for "small fixes"
|
|
11
|
+
|
|
12
|
+
**NEVER skip version bump on ship**
|
|
13
|
+
- Every ship requires version update
|
|
14
|
+
- Every ship requires CHANGELOG entry
|
|
15
|
+
|
|
16
|
+
### Git Commit Footer (CRITICAL - ALWAYS INCLUDE)
|
|
17
|
+
|
|
18
|
+
**Every commit made with prjct MUST include this footer:**
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
Generated with [p/](https://www.prjct.app/)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**This is NON-NEGOTIABLE. The prjct signature must appear in ALL commits.**
|
|
25
|
+
|
|
26
|
+
### PLAN BEFORE DESTRUCTIVE ACTIONS
|
|
27
|
+
|
|
28
|
+
For commands that modify git state (ship, merge, done):
|
|
29
|
+
```
|
|
30
|
+
1. Show the user what will happen
|
|
31
|
+
2. List all changes/files affected
|
|
32
|
+
3. WAIT for explicit approval ("yes", "proceed", "do it")
|
|
33
|
+
4. Only then execute
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**DO NOT assume approval. WAIT for it.**
|
|
37
|
+
|
|
38
|
+
### BLOCKING CONDITIONS
|
|
39
|
+
|
|
40
|
+
When a template says "STOP" or has a blocking symbol:
|
|
41
|
+
```
|
|
42
|
+
1. HALT execution immediately
|
|
43
|
+
2. TELL the user why you stopped
|
|
44
|
+
3. DO NOT proceed until the condition is resolved
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Examples of blockers:**
|
|
48
|
+
- `p. ship` on main branch → STOP, tell user to create branch
|
|
49
|
+
- `gh auth status` fails → STOP, tell user to authenticate
|
|
50
|
+
- No changes to commit → STOP, tell user nothing to ship
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
## INTELLIGENT BEHAVIOR (For SMART commands only)
|
|
2
|
+
|
|
3
|
+
### When Starting Tasks (`p. task`)
|
|
4
|
+
1. **Analyze** - Understand what user wants to achieve
|
|
5
|
+
2. **Classify** - Determine type: feature, bug, improvement, refactor, chore
|
|
6
|
+
3. **Explore** - Find similar code, patterns, affected files
|
|
7
|
+
4. **Ask** - Clarify ambiguities (use AskUserQuestion)
|
|
8
|
+
5. **Design** - Propose 2-3 approaches, get approval
|
|
9
|
+
6. **Break down** - Create actionable subtasks
|
|
10
|
+
7. **Track** - Update storage/state.json
|
|
11
|
+
|
|
12
|
+
### When Completing Tasks (`p. done`)
|
|
13
|
+
1. Check if there are more subtasks
|
|
14
|
+
2. If yes, advance to next subtask
|
|
15
|
+
3. If no, task is complete
|
|
16
|
+
4. Update storage, generate context
|
|
17
|
+
|
|
18
|
+
### When Shipping (`p. ship`)
|
|
19
|
+
1. Run tests (if configured)
|
|
20
|
+
2. Create PR (if on feature branch)
|
|
21
|
+
3. Bump version
|
|
22
|
+
4. Update CHANGELOG
|
|
23
|
+
5. Create git tag
|
|
24
|
+
|
|
25
|
+
### Key Intelligence Rules
|
|
26
|
+
- **Read before write** - Always read existing files before modifying
|
|
27
|
+
- **Explore before coding** - Use Task(Explore) to understand codebase
|
|
28
|
+
- **Ask when uncertain** - Use AskUserQuestion to clarify
|
|
29
|
+
- **Log everything** - Append to memory/events.jsonl
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## ARCHITECTURE: Write-Through Pattern
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
User Action → Storage (JSON) → Context (MD) → Sync Events
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| Layer | Path | Purpose |
|
|
40
|
+
|-------|------|---------|
|
|
41
|
+
| **Storage** | `storage/*.json` | Source of truth |
|
|
42
|
+
| **Context** | `context/*.md` | Claude-readable summaries |
|
|
43
|
+
| **Memory** | `memory/events.jsonl` | Audit trail (append-only) |
|
|
44
|
+
| **Agents** | `agents/*.md` | Domain specialists |
|
|
45
|
+
| **Sync** | `sync/pending.json` | Backend sync queue |
|
|
46
|
+
|
|
47
|
+
### File Structure
|
|
48
|
+
```
|
|
49
|
+
~/.prjct-cli/projects/{projectId}/
|
|
50
|
+
├── storage/
|
|
51
|
+
│ ├── state.json # Current task (SOURCE OF TRUTH)
|
|
52
|
+
│ ├── queue.json # Task queue
|
|
53
|
+
│ └── shipped.json # Shipped features
|
|
54
|
+
├── context/
|
|
55
|
+
│ ├── now.md # Current task (generated)
|
|
56
|
+
│ └── next.md # Queue (generated)
|
|
57
|
+
├── memory/
|
|
58
|
+
│ └── events.jsonl # Audit trail
|
|
59
|
+
├── agents/ # Domain specialists (auto-generated)
|
|
60
|
+
└── sync/
|
|
61
|
+
└── pending.json # Events for backend
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## LOADING DOMAIN AGENTS
|
|
67
|
+
|
|
68
|
+
When working on tasks, load relevant agents from `{globalPath}/agents/`:
|
|
69
|
+
- `frontend.md` - Frontend patterns, components
|
|
70
|
+
- `backend.md` - Backend patterns, APIs
|
|
71
|
+
- `database.md` - Database patterns, queries
|
|
72
|
+
- `uxui.md` - UX/UI guidelines
|
|
73
|
+
- `testing.md` - Testing patterns
|
|
74
|
+
- `devops.md` - CI/CD, containers
|
|
75
|
+
|
|
76
|
+
These agents contain project-specific patterns. **USE THEM**.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## SKILL INTEGRATION
|
|
81
|
+
|
|
82
|
+
Agents are linked to Claude Code skills from claude-plugins.dev.
|
|
83
|
+
|
|
84
|
+
### How Skills Work
|
|
85
|
+
|
|
86
|
+
1. **During `p. sync`**: Search claude-plugins.dev, install best matches
|
|
87
|
+
2. **During `p. task`**: Skills are auto-invoked for domain expertise
|
|
88
|
+
3. **Agent frontmatter** has `skills: [discovered-skill-name]` field
|
|
89
|
+
|
|
90
|
+
### Skill Location
|
|
91
|
+
|
|
92
|
+
Skills are markdown files in `~/.claude/skills/`
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
## STORAGE RULES (CROSS-AGENT COMPATIBILITY)
|
|
2
|
+
|
|
3
|
+
**NEVER use temporary files** - Write directly to final destination:
|
|
4
|
+
- WRONG: Create `.tmp/file.json`, then `mv` to final path
|
|
5
|
+
- CORRECT: Write directly to `{globalPath}/storage/state.json`
|
|
6
|
+
|
|
7
|
+
**JSON formatting** - Always use consistent format:
|
|
8
|
+
- 2-space indentation
|
|
9
|
+
- No trailing commas
|
|
10
|
+
- Keys in logical order (as defined in storage schemas)
|
|
11
|
+
|
|
12
|
+
**Atomic writes for JSON**:
|
|
13
|
+
```javascript
|
|
14
|
+
// Read → Modify → Write (no temp files)
|
|
15
|
+
const data = JSON.parse(fs.readFileSync(path, 'utf-8'))
|
|
16
|
+
data.newField = value
|
|
17
|
+
fs.writeFileSync(path, JSON.stringify(data, null, 2))
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Timestamps**: Always ISO-8601 with milliseconds (`.000Z`)
|
|
21
|
+
**UUIDs**: Always v4 format (lowercase)
|
|
22
|
+
**Line endings**: LF (not CRLF)
|
|
23
|
+
**Encoding**: UTF-8 without BOM
|
|
24
|
+
|
|
25
|
+
**NEVER**:
|
|
26
|
+
- Use `.tmp/` directories
|
|
27
|
+
- Use `mv` or `rename` operations for storage files
|
|
28
|
+
- Create backup files like `*.bak` or `*.old`
|
|
29
|
+
- Modify existing lines in `events.jsonl`
|
|
30
|
+
|
|
31
|
+
**Full specification**: See `{npm root -g}/prjct-cli/templates/global/STORAGE-SPEC.md`
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Preserve Markers (User Customizations)
|
|
36
|
+
|
|
37
|
+
User customizations in context files and agents survive regeneration using preserve markers:
|
|
38
|
+
|
|
39
|
+
```markdown
|
|
40
|
+
<!-- prjct:preserve -->
|
|
41
|
+
# My Custom Rules
|
|
42
|
+
- Always use tabs
|
|
43
|
+
- Prefer functional patterns
|
|
44
|
+
<!-- /prjct:preserve -->
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**How it works:**
|
|
48
|
+
- Content between markers is extracted before regeneration
|
|
49
|
+
- After regeneration, preserved content is appended under "Your Customizations"
|
|
50
|
+
- Named sections: `<!-- prjct:preserve:my-rules -->` for identification
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Configuration for modular CLAUDE.md composition",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"profiles": {
|
|
5
|
+
"full": {
|
|
6
|
+
"description": "All modules - maximum context (~2300 tokens)",
|
|
7
|
+
"modules": [
|
|
8
|
+
"CLAUDE-core.md",
|
|
9
|
+
"CLAUDE-commands.md",
|
|
10
|
+
"CLAUDE-git.md",
|
|
11
|
+
"CLAUDE-storage.md",
|
|
12
|
+
"CLAUDE-intelligence.md"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"standard": {
|
|
16
|
+
"description": "Standard modules - balanced (~1400 tokens)",
|
|
17
|
+
"modules": ["CLAUDE-core.md", "CLAUDE-commands.md", "CLAUDE-git.md"]
|
|
18
|
+
},
|
|
19
|
+
"minimal": {
|
|
20
|
+
"description": "Core only - minimum context (~500 tokens)",
|
|
21
|
+
"modules": ["CLAUDE-core.md"]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"default": "standard",
|
|
25
|
+
"commandProfiles": {
|
|
26
|
+
"sync": "minimal",
|
|
27
|
+
"next": "minimal",
|
|
28
|
+
"dash": "minimal",
|
|
29
|
+
"pause": "minimal",
|
|
30
|
+
"resume": "minimal",
|
|
31
|
+
"task": "full",
|
|
32
|
+
"done": "standard",
|
|
33
|
+
"ship": "full",
|
|
34
|
+
"bug": "full"
|
|
35
|
+
}
|
|
36
|
+
}
|