@open-product-primer/cli 2.12.0 → 2.12.1

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.
@@ -9,8 +9,8 @@
9
9
  // {decision, reason} protocol — cannot draw UI).
10
10
  // - 'plugin': a Claude Code function-hooks plugin (manifest + hooks.json + a register(on) module)
11
11
  // installed at .claude/skills/<id>/, loaded via the project-scope skills-directory auto-load
12
- // convention. Can draw UI ($.ui.toast, $.ui.render) but requires
13
- // CLAUDE_CODE_ENABLE_FUNCTION_HOOKS and is early access — its API may move between releases.
12
+ // convention. Can draw UI ($.ui.log, $.ui.render) but requires CLAUDE_CODE_ENABLE_FUNCTION_HOOKS
13
+ // and is early access — its API may move between releases.
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.CLAUDE_MODS_REGISTRY = void 0;
16
16
  exports.isPluginMod = isPluginMod;
@@ -20,20 +20,25 @@ function isPluginMod(mod) {
20
20
  }
21
21
  // register(on) module: on a Write/Edit tool.call to a bet's specs/<capability>/spec.md delta,
22
22
  // shells out to `oprim validate --json` (already runs checkSpecDeltaDrift()) and surfaces any
23
- // MODIFIED/REMOVED drift for that capability via a toast, at write time instead of only at
24
- // validate/CI time. Never denies the call — this is a write-time convenience on top of
23
+ // MODIFIED/REMOVED drift for that capability as a transcript line, at write time instead of only
24
+ // at validate/CI time. Never denies the call — this is a write-time convenience on top of
25
25
  // `oprim validate`, never a second source of required failures. Silently no-ops on any failure
26
26
  // (oprim not resolvable, malformed report, etc.).
27
27
  const SPEC_DELTA_DRIFT_INTERCEPTOR_REGISTER = `// Function-hooks module for the spec-delta-drift-interceptor mod — see claude-mods.ts.
28
- // EARLY ACCESS: register(on)/$.ui.toast are gated behind CLAUDE_CODE_ENABLE_FUNCTION_HOOKS and
29
- // may change shape between Claude Code releases.
30
-
31
- import { execSync } from 'node:child_process';
28
+ // EARLY ACCESS: register(on)/$.ui.log/$.process.run are gated behind
29
+ // CLAUDE_CODE_ENABLE_FUNCTION_HOOKS and may change shape between Claude Code releases. A hooks
30
+ // module may only import its own files by relative path and "claude-code" — no Node builtins — so
31
+ // shelling out goes through $.process.run, not node:child_process.
32
+ //
33
+ // Surfaces the drift as a transcript line via $.ui.log rather than $.ui.toast: a toast is a
34
+ // transient overlay whose rendering depends on the session's UI surface, while $.ui.log's default
35
+ // destination ("to: transcript") always lands as a plain line every surface shows — see the
36
+ // anthropics/claude-code \`mods/diff\` example, which uses the same call for its panel-toggle
37
+ // messages ("Diff panel shown"/"Diff panel hidden").
32
38
 
33
39
  export function register(on) {
34
- on('tool.call', async ($, e, next) => {
40
+ on('tool.call', { tool: ['Write', 'Edit'] }, async ($, e, next) => {
35
41
  const result = await next(e);
36
- if (e.tool !== 'Write' && e.tool !== 'Edit') return result;
37
42
 
38
43
  try {
39
44
  const filePath = String(e.file_path || '').replace(/\\\\/g, '/');
@@ -43,13 +48,11 @@ export function register(on) {
43
48
 
44
49
  let output;
45
50
  try {
46
- output = execSync('npx --no-install oprim validate --json', {
47
- encoding: 'utf-8',
48
- stdio: ['ignore', 'pipe', 'ignore'],
49
- });
50
- } catch (err) {
51
51
  // validate exits non-zero when a required check fails — stdout still carries the report
52
- output = err && err.stdout ? err.stdout.toString() : null;
52
+ const res = await $.process.run(['npx', '--no-install', 'oprim', 'validate', '--json']);
53
+ output = res.stdout;
54
+ } catch {
55
+ output = null;
53
56
  }
54
57
  if (!output) return result;
55
58
 
@@ -60,7 +63,7 @@ export function register(on) {
60
63
  if (drift.length === 0) return result;
61
64
 
62
65
  const reason = drift.map((c) => \`\${c.name}\${c.note ? \` (\${c.note})\` : ''}\`).join('; ');
63
- $.ui.toast(\`Spec-delta drift in \${capability}: \${reason}\`, { timeoutMs: 8000 });
66
+ $.ui.log(\`⚠ Spec-delta drift in \${capability}: \${reason}\`);
64
67
  } catch {
65
68
  // Graceful degradation — never error or block on interceptor failure.
66
69
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-product-primer/cli",
3
- "version": "2.12.0",
3
+ "version": "2.12.1",
4
4
  "description": "Open Product Primer CLI — product decisions, sequencing, and KPI tracking for repositories",
5
5
  "keywords": [
6
6
  "product",