@limina-labs/momentum 0.30.2
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/LICENSE +21 -0
- package/README.md +214 -0
- package/adapters/antigravity/adapter.js +196 -0
- package/adapters/antigravity/hooks.json +39 -0
- package/adapters/antigravity/instructions/AGENTS.md +638 -0
- package/adapters/antigravity/instructions/header.md +3 -0
- package/adapters/antigravity/instructions/surfaces.md +153 -0
- package/adapters/antigravity/instructions/vars.json +1 -0
- package/adapters/antigravity/scripts/antigravity-hook-adapter.sh +147 -0
- package/adapters/antigravity/skills/momentum-orient/SKILL.md +29 -0
- package/adapters/antigravity/skills/momentum-reviewer-architecture/SKILL.md +39 -0
- package/adapters/antigravity/skills/momentum-reviewer-qa/SKILL.md +38 -0
- package/adapters/antigravity/skills/momentum-reviewer-security/SKILL.md +42 -0
- package/adapters/antigravity/skills/swarm-supervisor/SKILL.md +75 -0
- package/adapters/antigravity/workflows/continue.md +39 -0
- package/adapters/antigravity/workflows/dispatch.md +49 -0
- package/adapters/antigravity/workflows/handoff.md +38 -0
- package/adapters/antigravity/workflows/review-code.md +84 -0
- package/adapters/antigravity/workflows/scout.md +42 -0
- package/adapters/antigravity/workflows/swarm.md +203 -0
- package/adapters/claude-code/adapter.js +148 -0
- package/adapters/claude-code/commands/continue.md +82 -0
- package/adapters/claude-code/commands/dispatch.md +154 -0
- package/adapters/claude-code/commands/handoff.md +85 -0
- package/adapters/claude-code/commands/review-code.md +194 -0
- package/adapters/claude-code/commands/scout.md +119 -0
- package/adapters/claude-code/commands/swarm.md +242 -0
- package/adapters/claude-code/instructions/header.md +3 -0
- package/adapters/claude-code/instructions/vars.json +1 -0
- package/adapters/claude-code/settings.json +36 -0
- package/adapters/codex/adapter.js +225 -0
- package/adapters/codex/agents/momentum-reviewer-architecture.toml +57 -0
- package/adapters/codex/agents/momentum-reviewer-qa.toml +52 -0
- package/adapters/codex/agents/momentum-reviewer-security.toml +57 -0
- package/adapters/codex/agents/swarm-supervisor.toml +76 -0
- package/adapters/codex/commands/continue.md +40 -0
- package/adapters/codex/commands/dispatch.md +111 -0
- package/adapters/codex/commands/handoff.md +57 -0
- package/adapters/codex/commands/scout.md +90 -0
- package/adapters/codex/commands/swarm.md +334 -0
- package/adapters/codex/hooks.json +36 -0
- package/adapters/codex/instructions/AGENTS.md +691 -0
- package/adapters/codex/instructions/header.md +3 -0
- package/adapters/codex/instructions/surfaces.md +206 -0
- package/adapters/codex/instructions/vars.json +1 -0
- package/adapters/codex/skills/momentum-orient/SKILL.md +29 -0
- package/adapters/opencode/adapter.js +224 -0
- package/adapters/opencode/agents/momentum-reviewer-architecture.md +54 -0
- package/adapters/opencode/agents/momentum-reviewer-qa.md +48 -0
- package/adapters/opencode/agents/momentum-reviewer-security.md +48 -0
- package/adapters/opencode/agents/swarm-supervisor.md +51 -0
- package/adapters/opencode/commands/continue.md +40 -0
- package/adapters/opencode/commands/dispatch.md +111 -0
- package/adapters/opencode/commands/handoff.md +57 -0
- package/adapters/opencode/commands/review-code.md +194 -0
- package/adapters/opencode/commands/scout.md +90 -0
- package/adapters/opencode/commands/swarm.md +334 -0
- package/adapters/opencode/instructions/AGENTS.md +604 -0
- package/adapters/opencode/instructions/header.md +3 -0
- package/adapters/opencode/instructions/surfaces.md +119 -0
- package/adapters/opencode/instructions/vars.json +1 -0
- package/adapters/opencode/plugins/momentum.js +219 -0
- package/adapters/opencode/skills/momentum-lanes/SKILL.md +30 -0
- package/adapters/opencode/skills/momentum-orient/SKILL.md +29 -0
- package/adapters/opencode/skills/momentum-track/SKILL.md +28 -0
- package/adapters/opencode/skills/momentum-validate/SKILL.md +31 -0
- package/bin/antigravity.js +112 -0
- package/bin/ecosystem.js +1302 -0
- package/bin/lanes.js +300 -0
- package/bin/momentum.js +1857 -0
- package/bin/okf.js +72 -0
- package/bin/orchestration-commands.js +305 -0
- package/bin/state-commands.js +218 -0
- package/bin/swarm.js +1104 -0
- package/bin/waves.js +147 -0
- package/core/adapter-capabilities.md +112 -0
- package/core/adapter-parity-matrix.md +170 -0
- package/core/commands/brainstorm-idea.md +98 -0
- package/core/commands/brainstorm-phase.md +129 -0
- package/core/commands/complete-phase.md +130 -0
- package/core/commands/ecosystem.md +161 -0
- package/core/commands/hotfix.md +64 -0
- package/core/commands/initiative.md +119 -0
- package/core/commands/lanes.md +94 -0
- package/core/commands/log.md +45 -0
- package/core/commands/migrate.md +70 -0
- package/core/commands/review.md +31 -0
- package/core/commands/session.md +79 -0
- package/core/commands/start-phase.md +161 -0
- package/core/commands/start-project.md +142 -0
- package/core/commands/sync-docs.md +81 -0
- package/core/commands/systematic-debug.md +46 -0
- package/core/commands/track.md +54 -0
- package/core/commands/validate.md +96 -0
- package/core/ecosystem/layout.md +128 -0
- package/core/ecosystem/lib/index.js +245 -0
- package/core/ecosystem/lib/initiative.js +258 -0
- package/core/ecosystem/lib/pointer.js +198 -0
- package/core/ecosystem/lib/state.js +295 -0
- package/core/ecosystem/schema/ecosystem.schema.json +85 -0
- package/core/ecosystem/schema/initiative.schema.json +61 -0
- package/core/ecosystem/scripts/session-append.sh +167 -0
- package/core/ecosystem/templates/ecosystem-agents.md +79 -0
- package/core/ecosystem/templates/ecosystem-claude.md +79 -0
- package/core/ecosystem/templates/ecosystem-settings-claude.json +14 -0
- package/core/ecosystem/templates/initiative-template.md +50 -0
- package/core/engines/subagent-dispatch.md +80 -0
- package/core/git-hooks/commit-msg +14 -0
- package/core/git-hooks/contract.js +176 -0
- package/core/git-hooks/pre-push +15 -0
- package/core/git-hooks/run-check.js +160 -0
- package/core/instructions/legacy-project-md-hashes.json +12 -0
- package/core/instructions/navigation.md +14 -0
- package/core/instructions/rules-body.md +454 -0
- package/core/lanes/lib/board.js +161 -0
- package/core/lanes/lib/land.js +301 -0
- package/core/lanes/lib/signals.js +207 -0
- package/core/lanes/lib/state.js +325 -0
- package/core/lib/frontmatter.js +163 -0
- package/core/lib/okf-migrate.js +374 -0
- package/core/lib/okf-types.js +61 -0
- package/core/lifecycle-contract.md +59 -0
- package/core/orchestration/capability-routing.js +120 -0
- package/core/orchestration/continue.js +102 -0
- package/core/orchestration/dispatch.js +366 -0
- package/core/orchestration/events.js +197 -0
- package/core/orchestration/handoff.js +317 -0
- package/core/orchestration/index.js +50 -0
- package/core/orchestration/run-artifact.js +93 -0
- package/core/orchestration/scout.js +327 -0
- package/core/orchestration/session-log.js +123 -0
- package/core/orchestration/tracking.js +180 -0
- package/core/orchestration/types.js +131 -0
- package/core/scripts/brainstorm-gate.sh +157 -0
- package/core/scripts/check-history-reminder.sh +110 -0
- package/core/scripts/sessionstart-handoff.sh +180 -0
- package/core/specs-templates/CLAUDE.md +484 -0
- package/core/specs-templates/README.md +32 -0
- package/core/specs-templates/specs/README.md +30 -0
- package/core/specs-templates/specs/adhoc/README.md +31 -0
- package/core/specs-templates/specs/adhoc/_TEMPLATE.md +29 -0
- package/core/specs-templates/specs/architecture/ecosystem.md +214 -0
- package/core/specs-templates/specs/backlog/backlog.md +46 -0
- package/core/specs-templates/specs/backlog/details/.gitkeep +0 -0
- package/core/specs-templates/specs/changelog/.gitkeep +0 -0
- package/core/specs-templates/specs/decisions/0000-template.md +33 -0
- package/core/specs-templates/specs/decisions/README.md +29 -0
- package/core/specs-templates/specs/decisions/impact-map.md +14 -0
- package/core/specs-templates/specs/decisions/index.md +4 -0
- package/core/specs-templates/specs/index.md +16 -0
- package/core/specs-templates/specs/phases/README.md +41 -0
- package/core/specs-templates/specs/phases/index.md +6 -0
- package/core/specs-templates/specs/planning/roadmap.md +23 -0
- package/core/specs-templates/specs/status.md +70 -0
- package/core/specs-templates/specs/vision/principles.md +16 -0
- package/core/specs-templates/specs/vision/project-charter.md +35 -0
- package/core/specs-templates/specs/vision/success-criteria.md +19 -0
- package/core/swarm/absorb.js +294 -0
- package/core/swarm/conductor.js +499 -0
- package/core/swarm/focus.js +151 -0
- package/core/swarm/inbox.js +222 -0
- package/core/swarm/join.js +138 -0
- package/core/swarm/lib/board.js +178 -0
- package/core/swarm/lib/brief.js +157 -0
- package/core/swarm/lib/git-sha-cache.js +71 -0
- package/core/swarm/lib/incremental-log.js +117 -0
- package/core/swarm/lib/manifest.js +578 -0
- package/core/swarm/lib/pre-merge.js +112 -0
- package/core/swarm/lib/saga.js +146 -0
- package/core/swarm/lib/sessions.js +83 -0
- package/core/swarm/lib/tokens.js +255 -0
- package/core/swarm/lib/wave-ordering.js +55 -0
- package/core/swarm/schema/board.schema.json +54 -0
- package/core/swarm/schema/contract.schema.json +56 -0
- package/core/swarm/schema/dispatch-run.schema.json +70 -0
- package/core/swarm/schema/manifest.schema.json +234 -0
- package/core/swarm/schema/signal.schema.json +61 -0
- package/core/swarm/signals.js +296 -0
- package/core/swarm/supervise.md +81 -0
- package/core/waves/lib/plan-graph.js +175 -0
- package/core/waves/lib/waves.js +83 -0
- package/package.json +46 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
## Momentum Recipes — opencode Commands
|
|
2
|
+
|
|
3
|
+
Every momentum recipe ships as a native opencode command at
|
|
4
|
+
`.opencode/commands/<name>.md` ([opencode commands
|
|
5
|
+
docs](https://opencode.ai/docs/commands/)). opencode auto-discovers them
|
|
6
|
+
at startup — type `/` in the TUI and the full recipe set appears; e.g.
|
|
7
|
+
`/brainstorm-phase` runs the phase-planning recipe. Arguments flow via
|
|
8
|
+
`$ARGUMENTS` (e.g. `/track BUG some description`).
|
|
9
|
+
|
|
10
|
+
The shipped recipe set (one command per recipe):
|
|
11
|
+
|
|
12
|
+
| Recipe | What it does |
|
|
13
|
+
|---|---|
|
|
14
|
+
| brainstorm-idea | Explore an idea before scaffolding anything |
|
|
15
|
+
| brainstorm-phase | Plan the next implementation phase (gate-protected) |
|
|
16
|
+
| start-project | Scaffold a new spec-driven project |
|
|
17
|
+
| start-phase | Begin a planned phase (autonomous execution contract) |
|
|
18
|
+
| complete-phase | Verify, retro, release a finished phase |
|
|
19
|
+
| sync-docs | Propagate history entries to other spec docs |
|
|
20
|
+
| track | Track a backlog item (bug / feature / tech debt / enhancement) |
|
|
21
|
+
| review | Review and groom the backlog between phases |
|
|
22
|
+
| log | Append a manual narrative entry to the history of the phase bound to your branch (fallback: status.md) |
|
|
23
|
+
| hotfix | Ship a bounded ad-hoc change (quick-task / spike) without a phase |
|
|
24
|
+
| lanes | Work with lanes — concurrent workstreams in one repo (Rule 15) |
|
|
25
|
+
| migrate | Onboard an existing project into momentum |
|
|
26
|
+
| validate | Check spec structure health |
|
|
27
|
+
| ecosystem | Cross-repo ecosystem coordination |
|
|
28
|
+
| initiative | Manage cross-repo initiatives |
|
|
29
|
+
| session | Append a manual narrative entry to today's ecosystem session log |
|
|
30
|
+
| systematic-debug | Systematically isolate, reproduce, and resolve task execution failures |
|
|
31
|
+
| scout | Read-only context fetch from one ecosystem member repo |
|
|
32
|
+
| dispatch | Parallel multi-repo fan-out + synthesis |
|
|
33
|
+
| handoff | Cross-session control transfer with structured context block |
|
|
34
|
+
| continue | Pick up a pending handoff in this repo |
|
|
35
|
+
| review-code | Multi-perspective code review (uses momentum-reviewer-* subagents) |
|
|
36
|
+
| swarm | Sustained parallel multi-project feature delivery (uses the swarm-supervisor agent) |
|
|
37
|
+
|
|
38
|
+
The recipes are platform-independent — they describe what to do, not how
|
|
39
|
+
opencode specifically should do it. When a recipe mentions "use the Task
|
|
40
|
+
tool" (Claude Code terminology), use opencode's task tool: invoke the
|
|
41
|
+
relevant subagent (`@momentum-reviewer-qa` mention or automatic task
|
|
42
|
+
dispatch).
|
|
43
|
+
|
|
44
|
+
## Momentum Skills
|
|
45
|
+
|
|
46
|
+
Momentum also ships skills at `.opencode/skills/<name>/SKILL.md`
|
|
47
|
+
([opencode skills docs](https://opencode.ai/docs/skills/)). opencode
|
|
48
|
+
discovers them natively and exposes them through the `skill` tool — the
|
|
49
|
+
agent loads a skill on demand when its description matches the work.
|
|
50
|
+
Skills complement commands: commands are user-invoked (`/name`), skills
|
|
51
|
+
are agent-invoked (momentum-orient runs Rule 1 orientation without you
|
|
52
|
+
asking).
|
|
53
|
+
|
|
54
|
+
Add project-specific skills under `.opencode/skills/<name>/SKILL.md`
|
|
55
|
+
with `name` + `description` frontmatter (name must match
|
|
56
|
+
`^[a-z0-9]+(-[a-z0-9]+)*$`).
|
|
57
|
+
|
|
58
|
+
## Momentum Plugin — enforcement hooks
|
|
59
|
+
|
|
60
|
+
Momentum's enforcement layer ships as one plugin at
|
|
61
|
+
`.opencode/plugins/momentum.js` ([opencode plugins
|
|
62
|
+
docs](https://opencode.ai/docs/plugins/)), auto-loaded at startup:
|
|
63
|
+
|
|
64
|
+
| Hook | Purpose |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `tool.execute.before` | Brainstorm gate — blocks write-class tools targeting `specs/**` while `.momentum/brainstorm-active` exists (throws to block, mirroring the Claude Code PreToolUse gate). |
|
|
67
|
+
| `tool.execute.after` | History reminder — prompts for a `history.md` append when meaningful edits land during phase work (Rule 8); bash tool calls additionally delegate to the installed scripts/check-history-reminder.sh, which also feeds the ecosystem session log (ENH-058). |
|
|
68
|
+
| `event (session.created)` | Handoff banner — surfaces pending `.momentum/inbox/` handoffs at session start. **Run-mode caveat**: this handler is registered only in TUI/serve sessions. In `opencode run` (headless/non-interactive) the handler is skipped — its mere presence hangs `opencode run` on 1.17.x (upstream candidate, noted in ENH-058). Session banners are meaningless in headless mode anyway. |
|
|
69
|
+
|
|
70
|
+
The plugin is self-contained (no npm dependencies) and reads the same
|
|
71
|
+
`.momentum/` sentinels as the other adapters' hook scripts — the
|
|
72
|
+
enforcement semantics are identical across platforms.
|
|
73
|
+
|
|
74
|
+
## Momentum Subagents
|
|
75
|
+
|
|
76
|
+
Momentum ships four agents at `.opencode/agents/` ([opencode agents
|
|
77
|
+
docs](https://opencode.ai/docs/agents/)):
|
|
78
|
+
|
|
79
|
+
- `momentum-reviewer-security.md` — OWASP/STRIDE-focused
|
|
80
|
+
- `momentum-reviewer-qa.md` — test coverage + edge cases + regression risk
|
|
81
|
+
- `momentum-reviewer-architecture.md` — rule compliance + pattern consistency
|
|
82
|
+
- `swarm-supervisor.md` — per-repo supervisor spawned by `/swarm start`
|
|
83
|
+
|
|
84
|
+
The three reviewers declare `mode: subagent` with `permission: edit: deny`
|
|
85
|
+
— they cannot modify the codebase. The `review-code` recipe dispatches
|
|
86
|
+
all three in one turn so opencode can fan them out via the task tool.
|
|
87
|
+
The swarm supervisor is not read-only — supervisors write code, that's
|
|
88
|
+
the job.
|
|
89
|
+
|
|
90
|
+
To add a project-specific reviewer, drop another `<name>.md` into
|
|
91
|
+
`.opencode/agents/` with `description` + `mode: subagent` frontmatter.
|
|
92
|
+
|
|
93
|
+
## Swarm — Lookup Pattern
|
|
94
|
+
|
|
95
|
+
Momentum's swarm primitive ships on opencode. The swarm recipe lives at
|
|
96
|
+
`.opencode/commands/swarm.md` (`/swarm <sub>`); the CLI floor is
|
|
97
|
+
`momentum swarm <sub> [args]` — both produce the same on-disk artifacts.
|
|
98
|
+
|
|
99
|
+
**Supervisor spawn**: the conductor dispatches spawns through
|
|
100
|
+
`adapters/opencode/adapter.js::spawn(directive)`, which shells
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
opencode run --dir <repoPath> --agent swarm-supervisor "<boot directive>"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`--dir` pins each supervisor's working directory to its repo — no MCP
|
|
107
|
+
cwd shim needed (unlike Codex). If `opencode` isn't on PATH,
|
|
108
|
+
`momentum swarm start --spawn` degrades to dry-run and prints the spawn
|
|
109
|
+
directives for manual launch.
|
|
110
|
+
|
|
111
|
+
## Instruction precedence note
|
|
112
|
+
|
|
113
|
+
opencode reads `AGENTS.md` (this file) as its primary project
|
|
114
|
+
instruction, with `CLAUDE.md` as a compatibility fallback — when both
|
|
115
|
+
exist (e.g. a project installed for multiple agents), `AGENTS.md` wins
|
|
116
|
+
and nothing is read twice. opencode also discovers Claude-compatible
|
|
117
|
+
skill paths (`.claude/skills/`, `.agents/skills/`); momentum's opencode
|
|
118
|
+
surfaces live under `.opencode/` so multi-adapter installs stay
|
|
119
|
+
side-by-side without collisions.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "TASK_TOOL": "the built-in **task** tool (subagent fan-out)", "TASK_TOOL_NAME": "The task tool" }
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
// momentum enforcement plugin for opencode.
|
|
2
|
+
//
|
|
3
|
+
// Installed by momentum init/upgrade --agent opencode into
|
|
4
|
+
// .opencode/plugins/momentum.js — auto-loaded by opencode at startup.
|
|
5
|
+
//
|
|
6
|
+
// One plugin, three hooks — the opencode-native equivalent of the shell
|
|
7
|
+
// hooks the other adapters wire (core/scripts/brainstorm-gate.sh,
|
|
8
|
+
// check-history-reminder.sh, sessionstart-handoff.sh). Reads the same
|
|
9
|
+
// .momentum/ sentinels, so enforcement semantics are identical across
|
|
10
|
+
// platforms:
|
|
11
|
+
//
|
|
12
|
+
// tool.execute.before — brainstorm gate: while .momentum/brainstorm-active
|
|
13
|
+
// exists, write-class tools targeting specs/** throw
|
|
14
|
+
// (throwing blocks the tool call).
|
|
15
|
+
// tool.execute.after — history reminder: meaningful edits during phase
|
|
16
|
+
// work prompt for a history.md append (Rule 8);
|
|
17
|
+
// bash tool calls additionally delegate to the
|
|
18
|
+
// installed scripts/check-history-reminder.sh,
|
|
19
|
+
// which also feeds the ecosystem session log
|
|
20
|
+
// (commit / pr events — ENH-058).
|
|
21
|
+
// event (session.created) — session banners: delegates to the installed
|
|
22
|
+
// scripts/sessionstart-handoff.sh (ecosystem
|
|
23
|
+
// context + handoff inbox, same output as every
|
|
24
|
+
// other adapter); pure-JS handoff fallback when
|
|
25
|
+
// the script is absent. TUI/serve sessions only;
|
|
26
|
+
// see the run-mode note below.
|
|
27
|
+
//
|
|
28
|
+
// Node builtins only, no npm dependencies. The ecosystem behaviors reuse the
|
|
29
|
+
// SAME installed shell scripts the other adapters wire (scripts/ self-guard
|
|
30
|
+
// and no-op outside ecosystems), so semantics stay identical across
|
|
31
|
+
// platforms. Fail-open by design: any unexpected error in reminder/banner
|
|
32
|
+
// paths is swallowed; only the gate throws, and only on a confirmed
|
|
33
|
+
// specs/-write during an active brainstorm.
|
|
34
|
+
|
|
35
|
+
import fs from "node:fs"
|
|
36
|
+
import path from "node:path"
|
|
37
|
+
import { spawnSync } from "node:child_process"
|
|
38
|
+
|
|
39
|
+
const WRITE_TOOLS = new Set(["write", "edit", "patch"])
|
|
40
|
+
const REMINDER_THROTTLE_MS = 30 * 60 * 1000 // one nudge per 30 min
|
|
41
|
+
const SCRIPT_TIMEOUT_MS = 3000
|
|
42
|
+
|
|
43
|
+
// Run an installed momentum hook script (scripts/<name>) with the canonical
|
|
44
|
+
// JSON hook payload on stdin. Returns trimmed combined output, or null when
|
|
45
|
+
// the script is missing/failed — callers treat null as "nothing to show".
|
|
46
|
+
function runInstalledScript(root, name, payload) {
|
|
47
|
+
try {
|
|
48
|
+
const script = path.join(root, "scripts", name)
|
|
49
|
+
if (!fs.existsSync(script)) return null
|
|
50
|
+
const r = spawnSync("bash", [script], {
|
|
51
|
+
cwd: root,
|
|
52
|
+
input: payload ? JSON.stringify(payload) : "",
|
|
53
|
+
encoding: "utf8",
|
|
54
|
+
timeout: SCRIPT_TIMEOUT_MS,
|
|
55
|
+
env: { ...process.env, MOMENTUM_PROJECT_DIR: root },
|
|
56
|
+
})
|
|
57
|
+
if (r.error) return null
|
|
58
|
+
const out = `${r.stdout || ""}${r.stderr || ""}`.trim()
|
|
59
|
+
return out.length ? out : ""
|
|
60
|
+
} catch {
|
|
61
|
+
return null
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function extractTargetPath(tool, args) {
|
|
66
|
+
if (!args || typeof args !== "object") return null
|
|
67
|
+
if (typeof args.filePath === "string") return args.filePath
|
|
68
|
+
if (typeof args.path === "string") return args.path
|
|
69
|
+
if (tool === "bash" && typeof args.command === "string") {
|
|
70
|
+
// Mirror brainstorm-gate.sh's shell heuristic: first specs/ path in the
|
|
71
|
+
// command (catches `> specs/...`, `sed -i ... specs/...`, `tee specs/...`).
|
|
72
|
+
const m = args.command.match(/specs\/[^\s"'\\]+/)
|
|
73
|
+
return m ? m[0] : null
|
|
74
|
+
}
|
|
75
|
+
return null
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isUnderSpecs(root, targetPath) {
|
|
79
|
+
const abs = path.isAbsolute(targetPath) ? targetPath : path.join(root, targetPath)
|
|
80
|
+
const rel = path.relative(path.join(root, "specs"), abs)
|
|
81
|
+
return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const MomentumPlugin = async ({ directory, worktree }) => {
|
|
85
|
+
const root = worktree || directory || process.cwd()
|
|
86
|
+
const momentumDir = path.join(root, ".momentum")
|
|
87
|
+
|
|
88
|
+
// tool.execute.after does NOT carry tool args (confirmed live, Phase 22 G5)
|
|
89
|
+
// — only the before hook sees them. Correlate by callID so the reminder
|
|
90
|
+
// knows which path a completed write touched. Bounded: entries are removed
|
|
91
|
+
// at after-time; the cap guards sessions whose after hooks never fire.
|
|
92
|
+
const pendingWrites = new Map()
|
|
93
|
+
const pendingBash = new Map()
|
|
94
|
+
const PENDING_CAP = 512
|
|
95
|
+
|
|
96
|
+
const remember = (map, key, value) => {
|
|
97
|
+
if (map.size >= PENDING_CAP) map.delete(map.keys().next().value)
|
|
98
|
+
map.set(key, value)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
"tool.execute.before": async (input, output) => {
|
|
103
|
+
const tool = (input && input.tool) || ""
|
|
104
|
+
if (!WRITE_TOOLS.has(tool) && tool !== "bash") return
|
|
105
|
+
const target = extractTargetPath(tool, output && output.args)
|
|
106
|
+
if (target && WRITE_TOOLS.has(tool) && input && input.callID) {
|
|
107
|
+
remember(pendingWrites, input.callID, target)
|
|
108
|
+
}
|
|
109
|
+
if (tool === "bash" && input && input.callID) {
|
|
110
|
+
const command = output && output.args && output.args.command
|
|
111
|
+
if (typeof command === "string") remember(pendingBash, input.callID, command)
|
|
112
|
+
}
|
|
113
|
+
if (!fs.existsSync(path.join(momentumDir, "brainstorm-active"))) return
|
|
114
|
+
if (!target) return // fail-open when no path is extractable
|
|
115
|
+
if (isUnderSpecs(root, target)) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
[
|
|
118
|
+
"[brainstorm-gate] Blocked: cannot write to specs/ during active brainstorm.",
|
|
119
|
+
`[brainstorm-gate] Path: ${target}`,
|
|
120
|
+
"[brainstorm-gate] The conversation IS the draft. Get explicit user approval, then:",
|
|
121
|
+
"[brainstorm-gate] rm .momentum/brainstorm-active",
|
|
122
|
+
"[brainstorm-gate] and retry the write.",
|
|
123
|
+
].join("\n"),
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
"tool.execute.after": async (input, output) => {
|
|
129
|
+
try {
|
|
130
|
+
const tool = (input && input.tool) || ""
|
|
131
|
+
// Bash completions delegate to the installed reminder script, which
|
|
132
|
+
// also appends commit/pr events to the ecosystem session log
|
|
133
|
+
// (ENH-058). The script self-guards: instant no-op outside
|
|
134
|
+
// ecosystems and for non-matching commands.
|
|
135
|
+
if (tool === "bash") {
|
|
136
|
+
let command = input && input.callID ? pendingBash.get(input.callID) : undefined
|
|
137
|
+
if (input && input.callID) pendingBash.delete(input.callID)
|
|
138
|
+
if (!command && output && output.args) command = output.args.command
|
|
139
|
+
if (typeof command !== "string" || !command) return
|
|
140
|
+
const out = runInstalledScript(root, "check-history-reminder.sh", {
|
|
141
|
+
tool_name: "Bash",
|
|
142
|
+
tool_input: { command },
|
|
143
|
+
})
|
|
144
|
+
if (out) console.log(out)
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
if (!WRITE_TOOLS.has(tool)) return
|
|
148
|
+
// Args live only in the before hook — recover the path via callID
|
|
149
|
+
// (fallback to output.args for synthetic/direct invocations).
|
|
150
|
+
let target = input && input.callID ? pendingWrites.get(input.callID) : undefined
|
|
151
|
+
if (input && input.callID) pendingWrites.delete(input.callID)
|
|
152
|
+
if (!target) target = extractTargetPath(tool, output && output.args)
|
|
153
|
+
if (!target) return
|
|
154
|
+
// Edits to the spec layer ARE the tracking — only code/doc edits
|
|
155
|
+
// outside specs/ and .momentum/ warrant a history nudge.
|
|
156
|
+
if (isUnderSpecs(root, target)) return
|
|
157
|
+
const rel = path.relative(root, path.isAbsolute(target) ? target : path.join(root, target))
|
|
158
|
+
if (rel.startsWith(".momentum")) return
|
|
159
|
+
|
|
160
|
+
const stampFile = path.join(momentumDir, "history-reminder-stamp")
|
|
161
|
+
const now = Date.now()
|
|
162
|
+
try {
|
|
163
|
+
const last = fs.statSync(stampFile).mtimeMs
|
|
164
|
+
if (now - last < REMINDER_THROTTLE_MS) return
|
|
165
|
+
} catch {
|
|
166
|
+
/* no stamp yet — proceed */
|
|
167
|
+
}
|
|
168
|
+
fs.mkdirSync(momentumDir, { recursive: true })
|
|
169
|
+
fs.writeFileSync(stampFile, String(now))
|
|
170
|
+
console.log(
|
|
171
|
+
"[momentum] Meaningful edit landed — if this completes a decision, discovery, or " +
|
|
172
|
+
"scope change, append a history entry to your phase's history.md (Rule 8). " +
|
|
173
|
+
"Resolve your phase from the current branch (Rule 15).",
|
|
174
|
+
)
|
|
175
|
+
} catch {
|
|
176
|
+
/* reminder is best-effort; never disturb the session */
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
// Handoff banner. Session events reach plugins ONLY via the generic
|
|
181
|
+
// `event` bus in opencode 1.17.x — a named "session.created" hook key
|
|
182
|
+
// never fires (live-verified, Phase 22 follow-up). The event handler is
|
|
183
|
+
// registered conditionally: its mere presence HANGS `opencode run`
|
|
184
|
+
// non-interactive mode (reproduced on 1.17.13), and a session-start
|
|
185
|
+
// banner is meaningless there anyway — so run-mode skips it.
|
|
186
|
+
...(process.argv.includes("run")
|
|
187
|
+
? {}
|
|
188
|
+
: {
|
|
189
|
+
event: async ({ event }) => {
|
|
190
|
+
try {
|
|
191
|
+
if (!event || event.type !== "session.created") return
|
|
192
|
+
// Preferred path (ENH-058): the installed script prints BOTH
|
|
193
|
+
// banners — ecosystem context (parent-walk + sibling-scan) and
|
|
194
|
+
// the handoff inbox — with the same output every other adapter
|
|
195
|
+
// shows. Non-TTY stdin keeps it prompt-free.
|
|
196
|
+
const banners = runInstalledScript(root, "sessionstart-handoff.sh", null)
|
|
197
|
+
if (banners !== null) {
|
|
198
|
+
if (banners) console.log(banners)
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
// Fallback (script not installed): pure-JS handoff banner.
|
|
202
|
+
const inboxDir = path.join(momentumDir, "inbox")
|
|
203
|
+
if (!fs.existsSync(inboxDir)) return
|
|
204
|
+
const pending = fs
|
|
205
|
+
.readdirSync(inboxDir)
|
|
206
|
+
.filter((f) => /^handoff-\d+\.md$/.test(f))
|
|
207
|
+
.sort()
|
|
208
|
+
if (pending.length === 0) return
|
|
209
|
+
console.log(
|
|
210
|
+
`[momentum] ${pending.length} pending handoff(s) in .momentum/inbox/: ` +
|
|
211
|
+
`${pending.join(", ")} — run /continue (or \`momentum continue\`) to pick up.`,
|
|
212
|
+
)
|
|
213
|
+
} catch {
|
|
214
|
+
/* banner is best-effort; never disturb the session */
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
}),
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: momentum-lanes
|
|
3
|
+
description: Work with concurrent workstreams (Rule 15). Activates when the session involves multiple active branches, cross-lane coordination, or when starting work that should not live on the current branch.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# momentum-lanes
|
|
7
|
+
|
|
8
|
+
Use this skill when you detect concurrent workstreams or need to coordinate
|
|
9
|
+
across branches. Key behaviors:
|
|
10
|
+
|
|
11
|
+
1. **Lane binding**: your phase is the phase bound to your branch
|
|
12
|
+
(`phase-N-shortname`). `specs/status.md` is the cross-lane overview.
|
|
13
|
+
2. **Lane-scoped tracking**: write ONLY your own phase's artifacts
|
|
14
|
+
(`tasks.md`, `history.md`, `evidence/`). Shared files (`status.md`,
|
|
15
|
+
`backlog.md`, `changelog/`) are append / own-row-touch only.
|
|
16
|
+
3. **Landing order**: one lane at a time, suite green on updated `main`
|
|
17
|
+
between landings, remaining lanes rebase.
|
|
18
|
+
|
|
19
|
+
When the user starts a second workstream or asks about what's in flight,
|
|
20
|
+
read the lane board before proceeding.
|
|
21
|
+
|
|
22
|
+
## When NOT to apply
|
|
23
|
+
|
|
24
|
+
- Single-lane, single-branch sessions with no cross-lane coordination
|
|
25
|
+
|
|
26
|
+
## References
|
|
27
|
+
|
|
28
|
+
- Rule 15 in `AGENTS.md` — concurrent workstreams
|
|
29
|
+
- `/lanes` command — board, queue, signal, land
|
|
30
|
+
- `specs/status.md` — cross-lane overview
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: momentum-orient
|
|
3
|
+
description: Read specs/status.md before starting any work in a momentum-managed project. Activates at the start of every new task to ensure the agent has current phase context. Codifies Rule 1 (Orient First).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# momentum-orient
|
|
7
|
+
|
|
8
|
+
When this skill activates (at session start or when the user asks you to
|
|
9
|
+
work on something new), read these files in order before any other action:
|
|
10
|
+
|
|
11
|
+
1. `specs/status.md` — current phase, blockers, P0 items, next actions
|
|
12
|
+
2. `specs/backlog/backlog.md` — P0/P1 items that may block the current task
|
|
13
|
+
3. `specs/phases/<active-phase>/tasks.md` — what's done / in flight / blocked
|
|
14
|
+
4. `AGENTS.md` — project rules and constraints (the complete rulebook)
|
|
15
|
+
|
|
16
|
+
Then proceed with the user's request, framing any output in terms of:
|
|
17
|
+
- which phase is active
|
|
18
|
+
- whether the requested work belongs in the active phase or is a side track
|
|
19
|
+
- any existing tasks or history entries that already cover the request
|
|
20
|
+
|
|
21
|
+
This skill is shipped by the momentum toolkit. It codifies Rule 1 (Orient
|
|
22
|
+
First) from the project rules. See `AGENTS.md` for the full set of rules.
|
|
23
|
+
|
|
24
|
+
## When NOT to apply this skill
|
|
25
|
+
|
|
26
|
+
- If the user's message is purely conversational ("what is X?") and doesn't
|
|
27
|
+
require touching the codebase, you don't need to orient.
|
|
28
|
+
- If you've already oriented this session and nothing on disk has changed
|
|
29
|
+
since, don't re-orient.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: momentum-track
|
|
3
|
+
description: Record a new backlog item (bug, feature, tech debt, or enhancement) when you discover work that needs tracking. Activates when the session identifies unplanned work that should be tracked in the backlog.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# momentum-track
|
|
7
|
+
|
|
8
|
+
When you discover something that should be tracked during a session
|
|
9
|
+
(a bug, a missing feature, tech debt, an enhancement), automatically:
|
|
10
|
+
|
|
11
|
+
1. Read `specs/backlog/backlog.md` to find the next available ID
|
|
12
|
+
2. Determine item type and prefix: `BUG-`, `FEAT-`, `TD-`, or `ENH-`
|
|
13
|
+
3. Add a row to the appropriate table with priority (infer from urgency), status `open`, and target phase or `unscheduled`
|
|
14
|
+
4. Mention the new item to the user: "I found [issue] and added it as [ID] to backlog"
|
|
15
|
+
|
|
16
|
+
This skill codifies Rule 3 (Auto-Track Discoveries) from the project rules.
|
|
17
|
+
|
|
18
|
+
## When NOT to apply
|
|
19
|
+
|
|
20
|
+
- If the user explicitly asks you not to track something
|
|
21
|
+
- If the issue is already tracked (check the backlog first)
|
|
22
|
+
- For purely conversational exploration where no work item is identified
|
|
23
|
+
|
|
24
|
+
## References
|
|
25
|
+
|
|
26
|
+
- `/track` command for manual tracking
|
|
27
|
+
- `specs/backlog/backlog.md` — the backlog file
|
|
28
|
+
- Rule 3 in `AGENTS.md` — auto-track discoveries
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: momentum-validate
|
|
3
|
+
description: Check spec structure health of the momentum project. Activates when the user runs `/validate`, asks for a health check, or when spec changes need verification before phase completion.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# momentum-validate
|
|
7
|
+
|
|
8
|
+
When spec health validation is needed:
|
|
9
|
+
|
|
10
|
+
1. Read `specs/status.md` — verify required fields are present
|
|
11
|
+
2. Read `specs/backlog/backlog.md` — verify all 4 section tables
|
|
12
|
+
3. For each phase directory under `specs/phases/`: verify all required files
|
|
13
|
+
and frontmatter
|
|
14
|
+
4. Check `.momentum/installed.json` — verify schema and agent entries
|
|
15
|
+
5. Verify `AGENTS.md` or `CLAUDE.md` primary instruction file has the
|
|
16
|
+
`## Project Extensions` marker
|
|
17
|
+
6. Report all failures found
|
|
18
|
+
|
|
19
|
+
This skill supports the `/validate` command for deep spec structure checks.
|
|
20
|
+
Use it proactively before `/complete-phase` to catch structural issues early.
|
|
21
|
+
|
|
22
|
+
## When NOT to apply
|
|
23
|
+
|
|
24
|
+
- During active implementation work (validation should not interrupt flow)
|
|
25
|
+
- When the user explicitly asks for no validation
|
|
26
|
+
|
|
27
|
+
## References
|
|
28
|
+
|
|
29
|
+
- `/validate` command — run health checks
|
|
30
|
+
- `specs/status.md` — project status
|
|
31
|
+
- Rule 9 in `AGENTS.md` — doc sync protocol
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// momentum antigravity <subcommand> — Antigravity-specific utilities.
|
|
4
|
+
//
|
|
5
|
+
// Phase 22b G3 (ADR-0006). The only subcommand today is `plugin-pack`:
|
|
6
|
+
// assembles momentum's skills into a native Antigravity PLUGIN bundle
|
|
7
|
+
// (`plugins/<name>/plugin.json` + `skills/`, per the vendor plugin layout —
|
|
8
|
+
// fact-sheet §6). Two targets:
|
|
9
|
+
//
|
|
10
|
+
// momentum antigravity plugin-pack → <cwd>/.agents/plugins/momentum/
|
|
11
|
+
// momentum antigravity plugin-pack --global → ~/.gemini/config/plugins/momentum/
|
|
12
|
+
//
|
|
13
|
+
// The --global form is the explicit OPT-IN way to get momentum's skills in
|
|
14
|
+
// every Antigravity workspace on this machine (global discovery root,
|
|
15
|
+
// priority below workspace files — a project-level install always wins).
|
|
16
|
+
// Hooks are deliberately NOT packed: plugin hooks run with CWD = the
|
|
17
|
+
// plugin's own directory, so momentum's project-relative hook commands only
|
|
18
|
+
// make sense installed per-project by `momentum init/upgrade`.
|
|
19
|
+
//
|
|
20
|
+
// momentum never installs or provisions the `agy` binary itself — see the
|
|
21
|
+
// VAL-002 adjudication (specs/adhoc/feat-VAL-002-antigravity-compatibility/).
|
|
22
|
+
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
const path = require('path');
|
|
25
|
+
const os = require('os');
|
|
26
|
+
|
|
27
|
+
const PLUGIN_NAME = 'momentum';
|
|
28
|
+
|
|
29
|
+
function copyDirRecursive(src, dest, dryRun, log) {
|
|
30
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
const s = path.join(src, entry.name);
|
|
33
|
+
const d = path.join(dest, entry.name);
|
|
34
|
+
if (entry.isDirectory()) {
|
|
35
|
+
if (!dryRun) fs.mkdirSync(d, { recursive: true });
|
|
36
|
+
copyDirRecursive(s, d, dryRun, log);
|
|
37
|
+
} else {
|
|
38
|
+
if (!dryRun) {
|
|
39
|
+
fs.mkdirSync(path.dirname(d), { recursive: true });
|
|
40
|
+
fs.copyFileSync(s, d);
|
|
41
|
+
}
|
|
42
|
+
log.push(d);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function cmdPluginPack(args) {
|
|
48
|
+
const global = args.includes('--global');
|
|
49
|
+
const dryRun = args.includes('--dry-run');
|
|
50
|
+
const positional = args.filter((a) => !a.startsWith('--'));
|
|
51
|
+
|
|
52
|
+
const skillsSrc = path.join(__dirname, '..', 'adapters', 'antigravity', 'skills');
|
|
53
|
+
if (!fs.existsSync(skillsSrc)) {
|
|
54
|
+
throw new Error(`antigravity skills source not found at ${skillsSrc}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const home = process.env.MOMENTUM_HOME_OVERRIDE || os.homedir();
|
|
58
|
+
const base = global
|
|
59
|
+
? path.join(home, '.gemini', 'config', 'plugins', PLUGIN_NAME)
|
|
60
|
+
: path.join(path.resolve(positional[0] || process.cwd()), '.agents', 'plugins', PLUGIN_NAME);
|
|
61
|
+
|
|
62
|
+
console.log(`→ Packing momentum as an Antigravity plugin${dryRun ? ' (dry-run)' : ''}...`);
|
|
63
|
+
console.log(` target: ${base}`);
|
|
64
|
+
|
|
65
|
+
const written = [];
|
|
66
|
+
const manifestPath = path.join(base, 'plugin.json');
|
|
67
|
+
if (!dryRun) {
|
|
68
|
+
fs.mkdirSync(base, { recursive: true });
|
|
69
|
+
fs.writeFileSync(manifestPath, JSON.stringify({ name: PLUGIN_NAME }, null, 2) + '\n');
|
|
70
|
+
}
|
|
71
|
+
written.push(manifestPath);
|
|
72
|
+
copyDirRecursive(skillsSrc, path.join(base, 'skills'), dryRun, written);
|
|
73
|
+
|
|
74
|
+
for (const f of written) {
|
|
75
|
+
console.log(` ${dryRun ? '✋ would write' : '+ wrote'}: ${path.relative(path.dirname(base), f)}`);
|
|
76
|
+
}
|
|
77
|
+
console.log('');
|
|
78
|
+
console.log(` ✓ plugin ${dryRun ? 'planned' : 'packed'} (${written.length} files).`);
|
|
79
|
+
console.log(` Validate: agy plugin validate "${base}"`);
|
|
80
|
+
if (global) {
|
|
81
|
+
console.log(' Global plugins apply to every Antigravity workspace on this machine;');
|
|
82
|
+
console.log(' a per-project momentum install always takes priority.');
|
|
83
|
+
}
|
|
84
|
+
return base;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function usage() {
|
|
88
|
+
console.log('Usage: momentum antigravity <subcommand>');
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log('Subcommands:');
|
|
91
|
+
console.log(' plugin-pack [target] [--global] [--dry-run]');
|
|
92
|
+
console.log(' Assemble momentum skills as a native Antigravity plugin at');
|
|
93
|
+
console.log(' <target>/.agents/plugins/momentum/ (or the global discovery');
|
|
94
|
+
console.log(' root ~/.gemini/config/plugins/momentum/ with --global).');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function runAntigravity(args) {
|
|
98
|
+
const sub = args[0];
|
|
99
|
+
if (!sub || sub === 'help' || sub === '--help') {
|
|
100
|
+
usage();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (sub === 'plugin-pack') {
|
|
104
|
+
cmdPluginPack(args.slice(1));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
console.error(`Unknown antigravity subcommand: ${sub}`);
|
|
108
|
+
usage();
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = { runAntigravity, cmdPluginPack };
|