create-claude-cabinet 0.13.1 → 0.14.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-claude-cabinet",
3
- "version": "0.13.1",
3
+ "version": "0.14.0",
4
4
  "description": "Claude Cabinet — opinionated process scaffolding for Claude Code projects",
5
5
  "bin": {
6
6
  "create-claude-cabinet": "bin/create-claude-cabinet.js"
@@ -7,13 +7,13 @@
7
7
 
8
8
  import { createServer } from 'node:http';
9
9
  import { readFile } from 'node:fs/promises';
10
- import { existsSync } from 'node:fs';
10
+ import { existsSync, readFileSync } from 'node:fs';
11
11
  import { fileURLToPath } from 'node:url';
12
- import { dirname, join, resolve } from 'node:path';
12
+ import { basename, dirname, join, resolve } from 'node:path';
13
13
  import Database from 'better-sqlite3';
14
14
 
15
15
  const __dirname = dirname(fileURLToPath(import.meta.url));
16
- const PORT = parseInt(process.env.PORT || process.argv.find((_, i, a) => a[i - 1] === '--port') || '3458');
16
+ const PREFERRED_PORT = parseInt(process.env.PORT || process.argv.find((_, i, a) => a[i - 1] === '--port') || '3458');
17
17
  const DB_PATH = resolve(process.argv.find((_, i, a) => a[i - 1] === '--db') || 'pib.db');
18
18
 
19
19
  if (!existsSync(DB_PATH)) {
@@ -22,6 +22,18 @@ if (!existsSync(DB_PATH)) {
22
22
  process.exit(1);
23
23
  }
24
24
 
25
+ // Derive project name from .ccrc.json, package.json, or directory name
26
+ function getProjectName() {
27
+ for (const file of ['.ccrc.json', 'package.json']) {
28
+ try {
29
+ const data = JSON.parse(readFileSync(resolve(file), 'utf-8'));
30
+ if (file === 'package.json' && data.name) return data.name;
31
+ } catch {}
32
+ }
33
+ return basename(resolve('.'));
34
+ }
35
+ const PROJECT_NAME = getProjectName();
36
+
25
37
  const db = new Database(DB_PATH, { readonly: false });
26
38
  db.pragma('journal_mode = WAL');
27
39
 
@@ -42,7 +54,7 @@ async function readBody(req) {
42
54
  }
43
55
 
44
56
  const server = createServer(async (req, res) => {
45
- const url = new URL(req.url, `http://localhost:${PORT}`);
57
+ const url = new URL(req.url, `http://localhost:${server.address()?.port || PREFERRED_PORT}`);
46
58
 
47
59
  if (req.method === 'OPTIONS') {
48
60
  res.writeHead(204, {
@@ -159,6 +171,11 @@ const server = createServer(async (req, res) => {
159
171
  return json(res, { ok: true });
160
172
  }
161
173
 
174
+ // GET /api/meta — project name and server info
175
+ if (req.method === 'GET' && url.pathname === '/api/meta') {
176
+ return json(res, { projectName: PROJECT_NAME });
177
+ }
178
+
162
179
  // GET /api/stats — dashboard summary
163
180
  if (req.method === 'GET' && url.pathname === '/api/stats') {
164
181
  const projects = db.prepare(`
@@ -182,7 +199,23 @@ const server = createServer(async (req, res) => {
182
199
  }
183
200
  });
184
201
 
185
- server.listen(PORT, () => {
186
- console.log(`Work tracker at http://localhost:${PORT}`);
202
+ server.listen(PREFERRED_PORT, () => {
203
+ const actualPort = server.address().port;
204
+ console.log(`Work tracker at http://localhost:${actualPort}`);
187
205
  console.log(`Database: ${DB_PATH}`);
206
+ console.log(`Project: ${PROJECT_NAME}`);
207
+ });
208
+
209
+ server.on('error', (err) => {
210
+ if (err.code === 'EADDRINUSE') {
211
+ console.log(`Port ${PREFERRED_PORT} in use, finding a free port...`);
212
+ server.listen(0, () => {
213
+ const actualPort = server.address().port;
214
+ console.log(`Work tracker at http://localhost:${actualPort}`);
215
+ console.log(`Database: ${DB_PATH}`);
216
+ console.log(`Project: ${PROJECT_NAME}`);
217
+ });
218
+ } else {
219
+ throw err;
220
+ }
188
221
  });
@@ -410,7 +410,7 @@
410
410
  </head>
411
411
  <body>
412
412
  <header>
413
- <h1>Work Tracker</h1>
413
+ <h1><span id="project-name" style="color: #7048e8;"></span> <span style="color: #5c5f66; font-weight: 400;">Work Tracker</span></h1>
414
414
  <div class="stats" id="stats"></div>
415
415
  </header>
416
416
 
@@ -456,14 +456,20 @@
456
456
  // Fetch data
457
457
  async function load() {
458
458
  try {
459
- const [projRes, actRes, statsRes] = await Promise.all([
459
+ const [projRes, actRes, statsRes, metaRes] = await Promise.all([
460
460
  fetch(`/api/projects?status=${currentStatus}`),
461
461
  fetch('/api/actions?status=all'),
462
462
  fetch('/api/stats'),
463
+ fetch('/api/meta'),
463
464
  ]);
464
465
  projects = await projRes.json();
465
466
  actions = await actRes.json();
466
467
  const stats = await statsRes.json();
468
+ const meta = await metaRes.json();
469
+ if (meta.projectName) {
470
+ document.title = `${meta.projectName} — Work Tracker`;
471
+ document.getElementById('project-name').textContent = meta.projectName;
472
+ }
467
473
  renderStats(stats);
468
474
  document.getElementById('loading').style.display = 'none';
469
475
  render();
@@ -78,3 +78,21 @@ With user confirmation:
78
78
  no unexpected fields were added or existing fields changed.
79
79
  - Update `system-status.md` if it exists
80
80
  - Report the published version and npm URL
81
+
82
+ ### 6. Update Local Consumers
83
+
84
+ Read `~/.claude/cc-registry.json` for all registered CC projects. For
85
+ each project that is NOT the CC source repo itself:
86
+
87
+ 1. Check its current version (`cat <path>/.ccrc.json | jq -r .version`)
88
+ 2. If it's older than the just-published version, update it:
89
+ - `cd <path> && npx create-claude-cabinet@latest --yes`
90
+ - Verify the install succeeded (`.ccrc.json` version matches)
91
+ 3. Report which consumers were updated and which were already current
92
+
93
+ **Important:**
94
+ - Never force-install or pass flags beyond `--yes` — the installer
95
+ reads the existing `.ccrc.json` to determine install type
96
+ - If a consumer's path doesn't exist, note it (stale registry entry)
97
+ but don't error — mention it in the report
98
+ - If an install fails, report the error but continue with other consumers
@@ -139,6 +139,12 @@ initialized, skip gracefully.
139
139
  sqlite3 pib.db "UPDATE actions SET completed = 1, completed_at = date('now') WHERE fid = '<fid>'"
140
140
  ```
141
141
 
142
+ **Field feedback resolution:** After closing actions, check `feedback/`
143
+ for `.md` files from consuming projects. For each, compare the described
144
+ friction against this session's commits. If the friction was addressed,
145
+ propose deleting the feedback file (it's a queue, not a ledger — the
146
+ fix lives in git history). Partially addressed feedback stays open.
147
+
142
148
  **Project completion scan:** After closing actions, check for projects
143
149
  where all actions are now done:
144
150
 
@@ -87,6 +87,33 @@ notes, create new items for each. Known work that lives only in completed
87
87
  items' notes will be forgotten. There is no "later" — create it now.
88
88
  -->
89
89
 
90
+ ## Resolve Field Feedback
91
+
92
+ After closing actions, check the `feedback/` directory for field feedback
93
+ files from consuming projects. For each file, evaluate whether this
94
+ session's work addressed the friction described.
95
+
96
+ **How to check:**
97
+ 1. Scan `feedback/` for `.md` files (skip `.gitkeep`)
98
+ 2. For each file, read the `component` from frontmatter and the friction
99
+ description
100
+ 3. Cross-reference against this session's git log and changed files —
101
+ did the session fix or address the reported friction?
102
+ 4. For each resolved item, present to the user:
103
+ > "Field feedback resolved: [title] from [source] — [one-line summary
104
+ > of what fixed it]. Delete the feedback file? (yes/no)"
105
+ 5. On confirmation, delete the feedback file. It served its purpose —
106
+ the friction was addressed and the fix is in the commit history.
107
+
108
+ **Why delete rather than mark resolved?** Feedback files are a queue, not
109
+ a ledger. The commit history records what was fixed and when. Keeping
110
+ resolved feedback files around creates stale noise that orient has to
111
+ filter through every session.
112
+
113
+ **Partially addressed feedback** stays open. If the session fixed one
114
+ aspect but not another, note what was fixed in the file (append a
115
+ `## Partial resolution` section) but don't delete it.
116
+
90
117
  ## Project Completion Scan
91
118
 
92
119
  After closing individual actions, check for projects that may be ready