@dtoolkit/dwork 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 +172 -0
- package/dist/cli/configure.d.ts +2 -0
- package/dist/cli/configure.d.ts.map +1 -0
- package/dist/cli/configure.js +83 -0
- package/dist/cli/configure.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +76 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +4 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +143 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/keys.d.ts +11 -0
- package/dist/cli/keys.d.ts.map +1 -0
- package/dist/cli/keys.js +85 -0
- package/dist/cli/keys.js.map +1 -0
- package/dist/cli/start.d.ts +2 -0
- package/dist/cli/start.d.ts.map +1 -0
- package/dist/cli/start.js +53 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/cli/status.d.ts +2 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +36 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/sync.d.ts +4 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +38 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/core/config.d.ts +21 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +31 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/db.d.ts +4 -0
- package/dist/core/db.d.ts.map +1 -0
- package/dist/core/db.js +90 -0
- package/dist/core/db.js.map +1 -0
- package/dist/core/indexer.d.ts +9 -0
- package/dist/core/indexer.d.ts.map +1 -0
- package/dist/core/indexer.js +145 -0
- package/dist/core/indexer.js.map +1 -0
- package/dist/core/models.d.ts +113 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +53 -0
- package/dist/core/models.js.map +1 -0
- package/dist/core/parser.d.ts +20 -0
- package/dist/core/parser.d.ts.map +1 -0
- package/dist/core/parser.js +126 -0
- package/dist/core/parser.js.map +1 -0
- package/dist/core/templates.d.ts +5 -0
- package/dist/core/templates.d.ts.map +1 -0
- package/dist/core/templates.js +84 -0
- package/dist/core/templates.js.map +1 -0
- package/dist/dashboard/index.html +1127 -0
- package/dist/dashboard/logo-dwork-complete.png +0 -0
- package/dist/dashboard/logo-dwork.png +0 -0
- package/dist/dashboard/server.d.ts +2 -0
- package/dist/dashboard/server.d.ts.map +1 -0
- package/dist/dashboard/server.js +27 -0
- package/dist/dashboard/server.js.map +1 -0
- package/dist/mcp/server.d.ts +5 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +242 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +63 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/routes/docs.d.ts +3 -0
- package/dist/server/routes/docs.d.ts.map +1 -0
- package/dist/server/routes/docs.js +53 -0
- package/dist/server/routes/docs.js.map +1 -0
- package/dist/server/routes/health.d.ts +3 -0
- package/dist/server/routes/health.d.ts.map +1 -0
- package/dist/server/routes/health.js +27 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/keys.d.ts +3 -0
- package/dist/server/routes/keys.d.ts.map +1 -0
- package/dist/server/routes/keys.js +58 -0
- package/dist/server/routes/keys.js.map +1 -0
- package/dist/server/routes/overview.d.ts +3 -0
- package/dist/server/routes/overview.d.ts.map +1 -0
- package/dist/server/routes/overview.js +12 -0
- package/dist/server/routes/overview.js.map +1 -0
- package/dist/server/routes/permissions.d.ts +3 -0
- package/dist/server/routes/permissions.d.ts.map +1 -0
- package/dist/server/routes/permissions.js +9 -0
- package/dist/server/routes/permissions.js.map +1 -0
- package/dist/server/routes/projects.d.ts +3 -0
- package/dist/server/routes/projects.d.ts.map +1 -0
- package/dist/server/routes/projects.js +50 -0
- package/dist/server/routes/projects.js.map +1 -0
- package/dist/server/routes/search.d.ts +3 -0
- package/dist/server/routes/search.d.ts.map +1 -0
- package/dist/server/routes/search.js +10 -0
- package/dist/server/routes/search.js.map +1 -0
- package/dist/server/routes/sync.d.ts +3 -0
- package/dist/server/routes/sync.d.ts.map +1 -0
- package/dist/server/routes/sync.js +11 -0
- package/dist/server/routes/sync.js.map +1 -0
- package/dist/server/routes/tasks.d.ts +3 -0
- package/dist/server/routes/tasks.d.ts.map +1 -0
- package/dist/server/routes/tasks.js +45 -0
- package/dist/server/routes/tasks.js.map +1 -0
- package/dist/service/docs.d.ts +26 -0
- package/dist/service/docs.d.ts.map +1 -0
- package/dist/service/docs.js +137 -0
- package/dist/service/docs.js.map +1 -0
- package/dist/service/overview.d.ts +18 -0
- package/dist/service/overview.d.ts.map +1 -0
- package/dist/service/overview.js +46 -0
- package/dist/service/overview.js.map +1 -0
- package/dist/service/projects.d.ts +34 -0
- package/dist/service/projects.d.ts.map +1 -0
- package/dist/service/projects.js +99 -0
- package/dist/service/projects.js.map +1 -0
- package/dist/service/search.d.ts +13 -0
- package/dist/service/search.d.ts.map +1 -0
- package/dist/service/search.js +59 -0
- package/dist/service/search.js.map +1 -0
- package/dist/service/sync.d.ts +9 -0
- package/dist/service/sync.d.ts.map +1 -0
- package/dist/service/sync.js +95 -0
- package/dist/service/sync.js.map +1 -0
- package/dist/service/tasks.d.ts +40 -0
- package/dist/service/tasks.d.ts.map +1 -0
- package/dist/service/tasks.js +156 -0
- package/dist/service/tasks.js.map +1 -0
- package/dist/service/utils.d.ts +2 -0
- package/dist/service/utils.d.ts.map +1 -0
- package/dist/service/utils.js +5 -0
- package/dist/service/utils.js.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Iván Campillo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="../../logo.png" alt="dtoolkit" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">@dtoolkit/dwork</h1>
|
|
6
|
+
<p align="center">AI-native, MD-driven project manager</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://www.npmjs.com/package/@dtoolkit/dwork"><img src="https://img.shields.io/npm/v/@dtoolkit/dwork.svg" alt="npm"></a>
|
|
10
|
+
<a href="../../LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License"></a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
dwork manages your projects using Markdown files as the source of truth. Tasks live in `BACKLOG.md`, documentation in numbered `docs/` files, all with YAML frontmatter. SQLite + FTS5 provides fast search and indexing — but the `.md` files are always the canonical source.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g @dtoolkit/dwork
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Initialize (creates config, database, optional first project)
|
|
27
|
+
dwork init
|
|
28
|
+
|
|
29
|
+
# Start the server (REST API + MCP on :7881)
|
|
30
|
+
dwork start
|
|
31
|
+
|
|
32
|
+
# Check status
|
|
33
|
+
dwork status
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## How It Works
|
|
37
|
+
|
|
38
|
+
Each project gets 4 mandatory Markdown files:
|
|
39
|
+
|
|
40
|
+
| File | Purpose |
|
|
41
|
+
|------|---------|
|
|
42
|
+
| `README.md` | Project overview |
|
|
43
|
+
| `TECH.md` | Technical stack and architecture |
|
|
44
|
+
| `ROADMAP.md` | Current, next, and future plans |
|
|
45
|
+
| `BACKLOG.md` | Tasks organized by priority (P0-P3) |
|
|
46
|
+
|
|
47
|
+
Tasks in `BACKLOG.md` use inline metadata:
|
|
48
|
+
|
|
49
|
+
```markdown
|
|
50
|
+
## P0
|
|
51
|
+
- [ ] Migrate auth to Supabase {deadline: 2026-06-01, estimate: 2d, type: task, status: doing}
|
|
52
|
+
|
|
53
|
+
## P1
|
|
54
|
+
- [ ] Redesign rankings {type: feature, estimate: 1w, detail: 001_rankings-redesign.md}
|
|
55
|
+
|
|
56
|
+
## Done
|
|
57
|
+
- [x] Setup project {type: task}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Additional docs go in `docs/` with auto-numbered filenames:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
docs/001_rankings-redesign.md
|
|
64
|
+
docs/002_auth-migration.md
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Architecture
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
Service Layer (all business logic)
|
|
71
|
+
├── CLI (commander)
|
|
72
|
+
├── REST API (Fastify, :7881)
|
|
73
|
+
├── MCP Server (streamable HTTP, :7881/mcp)
|
|
74
|
+
├── SDK Client (@dtoolkit/sdk)
|
|
75
|
+
└── Dashboard (React 18, :7882)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The service layer is the single source of business logic. All interfaces are thin wrappers.
|
|
79
|
+
|
|
80
|
+
## Dashboard
|
|
81
|
+
|
|
82
|
+
Web dashboard on port `7882` (API port + 1). Single-file React 18 app — CDN deps, no build step.
|
|
83
|
+
|
|
84
|
+
- **Overview** — default view. Stats (projects, tasks, docs) + global kanban with all tasks from every project. Drag & drop to change status.
|
|
85
|
+
- **Projects** — project list with task status badges. Click to open project detail.
|
|
86
|
+
- **Project detail** — three tabs:
|
|
87
|
+
- **Kanban** — per-project board with drag & drop (desktop + touch mobile). Click a card to open task detail modal.
|
|
88
|
+
- **Tasks** — table view with status, priority, type, estimate, deadline.
|
|
89
|
+
- **Docs** — file tree with collapsible directories. Click a file to edit its Markdown content inline.
|
|
90
|
+
- **Task detail modal** — opens on card click. Shows task metadata. If a detail doc is linked, shows an inline Markdown editor. If not, an "Add Detail" button creates and links one.
|
|
91
|
+
- **Search** — full-text search across tasks and docs.
|
|
92
|
+
- **New Project / Add Task** — modal dialogs.
|
|
93
|
+
- **Light / Dark themes** (Cloud / Ocean).
|
|
94
|
+
- **Mobile responsive** — hamburger menu, touch drag & drop on kanban, card-style task tables.
|
|
95
|
+
|
|
96
|
+
## MCP Tools
|
|
97
|
+
|
|
98
|
+
Connect via `http://localhost:7881/mcp` with Bearer token auth.
|
|
99
|
+
|
|
100
|
+
| Tool | Description |
|
|
101
|
+
|------|-------------|
|
|
102
|
+
| `get_project` | Full project context (README + TECH + task stats) |
|
|
103
|
+
| `list_projects` | All projects with summaries |
|
|
104
|
+
| `create_project` | Scaffold a new project (4 MDs + directory) |
|
|
105
|
+
| `get_tasks` | Tasks filtered by status/priority |
|
|
106
|
+
| `add_task` | Add task to BACKLOG.md |
|
|
107
|
+
| `update_task` | Modify task in BACKLOG.md |
|
|
108
|
+
| `get_roadmap` | Read ROADMAP.md |
|
|
109
|
+
| `get_docs` | List project documents |
|
|
110
|
+
| `add_doc` | Create numbered doc in docs/ |
|
|
111
|
+
| `search` | FTS5 search across tasks + docs |
|
|
112
|
+
| `what_to_do_next` | Suggest next tasks by priority/deadline |
|
|
113
|
+
| `sync` | Sync docs from source code via dproxy |
|
|
114
|
+
| `overview` | Global summary of all projects |
|
|
115
|
+
|
|
116
|
+
## REST API
|
|
117
|
+
|
|
118
|
+
All endpoints require `Authorization: Bearer <token>` except `/health`.
|
|
119
|
+
|
|
120
|
+
| Method | Endpoint | Purpose |
|
|
121
|
+
|--------|----------|---------|
|
|
122
|
+
| `GET` | `/health` | Status + stats (no auth) |
|
|
123
|
+
| `GET/POST` | `/projects` | List / create projects |
|
|
124
|
+
| `GET/PATCH/DELETE` | `/projects/:slug` | Read / update / delete project |
|
|
125
|
+
| `GET/POST` | `/projects/:slug/tasks` | List / add tasks |
|
|
126
|
+
| `PATCH/DELETE` | `/tasks/:id` | Update / delete task |
|
|
127
|
+
| `GET/POST` | `/projects/:slug/docs` | List / add docs |
|
|
128
|
+
| `GET/PATCH/DELETE` | `/docs/:id` | Read / update / delete doc |
|
|
129
|
+
| `POST` | `/search` | Full-text search across tasks + docs |
|
|
130
|
+
| `GET` | `/overview` | Global stats + per-project summaries |
|
|
131
|
+
| `GET` | `/next` | Suggested next tasks by priority/deadline |
|
|
132
|
+
| `POST` | `/sync/:slug` | Sync project docs from source via dproxy |
|
|
133
|
+
| `POST/GET/DELETE` | `/keys` | API key management |
|
|
134
|
+
|
|
135
|
+
## Configuration
|
|
136
|
+
|
|
137
|
+
Generated by `dwork init`:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"dataPath": "~/.dwork",
|
|
142
|
+
"port": 7881,
|
|
143
|
+
"host": "0.0.0.0",
|
|
144
|
+
"token": "sk-dwk_..."
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Dashboard runs on port `7882` (API port + 1) automatically.
|
|
149
|
+
|
|
150
|
+
## Data Structure
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
~/.dwork/
|
|
154
|
+
├── dwork.db SQLite index + FTS5
|
|
155
|
+
├── config.json
|
|
156
|
+
└── projects/
|
|
157
|
+
└── my-project/
|
|
158
|
+
├── README.md
|
|
159
|
+
├── TECH.md
|
|
160
|
+
├── ROADMAP.md
|
|
161
|
+
├── BACKLOG.md
|
|
162
|
+
└── docs/
|
|
163
|
+
└── 001_feature-name.md
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Part of dtoolkit
|
|
167
|
+
|
|
168
|
+
dwork is part of the [dtoolkit](https://github.com/ivncmp/dtoolkit) monorepo — an engineering toolkit for AI coding agents.
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../../src/cli/configure.ts"],"names":[],"mappings":"AAcA,wBAAsB,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,iBAmF/C"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join, resolve } from 'node:path';
|
|
4
|
+
import * as p from '@clack/prompts';
|
|
5
|
+
import pc from 'picocolors';
|
|
6
|
+
import { loadConfig } from '../core/config.js';
|
|
7
|
+
function resolveDataPath(pathArg) {
|
|
8
|
+
if (pathArg)
|
|
9
|
+
return resolve(pathArg.replace('~', homedir()));
|
|
10
|
+
return resolve(homedir(), '.dwork');
|
|
11
|
+
}
|
|
12
|
+
export async function configure(pathArg) {
|
|
13
|
+
const dataPath = resolveDataPath(pathArg);
|
|
14
|
+
let config;
|
|
15
|
+
try {
|
|
16
|
+
config = loadConfig(dataPath);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
console.log(`${pc.red('Not initialized.')} Run: ${pc.cyan('dwork init')}`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
p.intro(pc.cyan('dwork') + ' configure');
|
|
23
|
+
const answers = await p.group({
|
|
24
|
+
port: () => p.text({
|
|
25
|
+
message: 'API port',
|
|
26
|
+
initialValue: String(config.port),
|
|
27
|
+
validate: (v) => {
|
|
28
|
+
const n = parseInt(v ?? '', 10);
|
|
29
|
+
if (isNaN(n) || n < 1 || n > 65535)
|
|
30
|
+
return 'Invalid port';
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
host: () => p.select({
|
|
34
|
+
message: 'Bind address',
|
|
35
|
+
options: [
|
|
36
|
+
{ value: '0.0.0.0', label: '0.0.0.0 — All interfaces (accessible from network)' },
|
|
37
|
+
{ value: '127.0.0.1', label: '127.0.0.1 — Localhost only' },
|
|
38
|
+
],
|
|
39
|
+
initialValue: config.host,
|
|
40
|
+
}),
|
|
41
|
+
dproxyUrl: () => p.text({
|
|
42
|
+
message: 'dproxy URL (for sync)',
|
|
43
|
+
initialValue: config.dproxy?.url || 'http://localhost:7880',
|
|
44
|
+
}),
|
|
45
|
+
dproxyToken: () => p.text({
|
|
46
|
+
message: 'dproxy token (optional)',
|
|
47
|
+
initialValue: config.dproxy?.token || '',
|
|
48
|
+
}),
|
|
49
|
+
dproxyProvider: () => p.select({
|
|
50
|
+
message: 'dproxy provider',
|
|
51
|
+
options: [
|
|
52
|
+
{ value: 'claude', label: 'Claude' },
|
|
53
|
+
{ value: 'codex', label: 'Codex' },
|
|
54
|
+
{ value: 'gemini', label: 'Gemini' },
|
|
55
|
+
{ value: 'opencode', label: 'OpenCode' },
|
|
56
|
+
],
|
|
57
|
+
initialValue: config.dproxy?.provider || 'claude',
|
|
58
|
+
}),
|
|
59
|
+
}, {
|
|
60
|
+
onCancel: () => {
|
|
61
|
+
p.cancel('Configuration cancelled.');
|
|
62
|
+
process.exit(0);
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
const raw = JSON.parse(readFileSync(join(dataPath, 'config.json'), 'utf-8'));
|
|
66
|
+
const updated = {
|
|
67
|
+
...raw,
|
|
68
|
+
port: parseInt(answers.port, 10),
|
|
69
|
+
host: answers.host,
|
|
70
|
+
dproxy: {
|
|
71
|
+
url: answers.dproxyUrl,
|
|
72
|
+
token: answers.dproxyToken || undefined,
|
|
73
|
+
provider: answers.dproxyProvider,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
if (JSON.stringify(updated) === JSON.stringify(raw)) {
|
|
77
|
+
p.outro(pc.dim('No changes.'));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
writeFileSync(join(dataPath, 'config.json'), JSON.stringify(updated, null, 2) + '\n', 'utf-8');
|
|
81
|
+
p.outro(pc.green('Config updated. Restart the server to apply changes.'));
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=configure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configure.js","sourceRoot":"","sources":["../../src/cli/configure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import pc from 'picocolors';
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf-8'));
|
|
9
|
+
const program = new Command();
|
|
10
|
+
const banner = `\
|
|
11
|
+
_ _
|
|
12
|
+
| | | |
|
|
13
|
+
__| |_ _____ __| | __
|
|
14
|
+
/ _\` \\ \\ /\\ / / _ \\| '__| |/ /
|
|
15
|
+
| (_| |\\ V V / (_) | | | <
|
|
16
|
+
\\__,_| \\_/\\_/ \\___/|_| |_|\\_\\`;
|
|
17
|
+
const description = `${pc.green(banner)}\n\n${pc.green('AI-native, MD-driven project manager')}\n${pc.dim('Part of the dtoolkit suite')}`;
|
|
18
|
+
program.name('dwork').description(description).version(pkg.version);
|
|
19
|
+
program
|
|
20
|
+
.command('init')
|
|
21
|
+
.description('Initialize dwork (config, database, optional first project)')
|
|
22
|
+
.argument('[path]', 'Data path')
|
|
23
|
+
.option('--non-interactive', 'Non-interactive mode (for Docker/CI)')
|
|
24
|
+
.action(async (path, opts) => {
|
|
25
|
+
const { init } = await import('./init.js');
|
|
26
|
+
await init(path, { nonInteractive: opts.nonInteractive });
|
|
27
|
+
});
|
|
28
|
+
program
|
|
29
|
+
.command('start')
|
|
30
|
+
.description('Start the dwork server')
|
|
31
|
+
.argument('[path]', 'Data path')
|
|
32
|
+
.action(async (path) => {
|
|
33
|
+
const { start } = await import('./start.js');
|
|
34
|
+
await start(path);
|
|
35
|
+
});
|
|
36
|
+
program
|
|
37
|
+
.command('status')
|
|
38
|
+
.description('Check dwork status')
|
|
39
|
+
.argument('[path]', 'Data path')
|
|
40
|
+
.action(async (path) => {
|
|
41
|
+
const { status } = await import('./status.js');
|
|
42
|
+
await status(path);
|
|
43
|
+
});
|
|
44
|
+
program
|
|
45
|
+
.command('sync')
|
|
46
|
+
.description('Sync project docs from source code via dproxy')
|
|
47
|
+
.argument('<project>', 'Project slug')
|
|
48
|
+
.option('--path <path>', 'Data path')
|
|
49
|
+
.action(async (project, opts) => {
|
|
50
|
+
const { sync } = await import('./sync.js');
|
|
51
|
+
await sync(project, opts);
|
|
52
|
+
});
|
|
53
|
+
program
|
|
54
|
+
.command('configure')
|
|
55
|
+
.description('Reconfigure dwork (interactive)')
|
|
56
|
+
.argument('[path]', 'Data path')
|
|
57
|
+
.action(async (path) => {
|
|
58
|
+
const { configure } = await import('./configure.js');
|
|
59
|
+
await configure(path);
|
|
60
|
+
});
|
|
61
|
+
program
|
|
62
|
+
.command('keys')
|
|
63
|
+
.description('Manage API keys')
|
|
64
|
+
.argument('<action>', 'create | list | revoke')
|
|
65
|
+
.option('--url <url>', 'dwork URL (or DWORK_URL env)')
|
|
66
|
+
.option('--token <token>', 'Admin token (or DWORK_TOKEN env)')
|
|
67
|
+
.option('--user-id <userId>', 'User ID (create)')
|
|
68
|
+
.option('--user-name <userName>', 'User display name (create)')
|
|
69
|
+
.option('--permissions <perms>', 'read | write | read+write (create, default: read+write)')
|
|
70
|
+
.option('--key-id <keyId>', 'Key ID (revoke)')
|
|
71
|
+
.action(async (action, opts) => {
|
|
72
|
+
const { keys } = await import('./keys.js');
|
|
73
|
+
await keys(action, opts);
|
|
74
|
+
});
|
|
75
|
+
program.parse();
|
|
76
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAoBA,wBAAsB,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAE,iBAmJhF"}
|
package/dist/cli/init.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import * as p from '@clack/prompts';
|
|
6
|
+
import pc from 'picocolors';
|
|
7
|
+
import { createDatabase } from '../core/db.js';
|
|
8
|
+
import * as projectService from '../service/projects.js';
|
|
9
|
+
function generateToken() {
|
|
10
|
+
return `sk-dwk_${randomBytes(24).toString('base64url')}`;
|
|
11
|
+
}
|
|
12
|
+
function defaultDataPath() {
|
|
13
|
+
return join(homedir(), '.dwork');
|
|
14
|
+
}
|
|
15
|
+
export async function init(pathArg, flags) {
|
|
16
|
+
const nonInteractive = flags?.nonInteractive || process.env.DWORK_NON_INTERACTIVE === '1';
|
|
17
|
+
if (nonInteractive) {
|
|
18
|
+
return initNonInteractive(pathArg);
|
|
19
|
+
}
|
|
20
|
+
p.intro(pc.cyan('dwork') + ' — AI-native project manager');
|
|
21
|
+
const existingPath = resolve(pathArg || defaultDataPath());
|
|
22
|
+
if (existsSync(join(existingPath, 'config.json'))) {
|
|
23
|
+
p.log.info(`dwork already initialized at ${pc.green(existingPath)}`);
|
|
24
|
+
p.outro(pc.green('Done.'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const answers = await p.group({
|
|
28
|
+
dataPath: () => p.text({
|
|
29
|
+
message: 'Where should dwork store data?',
|
|
30
|
+
initialValue: pathArg || defaultDataPath(),
|
|
31
|
+
validate: (v) => (!v || v.length === 0 ? 'Path is required' : undefined),
|
|
32
|
+
}),
|
|
33
|
+
port: () => p.text({
|
|
34
|
+
message: 'API port?',
|
|
35
|
+
initialValue: '7881',
|
|
36
|
+
validate: (v) => {
|
|
37
|
+
const n = parseInt(v ?? '', 10);
|
|
38
|
+
if (isNaN(n) || n < 1 || n > 65535)
|
|
39
|
+
return 'Invalid port';
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
host: () => p.select({
|
|
43
|
+
message: 'Bind address?',
|
|
44
|
+
options: [
|
|
45
|
+
{ value: '0.0.0.0', label: '0.0.0.0 — All interfaces (accessible from network)' },
|
|
46
|
+
{ value: '127.0.0.1', label: '127.0.0.1 — Localhost only' },
|
|
47
|
+
],
|
|
48
|
+
initialValue: '0.0.0.0',
|
|
49
|
+
}),
|
|
50
|
+
token: () => p.text({
|
|
51
|
+
message: 'Access token (leave default to auto-generate)',
|
|
52
|
+
initialValue: generateToken(),
|
|
53
|
+
}),
|
|
54
|
+
createProject: () => p.confirm({
|
|
55
|
+
message: 'Create a first project now?',
|
|
56
|
+
initialValue: true,
|
|
57
|
+
}),
|
|
58
|
+
}, {
|
|
59
|
+
onCancel: () => {
|
|
60
|
+
p.cancel('Init cancelled.');
|
|
61
|
+
process.exit(0);
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
const dataPath = resolve(answers.dataPath.replace('~', homedir()));
|
|
65
|
+
if (existsSync(join(dataPath, 'config.json'))) {
|
|
66
|
+
p.log.info(`dwork already initialized at ${pc.green(dataPath)}`);
|
|
67
|
+
p.outro(pc.green('Done.'));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const port = parseInt(answers.port, 10);
|
|
71
|
+
const config = {
|
|
72
|
+
dataPath,
|
|
73
|
+
port,
|
|
74
|
+
host: answers.host,
|
|
75
|
+
token: answers.token,
|
|
76
|
+
};
|
|
77
|
+
const s = p.spinner();
|
|
78
|
+
s.start('Creating data directory');
|
|
79
|
+
mkdirSync(join(dataPath, 'projects'), { recursive: true });
|
|
80
|
+
writeFileSync(join(dataPath, 'config.json'), JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
81
|
+
s.stop('Config saved');
|
|
82
|
+
s.start('Initializing database');
|
|
83
|
+
const db = createDatabase(config);
|
|
84
|
+
s.stop('Database ready');
|
|
85
|
+
if (answers.createProject) {
|
|
86
|
+
const projectAnswers = await p.group({
|
|
87
|
+
slug: () => p.text({
|
|
88
|
+
message: 'Project slug (lowercase, hyphens)',
|
|
89
|
+
validate: (v) => {
|
|
90
|
+
if (!v || v.length === 0)
|
|
91
|
+
return 'Slug is required';
|
|
92
|
+
if (!/^[a-z0-9-]+$/.test(v))
|
|
93
|
+
return 'Only lowercase letters, numbers, and hyphens';
|
|
94
|
+
},
|
|
95
|
+
}),
|
|
96
|
+
name: () => p.text({
|
|
97
|
+
message: 'Project display name',
|
|
98
|
+
validate: (v) => (!v || v.length === 0 ? 'Name is required' : undefined),
|
|
99
|
+
}),
|
|
100
|
+
sourcePath: () => p.text({
|
|
101
|
+
message: 'Source code path (optional, for sync)',
|
|
102
|
+
initialValue: '',
|
|
103
|
+
}),
|
|
104
|
+
}, {
|
|
105
|
+
onCancel: () => {
|
|
106
|
+
p.cancel('Skipped project creation.');
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
if (projectAnswers.slug) {
|
|
110
|
+
s.start('Creating project');
|
|
111
|
+
projectService.createProject(db, config, projectAnswers.slug, projectAnswers.name, undefined, projectAnswers.sourcePath || undefined);
|
|
112
|
+
s.stop(`Project ${pc.green(projectAnswers.slug)} created`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
db.close();
|
|
116
|
+
p.note([
|
|
117
|
+
`Data: ${pc.green(dataPath)}`,
|
|
118
|
+
`Port: ${pc.green(String(port))}`,
|
|
119
|
+
`Host: ${pc.green(config.host)}`,
|
|
120
|
+
`Token: ${pc.green(config.token)}`,
|
|
121
|
+
].join('\n'), 'Configuration');
|
|
122
|
+
p.note([`Start the server:`, ` ${pc.cyan('dwork start')}`].join('\n'), 'Next steps');
|
|
123
|
+
p.outro(pc.green('dwork initialized. Ready to manage your projects.'));
|
|
124
|
+
}
|
|
125
|
+
function initNonInteractive(pathArg) {
|
|
126
|
+
const dataPath = resolve(pathArg || process.env.DWORK_DATA || defaultDataPath());
|
|
127
|
+
const port = parseInt(process.env.DWORK_PORT || '7881', 10);
|
|
128
|
+
const host = process.env.DWORK_HOST || '0.0.0.0';
|
|
129
|
+
const token = process.env.DWORK_TOKEN || generateToken();
|
|
130
|
+
if (existsSync(join(dataPath, 'config.json'))) {
|
|
131
|
+
console.log(`Config already exists at ${dataPath}, skipping init.`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const config = { dataPath, port, host, token };
|
|
135
|
+
mkdirSync(join(dataPath, 'projects'), { recursive: true });
|
|
136
|
+
writeFileSync(join(dataPath, 'config.json'), JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
137
|
+
const db = createDatabase(config);
|
|
138
|
+
db.close();
|
|
139
|
+
console.log(`dwork initialized at ${dataPath}`);
|
|
140
|
+
console.log(`Token: ${token}`);
|
|
141
|
+
console.log(`Start with: dwork start`);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface KeysOptions {
|
|
2
|
+
url?: string;
|
|
3
|
+
token?: string;
|
|
4
|
+
userId?: string;
|
|
5
|
+
userName?: string;
|
|
6
|
+
permissions?: string;
|
|
7
|
+
keyId?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function keys(action: string, opts: KeysOptions): Promise<void>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/cli/keys.ts"],"names":[],"mappings":"AAGA,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAoBD,wBAAsB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,iBA2F3D"}
|
package/dist/cli/keys.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
async function apiCall(url, token, method, path, body) {
|
|
4
|
+
const headers = { Authorization: `Bearer ${token}` };
|
|
5
|
+
if (body)
|
|
6
|
+
headers['Content-Type'] = 'application/json';
|
|
7
|
+
const res = await fetch(`${url}${path}`, {
|
|
8
|
+
method,
|
|
9
|
+
headers,
|
|
10
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
11
|
+
});
|
|
12
|
+
const data = await res.json();
|
|
13
|
+
return { ok: res.ok, status: res.status, data };
|
|
14
|
+
}
|
|
15
|
+
export async function keys(action, opts) {
|
|
16
|
+
const url = opts.url || process.env.DWORK_URL;
|
|
17
|
+
const token = opts.token || process.env.DWORK_TOKEN;
|
|
18
|
+
if (!url || !token) {
|
|
19
|
+
p.log.error(`${pc.red('Missing --url and --token (or DWORK_URL / DWORK_TOKEN env vars)')}`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
if (action === 'create') {
|
|
23
|
+
const userId = opts.userId;
|
|
24
|
+
const userName = opts.userName;
|
|
25
|
+
if (!userId || !userName) {
|
|
26
|
+
p.log.error(`${pc.red('--user-id and --user-name are required for create')}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const { ok, data } = await apiCall(url, token, 'POST', '/keys', {
|
|
30
|
+
userId,
|
|
31
|
+
userName,
|
|
32
|
+
permissions: opts.permissions || 'read+write',
|
|
33
|
+
});
|
|
34
|
+
if (!ok) {
|
|
35
|
+
p.log.error(`${pc.red('Failed to create key:')} ${JSON.stringify(data)}`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
const key = data;
|
|
39
|
+
p.log.success(`${pc.green('Key created')}`);
|
|
40
|
+
p.note([
|
|
41
|
+
`ID: ${pc.dim(key.id)}`,
|
|
42
|
+
`User: ${pc.green(userName)} (${userId})`,
|
|
43
|
+
`Permissions: ${pc.green(key.permissions)}`,
|
|
44
|
+
`Token: ${pc.green(key.token)}`,
|
|
45
|
+
``,
|
|
46
|
+
`${pc.dim('Save this token — it will not be shown again.')}`,
|
|
47
|
+
].join('\n'), 'API Key');
|
|
48
|
+
}
|
|
49
|
+
else if (action === 'list') {
|
|
50
|
+
const { ok, data } = await apiCall(url, token, 'GET', '/keys');
|
|
51
|
+
if (!ok) {
|
|
52
|
+
p.log.error(`${pc.red('Failed to list keys:')} ${JSON.stringify(data)}`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
const keyList = data;
|
|
56
|
+
if (keyList.length === 0) {
|
|
57
|
+
p.log.info('No API keys found.');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
p.log.info(`${pc.bold(`${keyList.length} key(s)`)}\n`);
|
|
61
|
+
for (const k of keyList) {
|
|
62
|
+
const status = k.status === 'active' ? pc.green('active') : pc.red('revoked');
|
|
63
|
+
const lastUsed = k.lastUsed ? pc.dim(k.lastUsed) : pc.dim('never');
|
|
64
|
+
console.log(` ${pc.dim(k.id)} ${k.userName} (${k.userId}) ${k.permissions} ${status} last: ${lastUsed} ${pc.dim(k.tokenPreview)}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else if (action === 'revoke') {
|
|
68
|
+
const keyId = opts.keyId;
|
|
69
|
+
if (!keyId) {
|
|
70
|
+
p.log.error(`${pc.red('--key-id is required for revoke')}`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
const { ok, data } = await apiCall(url, token, 'DELETE', `/keys/${keyId}`);
|
|
74
|
+
if (!ok) {
|
|
75
|
+
p.log.error(`${pc.red('Failed to revoke key:')} ${JSON.stringify(data)}`);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
p.log.success(`${pc.green('Key revoked:')} ${keyId}`);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
p.log.error(`${pc.red(`Unknown action: ${action}. Use create, list, or revoke.`)}`);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=keys.js.map
|