outcrop 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/cli.js +1137 -270
- package/docs/AGENTS.md +1 -0
- package/docs/API.md +36 -1
- package/docs/SPEC.md +9 -0
- package/package.json +1 -1
package/docs/AGENTS.md
CHANGED
|
@@ -13,6 +13,7 @@ You are working in (or against) an outcrop workspace: a directory of plain markd
|
|
|
13
13
|
|
|
14
14
|
- Frontmatter is flat `key: value` only: no nesting, no multiline values. Lists are inline (`depends_on: [ST-001, ST-002]`). Dates are `YYYY-MM-DD`.
|
|
15
15
|
- Valid `status`: `backlog | ready | in-progress | in-review | done | blocked`. Valid `priority`: `P1 | P2 | P3`.
|
|
16
|
+
- `order` is a number a human set by dragging a card. Leave it alone. Omit it on new tasks; never invent one to push your own work up the board.
|
|
16
17
|
- Task body sections in fixed order: `## Description`, `## Subtasks`, `## Acceptance criteria`, `## Test steps`, `## Notes`.
|
|
17
18
|
- Subtasks are `- [ ]` / `- [x]` checkboxes under `## Subtasks`. Do not reorder them: the API addresses checkboxes by index.
|
|
18
19
|
- IDs: tasks `ST-###`, epics `E##`. Filenames: `ST-###-slug.md`, `E##-slug.md`. Bare ID mentions anywhere in the workspace auto-link; `depends_on` and `epic` create graph edges.
|
package/docs/API.md
CHANGED
|
@@ -68,13 +68,29 @@ Body: any of
|
|
|
68
68
|
{
|
|
69
69
|
"status": "in-review",
|
|
70
70
|
"priority": "P2",
|
|
71
|
+
"epic": "E02",
|
|
72
|
+
"body": "## Subtasks\n\n- [ ] rewritten\n",
|
|
71
73
|
"checkbox": { "index": 0, "checked": true },
|
|
72
74
|
"rev": "1784910833019.7715"
|
|
73
75
|
}
|
|
74
76
|
```
|
|
75
77
|
|
|
78
|
+
- `body` replaces everything after the frontmatter. The frontmatter block is left byte-for-byte alone, so a body edit can never change an id, status, or rank. Over 1,000,000 characters is a `413`, never a silent truncation.
|
|
79
|
+
|
|
80
|
+
Plus exactly one of these, to move the card within its column group (see [SPEC: Ordering](SPEC.md#ordering)):
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{ "move": "up" } // or "down": swap with the neighbour
|
|
84
|
+
{ "before": "ST-004" } // place immediately above that task
|
|
85
|
+
{ "after": "ST-004" } // place immediately below it
|
|
86
|
+
```
|
|
87
|
+
|
|
76
88
|
- `rev` (recommended, from a prior GET): request is rejected if the file changed since. Omitting `rev` skips the check: last write wins. Multi-agent setups must send it.
|
|
77
89
|
- Mutations are format-preserving: only the targeted frontmatter line or checkbox is rewritten.
|
|
90
|
+
- A move is resolved against the destination, so `status` and `epic` in the same request are applied first: `{"status": "done", "before": "ST-004"}` moves the card to `done` and places it above ST-004 there.
|
|
91
|
+
- `epic` must name an epic that exists, or the request is a 400. `""` clears it.
|
|
92
|
+
- A move that would run past either end of the group is a no-op, not an error.
|
|
93
|
+
- **A move can write more than one file.** Placing a card usually rewrites only its own `order`, but the first move in a never-ordered group stamps ranks on its siblings, and a group that runs out of room between two ranks is respaced. `rev` guards the named task only — the sibling writes are not checked.
|
|
78
94
|
- With `BOARD_GIT_COMMIT=1`, each successful PATCH becomes a git commit (`ST-001: ready -> in-progress via board`).
|
|
79
95
|
|
|
80
96
|
Responses:
|
|
@@ -83,12 +99,22 @@ Responses:
|
|
|
83
99
|
|---|---|---|
|
|
84
100
|
| 200 | applied | `{ "ok": true, "rev": "<new rev>" }` |
|
|
85
101
|
| 200 (no-op) | nothing changed | `{ "ok": true, "rev": "...", "unchanged": true }` |
|
|
86
|
-
| 400 | invalid status/priority/checkbox/JSON | `{ "error": "..." }` |
|
|
102
|
+
| 400 | invalid status/priority/epic/checkbox/JSON, or a `before`/`after` target not in the group | `{ "error": "..." }` |
|
|
87
103
|
| 404 | unknown id | `{ "error": "..." }` |
|
|
88
104
|
| 409 | stale rev: file changed since read | `{ "error": "stale: ..." }` |
|
|
89
105
|
|
|
90
106
|
On 409: re-GET the item, reconcile, retry with the new rev.
|
|
91
107
|
|
|
108
|
+
### `GET /api/docs?file=REL.md`
|
|
109
|
+
|
|
110
|
+
The markdown source of a document, which is what `/docs` renders rather than serves:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{ "file": "NOTES.md", "body": "# Notes\n\n…", "rev": "1784910833019.7715" }
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`body` excludes the frontmatter block, matching what `PATCH` writes back. `404` for an unknown or out-of-workspace file. This is what the in-page editor reads.
|
|
117
|
+
|
|
92
118
|
### `PATCH /api/docs?file=REL.md`
|
|
93
119
|
|
|
94
120
|
Toggle a checkbox in a plain document, which has no id to address it by:
|
|
@@ -98,6 +124,15 @@ curl -X PATCH 'localhost:4311/api/docs?file=NOTES.md' -H 'content-type: applicat
|
|
|
98
124
|
-d '{"checkbox":{"index":2,"checked":true},"rev":"<rev>"}'
|
|
99
125
|
```
|
|
100
126
|
|
|
127
|
+
Or replace the whole body:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
curl -X PATCH 'localhost:4311/api/docs?file=NOTES.md' -H 'content-type: application/json' \
|
|
131
|
+
-d '{"body":"# Notes\n\nRewritten.\n","rev":"<rev>"}'
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`body` replaces everything after the frontmatter, which is preserved exactly. Over 1,000,000 characters is a `413`. A body identical to what is on disk is a `200` with `unchanged: true` and no write, so an editor that autosaves on a timer costs nothing when nothing was typed.
|
|
135
|
+
|
|
101
136
|
Checkboxes only — a document is not a task, so there is no status or priority to set. `index` counts `- [ ]` / `- [x]` lines from the top of the file, skipping fenced code blocks, exactly as it does for a task. `rev` is optional and behaves as it does elsewhere: supply it and a concurrent change is a `409`. `404` for an unknown or out-of-workspace file, `400` for an index that does not exist.
|
|
102
137
|
|
|
103
138
|
### `POST /api/tasks`, `POST /api/epics`, `POST /api/docs`
|
package/docs/SPEC.md
CHANGED
|
@@ -38,12 +38,21 @@ epic: E01 # owning epic id
|
|
|
38
38
|
status: ready # default set: backlog | ready | in-progress | in-review | done | blocked
|
|
39
39
|
# a workspace can redefine this set via "columns" in .outcrop.json
|
|
40
40
|
priority: P1 # P1 | P2 | P3
|
|
41
|
+
order: 150 # optional manual rank inside its column and epic; see below
|
|
41
42
|
depends_on: [] # list of task ids
|
|
42
43
|
created: 2026-07-07
|
|
43
44
|
```
|
|
44
45
|
|
|
45
46
|
Missing keys default to: `status: backlog`, `priority: P3`, empty strings/lists.
|
|
46
47
|
|
|
48
|
+
#### Ordering
|
|
49
|
+
|
|
50
|
+
The board draws each column grouped by `epic`, and each group sorted by `order` ascending. A task with no `order` sorts after every task that has one, falling back to priority then id. A workspace where nobody has reordered anything therefore looks exactly as it did before this key existed, and writing `order` is never required.
|
|
51
|
+
|
|
52
|
+
`order` is any finite number, and the gaps are deliberate: the board writes ranks spaced by 100 so an insert between two cards is a midpoint and rewrites one file. When two neighbours are closer than `0.001` the whole group is respaced to `100, 200, 300, …` in one pass.
|
|
53
|
+
|
|
54
|
+
Ranks are scoped to one column of one epic. The same value may appear in another column or under another epic without meaning anything. Moving a task between columns or epics leaves its `order` valid only for where it landed, so the board rewrites it on arrival.
|
|
55
|
+
|
|
47
56
|
### Epic keys
|
|
48
57
|
|
|
49
58
|
```yaml
|
package/package.json
CHANGED