briefops 1.0.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 +36 -0
- package/CODE_OF_CONDUCT.md +13 -0
- package/CONTRIBUTING.md +53 -0
- package/LICENSE +21 -0
- package/README.md +801 -0
- package/SECURITY.md +59 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +54 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/approve.d.ts +2 -0
- package/dist/commands/approve.js +38 -0
- package/dist/commands/approve.js.map +1 -0
- package/dist/commands/brief.d.ts +2 -0
- package/dist/commands/brief.js +81 -0
- package/dist/commands/brief.js.map +1 -0
- package/dist/commands/codex.d.ts +2 -0
- package/dist/commands/codex.js +163 -0
- package/dist/commands/codex.js.map +1 -0
- package/dist/commands/compare.d.ts +2 -0
- package/dist/commands/compare.js +48 -0
- package/dist/commands/compare.js.map +1 -0
- package/dist/commands/continue.d.ts +2 -0
- package/dist/commands/continue.js +66 -0
- package/dist/commands/continue.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +90 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/eval.d.ts +2 -0
- package/dist/commands/eval.js +89 -0
- package/dist/commands/eval.js.map +1 -0
- package/dist/commands/export.d.ts +2 -0
- package/dist/commands/export.js +105 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/finish.d.ts +2 -0
- package/dist/commands/finish.js +71 -0
- package/dist/commands/finish.js.map +1 -0
- package/dist/commands/handoff.d.ts +2 -0
- package/dist/commands/handoff.js +77 -0
- package/dist/commands/handoff.js.map +1 -0
- package/dist/commands/inbox.d.ts +2 -0
- package/dist/commands/inbox.js +36 -0
- package/dist/commands/inbox.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +13 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/inspect.d.ts +2 -0
- package/dist/commands/inspect.js +226 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/log.d.ts +2 -0
- package/dist/commands/log.js +96 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/memory.d.ts +2 -0
- package/dist/commands/memory.js +236 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/pack.d.ts +2 -0
- package/dist/commands/pack.js +42 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/commands/prime.d.ts +4 -0
- package/dist/commands/prime.js +44 -0
- package/dist/commands/prime.js.map +1 -0
- package/dist/commands/project.d.ts +2 -0
- package/dist/commands/project.js +50 -0
- package/dist/commands/project.js.map +1 -0
- package/dist/commands/shared.d.ts +3 -0
- package/dist/commands/shared.js +24 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/commands/skill.d.ts +2 -0
- package/dist/commands/skill.js +146 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/worker.d.ts +2 -0
- package/dist/commands/worker.js +128 -0
- package/dist/commands/worker.js.map +1 -0
- package/dist/core/adapter.d.ts +22 -0
- package/dist/core/adapter.js +167 -0
- package/dist/core/adapter.js.map +1 -0
- package/dist/core/approval.d.ts +26 -0
- package/dist/core/approval.js +86 -0
- package/dist/core/approval.js.map +1 -0
- package/dist/core/brief.d.ts +47 -0
- package/dist/core/brief.js +411 -0
- package/dist/core/brief.js.map +1 -0
- package/dist/core/codex.d.ts +53 -0
- package/dist/core/codex.js +286 -0
- package/dist/core/codex.js.map +1 -0
- package/dist/core/codexPlugin.d.ts +51 -0
- package/dist/core/codexPlugin.js +228 -0
- package/dist/core/codexPlugin.js.map +1 -0
- package/dist/core/compatibility.d.ts +2 -0
- package/dist/core/compatibility.js +16 -0
- package/dist/core/compatibility.js.map +1 -0
- package/dist/core/config.d.ts +19 -0
- package/dist/core/config.js +77 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/contextBudget.d.ts +12 -0
- package/dist/core/contextBudget.js +22 -0
- package/dist/core/contextBudget.js.map +1 -0
- package/dist/core/contextCompare.d.ts +27 -0
- package/dist/core/contextCompare.js +97 -0
- package/dist/core/contextCompare.js.map +1 -0
- package/dist/core/continuity.d.ts +25 -0
- package/dist/core/continuity.js +73 -0
- package/dist/core/continuity.js.map +1 -0
- package/dist/core/errors.d.ts +4 -0
- package/dist/core/errors.js +12 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/eval.d.ts +38 -0
- package/dist/core/eval.js +180 -0
- package/dist/core/eval.js.map +1 -0
- package/dist/core/exportPolicy.d.ts +7 -0
- package/dist/core/exportPolicy.js +17 -0
- package/dist/core/exportPolicy.js.map +1 -0
- package/dist/core/exportTargets.d.ts +25 -0
- package/dist/core/exportTargets.js +292 -0
- package/dist/core/exportTargets.js.map +1 -0
- package/dist/core/handoff.d.ts +48 -0
- package/dist/core/handoff.js +611 -0
- package/dist/core/handoff.js.map +1 -0
- package/dist/core/inbox.d.ts +15 -0
- package/dist/core/inbox.js +56 -0
- package/dist/core/inbox.js.map +1 -0
- package/dist/core/lock.d.ts +11 -0
- package/dist/core/lock.js +99 -0
- package/dist/core/lock.js.map +1 -0
- package/dist/core/log.d.ts +38 -0
- package/dist/core/log.js +93 -0
- package/dist/core/log.js.map +1 -0
- package/dist/core/memory.d.ts +86 -0
- package/dist/core/memory.js +353 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/memoryHygiene.d.ts +25 -0
- package/dist/core/memoryHygiene.js +95 -0
- package/dist/core/memoryHygiene.js.map +1 -0
- package/dist/core/memoryProposal.d.ts +40 -0
- package/dist/core/memoryProposal.js +279 -0
- package/dist/core/memoryProposal.js.map +1 -0
- package/dist/core/output.d.ts +7 -0
- package/dist/core/output.js +18 -0
- package/dist/core/output.js.map +1 -0
- package/dist/core/patch.d.ts +37 -0
- package/dist/core/patch.js +220 -0
- package/dist/core/patch.js.map +1 -0
- package/dist/core/paths.d.ts +33 -0
- package/dist/core/paths.js +84 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/prime.d.ts +17 -0
- package/dist/core/prime.js +298 -0
- package/dist/core/prime.js.map +1 -0
- package/dist/core/privacyDoctor.d.ts +14 -0
- package/dist/core/privacyDoctor.js +59 -0
- package/dist/core/privacyDoctor.js.map +1 -0
- package/dist/core/project.d.ts +16 -0
- package/dist/core/project.js +73 -0
- package/dist/core/project.js.map +1 -0
- package/dist/core/securityDoctor.d.ts +14 -0
- package/dist/core/securityDoctor.js +96 -0
- package/dist/core/securityDoctor.js.map +1 -0
- package/dist/core/skill.d.ts +16 -0
- package/dist/core/skill.js +81 -0
- package/dist/core/skill.js.map +1 -0
- package/dist/core/storage.d.ts +20 -0
- package/dist/core/storage.js +112 -0
- package/dist/core/storage.js.map +1 -0
- package/dist/core/tokens.d.ts +5 -0
- package/dist/core/tokens.js +24 -0
- package/dist/core/tokens.js.map +1 -0
- package/dist/core/worker.d.ts +51 -0
- package/dist/core/worker.js +312 -0
- package/dist/core/worker.js.map +1 -0
- package/dist/core/workflow.d.ts +61 -0
- package/dist/core/workflow.js +308 -0
- package/dist/core/workflow.js.map +1 -0
- package/dist/core/workspace.d.ts +7 -0
- package/dist/core/workspace.js +214 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/brief.d.ts +12 -0
- package/dist/schemas/brief.js +2 -0
- package/dist/schemas/brief.js.map +1 -0
- package/dist/schemas/eval.d.ts +96 -0
- package/dist/schemas/eval.js +30 -0
- package/dist/schemas/eval.js.map +1 -0
- package/dist/schemas/handoff.d.ts +33 -0
- package/dist/schemas/handoff.js +13 -0
- package/dist/schemas/handoff.js.map +1 -0
- package/dist/schemas/log.d.ts +51 -0
- package/dist/schemas/log.js +19 -0
- package/dist/schemas/log.js.map +1 -0
- package/dist/schemas/memory.d.ts +112 -0
- package/dist/schemas/memory.js +21 -0
- package/dist/schemas/memory.js.map +1 -0
- package/dist/schemas/memoryProposal.d.ts +181 -0
- package/dist/schemas/memoryProposal.js +46 -0
- package/dist/schemas/memoryProposal.js.map +1 -0
- package/dist/schemas/patch.d.ts +38 -0
- package/dist/schemas/patch.js +15 -0
- package/dist/schemas/patch.js.map +1 -0
- package/dist/schemas/project.d.ts +23 -0
- package/dist/schemas/project.js +8 -0
- package/dist/schemas/project.js.map +1 -0
- package/dist/schemas/skill.d.ts +26 -0
- package/dist/schemas/skill.js +9 -0
- package/dist/schemas/skill.js.map +1 -0
- package/dist/schemas/worker.d.ts +29 -0
- package/dist/schemas/worker.js +12 -0
- package/dist/schemas/worker.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/docs/codex-resume.md +13 -0
- package/docs/compatibility.md +49 -0
- package/docs/concept.md +13 -0
- package/docs/evals.md +18 -0
- package/docs/file-format.md +67 -0
- package/docs/handoff-briefs.md +9 -0
- package/docs/integrations/harnesses.md +74 -0
- package/docs/memory-lifecycle.md +23 -0
- package/docs/persistent-worker.md +15 -0
- package/docs/privacy-model.md +40 -0
- package/docs/quickstart.md +74 -0
- package/docs/release-checklist.md +68 -0
- package/docs/roadmap.md +33 -0
- package/docs/superpowers/plans/2026-06-08-briefops-oss-readiness.md +1272 -0
- package/docs/superpowers/plans/2026-06-08-codex-first-context-optimization.md +1176 -0
- package/docs/token-budget.md +63 -0
- package/examples/atlas-q/README.md +15 -0
- package/examples/codex-first-context/README.md +48 -0
- package/examples/codex-first-context/after-briefops-prime.md +40 -0
- package/examples/codex-first-context/before-manual-history-dump.md +18 -0
- package/examples/persistent-worker-demo/README.md +15 -0
- package/examples/persistent-worker-demo/after-codex-resume.md +17 -0
- package/examples/persistent-worker-demo/before-context-dump.md +5 -0
- package/examples/persistent-worker-demo/briefops-workspace/codex/prompts/resume_demo.md +29 -0
- package/examples/persistent-worker-demo/briefops-workspace/handoffs/handoff_demo.md +50 -0
- package/examples/persistent-worker-demo/briefops-workspace/logs/log_20260604_001.yaml +14 -0
- package/examples/persistent-worker-demo/briefops-workspace/logs/log_20260604_002.yaml +12 -0
- package/examples/persistent-worker-demo/briefops-workspace/memory/decisions.yaml +12 -0
- package/examples/persistent-worker-demo/briefops-workspace/memory/deprecated.yaml +1 -0
- package/examples/persistent-worker-demo/briefops-workspace/memory/facts.yaml +12 -0
- package/examples/persistent-worker-demo/briefops-workspace/memory/incidents.yaml +12 -0
- package/examples/persistent-worker-demo/briefops-workspace/memory/lessons.yaml +12 -0
- package/examples/persistent-worker-demo/briefops-workspace/memory-proposals/memprop_demo_001.memory-proposal.yaml +23 -0
- package/examples/persistent-worker-demo/briefops-workspace/projects/atlas-q.project.md +18 -0
- package/examples/persistent-worker-demo/briefops-workspace/skills/backtest-validation.skill.md +13 -0
- package/examples/persistent-worker-demo/briefops-workspace/skills/risk-review.skill.md +15 -0
- package/examples/persistent-worker-demo/briefops-workspace/workers/quant-reviewer.worker.yaml +12 -0
- package/examples/persistent-worker-demo/briefops-workspace/workers/summaries/quant-reviewer.summary.md +44 -0
- package/package.json +59 -0
- package/plugins/briefops-codex/.codex-plugin/plugin.json +39 -0
- package/plugins/briefops-codex/README.md +44 -0
- package/plugins/briefops-codex/skills/briefops-continue-worker/SKILL.md +22 -0
- package/plugins/briefops-codex/skills/briefops-finish-task/SKILL.md +22 -0
- package/plugins/briefops-codex/skills/briefops-prime-context/SKILL.md +24 -0
- package/plugins/briefops-codex/skills/briefops-review-memory/SKILL.md +27 -0
|
@@ -0,0 +1,1272 @@
|
|
|
1
|
+
# BriefOps OSS Readiness Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Move BriefOps from internal dogfood alpha to a public open-source release candidate with safe defaults, clear trust boundaries, release hygiene, and harness-friendly adoption guidance.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Keep BriefOps as a local-first file-backed CLI, not an agent harness. Strengthen the product edge: deterministic context priming, human-approved memory, safe shared exports, auditable local work history, and compatibility with stronger harnesses such as LazyCodex/OmO without adopting their global-hook runtime model.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** TypeScript, Node.js >=20, Commander, YAML, Zod, Vitest, GitHub Actions, npm package distribution.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## File Structure
|
|
14
|
+
|
|
15
|
+
Create:
|
|
16
|
+
- `SECURITY.md` - vulnerability reporting, supported versions, local data handling policy.
|
|
17
|
+
- `CONTRIBUTING.md` - development setup, test matrix, branch/commit expectations.
|
|
18
|
+
- `CODE_OF_CONDUCT.md` - concise community conduct policy.
|
|
19
|
+
- `CHANGELOG.md` - release notes beginning with `0.2.0-alpha.0` and next release section.
|
|
20
|
+
- `docs/integrations/harnesses.md` - how to use BriefOps with LazyCodex, OmO, Codex, Claude Code, Cursor, and other harnesses.
|
|
21
|
+
- `docs/release-checklist.md` - human release gate checklist.
|
|
22
|
+
- `src/core/output.ts` - safe explicit-output write helper.
|
|
23
|
+
- `src/core/privacyDoctor.ts` - privacy-oriented local workspace checks.
|
|
24
|
+
- `tests/output-safety.test.ts` - no-overwrite behavior for explicit output paths.
|
|
25
|
+
- `tests/privacy-doctor.test.ts` - privacy doctor behavior.
|
|
26
|
+
- `.github/dependabot.yml` - dependency update signal.
|
|
27
|
+
|
|
28
|
+
Modify:
|
|
29
|
+
- `package.json` - add repository, bugs, homepage, keywords, and release verification script.
|
|
30
|
+
- `README.md` - add OSS readiness, trust boundary, harness integration, and release status sections.
|
|
31
|
+
- `.github/workflows/ci.yml` - add audit/release-check steps.
|
|
32
|
+
- `src/commands/brief.ts` - add `--force` for explicit output overwrite.
|
|
33
|
+
- `src/commands/codex.ts` - add `--force` to prompt output commands and tighten plugin install messaging.
|
|
34
|
+
- `src/commands/continue.ts` - add `--force` for explicit output overwrite.
|
|
35
|
+
- `src/commands/doctor.ts` - add `--privacy` and optional `--fix-gitignore`.
|
|
36
|
+
- `src/commands/handoff.ts` - add `--force`.
|
|
37
|
+
- `src/commands/pack.ts` - add `--force`.
|
|
38
|
+
- `src/core/brief.ts` - use output helper for explicit output paths.
|
|
39
|
+
- `src/core/codex.ts` - use output helper for explicit output paths.
|
|
40
|
+
- `src/core/codexPlugin.ts` - plugin install should be idempotent but not silently overwrite changed generated files unless `--force`.
|
|
41
|
+
- `src/core/handoff.ts` - use output helper for explicit output paths and add missing lock around `saveCodexResumeFromHandoff`.
|
|
42
|
+
- `src/core/workflow.ts` - use output helper for explicit pack paths.
|
|
43
|
+
- `tests/cli-workflow.test.ts` - CLI coverage for `--force`, `doctor --privacy`, and plugin changed-file behavior.
|
|
44
|
+
- `tests/codex-plugin.test.ts` - plugin idempotency and changed-file safety.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Task 1: OSS Trust Documents And Package Metadata
|
|
49
|
+
|
|
50
|
+
**Files:**
|
|
51
|
+
- Create: `SECURITY.md`
|
|
52
|
+
- Create: `CONTRIBUTING.md`
|
|
53
|
+
- Create: `CODE_OF_CONDUCT.md`
|
|
54
|
+
- Create: `CHANGELOG.md`
|
|
55
|
+
- Modify: `package.json`
|
|
56
|
+
- Modify: `README.md`
|
|
57
|
+
|
|
58
|
+
- [x] **Step 1: Add `SECURITY.md`**
|
|
59
|
+
|
|
60
|
+
Create `SECURITY.md`:
|
|
61
|
+
|
|
62
|
+
```markdown
|
|
63
|
+
# Security Policy
|
|
64
|
+
|
|
65
|
+
BriefOps is a local-first CLI. It stores project memory, work logs, generated prompts, and plugin assets under `.briefops/` in the current repository.
|
|
66
|
+
|
|
67
|
+
## Supported Versions
|
|
68
|
+
|
|
69
|
+
| Version | Supported |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| 0.2.x alpha | Security fixes accepted |
|
|
72
|
+
|
|
73
|
+
## Reporting A Vulnerability
|
|
74
|
+
|
|
75
|
+
Please report suspected vulnerabilities through GitHub Security Advisories when available. If advisories are not enabled, open a GitHub issue with a minimal description and avoid posting secrets, private logs, or exploit payloads.
|
|
76
|
+
|
|
77
|
+
Include:
|
|
78
|
+
|
|
79
|
+
- BriefOps version
|
|
80
|
+
- Operating system
|
|
81
|
+
- Command used
|
|
82
|
+
- Whether `.briefops/` contains private project data
|
|
83
|
+
- Expected behavior
|
|
84
|
+
- Observed behavior
|
|
85
|
+
|
|
86
|
+
## Local Data Policy
|
|
87
|
+
|
|
88
|
+
BriefOps does not require a hosted service, MCP server, vector database, or network access.
|
|
89
|
+
|
|
90
|
+
Do not commit `.briefops/` unless you intentionally curated the contents for sharing. Use:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
briefops doctor --privacy
|
|
94
|
+
briefops prime --export-policy shared-only
|
|
95
|
+
briefops pack resume --export-policy shared-only
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
before sharing generated context outside your local machine.
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- [x] **Step 2: Add `CONTRIBUTING.md`**
|
|
102
|
+
|
|
103
|
+
Create `CONTRIBUTING.md`:
|
|
104
|
+
|
|
105
|
+
```markdown
|
|
106
|
+
# Contributing
|
|
107
|
+
|
|
108
|
+
Thanks for improving BriefOps.
|
|
109
|
+
|
|
110
|
+
BriefOps is intentionally small:
|
|
111
|
+
|
|
112
|
+
- local-first
|
|
113
|
+
- file-backed
|
|
114
|
+
- deterministic
|
|
115
|
+
- human-approved
|
|
116
|
+
- token-aware
|
|
117
|
+
- no hosted service required
|
|
118
|
+
- no MCP server required
|
|
119
|
+
|
|
120
|
+
## Development Setup
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm install
|
|
124
|
+
npm run build
|
|
125
|
+
npm test
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Run the CLI during development:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npm run dev -- --help
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Required Checks
|
|
135
|
+
|
|
136
|
+
Before opening a pull request:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npm run build
|
|
140
|
+
npm test
|
|
141
|
+
npm pack --dry-run
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Safety Rules
|
|
145
|
+
|
|
146
|
+
- Never auto-approve memory proposals or skill patches.
|
|
147
|
+
- Do not introduce hosted services, cloud sync, vector databases, or MCP as required runtime dependencies.
|
|
148
|
+
- Keep private local memory out of shared exports unless it is explicitly marked `visibility: shared` and `exportable: true`.
|
|
149
|
+
- Prefer small deterministic file-backed changes over agent runtime behavior.
|
|
150
|
+
|
|
151
|
+
## Pull Request Style
|
|
152
|
+
|
|
153
|
+
Include:
|
|
154
|
+
|
|
155
|
+
- What changed
|
|
156
|
+
- Why it matters for local-first continuity
|
|
157
|
+
- Tests run
|
|
158
|
+
- Any privacy or export-policy impact
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- [x] **Step 3: Add `CODE_OF_CONDUCT.md`**
|
|
162
|
+
|
|
163
|
+
Create `CODE_OF_CONDUCT.md`:
|
|
164
|
+
|
|
165
|
+
```markdown
|
|
166
|
+
# Code Of Conduct
|
|
167
|
+
|
|
168
|
+
BriefOps aims to be a practical, respectful open-source project.
|
|
169
|
+
|
|
170
|
+
We expect contributors to:
|
|
171
|
+
|
|
172
|
+
- be kind and direct
|
|
173
|
+
- critique code and ideas, not people
|
|
174
|
+
- respect privacy and local data boundaries
|
|
175
|
+
- avoid posting secrets, private logs, or sensitive project memory
|
|
176
|
+
- keep discussions focused on making BriefOps safer and more useful
|
|
177
|
+
|
|
178
|
+
Maintainers may remove comments, issues, or contributions that are abusive, harassing, spammy, or unsafe.
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
- [x] **Step 4: Add `CHANGELOG.md`**
|
|
182
|
+
|
|
183
|
+
Create `CHANGELOG.md`:
|
|
184
|
+
|
|
185
|
+
```markdown
|
|
186
|
+
# Changelog
|
|
187
|
+
|
|
188
|
+
## Unreleased
|
|
189
|
+
|
|
190
|
+
- Add OSS readiness hardening.
|
|
191
|
+
|
|
192
|
+
## 0.2.0-alpha.0
|
|
193
|
+
|
|
194
|
+
- Add Codex first-context workflow.
|
|
195
|
+
- Add local Codex plugin bundle generation.
|
|
196
|
+
- Add `briefops prime` and `briefops codex prime`.
|
|
197
|
+
- Add default worker selection with `briefops worker use`.
|
|
198
|
+
- Add persistent worker finish/continue flow.
|
|
199
|
+
- Add human-approved memory proposal flow.
|
|
200
|
+
- Add shared-only export policy.
|
|
201
|
+
- Add `doctor --security` and stale lock cleanup.
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
- [x] **Step 5: Update `package.json` metadata**
|
|
205
|
+
|
|
206
|
+
Modify `package.json`:
|
|
207
|
+
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"repository": {
|
|
211
|
+
"type": "git",
|
|
212
|
+
"url": "git+https://github.com/simony-816/briefops.git"
|
|
213
|
+
},
|
|
214
|
+
"bugs": {
|
|
215
|
+
"url": "https://github.com/simony-816/briefops/issues"
|
|
216
|
+
},
|
|
217
|
+
"homepage": "https://github.com/simony-816/briefops#readme",
|
|
218
|
+
"keywords": [
|
|
219
|
+
"codex",
|
|
220
|
+
"ai-agents",
|
|
221
|
+
"local-first",
|
|
222
|
+
"memory",
|
|
223
|
+
"context",
|
|
224
|
+
"handoff",
|
|
225
|
+
"developer-tools"
|
|
226
|
+
],
|
|
227
|
+
"scripts": {
|
|
228
|
+
"build": "tsc -p tsconfig.json",
|
|
229
|
+
"test": "vitest run",
|
|
230
|
+
"dev": "tsx src/index.ts",
|
|
231
|
+
"verify:release": "npm run build && npm test && npm pack --dry-run"
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Preserve existing fields and ordering where practical.
|
|
237
|
+
|
|
238
|
+
- [x] **Step 6: Run package metadata check**
|
|
239
|
+
|
|
240
|
+
Run:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
npm run build
|
|
244
|
+
npm test
|
|
245
|
+
npm pack --dry-run
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Expected: all pass and tarball includes `README.md`, `LICENSE`, `SECURITY.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `CHANGELOG.md`, `docs`, `plugins`, `examples`, and `dist`.
|
|
249
|
+
|
|
250
|
+
- [x] **Step 7: Commit**
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
git add SECURITY.md CONTRIBUTING.md CODE_OF_CONDUCT.md CHANGELOG.md package.json README.md
|
|
254
|
+
git commit -m "docs: add open-source trust documents"
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## Task 2: Safe Explicit Output Writes
|
|
260
|
+
|
|
261
|
+
**Files:**
|
|
262
|
+
- Create: `src/core/output.ts`
|
|
263
|
+
- Create: `tests/output-safety.test.ts`
|
|
264
|
+
- Modify: `src/commands/brief.ts`
|
|
265
|
+
- Modify: `src/commands/codex.ts`
|
|
266
|
+
- Modify: `src/commands/continue.ts`
|
|
267
|
+
- Modify: `src/commands/handoff.ts`
|
|
268
|
+
- Modify: `src/commands/pack.ts`
|
|
269
|
+
- Modify: `src/core/brief.ts`
|
|
270
|
+
- Modify: `src/core/codex.ts`
|
|
271
|
+
- Modify: `src/core/handoff.ts`
|
|
272
|
+
- Modify: `src/core/workflow.ts`
|
|
273
|
+
- Modify: `tests/cli-workflow.test.ts`
|
|
274
|
+
|
|
275
|
+
- [x] **Step 1: Write failing tests for explicit output no-overwrite**
|
|
276
|
+
|
|
277
|
+
Create `tests/output-safety.test.ts`:
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
import path from "node:path";
|
|
281
|
+
import { describe, expect, it } from "vitest";
|
|
282
|
+
import { generateCodexResume } from "../src/core/codex.js";
|
|
283
|
+
import { generateHandoff } from "../src/core/handoff.js";
|
|
284
|
+
import { createProject } from "../src/core/project.js";
|
|
285
|
+
import { createSkill } from "../src/core/skill.js";
|
|
286
|
+
import { readTextFile, writeTextFile } from "../src/core/storage.js";
|
|
287
|
+
import { createWorker } from "../src/core/worker.js";
|
|
288
|
+
import { packResume } from "../src/core/workflow.js";
|
|
289
|
+
import { initWorkspace } from "../src/core/workspace.js";
|
|
290
|
+
import { withTempDir } from "./helpers.js";
|
|
291
|
+
|
|
292
|
+
async function seed(dir: string): Promise<void> {
|
|
293
|
+
await initWorkspace(dir);
|
|
294
|
+
await createSkill({ cwd: dir, name: "risk-review" });
|
|
295
|
+
await createProject({ cwd: dir, name: "atlas-q" });
|
|
296
|
+
await createWorker({
|
|
297
|
+
cwd: dir,
|
|
298
|
+
name: "quant-reviewer",
|
|
299
|
+
project: "atlas-q",
|
|
300
|
+
skills: ["risk-review"]
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
describe("explicit output safety", () => {
|
|
305
|
+
it("does not overwrite explicit Codex resume output without force", async () => {
|
|
306
|
+
await withTempDir(async (dir) => {
|
|
307
|
+
await seed(dir);
|
|
308
|
+
const outputPath = path.join(dir, "resume.md");
|
|
309
|
+
await writeTextFile(outputPath, "keep me\n");
|
|
310
|
+
|
|
311
|
+
await expect(generateCodexResume({
|
|
312
|
+
cwd: dir,
|
|
313
|
+
worker: "quant-reviewer",
|
|
314
|
+
task: "Continue review.",
|
|
315
|
+
save: true,
|
|
316
|
+
outputPath
|
|
317
|
+
})).rejects.toThrow("Output file already exists");
|
|
318
|
+
|
|
319
|
+
expect(await readTextFile(outputPath)).toBe("keep me\n");
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it("overwrites explicit Codex resume output when force is true", async () => {
|
|
324
|
+
await withTempDir(async (dir) => {
|
|
325
|
+
await seed(dir);
|
|
326
|
+
const outputPath = path.join(dir, "resume.md");
|
|
327
|
+
await writeTextFile(outputPath, "replace me\n");
|
|
328
|
+
|
|
329
|
+
await generateCodexResume({
|
|
330
|
+
cwd: dir,
|
|
331
|
+
worker: "quant-reviewer",
|
|
332
|
+
task: "Continue review.",
|
|
333
|
+
save: true,
|
|
334
|
+
outputPath,
|
|
335
|
+
force: true
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
expect(await readTextFile(outputPath)).toContain("BriefOps Codex Resume");
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
it("does not overwrite explicit handoff output without force", async () => {
|
|
343
|
+
await withTempDir(async (dir) => {
|
|
344
|
+
await seed(dir);
|
|
345
|
+
const outputPath = path.join(dir, "handoff.md");
|
|
346
|
+
await writeTextFile(outputPath, "keep me\n");
|
|
347
|
+
|
|
348
|
+
await expect(generateHandoff({
|
|
349
|
+
cwd: dir,
|
|
350
|
+
worker: "quant-reviewer",
|
|
351
|
+
task: "Continue review.",
|
|
352
|
+
save: true,
|
|
353
|
+
outputPath
|
|
354
|
+
})).rejects.toThrow("Output file already exists");
|
|
355
|
+
|
|
356
|
+
expect(await readTextFile(outputPath)).toBe("keep me\n");
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it("does not overwrite explicit pack output without force", async () => {
|
|
361
|
+
await withTempDir(async (dir) => {
|
|
362
|
+
await seed(dir);
|
|
363
|
+
const outputPath = path.join(dir, "pack.md");
|
|
364
|
+
await writeTextFile(outputPath, "keep me\n");
|
|
365
|
+
|
|
366
|
+
await expect(packResume({
|
|
367
|
+
cwd: dir,
|
|
368
|
+
worker: "quant-reviewer",
|
|
369
|
+
task: "Continue review.",
|
|
370
|
+
outputPath
|
|
371
|
+
})).rejects.toThrow("Output file already exists");
|
|
372
|
+
|
|
373
|
+
expect(await readTextFile(outputPath)).toBe("keep me\n");
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
- [x] **Step 2: Run failing output safety tests**
|
|
380
|
+
|
|
381
|
+
Run:
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
npm test -- tests/output-safety.test.ts
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Expected: FAIL because `force` is not yet supported and explicit outputs currently overwrite.
|
|
388
|
+
|
|
389
|
+
- [x] **Step 3: Add output helper**
|
|
390
|
+
|
|
391
|
+
Create `src/core/output.ts`:
|
|
392
|
+
|
|
393
|
+
```ts
|
|
394
|
+
import path from "node:path";
|
|
395
|
+
import { BriefOpsError } from "./errors.js";
|
|
396
|
+
import { pathExists, writeTextFile } from "./storage.js";
|
|
397
|
+
|
|
398
|
+
export async function writeGeneratedOutput(options: {
|
|
399
|
+
defaultPath: string;
|
|
400
|
+
outputPath?: string;
|
|
401
|
+
content: string;
|
|
402
|
+
force?: boolean;
|
|
403
|
+
}): Promise<string> {
|
|
404
|
+
const targetPath = options.outputPath ?? options.defaultPath;
|
|
405
|
+
const isExplicit = Boolean(options.outputPath);
|
|
406
|
+
|
|
407
|
+
if (isExplicit && !options.force && await pathExists(targetPath)) {
|
|
408
|
+
throw new BriefOpsError(
|
|
409
|
+
`Output file already exists: ${targetPath}. Re-run with --force to overwrite.`
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
await writeTextFile(targetPath, options.content, {
|
|
414
|
+
force: !isExplicit || Boolean(options.force)
|
|
415
|
+
});
|
|
416
|
+
return targetPath;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export function resolveCliOutputPath(cwd: string, value?: string): string | undefined {
|
|
420
|
+
return value ? path.resolve(cwd, value) : undefined;
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
- [x] **Step 4: Thread `force?: boolean` through core option types**
|
|
425
|
+
|
|
426
|
+
Add `force?: boolean` to:
|
|
427
|
+
|
|
428
|
+
```ts
|
|
429
|
+
// src/core/brief.ts
|
|
430
|
+
export type SaveGeneratedBriefOptions = {
|
|
431
|
+
cwd: string;
|
|
432
|
+
generated: GeneratedBrief;
|
|
433
|
+
outputPath?: string;
|
|
434
|
+
force?: boolean;
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
// src/core/codex.ts
|
|
438
|
+
export type CodexMissionOptions = { /* existing fields */ force?: boolean };
|
|
439
|
+
export type CodexPlanOptions = { /* existing fields */ force?: boolean };
|
|
440
|
+
export type CodexResumeOptions = { /* existing fields */ force?: boolean };
|
|
441
|
+
|
|
442
|
+
// src/core/handoff.ts
|
|
443
|
+
export type GenerateHandoffOptions = { /* existing fields */ force?: boolean };
|
|
444
|
+
|
|
445
|
+
// src/core/workflow.ts
|
|
446
|
+
export type ContinueWorkOptions = { /* existing fields */ force?: boolean };
|
|
447
|
+
export type PackResumeOptions = { /* existing fields */ force?: boolean };
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
- [x] **Step 5: Use output helper in save functions**
|
|
451
|
+
|
|
452
|
+
In `src/core/codex.ts`, replace `writeTextFile(targetPath, ..., { force: true })` inside `saveCodexPrompt()` with:
|
|
453
|
+
|
|
454
|
+
```ts
|
|
455
|
+
return writeGeneratedOutput({
|
|
456
|
+
defaultPath: path.join(
|
|
457
|
+
workspacePaths(options.cwd).codexPrompts,
|
|
458
|
+
`${formatDateStamp()}-${options.kind}-${slugForFilename(options.name)}.md`
|
|
459
|
+
),
|
|
460
|
+
outputPath: options.outputPath,
|
|
461
|
+
content: options.content,
|
|
462
|
+
force: options.force
|
|
463
|
+
});
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
In `src/core/handoff.ts`, use the same pattern for `saveGeneratedHandoff()` and `saveCodexResumeFromHandoff()`.
|
|
467
|
+
|
|
468
|
+
In `src/core/workflow.ts`, use the same pattern for `packResume()`.
|
|
469
|
+
|
|
470
|
+
- [x] **Step 6: Add CLI `--force` flags**
|
|
471
|
+
|
|
472
|
+
For each command with `--output`, add:
|
|
473
|
+
|
|
474
|
+
```ts
|
|
475
|
+
.option("--force", "Overwrite an existing explicit output file.")
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
Pass:
|
|
479
|
+
|
|
480
|
+
```ts
|
|
481
|
+
force: Boolean(options.force)
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
to the corresponding core call.
|
|
485
|
+
|
|
486
|
+
- [x] **Step 7: Run output tests**
|
|
487
|
+
|
|
488
|
+
Run:
|
|
489
|
+
|
|
490
|
+
```bash
|
|
491
|
+
npm test -- tests/output-safety.test.ts
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
Expected: PASS.
|
|
495
|
+
|
|
496
|
+
- [x] **Step 8: Run regression tests**
|
|
497
|
+
|
|
498
|
+
Run:
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
npm test -- tests/cli-workflow.test.ts tests/persistent-worker.test.ts
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
Expected: PASS.
|
|
505
|
+
|
|
506
|
+
- [x] **Step 9: Commit**
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
git add src/core/output.ts src/core src/commands tests/output-safety.test.ts tests/cli-workflow.test.ts
|
|
510
|
+
git commit -m "fix: protect explicit output files"
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
---
|
|
514
|
+
|
|
515
|
+
## Task 3: Privacy Doctor And Gitignore Guard
|
|
516
|
+
|
|
517
|
+
**Files:**
|
|
518
|
+
- Create: `src/core/privacyDoctor.ts`
|
|
519
|
+
- Create: `tests/privacy-doctor.test.ts`
|
|
520
|
+
- Modify: `src/commands/doctor.ts`
|
|
521
|
+
- Modify: `README.md`
|
|
522
|
+
- Modify: `docs/quickstart.md`
|
|
523
|
+
|
|
524
|
+
- [x] **Step 1: Write failing privacy doctor tests**
|
|
525
|
+
|
|
526
|
+
Create `tests/privacy-doctor.test.ts`:
|
|
527
|
+
|
|
528
|
+
```ts
|
|
529
|
+
import { describe, expect, it } from "vitest";
|
|
530
|
+
import { addMemory } from "../src/core/memory.js";
|
|
531
|
+
import { runPrivacyDoctor } from "../src/core/privacyDoctor.js";
|
|
532
|
+
import { createProject } from "../src/core/project.js";
|
|
533
|
+
import { createSkill } from "../src/core/skill.js";
|
|
534
|
+
import { writeTextFile } from "../src/core/storage.js";
|
|
535
|
+
import { initWorkspace } from "../src/core/workspace.js";
|
|
536
|
+
import { withTempDir } from "./helpers.js";
|
|
537
|
+
|
|
538
|
+
async function seed(dir: string): Promise<void> {
|
|
539
|
+
await initWorkspace(dir);
|
|
540
|
+
await createSkill({ cwd: dir, name: "risk-review" });
|
|
541
|
+
await createProject({ cwd: dir, name: "atlas-q" });
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
describe("privacy doctor", () => {
|
|
545
|
+
it("warns when .briefops is not ignored", async () => {
|
|
546
|
+
await withTempDir(async (dir) => {
|
|
547
|
+
await seed(dir);
|
|
548
|
+
|
|
549
|
+
const result = await runPrivacyDoctor({ cwd: dir });
|
|
550
|
+
|
|
551
|
+
expect(result.ok).toBe(true);
|
|
552
|
+
expect(result.checks.find((check) => check.name === "Gitignore")?.status).toBe("warn");
|
|
553
|
+
});
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it("passes gitignore check when .briefops is ignored", async () => {
|
|
557
|
+
await withTempDir(async (dir) => {
|
|
558
|
+
await seed(dir);
|
|
559
|
+
await writeTextFile(`${dir}/.gitignore`, ".briefops/\n");
|
|
560
|
+
|
|
561
|
+
const result = await runPrivacyDoctor({ cwd: dir });
|
|
562
|
+
|
|
563
|
+
expect(result.checks.find((check) => check.name === "Gitignore")?.status).toBe("ok");
|
|
564
|
+
});
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
it("warns on private memory marked exportable", async () => {
|
|
568
|
+
await withTempDir(async (dir) => {
|
|
569
|
+
await seed(dir);
|
|
570
|
+
await writeTextFile(`${dir}/.gitignore`, ".briefops/\n");
|
|
571
|
+
await addMemory({
|
|
572
|
+
cwd: dir,
|
|
573
|
+
type: "lessons",
|
|
574
|
+
project: "atlas-q",
|
|
575
|
+
skill: "risk-review",
|
|
576
|
+
content: "Private lesson should not be exportable.",
|
|
577
|
+
visibility: "private",
|
|
578
|
+
exportable: true
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
const result = await runPrivacyDoctor({ cwd: dir });
|
|
582
|
+
|
|
583
|
+
expect(result.checks.find((check) => check.name === "Private exportable memory")?.status)
|
|
584
|
+
.toBe("warn");
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
it("warns on secret-like strings in local memory", async () => {
|
|
589
|
+
await withTempDir(async (dir) => {
|
|
590
|
+
await seed(dir);
|
|
591
|
+
await writeTextFile(`${dir}/.gitignore`, ".briefops/\n");
|
|
592
|
+
await addMemory({
|
|
593
|
+
cwd: dir,
|
|
594
|
+
type: "facts",
|
|
595
|
+
project: "atlas-q",
|
|
596
|
+
skill: "risk-review",
|
|
597
|
+
content: "Use API key sk-test-12345678901234567890 for local sandbox.",
|
|
598
|
+
visibility: "private",
|
|
599
|
+
exportable: false
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
const result = await runPrivacyDoctor({ cwd: dir });
|
|
603
|
+
|
|
604
|
+
expect(result.checks.find((check) => check.name === "Secret-like local memory")?.status)
|
|
605
|
+
.toBe("warn");
|
|
606
|
+
});
|
|
607
|
+
});
|
|
608
|
+
});
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
- [x] **Step 2: Run failing tests**
|
|
612
|
+
|
|
613
|
+
Run:
|
|
614
|
+
|
|
615
|
+
```bash
|
|
616
|
+
npm test -- tests/privacy-doctor.test.ts
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
Expected: FAIL because `runPrivacyDoctor` does not exist.
|
|
620
|
+
|
|
621
|
+
- [x] **Step 3: Implement privacy doctor**
|
|
622
|
+
|
|
623
|
+
Create `src/core/privacyDoctor.ts`:
|
|
624
|
+
|
|
625
|
+
```ts
|
|
626
|
+
import { promises as fs } from "node:fs";
|
|
627
|
+
import path from "node:path";
|
|
628
|
+
import { listMemory } from "./memory.js";
|
|
629
|
+
import { pathExists, readTextFile, writeTextFile } from "./storage.js";
|
|
630
|
+
import { requireWorkspace } from "./workspace.js";
|
|
631
|
+
|
|
632
|
+
export type PrivacyDoctorStatus = "ok" | "warn" | "fail";
|
|
633
|
+
|
|
634
|
+
export type PrivacyDoctorCheck = {
|
|
635
|
+
name: string;
|
|
636
|
+
status: PrivacyDoctorStatus;
|
|
637
|
+
detail: string;
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
export type PrivacyDoctorResult = {
|
|
641
|
+
ok: boolean;
|
|
642
|
+
checks: PrivacyDoctorCheck[];
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
function check(name: string, status: PrivacyDoctorStatus, detail: string): PrivacyDoctorCheck {
|
|
646
|
+
return { name, status, detail };
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
const secretPatterns = [
|
|
650
|
+
/\bsk-[A-Za-z0-9_-]{16,}\b/,
|
|
651
|
+
/\bghp_[A-Za-z0-9_]{20,}\b/,
|
|
652
|
+
/\bgithub_pat_[A-Za-z0-9_]{20,}\b/,
|
|
653
|
+
/\bAKIA[0-9A-Z]{16}\b/,
|
|
654
|
+
/\b(password|passwd|secret|token|api[_-]?key)\s*[:=]\s*\S+/i
|
|
655
|
+
];
|
|
656
|
+
|
|
657
|
+
async function gitignoreStatus(cwd: string): Promise<PrivacyDoctorCheck> {
|
|
658
|
+
const gitignorePath = path.join(cwd, ".gitignore");
|
|
659
|
+
if (!(await pathExists(gitignorePath))) {
|
|
660
|
+
return check("Gitignore", "warn", ".gitignore not found; add `.briefops/` before public use.");
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const raw = await readTextFile(gitignorePath);
|
|
664
|
+
const ignoresBriefOps = raw
|
|
665
|
+
.split(/\r?\n/)
|
|
666
|
+
.map((line) => line.trim())
|
|
667
|
+
.some((line) => line === ".briefops" || line === ".briefops/" || line === "/.briefops/");
|
|
668
|
+
|
|
669
|
+
return ignoresBriefOps
|
|
670
|
+
? check("Gitignore", "ok", ".briefops is ignored.")
|
|
671
|
+
: check("Gitignore", "warn", ".briefops is not ignored.");
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
export async function fixBriefOpsGitignore(cwd = process.cwd()): Promise<string> {
|
|
675
|
+
const gitignorePath = path.join(cwd, ".gitignore");
|
|
676
|
+
const existing = await pathExists(gitignorePath) ? await readTextFile(gitignorePath) : "";
|
|
677
|
+
const lines = existing.split(/\r?\n/).map((line) => line.trim());
|
|
678
|
+
if (!lines.includes(".briefops/") && !lines.includes(".briefops") && !lines.includes("/.briefops/")) {
|
|
679
|
+
const next = `${existing.trimEnd()}${existing.trim() ? "\n" : ""}.briefops/\n`;
|
|
680
|
+
await writeTextFile(gitignorePath, next, { force: true });
|
|
681
|
+
}
|
|
682
|
+
return gitignorePath;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
export async function runPrivacyDoctor(options: {
|
|
686
|
+
cwd?: string;
|
|
687
|
+
} = {}): Promise<PrivacyDoctorResult> {
|
|
688
|
+
const cwd = options.cwd ?? process.cwd();
|
|
689
|
+
await requireWorkspace(cwd);
|
|
690
|
+
|
|
691
|
+
const memory = await listMemory({ cwd });
|
|
692
|
+
const privateExportable = memory.filter((item) => item.visibility === "private" && item.exportable);
|
|
693
|
+
const secretLike = memory.filter((item) =>
|
|
694
|
+
secretPatterns.some((pattern) => pattern.test(item.content))
|
|
695
|
+
);
|
|
696
|
+
|
|
697
|
+
const checks: PrivacyDoctorCheck[] = [
|
|
698
|
+
await gitignoreStatus(cwd),
|
|
699
|
+
privateExportable.length > 0
|
|
700
|
+
? check("Private exportable memory", "warn", `${privateExportable.length} private item(s) are exportable.`)
|
|
701
|
+
: check("Private exportable memory", "ok", "No private exportable memory."),
|
|
702
|
+
secretLike.length > 0
|
|
703
|
+
? check("Secret-like local memory", "warn", `${secretLike.length} memory item(s) look like secrets.`)
|
|
704
|
+
: check("Secret-like local memory", "ok", "No secret-like memory found.")
|
|
705
|
+
];
|
|
706
|
+
|
|
707
|
+
return {
|
|
708
|
+
ok: checks.every((item) => item.status !== "fail"),
|
|
709
|
+
checks
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
Remove the unused `fs` import if TypeScript reports it.
|
|
715
|
+
|
|
716
|
+
- [x] **Step 4: Add CLI flags**
|
|
717
|
+
|
|
718
|
+
Modify `src/commands/doctor.ts`:
|
|
719
|
+
|
|
720
|
+
```ts
|
|
721
|
+
.option("--privacy", "Run privacy checks for local memory and share safety.")
|
|
722
|
+
.option("--fix-gitignore", "Add `.briefops/` to .gitignore when running --privacy.")
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
Behavior:
|
|
726
|
+
|
|
727
|
+
```ts
|
|
728
|
+
if (options.privacy) {
|
|
729
|
+
if (options.fixGitignore) {
|
|
730
|
+
const path = await fixBriefOpsGitignore();
|
|
731
|
+
console.log(`Updated gitignore: ${path}`);
|
|
732
|
+
console.log("");
|
|
733
|
+
}
|
|
734
|
+
const result = await runPrivacyDoctor();
|
|
735
|
+
printTable([
|
|
736
|
+
["Check", "Status", "Detail"],
|
|
737
|
+
...result.checks.map((item) => [item.name, item.status, item.detail])
|
|
738
|
+
]);
|
|
739
|
+
if (!result.ok) {
|
|
740
|
+
process.exitCode = 1;
|
|
741
|
+
}
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
- [x] **Step 5: Run privacy tests**
|
|
747
|
+
|
|
748
|
+
Run:
|
|
749
|
+
|
|
750
|
+
```bash
|
|
751
|
+
npm test -- tests/privacy-doctor.test.ts tests/cli-workflow.test.ts
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
Expected: PASS.
|
|
755
|
+
|
|
756
|
+
- [x] **Step 6: Document privacy workflow**
|
|
757
|
+
|
|
758
|
+
Add to `README.md`:
|
|
759
|
+
|
|
760
|
+
```markdown
|
|
761
|
+
## Privacy Check
|
|
762
|
+
|
|
763
|
+
Run this before publishing a repository, sharing a pack, or attaching BriefOps context outside your machine:
|
|
764
|
+
|
|
765
|
+
```bash
|
|
766
|
+
briefops doctor --privacy
|
|
767
|
+
briefops doctor --privacy --fix-gitignore
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
BriefOps is local-first, but `.briefops/` may contain private logs and memory. Keep `.briefops/` out of source control unless you intentionally curated the contents.
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
- [x] **Step 7: Commit**
|
|
774
|
+
|
|
775
|
+
```bash
|
|
776
|
+
git add src/core/privacyDoctor.ts src/commands/doctor.ts tests/privacy-doctor.test.ts tests/cli-workflow.test.ts README.md docs/quickstart.md
|
|
777
|
+
git commit -m "feat: add privacy doctor"
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
---
|
|
781
|
+
|
|
782
|
+
## Task 4: Plugin Trust Boundary And Idempotent Install Safety
|
|
783
|
+
|
|
784
|
+
**Files:**
|
|
785
|
+
- Modify: `src/core/codexPlugin.ts`
|
|
786
|
+
- Modify: `src/commands/codex.ts`
|
|
787
|
+
- Modify: `plugins/briefops-codex/README.md`
|
|
788
|
+
- Modify: `tests/codex-plugin.test.ts`
|
|
789
|
+
|
|
790
|
+
- [x] **Step 1: Write failing plugin changed-file test**
|
|
791
|
+
|
|
792
|
+
Add to `tests/codex-plugin.test.ts`:
|
|
793
|
+
|
|
794
|
+
```ts
|
|
795
|
+
it("does not overwrite changed local plugin files without force", async () => {
|
|
796
|
+
await withTempDir(async (dir) => {
|
|
797
|
+
await initWorkspace(dir);
|
|
798
|
+
await installCodexPlugin({ cwd: dir });
|
|
799
|
+
const skillPath = path.join(
|
|
800
|
+
dir,
|
|
801
|
+
".briefops/codex/plugin/briefops/skills/briefops-prime-context/SKILL.md"
|
|
802
|
+
);
|
|
803
|
+
await writeTextFile(skillPath, "custom local edit\n", { force: true });
|
|
804
|
+
|
|
805
|
+
await expect(installCodexPlugin({ cwd: dir })).rejects.toThrow(
|
|
806
|
+
"Generated plugin file has local changes"
|
|
807
|
+
);
|
|
808
|
+
|
|
809
|
+
expect(await readTextFile(skillPath)).toBe("custom local edit\n");
|
|
810
|
+
});
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
it("overwrites changed local plugin files with force", async () => {
|
|
814
|
+
await withTempDir(async (dir) => {
|
|
815
|
+
await initWorkspace(dir);
|
|
816
|
+
await installCodexPlugin({ cwd: dir });
|
|
817
|
+
const skillPath = path.join(
|
|
818
|
+
dir,
|
|
819
|
+
".briefops/codex/plugin/briefops/skills/briefops-prime-context/SKILL.md"
|
|
820
|
+
);
|
|
821
|
+
await writeTextFile(skillPath, "custom local edit\n", { force: true });
|
|
822
|
+
|
|
823
|
+
await installCodexPlugin({ cwd: dir, force: true });
|
|
824
|
+
|
|
825
|
+
expect(await readTextFile(skillPath)).toContain("BriefOps Prime Context");
|
|
826
|
+
});
|
|
827
|
+
});
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
- [x] **Step 2: Run failing plugin tests**
|
|
831
|
+
|
|
832
|
+
Run:
|
|
833
|
+
|
|
834
|
+
```bash
|
|
835
|
+
npm test -- tests/codex-plugin.test.ts
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
Expected: FAIL because plugin install currently overwrites generated files.
|
|
839
|
+
|
|
840
|
+
- [x] **Step 3: Make plugin install idempotent but changed-file safe**
|
|
841
|
+
|
|
842
|
+
In `src/core/codexPlugin.ts`, add:
|
|
843
|
+
|
|
844
|
+
```ts
|
|
845
|
+
async function writeGeneratedPluginFile(options: {
|
|
846
|
+
target: string;
|
|
847
|
+
content: string;
|
|
848
|
+
force: boolean;
|
|
849
|
+
}): Promise<void> {
|
|
850
|
+
if (await pathExists(options.target)) {
|
|
851
|
+
const existing = await readTextFile(options.target);
|
|
852
|
+
if (existing === options.content) {
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
if (!options.force) {
|
|
856
|
+
throw new BriefOpsError(
|
|
857
|
+
`Generated plugin file has local changes: ${options.target}. Re-run with --force to overwrite.`
|
|
858
|
+
);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
await writeTextFile(options.target, options.content, { force: true });
|
|
863
|
+
}
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
Import `BriefOpsError`.
|
|
867
|
+
|
|
868
|
+
Replace the install loop write with:
|
|
869
|
+
|
|
870
|
+
```ts
|
|
871
|
+
await writeGeneratedPluginFile({
|
|
872
|
+
target,
|
|
873
|
+
content: file.content,
|
|
874
|
+
force: Boolean(options.force)
|
|
875
|
+
});
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
- [x] **Step 4: Narrow plugin trust messaging**
|
|
879
|
+
|
|
880
|
+
Update generated skill text and `plugins/briefops-codex/README.md` to include:
|
|
881
|
+
|
|
882
|
+
```markdown
|
|
883
|
+
The BriefOps plugin is a local CLI helper. It does not require network access, does not publish to a marketplace, and should not auto-approve memory or skill patches. Use `--export-policy shared-only` before copying context outside the local workspace.
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
- [x] **Step 5: Run plugin tests**
|
|
887
|
+
|
|
888
|
+
Run:
|
|
889
|
+
|
|
890
|
+
```bash
|
|
891
|
+
npm test -- tests/codex-plugin.test.ts tests/cli-workflow.test.ts
|
|
892
|
+
```
|
|
893
|
+
|
|
894
|
+
Expected: PASS.
|
|
895
|
+
|
|
896
|
+
- [x] **Step 6: Commit**
|
|
897
|
+
|
|
898
|
+
```bash
|
|
899
|
+
git add src/core/codexPlugin.ts src/commands/codex.ts plugins/briefops-codex/README.md tests/codex-plugin.test.ts
|
|
900
|
+
git commit -m "fix: protect generated plugin files"
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
---
|
|
904
|
+
|
|
905
|
+
## Task 5: Harness Integration Documentation
|
|
906
|
+
|
|
907
|
+
**Files:**
|
|
908
|
+
- Create: `docs/integrations/harnesses.md`
|
|
909
|
+
- Modify: `README.md`
|
|
910
|
+
- Modify: `examples/codex-first-context/README.md`
|
|
911
|
+
|
|
912
|
+
- [x] **Step 1: Create harness integration doc**
|
|
913
|
+
|
|
914
|
+
Create `docs/integrations/harnesses.md`:
|
|
915
|
+
|
|
916
|
+
```markdown
|
|
917
|
+
# Harness Integrations
|
|
918
|
+
|
|
919
|
+
BriefOps is not an agent harness. It does not run models, manage subscriptions, install hooks, expose MCP tools, or route work across agents.
|
|
920
|
+
|
|
921
|
+
BriefOps is a local memory and context ledger that a harness can read before work and update after work.
|
|
922
|
+
|
|
923
|
+
## Recommended Pattern
|
|
924
|
+
|
|
925
|
+
Before a task:
|
|
926
|
+
|
|
927
|
+
```bash
|
|
928
|
+
briefops prime --task "<task>" --format codex --max-tokens 800
|
|
929
|
+
```
|
|
930
|
+
|
|
931
|
+
After meaningful work:
|
|
932
|
+
|
|
933
|
+
```bash
|
|
934
|
+
briefops finish --worker <worker> --task "<task>" --result "<result>"
|
|
935
|
+
briefops memory proposal-show latest
|
|
936
|
+
briefops approve latest
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
For a fresh thread:
|
|
940
|
+
|
|
941
|
+
```bash
|
|
942
|
+
briefops continue --worker <worker> --task "<next task>" --pack
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
For portable or shared context:
|
|
946
|
+
|
|
947
|
+
```bash
|
|
948
|
+
briefops prime --task "<task>" --format codex --export-policy shared-only
|
|
949
|
+
briefops pack resume --worker <worker> --task "<task>" --export-policy shared-only
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
## LazyCodex / OmO
|
|
953
|
+
|
|
954
|
+
Use LazyCodex or OmO for orchestration, hooks, LSP/MCP, and autonomous execution. Use BriefOps for durable local continuity.
|
|
955
|
+
|
|
956
|
+
Suggested human workflow:
|
|
957
|
+
|
|
958
|
+
```bash
|
|
959
|
+
briefops prime --task "Implement the next scoped change." --format codex --max-tokens 800
|
|
960
|
+
codex "Use the BriefOps prime context, then run ultrawork for this task."
|
|
961
|
+
briefops finish --worker <worker> --task "Implement the next scoped change." --result "<verified result>"
|
|
962
|
+
briefops memory proposal-show latest
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
Do not let a harness auto-run `briefops approve latest`. Approval should remain human-confirmed.
|
|
966
|
+
|
|
967
|
+
## Codex App And Codex CLI
|
|
968
|
+
|
|
969
|
+
Use `briefops codex plugin install` to generate local plugin assets under `.briefops/codex/plugin/briefops`.
|
|
970
|
+
|
|
971
|
+
This command does not write to global Codex folders by default.
|
|
972
|
+
|
|
973
|
+
## Claude Code
|
|
974
|
+
|
|
975
|
+
BriefOps can coexist with `CLAUDE.md`. Keep `CLAUDE.md` for always-loaded project instructions and use BriefOps for task history, approved memory, handoffs, and shared-only packs.
|
|
976
|
+
|
|
977
|
+
## Cursor
|
|
978
|
+
|
|
979
|
+
BriefOps can coexist with Cursor rules and memories. Keep Cursor rules for editor behavior and use BriefOps for auditable cross-thread work history.
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
- [x] **Step 2: Link integration doc from README**
|
|
983
|
+
|
|
984
|
+
Add to `README.md`:
|
|
985
|
+
|
|
986
|
+
```markdown
|
|
987
|
+
## Harness Integrations
|
|
988
|
+
|
|
989
|
+
BriefOps works best as a local memory ledger beside stronger harnesses such as Codex, LazyCodex, OmO, Claude Code, Cursor, and OpenCode. See `docs/integrations/harnesses.md`.
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
- [x] **Step 3: Run docs packaging check**
|
|
993
|
+
|
|
994
|
+
Run:
|
|
995
|
+
|
|
996
|
+
```bash
|
|
997
|
+
npm pack --dry-run
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
Expected: tarball includes `docs/integrations/harnesses.md`.
|
|
1001
|
+
|
|
1002
|
+
- [x] **Step 4: Commit**
|
|
1003
|
+
|
|
1004
|
+
```bash
|
|
1005
|
+
git add docs/integrations/harnesses.md README.md examples/codex-first-context/README.md
|
|
1006
|
+
git commit -m "docs: explain harness integrations"
|
|
1007
|
+
```
|
|
1008
|
+
|
|
1009
|
+
---
|
|
1010
|
+
|
|
1011
|
+
## Task 6: Release Readiness Automation
|
|
1012
|
+
|
|
1013
|
+
**Files:**
|
|
1014
|
+
- Create: `docs/release-checklist.md`
|
|
1015
|
+
- Create: `.github/dependabot.yml`
|
|
1016
|
+
- Modify: `.github/workflows/ci.yml`
|
|
1017
|
+
- Modify: `package.json`
|
|
1018
|
+
|
|
1019
|
+
- [x] **Step 1: Add release checklist**
|
|
1020
|
+
|
|
1021
|
+
Create `docs/release-checklist.md`:
|
|
1022
|
+
|
|
1023
|
+
```markdown
|
|
1024
|
+
# Release Checklist
|
|
1025
|
+
|
|
1026
|
+
Before publishing BriefOps:
|
|
1027
|
+
|
|
1028
|
+
```bash
|
|
1029
|
+
npm run build
|
|
1030
|
+
npm test
|
|
1031
|
+
npm audit --audit-level=moderate
|
|
1032
|
+
npm pack --dry-run
|
|
1033
|
+
briefops --help
|
|
1034
|
+
```
|
|
1035
|
+
|
|
1036
|
+
Manual smoke test:
|
|
1037
|
+
|
|
1038
|
+
```bash
|
|
1039
|
+
tmpdir="$(mktemp -d)"
|
|
1040
|
+
cd "$tmpdir"
|
|
1041
|
+
briefops init
|
|
1042
|
+
briefops codex install
|
|
1043
|
+
briefops codex plugin install
|
|
1044
|
+
briefops skill create risk-review
|
|
1045
|
+
briefops project create atlas-q
|
|
1046
|
+
briefops worker create quant-reviewer --project atlas-q --skills risk-review
|
|
1047
|
+
briefops worker use quant-reviewer
|
|
1048
|
+
briefops prime --task "Start this task." --format codex --max-tokens 800
|
|
1049
|
+
briefops doctor --security
|
|
1050
|
+
briefops doctor --privacy
|
|
1051
|
+
```
|
|
1052
|
+
|
|
1053
|
+
Confirm:
|
|
1054
|
+
|
|
1055
|
+
- `shared-only` exports omit private local memory.
|
|
1056
|
+
- Memory and skill patches require human approval.
|
|
1057
|
+
- Explicit output paths do not overwrite without `--force`.
|
|
1058
|
+
- `.briefops/` is ignored or intentionally curated.
|
|
1059
|
+
- `npm pack --dry-run` includes docs, examples, plugins, dist, README, LICENSE, SECURITY, CONTRIBUTING, CODE_OF_CONDUCT, CHANGELOG.
|
|
1060
|
+
```
|
|
1061
|
+
|
|
1062
|
+
- [x] **Step 2: Add Dependabot**
|
|
1063
|
+
|
|
1064
|
+
Create `.github/dependabot.yml`:
|
|
1065
|
+
|
|
1066
|
+
```yaml
|
|
1067
|
+
version: 2
|
|
1068
|
+
updates:
|
|
1069
|
+
- package-ecosystem: "npm"
|
|
1070
|
+
directory: "/"
|
|
1071
|
+
schedule:
|
|
1072
|
+
interval: "weekly"
|
|
1073
|
+
open-pull-requests-limit: 5
|
|
1074
|
+
```
|
|
1075
|
+
|
|
1076
|
+
- [x] **Step 3: Add CI audit**
|
|
1077
|
+
|
|
1078
|
+
Modify `.github/workflows/ci.yml`:
|
|
1079
|
+
|
|
1080
|
+
```yaml
|
|
1081
|
+
- name: Audit dependencies
|
|
1082
|
+
run: npm audit --audit-level=moderate
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
Place after `npm ci` and before build.
|
|
1086
|
+
|
|
1087
|
+
- [x] **Step 4: Add release verify script if not already present**
|
|
1088
|
+
|
|
1089
|
+
Ensure `package.json` has:
|
|
1090
|
+
|
|
1091
|
+
```json
|
|
1092
|
+
"verify:release": "npm run build && npm test && npm audit --audit-level=moderate && npm pack --dry-run"
|
|
1093
|
+
```
|
|
1094
|
+
|
|
1095
|
+
- [x] **Step 5: Run release verification**
|
|
1096
|
+
|
|
1097
|
+
Run:
|
|
1098
|
+
|
|
1099
|
+
```bash
|
|
1100
|
+
npm run verify:release
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
Expected: PASS.
|
|
1104
|
+
|
|
1105
|
+
- [x] **Step 6: Commit**
|
|
1106
|
+
|
|
1107
|
+
```bash
|
|
1108
|
+
git add docs/release-checklist.md .github/dependabot.yml .github/workflows/ci.yml package.json
|
|
1109
|
+
git commit -m "chore: add release readiness checks"
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
---
|
|
1113
|
+
|
|
1114
|
+
## Task 7: Final Product Gate
|
|
1115
|
+
|
|
1116
|
+
**Files:**
|
|
1117
|
+
- Modify: `README.md`
|
|
1118
|
+
- Modify: `docs/roadmap.md`
|
|
1119
|
+
- Modify: `CHANGELOG.md`
|
|
1120
|
+
- Modify: `package.json`
|
|
1121
|
+
- Modify: `package-lock.json`
|
|
1122
|
+
|
|
1123
|
+
- [x] **Step 1: Add release status to README**
|
|
1124
|
+
|
|
1125
|
+
Add:
|
|
1126
|
+
|
|
1127
|
+
```markdown
|
|
1128
|
+
## Release Status
|
|
1129
|
+
|
|
1130
|
+
BriefOps is pre-1.0. The current release is intended for developers who want a local-first memory and context ledger for AI coding agents. The public API and file formats may change before 1.0, but the core safety principles are stable:
|
|
1131
|
+
|
|
1132
|
+
- local files first
|
|
1133
|
+
- no hosted service required
|
|
1134
|
+
- no required MCP server
|
|
1135
|
+
- human-approved memory
|
|
1136
|
+
- shared-only export controls
|
|
1137
|
+
- deterministic CLI behavior
|
|
1138
|
+
```
|
|
1139
|
+
|
|
1140
|
+
- [x] **Step 2: Update roadmap**
|
|
1141
|
+
|
|
1142
|
+
In `docs/roadmap.md`, make the next milestones:
|
|
1143
|
+
|
|
1144
|
+
```markdown
|
|
1145
|
+
## Near Term
|
|
1146
|
+
|
|
1147
|
+
- privacy doctor
|
|
1148
|
+
- explicit output overwrite protection
|
|
1149
|
+
- OSS trust docs
|
|
1150
|
+
- harness integration guide
|
|
1151
|
+
- release readiness CI
|
|
1152
|
+
|
|
1153
|
+
## Later
|
|
1154
|
+
|
|
1155
|
+
- optional cross-harness projection
|
|
1156
|
+
- richer eval fixtures for token savings
|
|
1157
|
+
- curated shared-memory export bundles
|
|
1158
|
+
- signed release artifacts
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
- [x] **Step 3: Update changelog**
|
|
1162
|
+
|
|
1163
|
+
Move completed items into `CHANGELOG.md`:
|
|
1164
|
+
|
|
1165
|
+
```markdown
|
|
1166
|
+
## 0.2.1-alpha.0
|
|
1167
|
+
|
|
1168
|
+
- Add OSS trust documents.
|
|
1169
|
+
- Add privacy doctor.
|
|
1170
|
+
- Protect explicit output paths from accidental overwrite.
|
|
1171
|
+
- Protect generated Codex plugin files from silent local-change overwrite.
|
|
1172
|
+
- Add harness integration guidance.
|
|
1173
|
+
- Add release readiness checks.
|
|
1174
|
+
```
|
|
1175
|
+
|
|
1176
|
+
- [x] **Step 4: Run complete verification**
|
|
1177
|
+
|
|
1178
|
+
Run:
|
|
1179
|
+
|
|
1180
|
+
```bash
|
|
1181
|
+
npm run verify:release
|
|
1182
|
+
npm test -- tests/output-safety.test.ts tests/privacy-doctor.test.ts tests/codex-plugin.test.ts tests/cli-workflow.test.ts tests/safety.test.ts
|
|
1183
|
+
git diff --check
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
Expected:
|
|
1187
|
+
|
|
1188
|
+
- build passes
|
|
1189
|
+
- all tests pass
|
|
1190
|
+
- audit passes or reports only accepted non-production dev warnings that are documented before release
|
|
1191
|
+
- package dry-run includes expected files
|
|
1192
|
+
- diff check has no whitespace errors
|
|
1193
|
+
|
|
1194
|
+
- [x] **Step 5: Manual smoke test**
|
|
1195
|
+
|
|
1196
|
+
Run:
|
|
1197
|
+
|
|
1198
|
+
```bash
|
|
1199
|
+
tmpdir="$(mktemp -d)"
|
|
1200
|
+
cd "$tmpdir"
|
|
1201
|
+
node /Users/simon/Documents/briefops/dist/index.js init
|
|
1202
|
+
node /Users/simon/Documents/briefops/dist/index.js codex install
|
|
1203
|
+
node /Users/simon/Documents/briefops/dist/index.js codex plugin install
|
|
1204
|
+
node /Users/simon/Documents/briefops/dist/index.js skill create risk-review
|
|
1205
|
+
node /Users/simon/Documents/briefops/dist/index.js project create atlas-q
|
|
1206
|
+
node /Users/simon/Documents/briefops/dist/index.js worker create quant-reviewer --project atlas-q --skills risk-review
|
|
1207
|
+
node /Users/simon/Documents/briefops/dist/index.js worker use quant-reviewer
|
|
1208
|
+
node /Users/simon/Documents/briefops/dist/index.js prime --task "Start this task." --format codex --max-tokens 800
|
|
1209
|
+
node /Users/simon/Documents/briefops/dist/index.js doctor --security
|
|
1210
|
+
node /Users/simon/Documents/briefops/dist/index.js doctor --privacy
|
|
1211
|
+
```
|
|
1212
|
+
|
|
1213
|
+
Expected:
|
|
1214
|
+
|
|
1215
|
+
- plugin bundle path is printed
|
|
1216
|
+
- prime output includes `Codex Operating Note`
|
|
1217
|
+
- security doctor passes or gives actionable warnings
|
|
1218
|
+
- privacy doctor warns if `.briefops/` is not ignored
|
|
1219
|
+
|
|
1220
|
+
- [x] **Step 6: Commit**
|
|
1221
|
+
|
|
1222
|
+
```bash
|
|
1223
|
+
git add README.md docs/roadmap.md CHANGELOG.md package.json package-lock.json
|
|
1224
|
+
git commit -m "docs: mark release candidate readiness"
|
|
1225
|
+
```
|
|
1226
|
+
|
|
1227
|
+
---
|
|
1228
|
+
|
|
1229
|
+
## Completion Criteria
|
|
1230
|
+
|
|
1231
|
+
This plan is complete only when:
|
|
1232
|
+
|
|
1233
|
+
1. Explicit user output paths never overwrite existing files unless `--force` is passed.
|
|
1234
|
+
2. Generated plugin files are idempotent and do not silently erase local edits.
|
|
1235
|
+
3. `briefops doctor --privacy` exists and checks gitignore, private exportable memory, and secret-like memory strings.
|
|
1236
|
+
4. OSS trust files exist: `SECURITY.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `CHANGELOG.md`.
|
|
1237
|
+
5. CI runs build, tests, audit, and npm package dry-run.
|
|
1238
|
+
6. Package metadata includes repository, bugs, homepage, and keywords.
|
|
1239
|
+
7. Harness integration docs clearly position BriefOps beside LazyCodex/OmO rather than as a competing harness.
|
|
1240
|
+
8. README clearly says BriefOps is pre-1.0 but ready for public alpha use.
|
|
1241
|
+
9. `npm run verify:release` passes.
|
|
1242
|
+
10. Manual smoke test passes.
|
|
1243
|
+
|
|
1244
|
+
---
|
|
1245
|
+
|
|
1246
|
+
## Self-Review
|
|
1247
|
+
|
|
1248
|
+
Spec coverage:
|
|
1249
|
+
- Open-source readiness: Tasks 1, 6, 7.
|
|
1250
|
+
- P2 overwrite issue: Task 2.
|
|
1251
|
+
- P2 plugin trust/permission surface: Task 4.
|
|
1252
|
+
- P3 stale/privacy local data edge: Task 3.
|
|
1253
|
+
- BriefOps edge versus harness agents: Task 5.
|
|
1254
|
+
- Product completion direction: Tasks 6 and 7.
|
|
1255
|
+
|
|
1256
|
+
Placeholder scan:
|
|
1257
|
+
- No `TBD`, `TODO`, or “implement later” placeholders.
|
|
1258
|
+
- Every code-changing task includes exact file paths, commands, and expected outcomes.
|
|
1259
|
+
|
|
1260
|
+
Type consistency:
|
|
1261
|
+
- `force?: boolean` is consistently threaded through explicit output paths.
|
|
1262
|
+
- `runPrivacyDoctor` returns `PrivacyDoctorResult`, matching CLI rendering.
|
|
1263
|
+
- Plugin changed-file behavior uses existing `pathExists`, `readTextFile`, and `writeTextFile`.
|
|
1264
|
+
|
|
1265
|
+
---
|
|
1266
|
+
|
|
1267
|
+
## Execution Options
|
|
1268
|
+
|
|
1269
|
+
Plan complete and saved to `docs/superpowers/plans/2026-06-08-briefops-oss-readiness.md`.
|
|
1270
|
+
|
|
1271
|
+
1. **Subagent-Driven (recommended)** - dispatch a fresh subagent per task, review between tasks, fast iteration.
|
|
1272
|
+
2. **Inline Execution** - execute tasks in this session using executing-plans, with checkpoints after each task.
|