@limina-labs/momentum 0.30.2 → 0.31.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/README.md CHANGED
@@ -8,6 +8,8 @@
8
8
  [![npm](https://img.shields.io/npm/v/@limina-labs/momentum?logo=npm)](https://www.npmjs.com/package/@limina-labs/momentum)
9
9
  [![license](https://img.shields.io/github/license/LiminaLabsAI/momentum)](LICENSE)
10
10
  [![visit the site](https://img.shields.io/badge/site-trymomentum.github.io-4F46E5)](https://trymomentum.github.io/)
11
+
12
+ <sub>Built and maintained by <a href="https://github.com/LiminaLabsAI">Limina Labs</a></sub>
11
13
  </div>
12
14
 
13
15
  ---
@@ -24,13 +26,16 @@ momentum makes your project's memory durable. Phases, decisions, history, and ba
24
26
  npx @limina-labs/momentum@latest init
25
27
  ```
26
28
 
27
- That's it. The agent picks up the workflow on next session start.
29
+ momentum asks which coding agent to scaffold for there is no default. Pass
30
+ `--agent` to answer up front (required in non-interactive shells). That's it.
31
+ The agent picks up the workflow on next session start.
28
32
 
29
33
  > Always pin `@latest`. A bare `npx @limina-labs/momentum` can serve a
30
34
  > stale, cached version; `@latest` forces npx to resolve the newest release.
31
35
 
32
36
  ```bash
33
- # Want a specific adapter?
37
+ # Or pick the adapter up front:
38
+ npx @limina-labs/momentum@latest init --agent claude-code # Claude Code
34
39
  npx @limina-labs/momentum@latest init --agent opencode # opencode
35
40
  npx @limina-labs/momentum@latest init --agent codex # Codex
36
41
  npx @limina-labs/momentum@latest init --agent antigravity # Antigravity
package/bin/momentum.js CHANGED
@@ -1415,7 +1415,8 @@ OKF — specs/ as an Open Knowledge Format bundle (Phase 24, ADR-0005):
1415
1415
  momentum okf index [dir] Regenerate bundle indexes (root/phases/decisions)
1416
1416
 
1417
1417
  Options:
1418
- --agent <name> Agent to install for (default: claude-code)
1418
+ --agent <name> Agent to install for. \`init\` asks when this
1419
+ is omitted (and requires it without a TTY)
1419
1420
  Available: ${formatAvailableAgents()}
1420
1421
  --dry-run init/upgrade: preview the action set; write nothing
1421
1422
  --autostash upgrade: stash a dirty tree, upgrade, then restore it
@@ -1627,6 +1628,55 @@ function promptYesNo(question) {
1627
1628
 
1628
1629
  // ── Entry point ───────────────────────────────────────────────────────────────
1629
1630
 
1631
+ // ── init agent picker (v0.31.0) ──────────────────────────────────────────────
1632
+ //
1633
+ // `init` has no default adapter: an install that guesses is worse than one
1634
+ // that asks. Interactive shells get a numbered picker; non-interactive
1635
+ // callers (CI, agents, pipes) must pass --agent explicitly.
1636
+ // MOMENTUM_FORCE_INTERACTIVE=1 lets tests exercise the picker through pipes.
1637
+ function promptForAgent() {
1638
+ const agents = listAvailableAgents();
1639
+ const interactive = (process.stdin.isTTY && process.stdout.isTTY)
1640
+ || process.env.MOMENTUM_FORCE_INTERACTIVE === '1';
1641
+ if (!interactive) {
1642
+ console.error('Error: --agent is required when init runs non-interactively.');
1643
+ console.error(`Available: ${agents.join(', ')}`);
1644
+ console.error(`Example: npx @limina-labs/momentum@latest init --agent ${agents[0] || 'claude-code'}`);
1645
+ process.exit(1);
1646
+ }
1647
+ console.log('\nWhich coding agent should momentum install for?\n');
1648
+ agents.forEach((name, i) => console.log(` ${i + 1}. ${name}`));
1649
+ console.log('');
1650
+ const readline = require('node:readline');
1651
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1652
+ return new Promise((resolve) => {
1653
+ let resolved = false;
1654
+ // Piped stdin can end before an answer arrives — treat EOF as "no pick".
1655
+ rl.on('close', () => {
1656
+ if (!resolved) {
1657
+ console.error('\nError: no agent selected.');
1658
+ process.exit(1);
1659
+ }
1660
+ });
1661
+ const ask = () => {
1662
+ rl.question(`Agent [1-${agents.length}]: `, (answer) => {
1663
+ const input = answer.trim();
1664
+ // Accept the agent name itself or its 1-based list number.
1665
+ const pick = agents.includes(input) ? input : agents[Number(input) - 1];
1666
+ if (pick) {
1667
+ resolved = true;
1668
+ rl.close();
1669
+ resolve(pick);
1670
+ return;
1671
+ }
1672
+ console.log(` Enter 1-${agents.length} or an agent name.`);
1673
+ ask();
1674
+ });
1675
+ };
1676
+ ask();
1677
+ });
1678
+ }
1679
+
1630
1680
  async function main() {
1631
1681
  const args = process.argv.slice(2);
1632
1682
 
@@ -1642,6 +1692,10 @@ async function main() {
1642
1692
  // root command surface, upgrade's sweep override — ENH-049), so an
1643
1693
  // explicit flag is re-injected at that dispatch rather than silently
1644
1694
  // swallowed here.
1695
+ //
1696
+ // The claude-code fallback below serves upgrade/ecosystem paths only —
1697
+ // `init` never uses it: since v0.31.0 an omitted --agent makes init ask
1698
+ // interactively (or fail fast when there is no TTY to ask on).
1645
1699
  let agent = 'claude-code';
1646
1700
  let agentExplicit = false;
1647
1701
  const agentFlagIdx = args.indexOf('--agent');
@@ -1670,6 +1724,10 @@ async function main() {
1670
1724
  const initOpts = extractInitFlags(args.filter((a) => a !== '--dry-run'));
1671
1725
  const targetDir = initOpts.target || process.cwd();
1672
1726
  try {
1727
+ // v0.31.0: no silent default agent — momentum is multi-adapter, and a
1728
+ // hidden claude-code default scaffolds the wrong surface for every
1729
+ // other agent's users. Ask when we can, fail fast when we can't.
1730
+ if (!agentExplicit) agent = await promptForAgent();
1673
1731
  init(targetDir, agent, { dryRun });
1674
1732
  // Ecosystem auto-detect/scaffold mutates state — skip it on a dry run.
1675
1733
  if (!dryRun) await postInitEcosystem(targetDir, initOpts);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@limina-labs/momentum",
3
- "version": "0.30.2",
3
+ "version": "0.31.0",
4
4
  "description": "Agent-agnostic, specs-driven development framework — single project or multi-project ecosystem",
5
5
  "homepage": "https://trymomentum.github.io",
6
6
  "bin": {