@goodtek/vibeops 0.2.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/CHANGELOG.md +28 -0
- package/LICENSE +21 -0
- package/README.md +444 -0
- package/dist/agent/loader.js +71 -0
- package/dist/agent/prompt.js +66 -0
- package/dist/bootstrap/installer.js +149 -0
- package/dist/bootstrap/manifest.js +15 -0
- package/dist/bootstrap/substitute.js +35 -0
- package/dist/cli.js +241 -0
- package/dist/commands/agent-list.js +32 -0
- package/dist/commands/agent-prompt.js +59 -0
- package/dist/commands/agent-show.js +26 -0
- package/dist/commands/github-init.js +554 -0
- package/dist/commands/github-status.js +164 -0
- package/dist/commands/init.js +179 -0
- package/dist/commands/notion-init.js +764 -0
- package/dist/commands/notion-sync.js +405 -0
- package/dist/commands/notion-test.js +595 -0
- package/dist/commands/plan.js +114 -0
- package/dist/commands/status.js +17 -0
- package/dist/commands/task-check.js +155 -0
- package/dist/commands/task-done.js +98 -0
- package/dist/commands/task-generate.js +206 -0
- package/dist/commands/task-pull.js +277 -0
- package/dist/commands/task-rollback.js +174 -0
- package/dist/commands/task-start.js +90 -0
- package/dist/lib/brief.js +349 -0
- package/dist/lib/config.js +158 -0
- package/dist/lib/filesystem.js +67 -0
- package/dist/lib/git.js +237 -0
- package/dist/lib/github-cli.js +247 -0
- package/dist/lib/inquirer-helpers.js +111 -0
- package/dist/lib/logger.js +42 -0
- package/dist/lib/notion-client.js +459 -0
- package/dist/lib/notion-discovery.js +671 -0
- package/dist/lib/notion-env.js +140 -0
- package/dist/lib/notion-mappers.js +148 -0
- package/dist/lib/notion-schema.js +272 -0
- package/dist/lib/notion-sync.js +337 -0
- package/dist/lib/notion-target.js +247 -0
- package/dist/lib/package-json.js +133 -0
- package/dist/lib/paths.js +26 -0
- package/dist/lib/project-docs.js +95 -0
- package/dist/lib/prompt-builder.js +125 -0
- package/dist/lib/task-generator.js +183 -0
- package/dist/lib/task-prompt.js +23 -0
- package/dist/lib/task-pull.js +354 -0
- package/dist/lib/task-scaffold.js +128 -0
- package/dist/lib/task-summary.js +276 -0
- package/dist/lib/task.js +364 -0
- package/dist/status/collector.js +103 -0
- package/dist/status/format.js +177 -0
- package/dist/types/brief.js +126 -0
- package/dist/types/config.js +17 -0
- package/dist/types/task.js +1 -0
- package/dist/version.js +8 -0
- package/package.json +61 -0
- package/templates/.cursor/rules/00-project-governance.mdc +28 -0
- package/templates/.cursor/rules/01-agent-orchestration.mdc +48 -0
- package/templates/.cursor/rules/02-task-workflow.mdc +38 -0
- package/templates/.cursor/rules/03-git-safety.mdc +30 -0
- package/templates/.cursor/rules/04-docs-update.mdc +22 -0
- package/templates/.vibeops/agents/architect.md +47 -0
- package/templates/.vibeops/agents/builder.md +38 -0
- package/templates/.vibeops/agents/docs.md +54 -0
- package/templates/.vibeops/agents/orchestrator.md +40 -0
- package/templates/.vibeops/agents/planner.md +60 -0
- package/templates/.vibeops/agents/recovery.md +49 -0
- package/templates/.vibeops/agents/reviewer.md +47 -0
- package/templates/.vibeops/agents/tester.md +43 -0
- package/templates/.vibeops/prompts/create-plan.md +33 -0
- package/templates/.vibeops/prompts/generate-tasks.md +41 -0
- package/templates/.vibeops/prompts/implement-task.md +39 -0
- package/templates/.vibeops/prompts/review-task.md +34 -0
- package/templates/.vibeops/prompts/rollback.md +32 -0
- package/templates/.vibeops/prompts/start-project.md +39 -0
- package/templates/.vibeops/workflows/notion-sync.md +53 -0
- package/templates/.vibeops/workflows/project-start.md +73 -0
- package/templates/.vibeops/workflows/rollback.md +45 -0
- package/templates/.vibeops/workflows/task-lifecycle.md +71 -0
- package/templates/AGENTS.md +98 -0
- package/templates/docs/logs/README.md +38 -0
- package/templates/docs/project/00-overview.md +27 -0
- package/templates/docs/project/01-requirements.md +30 -0
- package/templates/docs/project/02-mvp-scope.md +36 -0
- package/templates/docs/project/03-architecture.md +34 -0
- package/templates/docs/project/04-tech-stack.md +29 -0
- package/templates/docs/project/05-current-state.md +35 -0
- package/templates/docs/project/06-decisions.md +20 -0
- package/templates/docs/project/07-backlog.md +23 -0
- package/templates/docs/project/08-env.md +29 -0
- package/templates/docs/project/09-deployment.md +28 -0
- package/templates/docs/tasks/TASK-000-template.md +72 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to VibeOps are documented here.
|
|
4
|
+
|
|
5
|
+
## 0.2.0 - 2026-05-12
|
|
6
|
+
|
|
7
|
+
Public release polish.
|
|
8
|
+
|
|
9
|
+
- Rename the npm package to `@goodtek/vibeops`. The CLI command is still `vibeops`.
|
|
10
|
+
- Publish as a public scoped package (`publishConfig.access = "public"`).
|
|
11
|
+
- Rewrite the README for public release: replace the internal walkthrough example with `Acme Automator`, remove internal phase labels, add a Support section (`support@goodtek.xyz`, `hello@goodtek.xyz`), and update the install command to `npm install -g @goodtek/vibeops`.
|
|
12
|
+
- Normalize CLI help, command descriptions, and program log/error messages to English so the output is consistent for international users.
|
|
13
|
+
- Replace the leftover internal example reference inside `src/types/config.ts` and the planner agent template with a generic project name.
|
|
14
|
+
|
|
15
|
+
No behavior changes — every command produces the same files and Git/Notion side effects as 0.1.0, only the user-facing text and packaging metadata changed.
|
|
16
|
+
|
|
17
|
+
## 0.1.0 - 2026-05-11
|
|
18
|
+
|
|
19
|
+
Initial release candidate.
|
|
20
|
+
|
|
21
|
+
- Project Bootstrapper: `vibeops init` installs Cursor rules, `AGENTS.md`, agents/prompts/workflows, project docs, and a TASK template into a project; `vibeops status` summarizes installation, tasks, Git, Notion, GitHub, and package state.
|
|
22
|
+
- Interactive Planner: `vibeops plan` runs 20 short questions and produces a normalized ProjectBrief plus a Cursor planning prompt.
|
|
23
|
+
- Task Generator: `vibeops task generate` builds a Cursor prompt for generating TASK files or, with `--scaffold`, writes placeholder TASK markdown directly.
|
|
24
|
+
- Git Task Lifecycle: `task start`, `task prompt`, `task check`, `task done`, and `task rollback` keep one TASK moving through `Planned → In Progress → Review → Done` with dry-run and read-only defaults and explicit rollback confirmation.
|
|
25
|
+
- Notion Dashboard Sync: `notion init`, `notion test`, `notion sync`, and `task pull` provide data-source-first discovery and resolution, schema and status-option validation, metadata-only sync, and local TASK skeleton pull.
|
|
26
|
+
- GitHub Integration: `github status` and `github init` use the `gh` CLI to connect or create a GitHub repository without storing `GITHUB_TOKEN` and without auto-pushing.
|
|
27
|
+
- Init Git Bootstrap: `vibeops init --git --initial-commit` optionally initializes Git and creates the first commit, and `vibeops status` distinguishes unborn / detached / normal HEAD states.
|
|
28
|
+
- Packaging: npm package metadata, MIT license, smoke checks, and publish dry-run workflow.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 VibeOps contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
# VibeOps
|
|
2
|
+
|
|
3
|
+
> Workflow rails for Cursor-based vibe coding projects.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@goodtek/vibeops)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
VibeOps is a local CLI that installs and operates the project structure needed to run Cursor-based vibe coding as reproducible TASKs: `AGENTS.md`, Cursor rules, project docs, TASK files, agents/prompts/workflows, Git lifecycle helpers, and optional Notion dashboard sync.
|
|
9
|
+
|
|
10
|
+
VibeOps does not write product code for you. Cursor is the builder. VibeOps keeps the workflow on rails.
|
|
11
|
+
|
|
12
|
+
## What Is VibeOps?
|
|
13
|
+
|
|
14
|
+
VibeOps is a **local CLI** for turning an idea into a repository that Cursor agents can work on safely and repeatably.
|
|
15
|
+
|
|
16
|
+
It gives a project:
|
|
17
|
+
|
|
18
|
+
- `docs/project/*` for product and architecture context.
|
|
19
|
+
- `docs/tasks/TASK-*.md` as the AI execution source of truth.
|
|
20
|
+
- `.cursor/rules/*` and `AGENTS.md` so Cursor knows how to behave.
|
|
21
|
+
- `.vibeops/agents`, `.vibeops/prompts`, `.vibeops/workflows` for reusable agent instructions.
|
|
22
|
+
- Git task lifecycle commands for start/check/done/rollback.
|
|
23
|
+
- Notion metadata sync for a human dashboard.
|
|
24
|
+
|
|
25
|
+
## Why It Exists
|
|
26
|
+
|
|
27
|
+
Vibe coding is fast, but chat history is a weak source of truth. Without a durable workflow, agents repeat work, drift outside scope, lose decision history, and leave teammates without a dashboard. VibeOps moves the durable context into Git files and uses CLI commands to keep each TASK bounded.
|
|
28
|
+
|
|
29
|
+
## Core Philosophy
|
|
30
|
+
|
|
31
|
+
- **VibeOps = workflow rail**: it structures the work, validates state, and prints prompts.
|
|
32
|
+
- **Cursor = builder**: Cursor reads the docs/TASKs and writes application code.
|
|
33
|
+
- **Git `docs/tasks` = AI execution source of truth**: TASK markdown beats chat memory.
|
|
34
|
+
- **Notion = human dashboard**: Notion shows metadata and progress, not canonical task bodies.
|
|
35
|
+
|
|
36
|
+
| What | Source of truth |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| AI execution input | Git `docs/tasks/*.md` |
|
|
39
|
+
| Project design/status | Git `docs/project/*.md` |
|
|
40
|
+
| Change and rollback evidence | Git commits/branches |
|
|
41
|
+
| Human dashboard | Notion Projects/Tasks DB |
|
|
42
|
+
| Not a source of truth | Cursor chat, Slack, memory |
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
VibeOps requires Node.js 20+.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install -g @goodtek/vibeops
|
|
50
|
+
vibeops --help
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The published package is `@goodtek/vibeops`. The installed CLI command is `vibeops`.
|
|
54
|
+
|
|
55
|
+
For local development from this repository:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pnpm install
|
|
59
|
+
pnpm build
|
|
60
|
+
node dist/cli.js --help
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# 1. Install VibeOps workflow files into the current project.
|
|
67
|
+
# Interactive mode can also initialize Git and create the first commit.
|
|
68
|
+
vibeops init
|
|
69
|
+
|
|
70
|
+
# Non-interactive Git bootstrap:
|
|
71
|
+
vibeops init --git --initial-commit
|
|
72
|
+
|
|
73
|
+
# 2. Answer 20 short planning questions and generate a Cursor planning prompt.
|
|
74
|
+
vibeops plan
|
|
75
|
+
|
|
76
|
+
# 3. Generate a TASK prompt or scaffold TASK markdown.
|
|
77
|
+
vibeops task generate --dry-run
|
|
78
|
+
|
|
79
|
+
# 4. Start one TASK at a time.
|
|
80
|
+
vibeops task start TASK-001
|
|
81
|
+
vibeops task prompt TASK-001 --agent builder
|
|
82
|
+
|
|
83
|
+
# 5. Review and move to human review.
|
|
84
|
+
vibeops task check TASK-001
|
|
85
|
+
vibeops task done TASK-001
|
|
86
|
+
|
|
87
|
+
# 6. Optional Notion dashboard sync.
|
|
88
|
+
vibeops notion init
|
|
89
|
+
vibeops notion test
|
|
90
|
+
vibeops notion sync --dry-run
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Quick Tutorial: Acme Automator
|
|
94
|
+
|
|
95
|
+
Suppose the idea is: “Build **Acme Automator**, a SaaS that schedules and runs browser automation jobs for marketing teams.”
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
mkdir acme-automator
|
|
99
|
+
cd acme-automator
|
|
100
|
+
|
|
101
|
+
vibeops init --name "Acme Automator" --git --initial-commit
|
|
102
|
+
vibeops plan --idea "Acme Automator: schedule and run browser automation jobs for marketing teams"
|
|
103
|
+
vibeops task generate --dry-run
|
|
104
|
+
|
|
105
|
+
vibeops task start TASK-001
|
|
106
|
+
vibeops task prompt TASK-001 --agent builder
|
|
107
|
+
# Paste the prompt into Cursor and let Cursor implement the TASK.
|
|
108
|
+
vibeops task check TASK-001
|
|
109
|
+
vibeops task done TASK-001
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If a Notion dashboard is enabled:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
vibeops notion init
|
|
116
|
+
vibeops notion test
|
|
117
|
+
vibeops notion sync --dry-run
|
|
118
|
+
vibeops notion sync
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Full Command Flow
|
|
122
|
+
|
|
123
|
+
```text
|
|
124
|
+
vibeops
|
|
125
|
+
├─ init [--dry-run] [--force] [--cwd <path>] [--name <projectName>]
|
|
126
|
+
│ [--git|--no-git] [--initial-commit|--no-initial-commit]
|
|
127
|
+
│ [--default-branch <name>] [--commit-message <message>]
|
|
128
|
+
├─ status [--json] [--cwd <path>]
|
|
129
|
+
├─ plan [--idea <text>] [--from <path>] [--output <path>] [--non-interactive] [--cwd <path>]
|
|
130
|
+
├─ agent
|
|
131
|
+
│ ├─ list [--json] [--cwd <path>]
|
|
132
|
+
│ ├─ show <name> [--raw] [--cwd <path>]
|
|
133
|
+
│ └─ prompt <name> <taskId> [--context <path...>] [--cwd <path>]
|
|
134
|
+
├─ task
|
|
135
|
+
│ ├─ generate [--from <path>] [--output <path>] [--count <n>] [--phase <name>] [--scaffold] [--dry-run] [--cwd <path>]
|
|
136
|
+
│ ├─ start <taskId> [--dry-run] [--allow-dirty] [--agent <name>] [--cwd <path>]
|
|
137
|
+
│ ├─ prompt <taskId> --agent <name> [--context <path...>] [--cwd <path>]
|
|
138
|
+
│ ├─ check <taskId> [--strict] [--agent <name>] [--cwd <path>]
|
|
139
|
+
│ ├─ done <taskId> [--dry-run] [--finalize] [--cwd <path>]
|
|
140
|
+
│ ├─ rollback <taskId> [--confirm | --confirm-destructive] [--strategy <name>] [--keep-branch] [--dry-run] [--cwd <path>]
|
|
141
|
+
│ └─ pull [--dry-run] [--json] [--status <list>] [--limit <n>] [--cwd <path>] [--verbose]
|
|
142
|
+
├─ notion
|
|
143
|
+
│ ├─ init [--dry-run] [--enable] [--projects-db <id>] [--tasks-db <id>] [--non-interactive] [--cwd <path>]
|
|
144
|
+
│ ├─ test [--json] [--debug-shape] [--cwd <path>]
|
|
145
|
+
│ └─ sync [--dry-run] [--json] [--only-tasks] [--only-project] [--cwd <path>]
|
|
146
|
+
└─ github
|
|
147
|
+
├─ status [--json] [--cwd <path>]
|
|
148
|
+
└─ init [--dry-run] [--yes] [--owner <user>] [--repo <name>] [--public|--private]
|
|
149
|
+
[--remote <name>] [--connect <owner/repo or url>] [--no-package-update] [--cwd <path>]
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Run any command with `--help` for the option details.
|
|
153
|
+
|
|
154
|
+
## Features
|
|
155
|
+
|
|
156
|
+
### Project Bootstrapper
|
|
157
|
+
|
|
158
|
+
`vibeops init` installs a project operating system: `AGENTS.md`, `.cursor/rules`, `docs/project`, `docs/tasks`, `.vibeops/agents`, `.vibeops/prompts`, `.vibeops/workflows`, `.vibeops.json`, and `.vibeops.env.example`. It is idempotent by default and only overwrites when `--force` is used.
|
|
159
|
+
|
|
160
|
+
### Interactive Planner
|
|
161
|
+
|
|
162
|
+
`vibeops plan` asks 20 short questions and produces a normalized brief plus a Cursor planning prompt. A non-interactive mode is available for safe placeholder output.
|
|
163
|
+
|
|
164
|
+
### Task Generator
|
|
165
|
+
|
|
166
|
+
`vibeops task generate` builds a Cursor prompt for generating TASK files. With `--scaffold`, it creates placeholder TASK markdown directly. It does not call an LLM.
|
|
167
|
+
|
|
168
|
+
### Git Task Lifecycle
|
|
169
|
+
|
|
170
|
+
`task start`, `task prompt`, `task check`, and `task done` keep one TASK moving through `Planned → In Progress → Review → Done`. `task done` defaults to `Review`; use `--finalize` only after human review.
|
|
171
|
+
|
|
172
|
+
### Rollback Safety
|
|
173
|
+
|
|
174
|
+
`task rollback` prints recovery options by default. Destructive Git actions require explicit confirmation (`--confirm` or `--confirm-destructive`) and should be reviewed before use.
|
|
175
|
+
|
|
176
|
+
### Notion Dashboard Sync
|
|
177
|
+
|
|
178
|
+
`notion init/test/sync` and `task pull` keep Notion as a metadata dashboard. VibeOps syncs project/task metadata only and never updates Notion page bodies.
|
|
179
|
+
|
|
180
|
+
## Runner Modes
|
|
181
|
+
|
|
182
|
+
- **Prompt mode (default)**: VibeOps prints Cursor-ready prompts. Cursor executes the code changes.
|
|
183
|
+
- VibeOps does not call LLM APIs and does not invoke Cursor CLI directly today; it works as a workflow rail around the human + Cursor loop.
|
|
184
|
+
|
|
185
|
+
## Notion Setup
|
|
186
|
+
|
|
187
|
+
Notion is optional. If enabled:
|
|
188
|
+
|
|
189
|
+
- `NOTION_TOKEN` is the **only** environment variable VibeOps reads. It lives in `.vibeops.env` (gitignored) or in `process.env`.
|
|
190
|
+
- Target IDs live in `.vibeops.json`, not in `.vibeops.env`.
|
|
191
|
+
- `projectsTargetId` / `tasksTargetId` are preferred resolved **data_source** IDs.
|
|
192
|
+
- `projectsDatabaseId` / `tasksDatabaseId` remain legacy/container fallbacks.
|
|
193
|
+
- `notion init` uses data_source-first discovery. If no data sources are found, it can search accessible pages, scan 1-depth inline database blocks, then resolve child databases to data source IDs.
|
|
194
|
+
- Legacy `NOTION_API_KEY` / `NOTION_PROJECT_DB` / `NOTION_TASK_DB` environment variables are no longer used. The `.vibeops.env.example` that `vibeops init` writes contains only `NOTION_TOKEN=`.
|
|
195
|
+
|
|
196
|
+
Required Projects DB properties:
|
|
197
|
+
|
|
198
|
+
| Property | Type |
|
|
199
|
+
| --- | --- |
|
|
200
|
+
| `Name` | `title` |
|
|
201
|
+
| `Project ID` | `rich_text` |
|
|
202
|
+
| `Status` | `status` |
|
|
203
|
+
| `Local Path` | `rich_text` |
|
|
204
|
+
| `Git Repo` | `rich_text` or `url` |
|
|
205
|
+
| `Current Phase` | `select` |
|
|
206
|
+
| `Docs Path` | `rich_text` |
|
|
207
|
+
| `Summary` | `rich_text` |
|
|
208
|
+
|
|
209
|
+
Required Tasks DB properties:
|
|
210
|
+
|
|
211
|
+
| Property | Type |
|
|
212
|
+
| --- | --- |
|
|
213
|
+
| `Name` | `title` |
|
|
214
|
+
| `Task ID` | `rich_text` |
|
|
215
|
+
| `Project ID` | `rich_text` |
|
|
216
|
+
| `Status` | `status` |
|
|
217
|
+
| `Priority` | `select` |
|
|
218
|
+
| `MVP Phase` | `select` |
|
|
219
|
+
| `Git Branch` | `rich_text` |
|
|
220
|
+
| `Docs Path` | `rich_text` |
|
|
221
|
+
| `Summary` | `rich_text` |
|
|
222
|
+
| `Result Summary` | `rich_text` |
|
|
223
|
+
|
|
224
|
+
> `MVP Phase` here is a Notion property name kept for compatibility with existing dashboards. It is a free-form label column and is not an internal release-phase tag.
|
|
225
|
+
|
|
226
|
+
Required Status options:
|
|
227
|
+
|
|
228
|
+
- Projects DB: `Building`, `Planning`, `Paused`, `Done`, `Archived`
|
|
229
|
+
- Tasks DB: `Planned`, `In Progress`, `Review`, `Done`, `Blocked`
|
|
230
|
+
|
|
231
|
+
VibeOps validates these options in `notion test` and `notion sync --dry-run`, but it never creates or mutates Notion schema.
|
|
232
|
+
|
|
233
|
+
## GitHub Setup
|
|
234
|
+
|
|
235
|
+
GitHub integration runs on top of the GitHub CLI (`gh`). VibeOps never stores `GITHUB_TOKEN` — authentication is owned by `gh auth login`.
|
|
236
|
+
|
|
237
|
+
1. Install `gh`:
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
brew install gh
|
|
241
|
+
# or follow https://cli.github.com/
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
2. Authenticate:
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
gh auth login
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
3. Probe state:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
vibeops github status
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
4. Connect or create a repo interactively:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
# plan only — no gh / git / file mutation
|
|
260
|
+
vibeops github init --dry-run
|
|
261
|
+
|
|
262
|
+
# plan a new public repo
|
|
263
|
+
vibeops github init --dry-run --owner <user> --repo <name> --public
|
|
264
|
+
|
|
265
|
+
# connect to an existing repo by slug or URL
|
|
266
|
+
vibeops github init --dry-run --connect <owner>/<repo>
|
|
267
|
+
vibeops github init --dry-run --connect https://github.com/<owner>/<repo>.git
|
|
268
|
+
vibeops github init --dry-run --connect git@github.com:<owner>/<repo>.git
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
`vibeops github init` applies four things in sequence:
|
|
272
|
+
|
|
273
|
+
- (optional) `gh repo create <owner>/<repo> --public|--private --source=. --remote=origin` for new repos.
|
|
274
|
+
- `git remote add origin <url>` (or `git remote set-url`) for the `--connect` path. Existing remotes are never silently overwritten — VibeOps asks first and defaults to No.
|
|
275
|
+
- Updates `package.json` `repository.url`, `homepage`, `bugs.url` (skip with `--no-package-update`).
|
|
276
|
+
- Writes the `github` section of `.vibeops.json`: `enabled`, `mode = "gh-cli"`, `owner`, `repo`, `remote`, `visibility`, `url`.
|
|
277
|
+
|
|
278
|
+
VibeOps never runs `git push`. Push your branch manually with `git push -u <remote> <branch>`.
|
|
279
|
+
|
|
280
|
+
## Init Git Bootstrap
|
|
281
|
+
|
|
282
|
+
`vibeops init` can optionally do the first local Git setup while installing the workflow files. In interactive mode it asks:
|
|
283
|
+
|
|
284
|
+
- Initialize Git repository?
|
|
285
|
+
- Use `main` as default branch?
|
|
286
|
+
- Create initial commit?
|
|
287
|
+
- Initial commit message
|
|
288
|
+
|
|
289
|
+
For non-interactive setup:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
vibeops init --git --initial-commit
|
|
293
|
+
vibeops init --git --no-initial-commit
|
|
294
|
+
vibeops init --git --default-branch main --commit-message "chore: initialize vibeops project"
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Safety rules:
|
|
298
|
+
|
|
299
|
+
- Existing Git repositories skip `git init`.
|
|
300
|
+
- Existing repositories with commits skip the initial commit path.
|
|
301
|
+
- `--dry-run` runs no Git commands.
|
|
302
|
+
- VibeOps never pushes and never changes remotes during `init`.
|
|
303
|
+
- Before the initial commit, VibeOps prints how many files will be included.
|
|
304
|
+
|
|
305
|
+
Before the first commit, `vibeops status` distinguishes an unborn branch from a detached HEAD:
|
|
306
|
+
|
|
307
|
+
```text
|
|
308
|
+
Git
|
|
309
|
+
branch main (unborn, no commits yet)
|
|
310
|
+
status dirty
|
|
311
|
+
hint create the first commit or run `vibeops init --git --initial-commit`
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Status Output
|
|
315
|
+
|
|
316
|
+
`vibeops status` summarizes the local project surface only. It never calls the Notion API and never spawns `gh`. The Notion section reads from `.vibeops.env` / `process.env` (for `NOTION_TOKEN` presence) and `.vibeops.json` (for target IDs). The GitHub section reads from `.vibeops.json`. The Package section reads from `package.json`.
|
|
317
|
+
|
|
318
|
+
Example output for a fully-configured project:
|
|
319
|
+
|
|
320
|
+
```text
|
|
321
|
+
Git
|
|
322
|
+
branch main
|
|
323
|
+
status clean
|
|
324
|
+
|
|
325
|
+
Notion
|
|
326
|
+
enabled yes
|
|
327
|
+
token configured (.vibeops.env)
|
|
328
|
+
projects target configured
|
|
329
|
+
tasks target configured
|
|
330
|
+
hint run `vibeops notion test`
|
|
331
|
+
|
|
332
|
+
GitHub
|
|
333
|
+
enabled yes
|
|
334
|
+
mode gh-cli
|
|
335
|
+
owner/repo goodtekxyz/vibeops
|
|
336
|
+
remote origin
|
|
337
|
+
url https://github.com/goodtekxyz/vibeops
|
|
338
|
+
|
|
339
|
+
Package
|
|
340
|
+
name @goodtek/vibeops
|
|
341
|
+
version 0.2.0
|
|
342
|
+
bin vibeops
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
For a fresh project that has not been wired to Notion or GitHub yet:
|
|
346
|
+
|
|
347
|
+
```text
|
|
348
|
+
Notion
|
|
349
|
+
enabled no
|
|
350
|
+
token missing
|
|
351
|
+
projects target missing
|
|
352
|
+
tasks target missing
|
|
353
|
+
hint run `vibeops notion init`
|
|
354
|
+
|
|
355
|
+
GitHub
|
|
356
|
+
enabled no
|
|
357
|
+
hint run `vibeops github init`
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
If the project has no `package.json`, the Package section degrades gracefully:
|
|
361
|
+
|
|
362
|
+
```text
|
|
363
|
+
Package
|
|
364
|
+
package.json missing
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
`vibeops status --json` exposes the same surface programmatically, including `notion.tokenSource`, `notion.hasProjectsTarget`, `notion.hasTasksTarget`, the entire `github` object, and the entire `package` object. Legacy environment variables (`NOTION_API_KEY`, `NOTION_PROJECT_DB`, `NOTION_TASK_DB`) are no longer surfaced — VibeOps only uses `NOTION_TOKEN`.
|
|
368
|
+
|
|
369
|
+
## Git Rollback Safety
|
|
370
|
+
|
|
371
|
+
- `task start` records base branch, base commit, and task branch in task state.
|
|
372
|
+
- `task check` is read-only and reports working tree + committed changes.
|
|
373
|
+
- `task done` validates TASK Result/Test Result and moves to Review by default.
|
|
374
|
+
- `task rollback` is advisory unless explicit confirmation flags are supplied.
|
|
375
|
+
|
|
376
|
+
## Agent Workflow
|
|
377
|
+
|
|
378
|
+
Agents are Markdown files under `.vibeops/agents`. Use:
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
vibeops agent list
|
|
382
|
+
vibeops agent show builder
|
|
383
|
+
vibeops task prompt TASK-001 --agent builder
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
The default project template includes agents such as `orchestrator`, `planner`, `architect`, `builder`, `reviewer`, `tester`, `docs`, and `recovery`.
|
|
387
|
+
|
|
388
|
+
## Packaging / npm Usage
|
|
389
|
+
|
|
390
|
+
This package exposes the `vibeops` binary:
|
|
391
|
+
|
|
392
|
+
```json
|
|
393
|
+
{
|
|
394
|
+
"bin": {
|
|
395
|
+
"vibeops": "dist/cli.js"
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Package contents are limited by `package.json#files` to built output, templates, and top-level docs/license files. `dist/` is generated by `pnpm build` / `prepack` and is not committed.
|
|
401
|
+
|
|
402
|
+
Useful maintainer commands:
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
pnpm typecheck
|
|
406
|
+
pnpm build
|
|
407
|
+
pnpm smoke
|
|
408
|
+
pnpm pack
|
|
409
|
+
pnpm publish --dry-run --access public --no-git-checks
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Actual `npm publish` is a manual release action and is not performed by this repository workflow.
|
|
413
|
+
|
|
414
|
+
## Security Notes
|
|
415
|
+
|
|
416
|
+
- `.vibeops.env` is gitignored and must contain secrets such as `NOTION_TOKEN`.
|
|
417
|
+
- VibeOps masks tokens in CLI output.
|
|
418
|
+
- Notion test/debug output is token-safe.
|
|
419
|
+
- `notion sync --dry-run` performs no mutation.
|
|
420
|
+
- `task pull --dry-run` performs no file or Notion mutation.
|
|
421
|
+
- Notion page bodies are never synced.
|
|
422
|
+
- Git destructive rollback paths require explicit confirmation.
|
|
423
|
+
- `github init` uses `gh` CLI auth — VibeOps never stores `GITHUB_TOKEN`.
|
|
424
|
+
- `github init --dry-run` runs zero `gh` / `git remote` / file mutations and produces only a plan.
|
|
425
|
+
|
|
426
|
+
## Support
|
|
427
|
+
|
|
428
|
+
- Bugs, setup issues, and usage questions: [support@goodtek.xyz](mailto:support@goodtek.xyz)
|
|
429
|
+
- Collaboration and feedback: [hello@goodtek.xyz](mailto:hello@goodtek.xyz)
|
|
430
|
+
- Issue tracker: [github.com/goodtekxyz/vibeops/issues](https://github.com/goodtekxyz/vibeops/issues)
|
|
431
|
+
|
|
432
|
+
## Documentation
|
|
433
|
+
|
|
434
|
+
- [`AGENTS.md`](AGENTS.md) — agent operating guide.
|
|
435
|
+
- [`docs/project/00-overview.md`](docs/project/00-overview.md) — vision and scope.
|
|
436
|
+
- [`docs/project/01-architecture.md`](docs/project/01-architecture.md) — CLI / config / data flow.
|
|
437
|
+
- [`docs/project/03-current-state.md`](docs/project/03-current-state.md) — current implementation state.
|
|
438
|
+
- [`docs/project/04-decisions.md`](docs/project/04-decisions.md) — decisions already made.
|
|
439
|
+
- [`docs/project/05-backlog.md`](docs/project/05-backlog.md) — task order.
|
|
440
|
+
- [`docs/tasks/`](docs/tasks/) — TASK files used by Cursor.
|
|
441
|
+
|
|
442
|
+
## License
|
|
443
|
+
|
|
444
|
+
MIT © VibeOps contributors
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { basename, extname, join } from "node:path";
|
|
3
|
+
import matter from "gray-matter";
|
|
4
|
+
import { isDirectory, readText } from "../lib/filesystem.js";
|
|
5
|
+
function metaFromFile(filePath, data, body) {
|
|
6
|
+
const fallbackName = basename(filePath, extname(filePath));
|
|
7
|
+
const name = typeof data["name"] === "string" ? data["name"] : fallbackName;
|
|
8
|
+
const role = typeof data["role"] === "string" ? data["role"] : extractFirstHeading(body);
|
|
9
|
+
const description = typeof data["description"] === "string" ? data["description"] : undefined;
|
|
10
|
+
return { name, role, description, filePath };
|
|
11
|
+
}
|
|
12
|
+
function extractFirstHeading(body) {
|
|
13
|
+
for (const line of body.split("\n")) {
|
|
14
|
+
const m = /^#\s+(.*)$/.exec(line.trim());
|
|
15
|
+
if (m)
|
|
16
|
+
return m[1].trim();
|
|
17
|
+
}
|
|
18
|
+
return "(no role)";
|
|
19
|
+
}
|
|
20
|
+
function frontmatterSlice(raw) {
|
|
21
|
+
if (!raw.startsWith("---"))
|
|
22
|
+
return "";
|
|
23
|
+
const end = raw.indexOf("\n---", 3);
|
|
24
|
+
if (end < 0)
|
|
25
|
+
return "";
|
|
26
|
+
return raw.slice(0, end + 4);
|
|
27
|
+
}
|
|
28
|
+
export async function loadAgent(filePath) {
|
|
29
|
+
const raw = await readText(filePath);
|
|
30
|
+
const parsed = matter(raw);
|
|
31
|
+
const meta = metaFromFile(filePath, parsed.data, parsed.content);
|
|
32
|
+
return {
|
|
33
|
+
meta,
|
|
34
|
+
body: parsed.content.trimStart(),
|
|
35
|
+
rawFrontmatter: frontmatterSlice(raw),
|
|
36
|
+
raw,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export async function listAgents(agentsDir) {
|
|
40
|
+
if (!(await isDirectory(agentsDir)))
|
|
41
|
+
return [];
|
|
42
|
+
const entries = await readdir(agentsDir, { withFileTypes: true });
|
|
43
|
+
const files = entries
|
|
44
|
+
.filter((e) => e.isFile() && e.name.endsWith(".md"))
|
|
45
|
+
.map((e) => join(agentsDir, e.name))
|
|
46
|
+
.sort();
|
|
47
|
+
const records = [];
|
|
48
|
+
for (const f of files) {
|
|
49
|
+
try {
|
|
50
|
+
records.push(await loadAgent(f));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// skip malformed agent files
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return records;
|
|
57
|
+
}
|
|
58
|
+
export async function findAgent(agentsDir, name) {
|
|
59
|
+
const all = await listAgents(agentsDir);
|
|
60
|
+
const target = name.toLowerCase();
|
|
61
|
+
for (const a of all) {
|
|
62
|
+
if (a.meta.name.toLowerCase() === target)
|
|
63
|
+
return a;
|
|
64
|
+
}
|
|
65
|
+
for (const a of all) {
|
|
66
|
+
const filenameKey = basename(a.meta.filePath, extname(a.meta.filePath)).toLowerCase();
|
|
67
|
+
if (filenameKey === target)
|
|
68
|
+
return a;
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { relative } from "node:path";
|
|
2
|
+
import { readText } from "../lib/filesystem.js";
|
|
3
|
+
function relOrAbs(root, p) {
|
|
4
|
+
const r = relative(root, p);
|
|
5
|
+
return r === "" ? "." : r.startsWith("..") ? p : r;
|
|
6
|
+
}
|
|
7
|
+
function header(inputs) {
|
|
8
|
+
const lines = [];
|
|
9
|
+
lines.push(`# Cursor prompt — agent: ${inputs.agent.meta.name}`);
|
|
10
|
+
lines.push("");
|
|
11
|
+
if (inputs.config) {
|
|
12
|
+
lines.push(`Project: \`${inputs.config.name}\``);
|
|
13
|
+
lines.push(`VibeOps: \`${inputs.config.vibeopsVersion}\``);
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
lines.push("Project: (no .vibeops.json found — running outside a VibeOps project)");
|
|
17
|
+
}
|
|
18
|
+
if (inputs.task) {
|
|
19
|
+
lines.push(`TASK: \`${inputs.task.meta.id}\``);
|
|
20
|
+
lines.push(`TASK file: \`${relOrAbs(inputs.projectRoot, inputs.task.meta.filePath)}\``);
|
|
21
|
+
}
|
|
22
|
+
lines.push("");
|
|
23
|
+
return lines.join("\n");
|
|
24
|
+
}
|
|
25
|
+
function agentSection(agent) {
|
|
26
|
+
return `## Agent definition (${agent.meta.name})\n\n${agent.body.trim()}\n`;
|
|
27
|
+
}
|
|
28
|
+
function taskSection(task) {
|
|
29
|
+
return `## TASK file content\n\n${task.body.trim()}\n`;
|
|
30
|
+
}
|
|
31
|
+
async function contextSection(paths, projectRoot) {
|
|
32
|
+
if (paths.length === 0)
|
|
33
|
+
return "";
|
|
34
|
+
const parts = ["## Extra context\n"];
|
|
35
|
+
for (const p of paths) {
|
|
36
|
+
try {
|
|
37
|
+
const text = await readText(p);
|
|
38
|
+
parts.push(`### ${relOrAbs(projectRoot, p)}\n\n\`\`\`\n${text}\n\`\`\`\n`);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
parts.push(`### ${relOrAbs(projectRoot, p)}\n\n_(could not read file)_\n`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return parts.join("\n");
|
|
45
|
+
}
|
|
46
|
+
const FOOTER = `---
|
|
47
|
+
|
|
48
|
+
Apply the **Role / Inputs / Output Format / Rules / Forbidden** sections of the agent definition above as-is.
|
|
49
|
+
Your output must be a single markdown blob that pastes cleanly into the Cursor chat.
|
|
50
|
+
|
|
51
|
+
When done, follow the "Completion report" format in \`AGENTS.md\`:
|
|
52
|
+
TASK ID · summary · changed files · verification · doc updates (05-current-state / TASK / docs/logs).
|
|
53
|
+
`;
|
|
54
|
+
export async function buildPrompt(inputs) {
|
|
55
|
+
const parts = [
|
|
56
|
+
header(inputs),
|
|
57
|
+
agentSection(inputs.agent),
|
|
58
|
+
];
|
|
59
|
+
if (inputs.task)
|
|
60
|
+
parts.push(taskSection(inputs.task));
|
|
61
|
+
const extra = await contextSection(inputs.contextPaths ?? [], inputs.projectRoot);
|
|
62
|
+
if (extra.length > 0)
|
|
63
|
+
parts.push(extra);
|
|
64
|
+
parts.push(FOOTER);
|
|
65
|
+
return parts.join("\n");
|
|
66
|
+
}
|