@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.
Files changed (53) hide show
  1. package/.eslintrc.json +22 -0
  2. package/.github/workflows/publish.yml +41 -0
  3. package/.prettierignore +17 -0
  4. package/LICENSE +21 -0
  5. package/README.md +183 -0
  6. package/dist/cli.d.ts +1 -0
  7. package/dist/cli.js +2950 -0
  8. package/dist/index.d.ts +406 -0
  9. package/dist/index.js +2737 -0
  10. package/dist/mcp-server.d.ts +7 -0
  11. package/dist/mcp-server.js +2665 -0
  12. package/docs/research/crdt.md +777 -0
  13. package/docs/research/github-issues.md +684 -0
  14. package/docs/research/gql.md +876 -0
  15. package/docs/research/index.md +19 -0
  16. package/docs/specs/conflict-resolution.md +1254 -0
  17. package/docs/specs/hardcopy.md +742 -0
  18. package/docs/specs/patchwork-integration.md +227 -0
  19. package/docs/specs/plugin-architecture.md +747 -0
  20. package/mcp.json +8 -0
  21. package/package.json +64 -0
  22. package/scripts/install-graphqlite.ts +156 -0
  23. package/src/cli.ts +356 -0
  24. package/src/config.ts +104 -0
  25. package/src/conflict-store.ts +136 -0
  26. package/src/conflict.ts +147 -0
  27. package/src/crdt.ts +100 -0
  28. package/src/db.ts +600 -0
  29. package/src/env.ts +34 -0
  30. package/src/format.ts +72 -0
  31. package/src/formats/github-issue.ts +55 -0
  32. package/src/hardcopy/core.ts +78 -0
  33. package/src/hardcopy/diff.ts +188 -0
  34. package/src/hardcopy/index.ts +67 -0
  35. package/src/hardcopy/init.ts +24 -0
  36. package/src/hardcopy/push.ts +444 -0
  37. package/src/hardcopy/sync.ts +37 -0
  38. package/src/hardcopy/types.ts +49 -0
  39. package/src/hardcopy/views.ts +199 -0
  40. package/src/hardcopy.ts +1 -0
  41. package/src/index.ts +13 -0
  42. package/src/llm-merge.ts +109 -0
  43. package/src/mcp-server.ts +388 -0
  44. package/src/merge.ts +75 -0
  45. package/src/provider.ts +40 -0
  46. package/src/providers/a2a/index.ts +166 -0
  47. package/src/providers/git/index.ts +212 -0
  48. package/src/providers/github/index.ts +236 -0
  49. package/src/providers/github/issues.ts +66 -0
  50. package/src/providers.ts +7 -0
  51. package/src/types.ts +101 -0
  52. package/tsconfig.json +21 -0
  53. 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
@@ -0,0 +1,17 @@
1
+ .*
2
+
3
+ node_modules
4
+ lib
5
+ dist
6
+ static
7
+ .git
8
+ .docusaurus
9
+ .github
10
+ package.json
11
+ package-lock.json
12
+ CHANGELOG.md
13
+
14
+ /.nx/cache
15
+ /.nx/workspace-data
16
+
17
+ *.md
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
+ ![Aprovan Labs](https://raw.githubusercontent.com/AprovanLabs/aprovan.com/main/docs/assets/header-labs.svg)
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