outcrop 0.1.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/LICENSE +21 -0
- package/README.md +398 -0
- package/assets/logo.svg +19 -0
- package/dist/cli.js +4107 -0
- package/docs/AGENTS.md +39 -0
- package/docs/API.md +176 -0
- package/docs/SPEC.md +101 -0
- package/package.json +64 -0
package/docs/AGENTS.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Agent instructions for outcrop workspaces
|
|
2
|
+
|
|
3
|
+
[README](../README.md) · [SPEC](SPEC.md) · [API](API.md) · **AGENTS**
|
|
4
|
+
|
|
5
|
+
You are working in (or against) an outcrop workspace: a directory of plain markdown files that doubles as a task tracker and a docs site. The files are the source of truth. This page tells you how to work in one safely.
|
|
6
|
+
|
|
7
|
+
## Two ways to work
|
|
8
|
+
|
|
9
|
+
1. **HTTP API** (preferred when the board is running): read JSON, mutate with revision checks. See [API.md](API.md).
|
|
10
|
+
2. **Direct file edits**: read and write the markdown files yourself. Follow the format rules below exactly; the running board live-reloads on every change, and humans see your edits instantly.
|
|
11
|
+
|
|
12
|
+
## File format rules (non-negotiable)
|
|
13
|
+
|
|
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
|
+
- Valid `status`: `backlog | ready | in-progress | in-review | done | blocked`. Valid `priority`: `P1 | P2 | P3`.
|
|
16
|
+
- Task body sections in fixed order: `## Description`, `## Subtasks`, `## Acceptance criteria`, `## Test steps`, `## Notes`.
|
|
17
|
+
- Subtasks are `- [ ]` / `- [x]` checkboxes under `## Subtasks`. Do not reorder them: the API addresses checkboxes by index.
|
|
18
|
+
- 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.
|
|
19
|
+
- Cross-doc references are real relative markdown links (`[PRD](PRD.md)`), not code spans: links drive navigation and backlinks.
|
|
20
|
+
|
|
21
|
+
Full normative format: [SPEC.md](SPEC.md).
|
|
22
|
+
|
|
23
|
+
## Lifecycle gate
|
|
24
|
+
|
|
25
|
+
Implement and self-verify up to `in-review`. **Only a human moves a task to `done`**, after running its test steps. Never set `done` yourself unless the workspace's own docs explicitly say otherwise.
|
|
26
|
+
|
|
27
|
+
## Working with other agents (and humans)
|
|
28
|
+
|
|
29
|
+
- Every item carries a `rev` (file mtime at read). PATCH with the rev you read; a 409 means someone changed the file first: re-read, reconcile, retry or move on.
|
|
30
|
+
- To claim a task, set `status: in-progress` in one rev-checked PATCH. If you get 409, the task may already be claimed: pick another.
|
|
31
|
+
- Subscribe to `GET /sse` to hear about workspace changes instead of polling.
|
|
32
|
+
- If `BOARD_GIT_COMMIT=1` is set (or `gitCommit: true` in `.outcrop.json`), every board mutation becomes a git commit: keep your own direct-edit commits small and scoped so the history stays readable.
|
|
33
|
+
- The workspace may define its own columns: `GET /api/settings` for the valid `status` values before you invent one.
|
|
34
|
+
|
|
35
|
+
## Don'ts
|
|
36
|
+
|
|
37
|
+
- Don't rewrite frontmatter formatting you don't need to touch (keep diffs minimal; mutations are format-preserving).
|
|
38
|
+
- Don't invent new statuses, priorities, or frontmatter keys.
|
|
39
|
+
- Don't edit files under `board/`, `.git/`, or `node_modules/`.
|
package/docs/API.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# outcrop HTTP API
|
|
2
|
+
|
|
3
|
+
[README](../README.md) · [SPEC](SPEC.md) · **API** · [AGENTS](AGENTS.md)
|
|
4
|
+
|
|
5
|
+
Local server, default `http://localhost:4311`. No auth: it binds for local use. All JSON.
|
|
6
|
+
|
|
7
|
+
**Endpoints at a glance**
|
|
8
|
+
|
|
9
|
+
| Method | Path | Purpose |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `GET` | `/api/tasks` | All tasks |
|
|
12
|
+
| `POST` | `/api/tasks` | Create a task |
|
|
13
|
+
| `POST` | `/api/epics` | Create an epic |
|
|
14
|
+
| `POST` | `/api/docs` | Create a document |
|
|
15
|
+
| `GET` | `/api/epics` | All epics |
|
|
16
|
+
| `GET` | `/api/tasks/:id` | One item (task or epic) |
|
|
17
|
+
| `GET` | `/api/docs-search?q=` | Full-text doc search |
|
|
18
|
+
| `GET` | `/api/graph` | Document link graph |
|
|
19
|
+
| `GET` | `/api/items/:id/pane` | Rendered detail pane (HTML fragment) |
|
|
20
|
+
| `PATCH` | `/api/items/:id` | Mutate status, priority, or a checkbox |
|
|
21
|
+
| `PATCH` | `/api/docs?file=` | Toggle a checkbox in a document |
|
|
22
|
+
| `GET` | `/api/settings` | Workspace settings |
|
|
23
|
+
| `PUT` | `/api/settings` | Replace workspace settings |
|
|
24
|
+
| `GET` | `/sse` | Change stream |
|
|
25
|
+
|
|
26
|
+
## Read
|
|
27
|
+
|
|
28
|
+
### `GET /api/tasks`
|
|
29
|
+
|
|
30
|
+
All tasks. Each:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"id": "ST-001",
|
|
35
|
+
"title": "Engine crate and index",
|
|
36
|
+
"epic": "E01",
|
|
37
|
+
"status": "in-progress",
|
|
38
|
+
"priority": "P1",
|
|
39
|
+
"depends_on": ["ST-000"],
|
|
40
|
+
"created": "2026-07-07",
|
|
41
|
+
"body": "## Description\n...",
|
|
42
|
+
"file": "ST-001-engine-crate-and-index.md",
|
|
43
|
+
"rev": "1784910833019.7715",
|
|
44
|
+
"subtasksDone": 2,
|
|
45
|
+
"subtasksTotal": 5
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### `GET /api/epics`
|
|
50
|
+
|
|
51
|
+
All epics: `id`, `title`, `milestone`, `status`, `created`, `body`, `file`, `rev`.
|
|
52
|
+
|
|
53
|
+
### `GET /api/tasks/:id`
|
|
54
|
+
|
|
55
|
+
One item by id (task or epic). 404 if unknown.
|
|
56
|
+
|
|
57
|
+
### `GET /api/docs-search?q=term`
|
|
58
|
+
|
|
59
|
+
Full-text search over all docs: `[{ "file": "PRD.md", "count": 16, "snippets": ["..."] }]`, sorted by count.
|
|
60
|
+
|
|
61
|
+
## Write
|
|
62
|
+
|
|
63
|
+
### `PATCH /api/items/:id`
|
|
64
|
+
|
|
65
|
+
Body: any of
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"status": "in-review",
|
|
70
|
+
"priority": "P2",
|
|
71
|
+
"checkbox": { "index": 0, "checked": true },
|
|
72
|
+
"rev": "1784910833019.7715"
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- `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
|
+
- Mutations are format-preserving: only the targeted frontmatter line or checkbox is rewritten.
|
|
78
|
+
- With `BOARD_GIT_COMMIT=1`, each successful PATCH becomes a git commit (`ST-001: ready -> in-progress via board`).
|
|
79
|
+
|
|
80
|
+
Responses:
|
|
81
|
+
|
|
82
|
+
| Status | Meaning | Body |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| 200 | applied | `{ "ok": true, "rev": "<new rev>" }` |
|
|
85
|
+
| 200 (no-op) | nothing changed | `{ "ok": true, "rev": "...", "unchanged": true }` |
|
|
86
|
+
| 400 | invalid status/priority/checkbox/JSON | `{ "error": "..." }` |
|
|
87
|
+
| 404 | unknown id | `{ "error": "..." }` |
|
|
88
|
+
| 409 | stale rev: file changed since read | `{ "error": "stale: ..." }` |
|
|
89
|
+
|
|
90
|
+
On 409: re-GET the item, reconcile, retry with the new rev.
|
|
91
|
+
|
|
92
|
+
### `PATCH /api/docs?file=REL.md`
|
|
93
|
+
|
|
94
|
+
Toggle a checkbox in a plain document, which has no id to address it by:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
curl -X PATCH 'localhost:4311/api/docs?file=NOTES.md' -H 'content-type: application/json' \
|
|
98
|
+
-d '{"checkbox":{"index":2,"checked":true},"rev":"<rev>"}'
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
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
|
+
|
|
103
|
+
### `POST /api/tasks`, `POST /api/epics`, `POST /api/docs`
|
|
104
|
+
|
|
105
|
+
Create a file. The server assigns the id and the filename, so a create cannot collide with what is already on disk:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
curl -X POST localhost:4311/api/tasks -H 'content-type: application/json' \
|
|
109
|
+
-d '{"title":"Wire up password reset","epic":"E01","status":"ready","priority":"P1",
|
|
110
|
+
"body":"Reset by email.","subtasks":"send the mail\nverify the token"}'
|
|
111
|
+
# -> 201 {"ok":true,"id":"ST-004","file":"tasks/ST-004-wire-up-password-reset.md"}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- `title` (required): folded to a single line, 200 characters max. The filename slug is derived from it.
|
|
115
|
+
- `body`: markdown for the `## Description` section.
|
|
116
|
+
- Tasks also take `epic` (must exist), `status` (must be a current column), `priority` (`P1` to `P3`), and `subtasks` (one per line; `-` and `- [ ]` prefixes are tolerated and normalized).
|
|
117
|
+
- Docs take `path` instead of getting a generated name: workspace-relative, `.md`, at most four segments, each a plain name. Missing folders are created.
|
|
118
|
+
|
|
119
|
+
`400` for a bad title, status, priority, epic, or path. `409` if the target file already exists. A create never overwrites, and the write uses `wx` so a file appearing mid-request is a conflict rather than a clobber. Ids come from the highest existing number plus one, per series (`ST-###`, `E##`).
|
|
120
|
+
|
|
121
|
+
Paths are refused rather than sanitized: `..`, absolute paths, dotfiles, anything outside the workspace, and the excluded directories (`.git`, `.claude`, `board`, `node_modules`) are all `400`.
|
|
122
|
+
|
|
123
|
+
### `GET /api/settings`, `PUT /api/settings`
|
|
124
|
+
|
|
125
|
+
Workspace settings, persisted as `.outcrop.json` at the workspace root. `PUT` replaces the whole object (no merge) and returns the normalized result:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{ "title": "Payments rewrite", "views": ["board", "docs", "graph"], "columns": ["backlog", "ready", "done"], "gitCommit": false }
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Fields are optional and normalized rather than rejected: `columns` entries are lowercased and slugged, non-slug and duplicate entries are dropped, and an empty list falls back to the default six. `views` is filtered to `board`/`docs`/`graph` and returned in that order; an omitted or all-unrecognized list falls back to all three. A blank `title` falls back to the workspace directory name. `gitCommit` must be boolean `true` to enable; `BOARD_GIT_COMMIT=1` forces it on regardless. A successful `PUT` fires an SSE `change`.
|
|
132
|
+
|
|
133
|
+
The one rejection: a `views` list that is present but names no known view is a `400`, not a silent reset. Serving nothing is never what the caller meant, and quietly turning everything back on would hide the mistake.
|
|
134
|
+
|
|
135
|
+
Disabling a view takes effect immediately: its route `302`s to the first view still enabled (`views` order is `board`, `docs`, `graph`). The API and `/sse` are unaffected either way.
|
|
136
|
+
|
|
137
|
+
No `rev` check here: settings are a small last-write-wins file, not a task.
|
|
138
|
+
|
|
139
|
+
## Events
|
|
140
|
+
|
|
141
|
+
### `GET /sse`
|
|
142
|
+
|
|
143
|
+
`text/event-stream`. One message type: `data: change`, debounced 120ms, fired on any markdown change in the workspace (from the board, an agent, or an editor). Re-fetch what you care about on receipt. Keep-alive comment pings every 25s.
|
|
144
|
+
|
|
145
|
+
Open one per tab and keep it. Browsers cap concurrent connections per origin (six on HTTP/1.1) and are slow to release a closed page's socket, so a client that reconnects on every navigation can starve itself of connections. The docs viewer navigates in place for exactly this reason. The server also caps the client set and drops the oldest connection past the limit; a dropped EventSource reconnects on its own.
|
|
146
|
+
|
|
147
|
+
## HTML
|
|
148
|
+
|
|
149
|
+
`GET /` board, `GET /docs?file=REL.md` docs viewer, `GET /graph` link graph. Same data, human-shaped. Any of them `302`s to the first enabled view when disabled in `views`.
|
|
150
|
+
|
|
151
|
+
Both carry an `ETag` over their own rendered output and honour `If-None-Match` with a `304`. The board's live-reload uses this: a write anywhere in the workspace broadcasts a `change`, but most writes leave a given page byte-identical, so the client revalidates and does no work. Send the header yourself (with `cache: "no-store"` from `fetch`) if you want to see the `304` rather than have the browser replay it as a `200`.
|
|
152
|
+
|
|
153
|
+
`GET /styles.css` is the precompiled stylesheet, served `immutable` when requested with the `?v=` hash the pages link. HTML, CSS, and JSON responses are gzipped when the request allows it; `/sse` never is.
|
|
154
|
+
|
|
155
|
+
### `GET /api/graph`
|
|
156
|
+
|
|
157
|
+
The document link graph, one node per markdown file in the workspace:
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"nodes": [{ "id": "docs/SPEC.md", "label": "Workspace format", "group": "docs", "deg": 7 }],
|
|
162
|
+
"links": [{ "source": "README.md", "target": "docs/SPEC.md" }]
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
- `id`: workspace-relative path, the same value `/docs?file=` takes.
|
|
167
|
+
- `label`: frontmatter `title` if there is one, otherwise the filename without `.md`.
|
|
168
|
+
- `group`: the folder it came from (`planner` for workspace-root files).
|
|
169
|
+
- `deg`: how many edges touch it, counting both directions.
|
|
170
|
+
- `links`: deduplicated and directed source to target. An edge is any markdown link to another `.md`, a bare `ST-###` / `E##` mention, an `epic:` and a `depends_on:` entry, which are the same relations the backlink index is built from. Self-links are dropped, and every endpoint is guaranteed to be a node in `nodes`.
|
|
171
|
+
|
|
172
|
+
Cached until the workspace changes. This is what the `/graph` view fetches; the layout is computed in the browser, so nothing about node positions is server state.
|
|
173
|
+
|
|
174
|
+
### `GET /api/items/:id/pane`
|
|
175
|
+
|
|
176
|
+
The task or epic detail pane as an HTML fragment, the same markup the board's slide-over shows. Panes are not inlined in the board page (with a few hundred tasks they were ~80% of it), so the UI fetches this on click. `404` for an unknown id. No `ETag`: it's small and the client caches it until the next workspace change.
|
package/docs/SPEC.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# outcrop workspace format (v0)
|
|
2
|
+
|
|
3
|
+
[README](../README.md) · **SPEC** · [API](API.md) · [AGENTS](AGENTS.md)
|
|
4
|
+
|
|
5
|
+
Normative spec for the on-disk format outcrop reads and writes. Any tool or agent that follows this spec interoperates with outcrop without going through it.
|
|
6
|
+
|
|
7
|
+
> Read this if you're writing files directly (an agent, a script, a generator). If you only want to run the board, [README.md](../README.md) is enough.
|
|
8
|
+
|
|
9
|
+
## Workspace layout
|
|
10
|
+
|
|
11
|
+
A workspace is a directory containing:
|
|
12
|
+
|
|
13
|
+
| Path | Required | Contents |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `tasks/` | no | One markdown file per task: `ST-###-slug.md`. Without it the board is simply empty; set `views` to `["docs"]` in `.outcrop.json` to hide it |
|
|
16
|
+
| `epics/` | no | One markdown file per epic: `E##-slug.md` |
|
|
17
|
+
| `*.md` (root) | no | Docs (README, PRD, architecture, ...), shown in the docs viewer under the `planner` folder. Raw HTML is rendered for an allowlisted subset of tags and attributes; anything else is escaped and displayed as text |
|
|
18
|
+
| any other dir of `.md` | no | Doc groups (e.g. `decisions/`), each a foldable folder in the docs viewer |
|
|
19
|
+
| `.outcrop.json` | no | Workspace settings: `title`, `views`, `columns`, `gitCommit`. Absent = defaults. See [API](API.md#get-apisettings-put-apisettings) |
|
|
20
|
+
|
|
21
|
+
Excluded from doc indexing: `.git/`, `.claude/`, `board/`, `node_modules/`, dot-directories.
|
|
22
|
+
|
|
23
|
+
## Frontmatter
|
|
24
|
+
|
|
25
|
+
YAML-ish, deliberately restricted so any language can parse it with a few lines:
|
|
26
|
+
|
|
27
|
+
- Delimited by `---` lines at the top of the file.
|
|
28
|
+
- Flat `key: value` pairs only. No nesting, no multiline values, no quoting semantics: the value is the raw string after the first `:`.
|
|
29
|
+
- Lists are inline: `depends_on: [ST-001, ST-002]` (comma-separated, brackets).
|
|
30
|
+
- Dates are `YYYY-MM-DD`.
|
|
31
|
+
|
|
32
|
+
### Task keys
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
id: ST-001 # required, unique, grammar: ST-\d{3}
|
|
36
|
+
title: Short imperative title
|
|
37
|
+
epic: E01 # owning epic id
|
|
38
|
+
status: ready # default set: backlog | ready | in-progress | in-review | done | blocked
|
|
39
|
+
# a workspace can redefine this set via "columns" in .outcrop.json
|
|
40
|
+
priority: P1 # P1 | P2 | P3
|
|
41
|
+
depends_on: [] # list of task ids
|
|
42
|
+
created: 2026-07-07
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Missing keys default to: `status: backlog`, `priority: P3`, empty strings/lists.
|
|
46
|
+
|
|
47
|
+
### Epic keys
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
id: E01 # required, unique, grammar: E\d{2}
|
|
51
|
+
title: Epic title
|
|
52
|
+
milestone: M0
|
|
53
|
+
status: active # free-form for epics
|
|
54
|
+
created: 2026-07-07
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Task body
|
|
58
|
+
|
|
59
|
+
Sections in fixed order, all optional but ordered:
|
|
60
|
+
|
|
61
|
+
```markdown
|
|
62
|
+
## Description
|
|
63
|
+
## Subtasks
|
|
64
|
+
## Acceptance criteria
|
|
65
|
+
## Test steps
|
|
66
|
+
## Notes
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Subtasks are checkbox list items under `## Subtasks`:
|
|
70
|
+
|
|
71
|
+
```markdown
|
|
72
|
+
- [ ] not done
|
|
73
|
+
- [x] done
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Checkbox index (0-based, top to bottom, skipping fenced code blocks) is the address used by the mutation API. Reordering checkboxes changes addresses: avoid it.
|
|
77
|
+
|
|
78
|
+
## References and links
|
|
79
|
+
|
|
80
|
+
- Bare `ST-###` or `E##` anywhere in a body is an auto-linked mention.
|
|
81
|
+
- `depends_on` and `epic` frontmatter create typed graph edges.
|
|
82
|
+
- Relative markdown links between docs (`[PRD](PRD.md)`) drive docs navigation and backlinks. Code spans do not.
|
|
83
|
+
- Backlinks are derived, never stored.
|
|
84
|
+
|
|
85
|
+
## Timeline rendering
|
|
86
|
+
|
|
87
|
+
A doc renders a Gantt-style timeline above its body when its frontmatter has `render: timeline`, or the file is named `TIMELINE.md`. The first markdown table with `start` and `end` columns (dates as `YYYY-MM-DD`) is used; optional columns: `id`/`milestone`, `title`, `status` (`done | active | pending`), `epic`.
|
|
88
|
+
|
|
89
|
+
## Revisions and concurrency
|
|
90
|
+
|
|
91
|
+
An item's `rev` is its file's mtime in milliseconds, as a string. Writers must:
|
|
92
|
+
|
|
93
|
+
1. Read the file (capturing rev).
|
|
94
|
+
2. Mutate format-preservingly (change only the line/value being changed).
|
|
95
|
+
3. Reject their own write if the file's rev changed since read.
|
|
96
|
+
|
|
97
|
+
outcrop's HTTP API enforces this with 409 responses. Direct-editing agents should follow the same read-check-write discipline when a board is live.
|
|
98
|
+
|
|
99
|
+
## Lifecycle
|
|
100
|
+
|
|
101
|
+
`backlog -> ready -> in-progress -> in-review -> done`, plus `blocked` from anywhere. Convention: automated agents stop at `in-review`; a human moves items to `done` after running the task's test steps.
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "outcrop",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Serve a folder of markdown tasks and docs as a live kanban board, docs site, and agent API. AI-native, zero-config, files are the database.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"outcrop": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"assets/logo.svg",
|
|
12
|
+
"docs/API.md",
|
|
13
|
+
"docs/SPEC.md",
|
|
14
|
+
"docs/AGENTS.md",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build:css": "tailwindcss -c tailwind.config.js -i src/styles.css -o src/styles.gen.css --minify",
|
|
19
|
+
"build": "bun run build:css && bun run build:client && bun build src/cli.ts --target=node --outfile=dist/cli.js --banner='#!/usr/bin/env node'",
|
|
20
|
+
"lint": "oxlint --deny-warnings src/",
|
|
21
|
+
"lint:fix": "oxlint --fix --deny-warnings src/",
|
|
22
|
+
"fmt": "oxfmt src/",
|
|
23
|
+
"fmt:check": "oxfmt --check src/",
|
|
24
|
+
"typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p src/client/tsconfig.json",
|
|
25
|
+
"test": "bun test",
|
|
26
|
+
"check": "bun run fmt:check && bun run lint && bun run typecheck && bun run test",
|
|
27
|
+
"prepare": "git config core.hooksPath .githooks || true",
|
|
28
|
+
"prepublishOnly": "bun run check && bun run build",
|
|
29
|
+
"build:client": "bun build src/client/head.ts src/client/board.ts src/client/docs.ts src/client/graph.ts --target=browser --format=iife --outdir=src/generated"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"kanban",
|
|
36
|
+
"markdown",
|
|
37
|
+
"tasks",
|
|
38
|
+
"local-first",
|
|
39
|
+
"board",
|
|
40
|
+
"planning",
|
|
41
|
+
"ai",
|
|
42
|
+
"agents",
|
|
43
|
+
"mcp",
|
|
44
|
+
"workspace"
|
|
45
|
+
],
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"author": "amirulhakiim",
|
|
48
|
+
"homepage": "https://github.com/amirulhakiim/outcrop#readme",
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/amirulhakiim/outcrop/issues"
|
|
51
|
+
},
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/amirulhakiim/outcrop.git"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/bun": "^1.3.14",
|
|
58
|
+
"@types/node": "^26.1.2",
|
|
59
|
+
"oxfmt": "^0.62.0",
|
|
60
|
+
"oxlint": "^1.77.0",
|
|
61
|
+
"tailwindcss": "^3.4.19",
|
|
62
|
+
"typescript": "^7.0.2"
|
|
63
|
+
}
|
|
64
|
+
}
|