@open-product-primer/cli 0.9.0 → 0.11.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.
@@ -128,5 +128,11 @@ function initCommand() {
128
128
  console.log('\n' + chalk_1.default.green('✓') + ` Agent skills installed: ${selectedAgents.join(', ')}`);
129
129
  }
130
130
  console.log('\nRun ' + chalk_1.default.cyan('oprim doctor') + ' to verify your setup.');
131
+ console.log('\n' +
132
+ chalk_1.default.bold('Next:') +
133
+ ' capture your first product decision. A bet is a time-bound commitment — what you\'re building, why now, and what would make you stop.' +
134
+ '\nOpen your AI agent and run ' +
135
+ chalk_1.default.cyan('/oprim:bet') +
136
+ ' to create one.');
131
137
  });
132
138
  }
@@ -328,6 +328,8 @@ description: Create a new Product Decision Record in oprim/decisions/ with auto-
328
328
 
329
329
  Create a new Product Decision Record (PDR) in \`oprim/decisions/\`.
330
330
 
331
+ **Interactive prompts:** Use the **AskUserQuestion tool** for every question in this skill — do not write questions as plain text.
332
+
331
333
  ## Steps
332
334
 
333
335
  ### 1. Get the decision title
@@ -388,6 +390,12 @@ description: Create a new bet directory and bet-decision artifact in oprim/bets/
388
390
 
389
391
  Create a new bet in \`oprim/bets/\` and register it on the sequencing board.
390
392
 
393
+ **Interactive prompts:** Use the **AskUserQuestion tool** for every question in this skill — do not write questions as plain text.
394
+
395
+ ## What you're creating
396
+
397
+ A bet is a product decision you're committing to explore: a problem worth solving, a hypothesis worth testing, or a direction worth taking. You'll name it, explain why now, and set a kill criterion so you know when to stop.
398
+
391
399
  ## Steps
392
400
 
393
401
  ### 1. Get the bet title
@@ -407,7 +415,10 @@ After receiving the title, validate: if fewer than 4 words OR fewer than 25 char
407
415
  - If "y": proceed with the original title
408
416
 
409
417
  ### 2. Assign the next BET ID
410
- Scan \`oprim/bets/\` for directories matching \`BET-(\\d+)\`. Extract all integers. Assign max+1, zero-padded to 3 digits. Default \`001\` if none.
418
+ Scan both \`oprim/bets/\` and \`oprim/bets/archived/\` for directories whose names match \`BET-(\\d+)(-[^/]*)?\` (handles both \`BET-NNN/\` and \`BET-NNN-<slug>/\`). Extract the numeric part from each match. Assign max+1, zero-padded to 3 digits. Default \`001\` if none found in either location.
419
+
420
+ ### 2b. Derive the slug
421
+ From the bet title: lowercase all characters, replace any character that is not a letter or digit with a hyphen, collapse consecutive hyphens to one, strip leading/trailing hyphens, truncate to 40 characters at the last hyphen boundary. This becomes \`<slug>\`. Example: "Add title slugs to bet directories for scannability" → \`add-title-slugs-to-bet-dirs-for\`.
411
422
 
412
423
  ### 3. Check sequence.yaml exists
413
424
  If \`oprim/sequence.yaml\` not found: report and stop — advise \`oprim init\`.
@@ -415,7 +426,7 @@ If \`oprim/sequence.yaml\` not found: report and stop — advise \`oprim init\`.
415
426
  ### 4. Gather content
416
427
  Ask: Decision (Build now / Defer / Kill, default Build now), Owner, Review date (YYYY-MM-DD), Why now, Alternatives considered, Expected outcomes (metric: baseline → target in timeframe), Kill criteria / rollback trigger, PDR links (optional).
417
428
 
418
- ### 5. Write oprim/bets/BET-NNN/bet-decision.md
429
+ ### 5. Write oprim/bets/BET-NNN-<slug>/bet-decision.md
419
430
  \`\`\`
420
431
  # Decision: BET-NNN <title>
421
432
  <!-- Naming tip: verb + object [for context] — e.g. "Improve bet naming for scannability" not "Naming" -->
@@ -455,7 +466,7 @@ Read → parse YAML → append → write back (2-space indentation):
455
466
 
456
467
  ### 7. Prompt for optional discovery scaffolding
457
468
  Ask: "Do you want to scaffold a discovery.md now? (y/N)"
458
- - If "y": write \`oprim/bets/BET-NNN/discovery.md\` from the discovery template (same structure as \`oprim/templates/discovery.md\`).
469
+ - If "y": write \`oprim/bets/BET-NNN-<slug>/discovery.md\` from the discovery template (same structure as \`oprim/templates/discovery.md\`).
459
470
  - If "n" or Enter: skip silently.
460
471
 
461
472
  ### 8. Report what was created
@@ -469,6 +480,8 @@ description: Create or append to a criteria.yaml contract for a bet, with struct
469
480
 
470
481
  Create or append to \`oprim/bets/BET-NNN/criteria.yaml\`.
471
482
 
483
+ **Interactive prompts:** Use the **AskUserQuestion tool** for every question in this skill — do not write questions as plain text.
484
+
472
485
  ## Steps
473
486
 
474
487
  ### 1. Identify the bet
@@ -517,11 +530,13 @@ If not: create with \`metrics:\` list.
517
530
  function archiveSkill() {
518
531
  return `---
519
532
  name: oprim-archive
520
- description: Archive a completed bet — moves it to oprim/bets/archived/BET-NNN/ and removes its sequence.yaml entry
533
+ description: Archive a completed bet — moves it to oprim/bets/archived/ and removes its sequence.yaml entry
521
534
  ---
522
535
 
523
536
  Archive a completed bet by moving it to \`oprim/bets/archived/\` and removing it from \`sequence.yaml\`.
524
537
 
538
+ **Interactive prompts:** Use the **AskUserQuestion tool** for every question in this skill — do not write questions as plain text.
539
+
525
540
  ## Steps
526
541
 
527
542
  ### 1. Get the bet ID
@@ -532,11 +547,19 @@ If not provided, ask: "Which bet ID would you like to archive? (e.g., BET-005)"
532
547
 
533
548
  Normalize the input: accept \`bet-005\`, \`005\`, \`5\`, or \`BET-005\` — always treat as \`BET-NNN\` zero-padded to 3 digits.
534
549
 
535
- ### 2. Check the bet directory exists
550
+ ### 2. Resolve the bet directory
551
+
552
+ Look for the bet directory in \`oprim/bets/\` using two patterns:
553
+ 1. Exact match: \`oprim/bets/BET-NNN/\` (legacy non-slug format)
554
+ 2. Slug variant: any directory starting with \`BET-NNN-\` (e.g., \`BET-NNN-<slug>/\`)
555
+
556
+ Use whichever pattern matches. Call this the **resolved directory name**.
536
557
 
537
- Check whether \`oprim/bets/BET-NNN/\` exists.
558
+ If multiple directories match (e.g., both \`BET-NNN/\` and \`BET-NNN-slug/\` exist):
559
+ - Report: "Ambiguous: found multiple directories for BET-NNN: [list them]. Please archive manually."
560
+ - Stop.
538
561
 
539
- If not found:
562
+ If neither pattern matches:
540
563
  - Report: "Bet BET-NNN was not found in oprim/bets/. Nothing was changed."
541
564
  - Stop.
542
565
 
@@ -566,9 +589,9 @@ Create the archive subfolder if it doesn't exist:
566
589
  mkdir -p oprim/bets/archived
567
590
  \`\`\`
568
591
 
569
- Move the directory:
592
+ Move the resolved directory:
570
593
  \`\`\`bash
571
- mv oprim/bets/BET-NNN oprim/bets/archived/BET-NNN
594
+ mv oprim/bets/<resolved-dir> oprim/bets/archived/<resolved-dir>
572
595
  \`\`\`
573
596
 
574
597
  ### 5. Remove the bet entry from sequence.yaml
@@ -581,7 +604,7 @@ Read \`oprim/sequence.yaml\`, parse it, and remove the entry with \`id: BET-NNN\
581
604
  ## Bet Archived
582
605
 
583
606
  **Bet:** BET-NNN
584
- **Archived to:** oprim/bets/archived/BET-NNN/
607
+ **Archived to:** oprim/bets/archived/<resolved-dir>/
585
608
  **Removed from sequence.yaml:** ✓
586
609
 
587
610
  The bet is preserved in full at the archive location.
@@ -626,6 +649,8 @@ description: Validate and update the primer sequencing board — triage mode com
626
649
 
627
650
  Manage the primer sequencing board in \`oprim/sequence.yaml\`.
628
651
 
652
+ **Interactive prompts:** Use the **AskUserQuestion tool** for every question in this skill — do not write questions as plain text.
653
+
629
654
  ## Entry modes
630
655
 
631
656
  **Triage mode** — no intention provided: reads board state, computes health, surfaces specific actionable suggestions.
@@ -718,6 +743,8 @@ description: Create a KPI review artifact for a completed bet, pre-filled from c
718
743
 
719
744
  Create a KPI review in \`oprim/reviews/\`.
720
745
 
746
+ **Interactive prompts:** Use the **AskUserQuestion tool** for every question in this skill — do not write questions as plain text.
747
+
721
748
  ## Steps
722
749
 
723
750
  ### 1. Identify the bet
@@ -777,7 +804,7 @@ function pdrInlineContent() {
777
804
  return `Create a new PDR in \`oprim/decisions/\`. Scan for \`PDR-(\\d+)-\` to assign next ID (zero-padded, default 001). Gather: title, context, decision, alternatives, consequences, evidence, related bets/specs. Ask if superseding an existing PDR. Write \`oprim/decisions/PDR-NNN-<slug>.md\`. If superseding: update old PDR Status to "Superseded by PDR-NNN". Report what was created.`;
778
805
  }
779
806
  function betInlineContent() {
780
- return `Create a new bet in \`oprim/bets/\`. Before asking for the title, show: "Naming tip: verb + object [for context] — Good: 'Improve bet naming for scannability' / Bad: 'Naming'". Scan \`BET-(\\d+)\` dirs for next ID (zero-padded, default 001). Check \`oprim/sequence.yaml\` exists (stop if not — advise oprim init). After receiving the title, validate: if fewer than 4 words OR fewer than 25 characters, warn "this title may be too vague", suggest a reformulation, and ask "Proceed anyway? (y/N)" — if "n", prompt for a revised title. Gather: decision (default Build now), owner, review date, why-now, alternatives, expected outcomes, kill criteria, PDR links. Write \`oprim/bets/BET-NNN/bet-decision.md\` with an inline naming tip comment in the header. Append entry to sequence.yaml backlog: \`{id, title, blocked_by: [], unlocks: [], requires_pdrs: []}\`. Then ask: "Do you want to scaffold a discovery.md now? (y/N)" — if "y", write \`oprim/bets/BET-NNN/discovery.md\` from the discovery template (sections: Problem Framing, User Research Signals, Competitive Context, Open Questions); if "n" or Enter, skip silently. Report what was created.`;
807
+ return `Create a new bet in \`oprim/bets/\`. First explain: "A bet is a product decision you're committing to explore — a problem worth solving, a hypothesis worth testing, or a direction worth taking. You'll name it, explain why now, and set a kill criterion." Then show: "Naming tip: verb + object [for context] — Good: 'Improve bet naming for scannability' / Bad: 'Naming'". Scan \`BET-(\\d+)\` dirs for next ID (zero-padded, default 001). Check \`oprim/sequence.yaml\` exists (stop if not — advise oprim init). After receiving the title, validate: if fewer than 4 words OR fewer than 25 characters, warn "this title may be too vague", suggest a reformulation, and ask "Proceed anyway? (y/N)" — if "n", prompt for a revised title. Gather: decision (default Build now), owner, review date, why-now, alternatives, expected outcomes, kill criteria, PDR links. Write \`oprim/bets/BET-NNN/bet-decision.md\` with an inline naming tip comment in the header. Append entry to sequence.yaml backlog: \`{id, title, blocked_by: [], unlocks: [], requires_pdrs: []}\`. Then ask: "Do you want to scaffold a discovery.md now? (y/N)" — if "y", write \`oprim/bets/BET-NNN/discovery.md\` from the discovery template (sections: Problem Framing, User Research Signals, Competitive Context, Open Questions); if "n" or Enter, skip silently. Report what was created.`;
781
808
  }
782
809
  function criteriaInlineContent() {
783
810
  return `Add metrics to \`oprim/bets/BET-NNN/criteria.yaml\`. Verify bet dir exists. Gather: metric ID, name, baseline, target, timeframe, launch date, segment. Ask source type (amplitude or bigquery). Amplitude: event, aggregation, denominator_event. BigQuery: table, metric_column, filter, aggregation, denominator_query. If file exists: append to metrics list (never overwrite). If not: create. Ask if adding more metrics. Report what was created.`;
@@ -826,7 +853,6 @@ nudge_flag=".claude/hooks/.sequence-nudge"
826
853
  # --- Archive co-archival block ---
827
854
  if [ -f "$archive_flag" ]; then
828
855
  change=$(tr -d '[:space:]' < "$archive_flag")
829
- rm -f "$archive_flag"
830
856
 
831
857
  if [ -z "$change" ]; then
832
858
  latest=$(ls openspec/changes/archive/ 2>/dev/null | sort -r | head -1)
@@ -836,6 +862,7 @@ if [ -f "$archive_flag" ]; then
836
862
  if [ -n "$change" ]; then
837
863
  archive_dir=$(ls openspec/changes/archive/ 2>/dev/null | grep -F "$change" | sort -r | head -1)
838
864
  if [ -n "$archive_dir" ]; then
865
+ rm -f "$archive_flag"
839
866
  proposal="openspec/changes/archive/$archive_dir/proposal.md"
840
867
  if [ -f "$proposal" ]; then
841
868
  bet_id=$(grep -oE 'BET-[0-9]+' "$proposal" | head -1)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-product-primer/cli",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Open Product Primer CLI — product decisions, sequencing, and KPI tracking for repositories",
5
5
  "keywords": [
6
6
  "product",