@aprovan/hardcopy 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/.eslintrc.json +22 -0
- package/.github/workflows/publish.yml +41 -0
- package/.prettierignore +17 -0
- package/LICENSE +21 -0
- package/README.md +183 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +2950 -0
- package/dist/index.d.ts +406 -0
- package/dist/index.js +2737 -0
- package/dist/mcp-server.d.ts +7 -0
- package/dist/mcp-server.js +2665 -0
- package/docs/research/crdt.md +777 -0
- package/docs/research/github-issues.md +684 -0
- package/docs/research/gql.md +876 -0
- package/docs/research/index.md +19 -0
- package/docs/specs/conflict-resolution.md +1254 -0
- package/docs/specs/hardcopy.md +742 -0
- package/docs/specs/patchwork-integration.md +227 -0
- package/docs/specs/plugin-architecture.md +747 -0
- package/mcp.json +8 -0
- package/package.json +64 -0
- package/scripts/install-graphqlite.ts +156 -0
- package/src/cli.ts +356 -0
- package/src/config.ts +104 -0
- package/src/conflict-store.ts +136 -0
- package/src/conflict.ts +147 -0
- package/src/crdt.ts +100 -0
- package/src/db.ts +600 -0
- package/src/env.ts +34 -0
- package/src/format.ts +72 -0
- package/src/formats/github-issue.ts +55 -0
- package/src/hardcopy/core.ts +78 -0
- package/src/hardcopy/diff.ts +188 -0
- package/src/hardcopy/index.ts +67 -0
- package/src/hardcopy/init.ts +24 -0
- package/src/hardcopy/push.ts +444 -0
- package/src/hardcopy/sync.ts +37 -0
- package/src/hardcopy/types.ts +49 -0
- package/src/hardcopy/views.ts +199 -0
- package/src/hardcopy.ts +1 -0
- package/src/index.ts +13 -0
- package/src/llm-merge.ts +109 -0
- package/src/mcp-server.ts +388 -0
- package/src/merge.ts +75 -0
- package/src/provider.ts +40 -0
- package/src/providers/a2a/index.ts +166 -0
- package/src/providers/git/index.ts +212 -0
- package/src/providers/github/index.ts +236 -0
- package/src/providers/github/issues.ts +66 -0
- package/src/providers.ts +7 -0
- package/src/types.ts +101 -0
- package/tsconfig.json +21 -0
- package/tsup.config.ts +10 -0
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"browser": true,
|
|
4
|
+
"es2021": true
|
|
5
|
+
},
|
|
6
|
+
"ignorePatterns": ["**/*.js", "**/*.d.ts"],
|
|
7
|
+
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
|
8
|
+
"parser": "@typescript-eslint/parser",
|
|
9
|
+
"parserOptions": {
|
|
10
|
+
"ecmaVersion": "latest",
|
|
11
|
+
"sourceType": "module"
|
|
12
|
+
},
|
|
13
|
+
"plugins": ["@typescript-eslint", "eslint-plugin-tsdoc"],
|
|
14
|
+
"rules": {
|
|
15
|
+
"require-yield": "off",
|
|
16
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
17
|
+
"@typescript-eslint/ban-ts-comment": "off",
|
|
18
|
+
"@typescript-eslint/no-non-null-assertion": "off",
|
|
19
|
+
"@typescript-eslint/no-namespace": "off",
|
|
20
|
+
"tsdoc/syntax": "warn"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Publish Packages to NPM
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
env:
|
|
9
|
+
HUSKY: 0
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
name: Publish
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
id-token: write
|
|
18
|
+
steps:
|
|
19
|
+
- name: Checkout
|
|
20
|
+
uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Setup pnpm
|
|
23
|
+
uses: pnpm/action-setup@v4
|
|
24
|
+
|
|
25
|
+
- name: Setup Node.js
|
|
26
|
+
uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: 20
|
|
29
|
+
registry-url: 'https://registry.npmjs.org'
|
|
30
|
+
|
|
31
|
+
- name: Install dependencies
|
|
32
|
+
run: pnpm install
|
|
33
|
+
|
|
34
|
+
- name: Build packages
|
|
35
|
+
run: pnpm run build
|
|
36
|
+
|
|
37
|
+
- name: Publish packages
|
|
38
|
+
run: pnpm -r publish --no-git-checks --access public
|
|
39
|
+
env:
|
|
40
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
41
|
+
continue-on-error: true
|
package/.prettierignore
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aprovan Labs
|
|
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,183 @@
|
|
|
1
|
+
# hardcopy
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
<br />
|
|
5
|
+
<a href="https://aprovan.com">
|
|
6
|
+
<img height="20" src="https://img.shields.io/badge/aprovan.com-ef4444?style=flat-square" alt="aprovan.com">
|
|
7
|
+
</a>
|
|
8
|
+
<a href="https://github.com/AprovanLabs">
|
|
9
|
+
<img height="20" src="https://img.shields.io/badge/-AprovanLabs-000000?style=flat-square&logo=GitHub&logoColor=white&link=https://github.com/AprovanLabs/" alt="Aprovan Labs GitHub" />
|
|
10
|
+
</a>
|
|
11
|
+
<a href="https://www.linkedin.com/company/aprovan">
|
|
12
|
+
<img height="20" src="https://img.shields.io/badge/-Aprovan-blue?style=flat-square&logo=Linkedin&logoColor=white&link=https://www.linkedin.com/company/aprovan)" alt="Aprovan LinkedIn">
|
|
13
|
+
</a>
|
|
14
|
+
|
|
15
|
+
Keep everything close at hand
|
|
16
|
+
|
|
17
|
+
## Getting Started
|
|
18
|
+
|
|
19
|
+
### Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add @aprovan/hardcopy
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or for local development:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# From the hardcopy repo
|
|
29
|
+
pnpm install
|
|
30
|
+
pnpm -F @aprovan/hardcopy build
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Initialize
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# If installed as dependency
|
|
37
|
+
pnpm exec hardcopy init
|
|
38
|
+
|
|
39
|
+
# Local development
|
|
40
|
+
pnpm hardcopy init
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This creates:
|
|
44
|
+
- `.hardcopy/` — database and CRDT storage
|
|
45
|
+
- `hardcopy.yaml` — source and view configuration
|
|
46
|
+
|
|
47
|
+
### Configuration
|
|
48
|
+
|
|
49
|
+
Create a `hardcopy.yaml` in your project root:
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
sources:
|
|
53
|
+
- name: github
|
|
54
|
+
provider: github
|
|
55
|
+
orgs: [AprovanLabs]
|
|
56
|
+
# Or specify repos directly:
|
|
57
|
+
# repos: [AprovanLabs/zolvery, AprovanLabs/hardcopy]
|
|
58
|
+
|
|
59
|
+
- name: agents
|
|
60
|
+
provider: a2a
|
|
61
|
+
endpoint: http://localhost:8080
|
|
62
|
+
links:
|
|
63
|
+
- edge: a2a.TRACKS
|
|
64
|
+
to: github.Issue
|
|
65
|
+
match: "github:{{task.meta.github.repository}}#{{task.meta.github.issue_number}}"
|
|
66
|
+
|
|
67
|
+
- name: git
|
|
68
|
+
provider: git
|
|
69
|
+
repositories:
|
|
70
|
+
- path: ~/Projects/example
|
|
71
|
+
links:
|
|
72
|
+
- edge: git.TRACKS
|
|
73
|
+
to: a2a.Task
|
|
74
|
+
match: "a2a:{{branch.meta.a2a.task_id}}"
|
|
75
|
+
|
|
76
|
+
views:
|
|
77
|
+
- path: issues
|
|
78
|
+
description: "Open GitHub issues"
|
|
79
|
+
query: |
|
|
80
|
+
MATCH (i:github.Issue)
|
|
81
|
+
WHERE i.attrs->>'state' = 'open'
|
|
82
|
+
RETURN i
|
|
83
|
+
render:
|
|
84
|
+
- path: "{{attrs.number}}.github.issue.md"
|
|
85
|
+
type: github.Issue
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Conflict Resolution
|
|
89
|
+
|
|
90
|
+
Conflict resolution uses `diff3` for clean merges, with automatic LLM fallback for conflicts. Configure via environment variables:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
export OPENAI_BASE_URL=https://api.openai.com/v1 # or any OpenAI-compatible endpoint
|
|
94
|
+
export OPENAI_API_KEY=sk-...
|
|
95
|
+
export OPENAI_MODEL=gpt-4o # optional, defaults to gpt-4o
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Providers
|
|
99
|
+
|
|
100
|
+
#### GitHub
|
|
101
|
+
|
|
102
|
+
Requires `GITHUB_TOKEN` environment variable for API access:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
export GITHUB_TOKEN=ghp_xxxxxxxxxxxx
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Configuration options:
|
|
109
|
+
- `orgs` — fetch all repos from these organizations
|
|
110
|
+
- `repos` — specific repos (e.g., `owner/repo`)
|
|
111
|
+
- `token` — override env token (not recommended)
|
|
112
|
+
|
|
113
|
+
#### Git
|
|
114
|
+
|
|
115
|
+
Discovers branches and worktrees from local repositories. Reads A2A metadata from `.a2a/session.json` in worktrees for task linking.
|
|
116
|
+
|
|
117
|
+
Configuration options:
|
|
118
|
+
- `repositories[].path` — paths to git repos (supports `~`)
|
|
119
|
+
- `links` — edge configuration for task linking
|
|
120
|
+
|
|
121
|
+
#### A2A
|
|
122
|
+
|
|
123
|
+
Connects to an A2A-compatible agent endpoint.
|
|
124
|
+
|
|
125
|
+
Configuration options:
|
|
126
|
+
- `endpoint` — base URL of the A2A server
|
|
127
|
+
- `links` — edge configuration for cross-provider linking
|
|
128
|
+
|
|
129
|
+
### Commands
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Initialize hardcopy
|
|
133
|
+
pnpm hardcopy init
|
|
134
|
+
|
|
135
|
+
# Sync all sources (fetch remote data)
|
|
136
|
+
pnpm hardcopy sync
|
|
137
|
+
|
|
138
|
+
# Refresh a view (render to file tree)
|
|
139
|
+
pnpm hardcopy refresh <view>
|
|
140
|
+
|
|
141
|
+
# Show sync status
|
|
142
|
+
pnpm hardcopy status
|
|
143
|
+
|
|
144
|
+
# Push local changes to remotes
|
|
145
|
+
pnpm hardcopy push [file]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### File Structure
|
|
149
|
+
|
|
150
|
+
After syncing and refreshing views:
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
project/
|
|
154
|
+
├── hardcopy.yaml
|
|
155
|
+
├── .hardcopy/
|
|
156
|
+
│ ├── db.sqlite # LibSQL database (nodes + edges)
|
|
157
|
+
│ ├── crdt/ # Per-node CRDT snapshots
|
|
158
|
+
│ └── errors/ # Sync error reports
|
|
159
|
+
└── issues/ # View directory
|
|
160
|
+
├── .index # Pagination state
|
|
161
|
+
├── 42.github.issue.md
|
|
162
|
+
└── 43.github.issue.md
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Programmatic Usage
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import { Hardcopy } from "@aprovan/hardcopy";
|
|
169
|
+
|
|
170
|
+
const hc = new Hardcopy({ root: process.cwd() });
|
|
171
|
+
await hc.initialize();
|
|
172
|
+
|
|
173
|
+
// Sync all sources
|
|
174
|
+
const stats = await hc.sync();
|
|
175
|
+
console.log(`Synced ${stats.nodes} nodes`);
|
|
176
|
+
|
|
177
|
+
// Query the database
|
|
178
|
+
const db = hc.getDatabase();
|
|
179
|
+
const issues = await db.queryNodes("github.Issue");
|
|
180
|
+
|
|
181
|
+
await hc.close();
|
|
182
|
+
```
|
|
183
|
+
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|