prjct-cli 2.60.0 → 2.63.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
@@ -2,6 +2,21 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [2.63.0] - 2026-06-23
6
+
7
+ ### Added
8
+ - eval result publishing
9
+
10
+ ## [2.62.0] - 2026-06-23
11
+
12
+ ### Added
13
+ - Point CLI metadata to cli site
14
+
15
+ ## [2.61.0] - 2026-06-23
16
+
17
+ ### Added
18
+ - Improve prjct-cli maintainability performance and UX
19
+
5
20
  ## [2.60.0] - 2026-06-22
6
21
 
7
22
  ### Added
package/README.md CHANGED
@@ -178,6 +178,24 @@ command is idempotent and reports what changed.
178
178
  prjct should justify itself with project evidence, not vague claims. These
179
179
  read-only commands show whether the project is actually compounding:
180
180
 
181
+ ### Version evals
182
+
183
+ Use `prjct eval` to measure product readiness between versions and publish the
184
+ evidence to GitHub:
185
+
186
+ ```bash
187
+ prjct eval run --candidate 2.62.0
188
+ prjct eval compare --baseline 2.61.0 --candidate 2.62.0 --md
189
+ prjct eval run --candidate "$GITHUB_SHA" --publish --target github
190
+ prjct eval compare --baseline "$BASELINE" --candidate "$CANDIDATE" --publish --target github
191
+ ```
192
+
193
+ Local artifacts live under `$PRJCT_CLI_HOME/evals/<repo>/`. GitHub publishing
194
+ writes JSON + Markdown to an `eval-results` branch, including
195
+ `summary/latest.json` and `summary/latest-comparison.json`. See
196
+ [EVALS.md](./EVALS.md) and `.github/workflows/prjct-evals.yml` for the
197
+ CI workflow.
198
+
181
199
  | Command | What it proves |
182
200
  |---|---|
183
201
  | `prjct value --md` | Durable memory, preventive guardrails, shipped work, sync metrics, and detected agent coverage. |
@@ -609,7 +627,7 @@ tradeoffs: [docs/storage-and-paths.md](./docs/storage-and-paths.md).
609
627
 
610
628
  ## Links
611
629
 
612
- - [Website](https://prjct.app)
630
+ - [Website](https://cli.prjct.app)
613
631
  - [GitHub](https://github.com/jlopezlira/prjct-cli)
614
632
  - [npm](https://www.npmjs.com/package/prjct-cli)
615
633
  - [Changelog](CHANGELOG.md)
package/bin/prjct.cjs CHANGED
@@ -16,7 +16,11 @@ const path = require('node:path')
16
16
  const SCRIPT_PATH = fs.realpathSync(__filename)
17
17
  const SCRIPT_DIR = path.dirname(SCRIPT_PATH)
18
18
  const ROOT_DIR = path.resolve(SCRIPT_DIR, '..')
19
- const HOME = os.homedir()
19
+ const HOME = process.env.HOME || process.env.USERPROFILE || os.homedir()
20
+ const CLI_HOME = process.env.PRJCT_CLI_HOME
21
+ ? path.resolve(process.env.PRJCT_CLI_HOME)
22
+ : path.join(HOME, '.prjct-cli')
23
+ const SETUP_STAMP_PATH = path.join(CLI_HOME, 'state', 'setup-version.json')
20
24
 
21
25
  function pathEntries() {
22
26
  return (process.env.PATH || '').split(path.delimiter).filter(Boolean)
@@ -114,12 +118,76 @@ function copyDirContents(srcDir, destDir) {
114
118
  }
115
119
  }
116
120
 
121
+ function packageVersion() {
122
+ try {
123
+ return JSON.parse(fs.readFileSync(path.join(ROOT_DIR, 'package.json'), 'utf-8')).version || ''
124
+ } catch {
125
+ return ''
126
+ }
127
+ }
128
+
129
+ function fileMissingWhenSourceExists(src, dest) {
130
+ try {
131
+ return fs.existsSync(src) && !fs.existsSync(dest)
132
+ } catch {
133
+ return false
134
+ }
135
+ }
136
+
137
+ function readSetupStamp() {
138
+ try {
139
+ return JSON.parse(fs.readFileSync(SETUP_STAMP_PATH, 'utf-8'))
140
+ } catch {
141
+ return null
142
+ }
143
+ }
144
+
145
+ function writeSetupStamp(version) {
146
+ try {
147
+ fs.mkdirSync(path.dirname(SETUP_STAMP_PATH), { recursive: true })
148
+ fs.writeFileSync(
149
+ SETUP_STAMP_PATH,
150
+ `${JSON.stringify({ version, completedAt: new Date().toISOString() }, null, 2)}\n`,
151
+ 'utf-8'
152
+ )
153
+ } catch {
154
+ /* best effort */
155
+ }
156
+ }
157
+
158
+ function shouldRunSetup(version) {
159
+ const stamp = readSetupStamp()
160
+ if (!stamp || stamp.version !== version) return true
161
+
162
+ if (fs.existsSync(path.join(HOME, '.claude', 'commands', 'p.md'))) return true
163
+ if (fs.existsSync(path.join(HOME, '.gemini', 'commands', 'p.toml'))) return true
164
+
165
+ const statuslineSrc = path.join(ROOT_DIR, 'assets', 'statusline', 'statusline.sh')
166
+ const statuslineDest = path.join(CLI_HOME, 'statusline', 'statusline.sh')
167
+ if (fileMissingWhenSourceExists(statuslineSrc, statuslineDest)) return true
168
+
169
+ const claudeSkillSrc = path.join(ROOT_DIR, 'templates', 'skills', 'prjct', 'SKILL.md')
170
+ const claudeSkillDest = path.join(HOME, '.claude', 'skills', 'prjct', 'SKILL.md')
171
+ if (fileMissingWhenSourceExists(claudeSkillSrc, claudeSkillDest)) return true
172
+
173
+ const codexSkillSrc = path.join(ROOT_DIR, 'templates', 'codex', 'SKILL.md')
174
+ const codexSkillDest = path.join(HOME, '.codex', 'skills', 'prjct', 'SKILL.md')
175
+ if (
176
+ fs.existsSync(path.join(HOME, '.codex')) &&
177
+ fileMissingWhenSourceExists(codexSkillSrc, codexSkillDest)
178
+ ) {
179
+ return true
180
+ }
181
+
182
+ return false
183
+ }
184
+
117
185
  function ensureSetup() {
118
186
  removeIfExists(path.join(HOME, '.claude', 'commands', 'p.md'))
119
187
  removeIfExists(path.join(HOME, '.gemini', 'commands', 'p.toml'))
120
188
 
121
189
  const statuslineSrc = path.join(ROOT_DIR, 'assets', 'statusline', 'statusline.sh')
122
- const statuslineDir = path.join(HOME, '.prjct-cli', 'statusline')
190
+ const statuslineDir = path.join(CLI_HOME, 'statusline')
123
191
  const statuslineDest = path.join(statuslineDir, 'statusline.sh')
124
192
  const claudeStatusline = path.join(HOME, '.claude', 'prjct-statusline.sh')
125
193
 
@@ -241,7 +309,23 @@ function main() {
241
309
  const args = process.argv.slice(2)
242
310
  if (args[0] === 'mcp-server') runMcpServer(args)
243
311
 
244
- ensureSetup()
312
+ const setupSkipCommands = new Set([
313
+ '-v',
314
+ '--version',
315
+ 'version',
316
+ '-h',
317
+ '--help',
318
+ 'help',
319
+ 'eval',
320
+ 'hook',
321
+ '__internal-auto-update',
322
+ '__post-upgrade',
323
+ ])
324
+ const version = packageVersion()
325
+ if (!setupSkipCommands.has(args[0]) && shouldRunSetup(version)) {
326
+ ensureSetup()
327
+ writeSetupStamp(version)
328
+ }
245
329
 
246
330
  if (runWithBun(args)) return
247
331
  runWithNode(args)