codequill 0.8.1-beta.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +121 -0
  3. package/dist/commands/attest.js +442 -0
  4. package/dist/commands/attest.js.map +1 -0
  5. package/dist/commands/backup.js +370 -0
  6. package/dist/commands/backup.js.map +1 -0
  7. package/dist/commands/claim.js +104 -0
  8. package/dist/commands/claim.js.map +1 -0
  9. package/dist/commands/log.js +188 -0
  10. package/dist/commands/log.js.map +1 -0
  11. package/dist/commands/login.js +147 -0
  12. package/dist/commands/login.js.map +1 -0
  13. package/dist/commands/prove.js +244 -0
  14. package/dist/commands/prove.js.map +1 -0
  15. package/dist/commands/publish.js +243 -0
  16. package/dist/commands/publish.js.map +1 -0
  17. package/dist/commands/pull.js +174 -0
  18. package/dist/commands/pull.js.map +1 -0
  19. package/dist/commands/quota.js +94 -0
  20. package/dist/commands/quota.js.map +1 -0
  21. package/dist/commands/revoke.js +97 -0
  22. package/dist/commands/revoke.js.map +1 -0
  23. package/dist/commands/snapshot.js +128 -0
  24. package/dist/commands/snapshot.js.map +1 -0
  25. package/dist/commands/status.js +234 -0
  26. package/dist/commands/status.js.map +1 -0
  27. package/dist/commands/verifyAttestation.js +212 -0
  28. package/dist/commands/verifyAttestation.js.map +1 -0
  29. package/dist/commands/verifyProof.js +145 -0
  30. package/dist/commands/verifyProof.js.map +1 -0
  31. package/dist/commands/wait.js +36 -0
  32. package/dist/commands/wait.js.map +1 -0
  33. package/dist/commands/who.js +55 -0
  34. package/dist/commands/who.js.map +1 -0
  35. package/dist/commands/why.js +412 -0
  36. package/dist/commands/why.js.map +1 -0
  37. package/dist/index.js +50 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/launcher.js +69 -0
  40. package/dist/launcher.js.map +1 -0
  41. package/dist/services/api.js +51 -0
  42. package/dist/services/api.js.map +1 -0
  43. package/dist/services/apiClient.js +166 -0
  44. package/dist/services/apiClient.js.map +1 -0
  45. package/dist/services/authStore.js +84 -0
  46. package/dist/services/authStore.js.map +1 -0
  47. package/dist/services/config.js +19 -0
  48. package/dist/services/config.js.map +1 -0
  49. package/dist/services/confirm.js +58 -0
  50. package/dist/services/confirm.js.map +1 -0
  51. package/dist/services/crypto.js +38 -0
  52. package/dist/services/crypto.js.map +1 -0
  53. package/dist/services/errors.js +17 -0
  54. package/dist/services/errors.js.map +1 -0
  55. package/dist/services/fs.js +25 -0
  56. package/dist/services/fs.js.map +1 -0
  57. package/dist/services/git.js +121 -0
  58. package/dist/services/git.js.map +1 -0
  59. package/dist/services/manifests/attestationManifest.js +35 -0
  60. package/dist/services/manifests/attestationManifest.js.map +1 -0
  61. package/dist/services/manifests/proofManifest.js +151 -0
  62. package/dist/services/manifests/proofManifest.js.map +1 -0
  63. package/dist/services/manifests/snapshotManifest.js +214 -0
  64. package/dist/services/manifests/snapshotManifest.js.map +1 -0
  65. package/dist/services/merkle.js +92 -0
  66. package/dist/services/merkle.js.map +1 -0
  67. package/dist/services/paths.js +16 -0
  68. package/dist/services/paths.js.map +1 -0
  69. package/dist/services/snapshotIndex.js +401 -0
  70. package/dist/services/snapshotIndex.js.map +1 -0
  71. package/dist/services/txWaiter.js +84 -0
  72. package/dist/services/txWaiter.js.map +1 -0
  73. package/dist/services/ui.js +98 -0
  74. package/dist/services/ui.js.map +1 -0
  75. package/dist/services/utilities.js +45 -0
  76. package/dist/services/utilities.js.map +1 -0
  77. package/dist/services/zip.js +24 -0
  78. package/dist/services/zip.js.map +1 -0
  79. package/dist/types/api.js +2 -0
  80. package/dist/types/api.js.map +1 -0
  81. package/dist/version.js +7 -0
  82. package/dist/version.js.map +1 -0
  83. package/package.json +52 -0
@@ -0,0 +1,243 @@
1
+ import { colors, shortCommit, spinner } from '../services/ui.js';
2
+ import { apiClient } from '../services/apiClient.js';
3
+ import { getBaseUrl } from '../services/config.js';
4
+ import { waitForTxConfirmation } from '../services/txWaiter.js';
5
+ import { detectGitRepo, deriveRepoName } from '../services/git.js';
6
+ import { SnapshotIndex } from '../services/snapshotIndex.js';
7
+ import { assertAuthenticated } from '../services/utilities.js';
8
+ import fs from 'node:fs/promises';
9
+ import path from 'node:path';
10
+ import { gzipSync } from 'node:zlib';
11
+ import { fileExists } from "../services/fs.js";
12
+ import { confirmDangerousAction } from "../services/confirm.js";
13
+ export async function handlePublish(opts) {
14
+ if (!assertAuthenticated())
15
+ return;
16
+ const log = (...args) => { if (!opts.json)
17
+ console.log(...args); };
18
+ // Must run inside repo (no --path)
19
+ const git = detectGitRepo(process.cwd());
20
+ if (!git.isRepo || !git.root) {
21
+ console.error(colors.error('This command must be run inside a git repository.'));
22
+ process.exitCode = 1;
23
+ return;
24
+ }
25
+ const derivedRepoName = deriveRepoName(git.root, git.remote);
26
+ if (!derivedRepoName) {
27
+ console.error(colors.error('Unable to determine repo name from git remote.'));
28
+ process.exitCode = 1;
29
+ return;
30
+ }
31
+ const commitHashForLookup = String(opts.commit ?? git.head ?? '').trim();
32
+ if (!commitHashForLookup) {
33
+ console.error(colors.error('Unable to determine commit (no commit provided and HEAD is missing).'));
34
+ process.exitCode = 1;
35
+ return;
36
+ }
37
+ const fname = `snapshot-${shortCommit(commitHashForLookup)}.json`;
38
+ const manifestPathAbs = path.join(git.root, '.codequill', 'snapshots', fname);
39
+ if (!(await fileExists(manifestPathAbs))) {
40
+ console.error(colors.error('Snapshot manifest not found.'));
41
+ if (!opts.json) {
42
+ console.error(colors.dim(`Expected: ${path.relative(process.cwd(), manifestPathAbs)}`));
43
+ console.error(colors.dim(`Tip: run \`codequill snapshot --commit ${commitHashForLookup || '<hash>'}\` first.`));
44
+ }
45
+ process.exitCode = 1;
46
+ return;
47
+ }
48
+ // 1) Read + parse manifest
49
+ const sRead = spinner(`Reading manifest: ${path.relative(process.cwd(), manifestPathAbs)} ...`, opts.json);
50
+ let manifestObj;
51
+ let rawBytes;
52
+ try {
53
+ rawBytes = await fs.readFile(manifestPathAbs);
54
+ manifestObj = JSON.parse(rawBytes.toString('utf8'));
55
+ sRead.succeed(colors.success('Manifest loaded.'));
56
+ }
57
+ catch (e) {
58
+ sRead.fail(colors.error('Failed to read manifest.'));
59
+ console.error(colors.error(String(e?.message || e)));
60
+ process.exitCode = 1;
61
+ return;
62
+ }
63
+ // 2) Validate / normalize
64
+ try {
65
+ if (!manifestObj || typeof manifestObj !== 'object')
66
+ throw new Error('Invalid manifest JSON.');
67
+ if (!manifestObj.repo || !manifestObj.commit || !manifestObj.merkle_root || !manifestObj.content_root || !Array.isArray(manifestObj.files)) {
68
+ throw new Error('Invalid manifest: missing required fields (repo, commit, merkle_root, content_root, files).');
69
+ }
70
+ }
71
+ catch (e) {
72
+ console.error(colors.error(String(e?.message || e)));
73
+ process.exitCode = 1;
74
+ return;
75
+ }
76
+ const repoNameFromManifest = String(manifestObj.repo ?? '').trim();
77
+ const commitHash = String(manifestObj.commit ?? '').trim();
78
+ const merkleRoot = String(manifestObj.merkle_root ?? '').trim();
79
+ const contentRoot = String(manifestObj.content_root ?? '').trim();
80
+ const version = String(manifestObj.version ?? 'codequill-snapshot:v1');
81
+ if (!repoNameFromManifest || !commitHash || !merkleRoot || !contentRoot) {
82
+ console.error(colors.error('Invalid manifest: missing repo / commit / merkle_root / content_root.'));
83
+ process.exitCode = 1;
84
+ return;
85
+ }
86
+ // Safety: publish only for the repo we’re inside
87
+ if (repoNameFromManifest !== derivedRepoName) {
88
+ console.error(colors.error('Manifest repo does not match current git repo.'));
89
+ if (!opts.json) {
90
+ console.error(colors.dim(`Manifest repo: ${repoNameFromManifest}`));
91
+ console.error(colors.dim(`Git repo: ${derivedRepoName}`));
92
+ console.error(colors.dim('Tip: run `codequill snapshot` inside this repo to generate the correct manifest.'));
93
+ }
94
+ process.exitCode = 1;
95
+ return;
96
+ }
97
+ if (!opts.noConfirm && !opts.json) {
98
+ const ok = await confirmDangerousAction('You are about to publish a snapshot', [
99
+ ` Manifest ${path.relative(process.cwd(), manifestPathAbs)}`,
100
+ ` Repo ${repoNameFromManifest}`,
101
+ ` Commit ${commitHash}`,
102
+ ` Merkle Root ${merkleRoot}`,
103
+ ` Files ${Array.isArray(manifestObj.files) ? manifestObj.files.length : 0}`,
104
+ ` Version ${version}`,
105
+ ], 'This action anchors the snapshot on-chain.');
106
+ if (!ok) {
107
+ log(colors.dim('Publish cancelled.'));
108
+ return;
109
+ }
110
+ }
111
+ // 3) Gzip manifest bytes for upload
112
+ const sGz = spinner('Compressing manifest (gzip) ...', opts.json);
113
+ let gzBytes;
114
+ try {
115
+ gzBytes = gzipSync(rawBytes, { level: 9 });
116
+ sGz.succeed(colors.success(`Compressed (${rawBytes.length} → ${gzBytes.length} bytes).`));
117
+ }
118
+ catch (e) {
119
+ sGz.fail(colors.error('Failed to gzip manifest.'));
120
+ console.error(colors.error(String(e?.message || e)));
121
+ process.exitCode = 1;
122
+ return;
123
+ }
124
+ // 4) Build multipart
125
+ const form = new FormData();
126
+ form.append('repo_name', repoNameFromManifest);
127
+ form.append('commit_hash', commitHash);
128
+ form.append('merkle_root', merkleRoot);
129
+ form.append('version', version);
130
+ form.append('manifest_encoding', 'gzip');
131
+ form.append('manifest_original_name', path.basename(manifestPathAbs));
132
+ const gzFilename = `${path.basename(manifestPathAbs).replace(/\.json$/i, '') || 'manifest'}.json.gz`;
133
+ const file = new File([new Uint8Array(gzBytes)], gzFilename, { type: 'application/gzip' });
134
+ form.append('manifest', file);
135
+ // 5) Publish
136
+ const sPub = spinner('Publishing ...', opts.json);
137
+ let res;
138
+ try {
139
+ res = await apiClient.postMultipart('/v1/cli/publish', form);
140
+ sPub.succeed(colors.success('Publish submitted.'));
141
+ }
142
+ catch (e) {
143
+ sPub.fail(colors.error('Publish failed.'));
144
+ console.error(colors.error(String(e?.message || e)));
145
+ process.exitCode = 1;
146
+ return;
147
+ }
148
+ try {
149
+ const index = new SnapshotIndex({ repoRoot: git.root, repoName: derivedRepoName });
150
+ await index.load();
151
+ // Ensure manifest lives inside .codequill/snapshots/
152
+ const relFromRepo = path.relative(git.root, manifestPathAbs).split(path.sep).join('/');
153
+ index.upsertFromManifestFile({
154
+ manifestFileRel: relFromRepo,
155
+ manifest: {
156
+ commit: manifestObj.commit,
157
+ merkle_root: manifestObj.merkle_root,
158
+ timestamp: typeof manifestObj.timestamp === 'number' ? manifestObj.timestamp : 0,
159
+ },
160
+ kind: relFromRepo.toLowerCase().includes('published-') ? 'pulled' : 'local',
161
+ });
162
+ const publishedAt = typeof res.published_at === 'number' ? res.published_at : Math.floor(Date.now() / 1000);
163
+ index.attachPublishedByRoot({
164
+ merkle_root: manifestObj.merkle_root,
165
+ meta: {
166
+ snapshot_id: res.snapshot_id,
167
+ published_at: publishedAt,
168
+ tx_hash: res.tx_hash,
169
+ chain_id: res.chain_id,
170
+ manifest_cid: res.manifest_cid,
171
+ wallet_address: res.wallet_address,
172
+ },
173
+ });
174
+ await index.save();
175
+ }
176
+ catch {
177
+ // Index is a cache/helper; publish remains successful even if index fails.
178
+ }
179
+ // 7) Output
180
+ if (opts.json) {
181
+ console.log(JSON.stringify(res, null, 2));
182
+ }
183
+ else {
184
+ console.log('');
185
+ console.log(colors.bold('🚀 Publish started'));
186
+ console.log(colors.dim('────────────────────────────────────────'));
187
+ console.log(colors.dim('Publish'));
188
+ console.log(` Repository ${repoNameFromManifest}`);
189
+ console.log(` Commit ${commitHash}`);
190
+ console.log(` Merkle Root ${merkleRoot}`);
191
+ console.log(` Snapshot URL ${getBaseUrl() + '/s/' + res.snapshot_id}`);
192
+ console.log(` Repo ID ${res.repository_id}`);
193
+ console.log(` Tx Hash ${res.tx_hash}`);
194
+ console.log(` Manifest CID ${res.manifest_cid}`);
195
+ if (res.chain_id)
196
+ console.log(` Chain ID ${res.chain_id}`);
197
+ if (res.wallet_address)
198
+ console.log(` Wallet ${res.wallet_address}`);
199
+ if (res.explorer_url)
200
+ console.log(` Explorer ${res.explorer_url}`);
201
+ console.log(colors.dim('────────────────────────────────────────'));
202
+ }
203
+ if (opts.noWait) {
204
+ log(colors.dim('Note: skipping confirmation wait (--no-wait).'));
205
+ return;
206
+ }
207
+ // 8) Wait confirmation
208
+ const confTarget = Math.max(1, Number(opts.confirmations ?? 1));
209
+ try {
210
+ await waitForTxConfirmation({
211
+ txHash: res.tx_hash,
212
+ confirmations: confTarget,
213
+ timeoutMs: opts.timeoutMs,
214
+ silent: opts.json,
215
+ });
216
+ log(colors.success(`✓ Confirmed on-chain (${confTarget} confirmation${confTarget > 1 ? 's' : ''}).`));
217
+ }
218
+ catch (e) {
219
+ console.error(colors.error(String(e?.message || e)));
220
+ process.exitCode = 1;
221
+ }
222
+ }
223
+ export function registerPublishCommand(program) {
224
+ program
225
+ .command('publish [commit]')
226
+ .description('Publish a local snapshot manifest (by commit, default HEAD) to IPFS + anchor Merkle root on-chain')
227
+ .option('--no-confirm', 'Skip interactive confirmation')
228
+ .option('--confirmations <n>', 'Wait for N confirmations (default: 1)', (v) => parseInt(v, 10))
229
+ .option('--timeout <ms>', 'Timeout waiting for confirmation (ms)', (v) => parseInt(v, 10))
230
+ .option('--no-wait', 'Do not wait for confirmation')
231
+ .option('--json', 'Output result in JSON format', false)
232
+ .action(async (commit, options) => {
233
+ await handlePublish({
234
+ commit,
235
+ noConfirm: !!options.noConfirm,
236
+ confirmations: options.confirmations,
237
+ timeoutMs: options.timeout,
238
+ noWait: options.wait === false,
239
+ json: !!options.json,
240
+ });
241
+ });
242
+ }
243
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,174 @@
1
+ import { colors, shortCommit, spinner } from '../services/ui.js';
2
+ import { apiClient } from '../services/apiClient.js';
3
+ import { ApiError } from '../services/errors.js';
4
+ import { detectGitRepo, deriveRepoName } from '../services/git.js';
5
+ import { ensureDir, fileExists, writeFileUtf8 } from '../services/fs.js';
6
+ import { SnapshotIndex } from '../services/snapshotIndex.js';
7
+ import path from 'node:path';
8
+ import { assertAuthenticated } from "../services/utilities.js";
9
+ function safeFileName(x) {
10
+ return String(x ?? '').replace(/[^a-zA-Z0-9._-]+/g, '-');
11
+ }
12
+ async function fetchPublished(repoName) {
13
+ const res = await apiClient.get(`/v1/cli/snapshots?repo_name=${encodeURIComponent(repoName)}`);
14
+ return Array.isArray(res?.snapshots) ? res.snapshots : [];
15
+ }
16
+ async function fetchManifest(snapshotId) {
17
+ const res = await apiClient.get(`/v1/cli/snapshots/${encodeURIComponent(snapshotId)}/manifest`);
18
+ if (!res?.manifest || typeof res.manifest !== 'object') {
19
+ throw new Error('Invalid backend manifest response.');
20
+ }
21
+ return res.manifest;
22
+ }
23
+ export async function handlePull(_opts) {
24
+ if (!assertAuthenticated())
25
+ return;
26
+ const git = detectGitRepo(process.cwd());
27
+ if (!git.isRepo || !git.root) {
28
+ console.error(colors.error('This command must be run inside a git repository.'));
29
+ process.exitCode = 1;
30
+ return;
31
+ }
32
+ const repoName = deriveRepoName(git.root, git.remote);
33
+ if (!repoName) {
34
+ console.error(colors.error('Unable to determine repository name from git remote.'));
35
+ console.error(colors.dim('Make sure you have a GitHub origin remote configured.'));
36
+ process.exitCode = 1;
37
+ return;
38
+ }
39
+ // Ensure snapshots folder exists
40
+ const snapshotsDirAbs = path.join(git.root, '.codequill', 'snapshots');
41
+ await ensureDir(snapshotsDirAbs);
42
+ // Load index (will rebuild from disk if missing/corrupt)
43
+ const index = new SnapshotIndex({ repoRoot: git.root, repoName });
44
+ await index.load();
45
+ // Fetch published snapshots
46
+ const s = spinner(`Fetching published snapshots for ${repoName} ...`);
47
+ let published = [];
48
+ try {
49
+ published = await fetchPublished(repoName);
50
+ s.succeed(colors.success(`Found ${published.length} published snapshot${published.length === 1 ? '' : 's'}.`));
51
+ }
52
+ catch (e) {
53
+ s.fail(colors.error('Failed to fetch published snapshots.'));
54
+ if (e instanceof ApiError && e.status === 401) {
55
+ console.error(colors.error('Unauthorized. Run `codequill login` again.'));
56
+ }
57
+ else if (e instanceof ApiError) {
58
+ console.error(colors.error(`${e.message} (${e.status})`));
59
+ if (e.requestId)
60
+ console.error(colors.dim(`Request ID: ${e.requestId}`));
61
+ if (e.method && e.url)
62
+ console.error(colors.dim(`Endpoint: ${e.method} ${e.url}`));
63
+ }
64
+ else {
65
+ console.error(colors.error(String(e?.message || e)));
66
+ }
67
+ process.exitCode = 1;
68
+ return;
69
+ }
70
+ if (published.length === 0) {
71
+ console.log('');
72
+ console.log(colors.warn('⚠ No published snapshots found for this repository.'));
73
+ console.log(colors.dim('Hint: run `codequill publish <manifest>` to anchor your first snapshot on-chain.'));
74
+ return;
75
+ }
76
+ // Sort newest first (nice UX + consistent latest)
77
+ published.sort((a, b) => (Number(b.published_at ?? 0) - Number(a.published_at ?? 0)));
78
+ // Enrich index with backend published list (adds published meta + remote-only items)
79
+ index.enrichFromBackend(published);
80
+ // Determine which ones we need to download:
81
+ // - remote-only items, OR items whose file is missing on disk
82
+ const items = index.list();
83
+ const wantByRoot = new Map();
84
+ for (const it of items) {
85
+ if (!it.published)
86
+ continue;
87
+ const root = it.merkle_root;
88
+ if (!root)
89
+ continue;
90
+ const snapshotId = String(it.published.snapshot_id ?? '').trim();
91
+ if (!snapshotId)
92
+ continue;
93
+ const hasFile = !!it.file;
94
+ let fileOk = false;
95
+ if (hasFile && it.file) {
96
+ const abs = path.join(git.root, it.file);
97
+ fileOk = await fileExists(abs);
98
+ }
99
+ if (!hasFile || !fileOk) {
100
+ // Find commit hash from backend list (more reliable)
101
+ const pub = published.find((p) => String(p.snapshot_id) === snapshotId);
102
+ const commitHash = String(pub?.commit_hash ?? it.commit ?? '').trim();
103
+ wantByRoot.set(root, { snapshot_id: snapshotId, commit_hash: commitHash });
104
+ }
105
+ }
106
+ const toPull = Array.from(wantByRoot.values());
107
+ console.log('');
108
+ console.log(colors.bold('⬇️ CodeQuill Pull'));
109
+ console.log(colors.dim('────────────────────────────────────────'));
110
+ console.log(`Repository ${repoName}`);
111
+ console.log(`Published ${published.length}`);
112
+ console.log(`To download ${toPull.length}`);
113
+ console.log(colors.dim('────────────────────────────────────────'));
114
+ if (toPull.length === 0) {
115
+ console.log(colors.success('✔ Nothing to pull. Published history is already present locally.'));
116
+ // still save index because enrichFromBackend might have updated ordering/latest
117
+ await index.save();
118
+ return;
119
+ }
120
+ let ok = 0;
121
+ let fail = 0;
122
+ for (const p of toPull) {
123
+ const label = `${p.snapshot_id} (${shortCommit(p.commit_hash)})`;
124
+ const sOne = spinner(`Downloading manifest ${label} ...`);
125
+ try {
126
+ const manifest = await fetchManifest(p.snapshot_id);
127
+ const cShort = safeFileName(shortCommit(p.commit_hash || manifest.commit));
128
+ const fname = `snapshot-${cShort}.json`;
129
+ const outAbs = path.join(snapshotsDirAbs, fname);
130
+ const outRel = path.relative(git.root, outAbs).split(path.sep).join('/'); // normalize to forward slashes
131
+ await writeFileUtf8(outAbs, JSON.stringify(manifest, null, 2));
132
+ // Upsert disk item into index (no full rescan required)
133
+ index.upsertFromManifestFile({
134
+ manifestFileRel: outRel,
135
+ manifest: {
136
+ commit: manifest.commit,
137
+ merkle_root: manifest.merkle_root,
138
+ timestamp: manifest.timestamp,
139
+ },
140
+ kind: 'pulled',
141
+ });
142
+ sOne.succeed(colors.success(`Saved: ${path.relative(process.cwd(), outAbs)}`));
143
+ ok += 1;
144
+ }
145
+ catch (e) {
146
+ sOne.fail(colors.error(`Failed: ${label}`));
147
+ console.error(colors.dim(String(e?.message || e)));
148
+ fail += 1;
149
+ }
150
+ }
151
+ // One save at end (fast + consistent)
152
+ const sIdx = spinner('Updating index ...');
153
+ try {
154
+ await index.save();
155
+ sIdx.succeed(colors.success('Index updated.'));
156
+ }
157
+ catch (e) {
158
+ sIdx.fail(colors.warn('Index update failed (snapshots are still downloaded).'));
159
+ console.error(colors.dim(String(e?.message || e)));
160
+ }
161
+ console.log(colors.dim('────────────────────────────────────────'));
162
+ console.log(`${colors.success('Downloaded')} ${ok}`);
163
+ if (fail)
164
+ console.log(`${colors.error('Failed')} ${fail}`);
165
+ }
166
+ export function registerPullCommand(program) {
167
+ program
168
+ .command('pull')
169
+ .description('Download all published snapshot manifests for the current repository into .codequill/snapshots')
170
+ .action(async () => {
171
+ await handlePull({});
172
+ });
173
+ }
174
+ //# sourceMappingURL=pull.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import { apiClient } from '../services/apiClient.js';
2
+ import { colors, spinner } from '../services/ui.js';
3
+ import { ApiError } from '../services/errors.js';
4
+ import { deriveRepoName, detectGitRepo } from "../services/git.js";
5
+ import { assertAuthenticated } from "../services/utilities.js";
6
+ export async function handleQuota(opts) {
7
+ if (!assertAuthenticated())
8
+ return;
9
+ const git = detectGitRepo(process.cwd());
10
+ if (!git.isRepo || !git.root) {
11
+ console.error(colors.error('This command must be run inside a git repository.'));
12
+ process.exitCode = 1;
13
+ return;
14
+ }
15
+ const repoName = deriveRepoName(git.root, git.remote);
16
+ if (!repoName) {
17
+ console.error(colors.error('Unable to determine repository name from git remote.'));
18
+ console.error(colors.dim('Make sure you have a GitHub origin remote configured.'));
19
+ process.exitCode = 1;
20
+ return;
21
+ }
22
+ const s = spinner(`Loading CodeQuill quota for ${repoName} ...`);
23
+ let quota;
24
+ try {
25
+ const q = encodeURIComponent(repoName);
26
+ quota = await apiClient.get(`/v1/cli/quota?repo_name=${q}`);
27
+ s.succeed(colors.success('Quota loaded.'));
28
+ }
29
+ catch (e) {
30
+ s.fail(colors.error('Failed to load quota.'));
31
+ if (e instanceof ApiError && e.status === 401) {
32
+ console.error(colors.error('Unauthorized. Run `codequill login` again.'));
33
+ }
34
+ else if (e instanceof ApiError) {
35
+ console.error(colors.error(`${e.message} (${e.status})`));
36
+ if (e.requestId)
37
+ console.error(colors.dim(`Request ID: ${e.requestId}`));
38
+ if (e.method && e.url)
39
+ console.error(colors.dim(`Endpoint: ${e.method} ${e.url}`));
40
+ }
41
+ else {
42
+ console.error(colors.error(String(e?.message || e)));
43
+ }
44
+ process.exitCode = 1;
45
+ return;
46
+ }
47
+ if (opts.json) {
48
+ const payload = {
49
+ workspace_name: quota.workspace_name,
50
+ plan_code: quota.plan_code,
51
+ claim_public_limit: quota.claim_public_limit,
52
+ claim_private_limit: quota.claim_private_limit,
53
+ api_repository_limit: quota.api_repository_limit,
54
+ collaborator_limit: quota.collaborator_limit,
55
+ publish_monthly_limit: quota.publish_monthly_limit,
56
+ attestation_monthly_limit: quota.attestation_monthly_limit,
57
+ claim_public_used: quota.claim_public_used,
58
+ claim_private_used: quota.claim_private_used,
59
+ api_repository_used: quota.api_repository_used,
60
+ collaborator_used: quota.collaborator_used,
61
+ publish_used: quota.publish_used,
62
+ attestation_used: quota.attestation_used
63
+ };
64
+ console.log(JSON.stringify(payload, null, 2));
65
+ return;
66
+ }
67
+ console.log(colors.bold('Workspace:'), colors.info(quota.workspace_name));
68
+ console.log(colors.bold('Subscription plan:'), colors.info(quota.plan_code));
69
+ console.log('\nClaimed repositories:');
70
+ console.log(` - Public: ${quota.claim_public_used} / ${quota.claim_public_limit}`);
71
+ console.log(` - Private: ${quota.claim_private_used} / ${quota.claim_private_limit}`);
72
+ console.log('\nCI integrations:');
73
+ console.log(` - Used: ${quota.api_repository_used} / ${quota.api_repository_limit}`);
74
+ console.log('\nSnapshots:');
75
+ console.log(` - Used this month: ${quota.publish_used} / ${quota.publish_monthly_limit}`);
76
+ console.log('\nAttestations:');
77
+ console.log(` - Used this month: ${quota.attestation_used} / ${quota.attestation_monthly_limit}`);
78
+ console.log('\nBackups:');
79
+ console.log(` - Used this month: ${quota.backup_used} / ${quota.backup_monthly_limit}`);
80
+ console.log('\nCollaborators:');
81
+ console.log(` - Used : ${quota.collaborator_used} / ${quota.collaborator_limit}`);
82
+ }
83
+ export function registerQuotaCommand(program) {
84
+ program
85
+ .command('quota')
86
+ .description('Show your subscription plan and quota usage for the current workspace')
87
+ .option('--json', 'Output machine-readable JSON', false)
88
+ .action(async (options) => {
89
+ await handleQuota({
90
+ json: !!options.json
91
+ });
92
+ });
93
+ }
94
+ //# sourceMappingURL=quota.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quota.js","sourceRoot":"","sources":["../../src/commands/quota.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ import { colors, spinner } from '../services/ui.js';
2
+ import { apiClient } from '../services/apiClient.js';
3
+ import { assertAuthenticated } from '../services/utilities.js';
4
+ import { waitForTxConfirmation } from '../services/txWaiter.js';
5
+ import { getBaseUrl } from '../services/config.js';
6
+ export async function handleRevoke(attestationId, opts) {
7
+ if (!assertAuthenticated())
8
+ return;
9
+ const id = String(attestationId || '').trim();
10
+ if (!id) {
11
+ console.error(colors.error('Missing <attestationId>.'));
12
+ process.exitCode = 1;
13
+ return;
14
+ }
15
+ // 1) Call backend (backend resolves uuid -> (repoId,digest,type) + author wallet and relays revoke tx)
16
+ const s = spinner('Revoking attestation ...');
17
+ let res;
18
+ try {
19
+ // Keep payload explicit. Backend can ignore fields it doesn't support yet.
20
+ const body = {
21
+ attestation_id: id,
22
+ // Off-chain context (DB + UI)
23
+ reason: opts.reason ? String(opts.reason) : undefined,
24
+ replacement_attestation_id: opts.replacement ? String(opts.replacement) : undefined,
25
+ // Optional on-chain context (if your contract includes these)
26
+ note_cid: opts.noteCid ? String(opts.noteCid) : undefined,
27
+ onchain_reason: typeof opts.onchainReason === 'number' ? opts.onchainReason : undefined,
28
+ };
29
+ res = await apiClient.post('/v1/cli/attest/revoke', body);
30
+ if (!res || !res.attestation_id)
31
+ throw new Error('Malformed revoke response.');
32
+ s.succeed(colors.success(res.status === 'already_revoked' ? 'Already revoked.' : 'Revocation submitted.'));
33
+ }
34
+ catch (e) {
35
+ s.fail(colors.error('Revocation failed.'));
36
+ console.error(colors.error(String(e?.message || e)));
37
+ process.exitCode = 1;
38
+ return;
39
+ }
40
+ // 2) Output
41
+ console.log('');
42
+ console.log(colors.bold('🧯 Attestation revocation'));
43
+ console.log(colors.dim('────────────────────────────────────────'));
44
+ console.log(` Attestation ID ${res.attestation_id}`);
45
+ console.log(` Status ${res.status}`);
46
+ console.log(` URL ${getBaseUrl() + '/a/' + res.attestation_id}`);
47
+ if (res.tx_hash)
48
+ console.log(` Tx Hash ${res.tx_hash}`);
49
+ if (res.chain_id)
50
+ console.log(` Chain ID ${res.chain_id}`);
51
+ if (res.explorer_url)
52
+ console.log(` Explorer ${res.explorer_url}`);
53
+ console.log(colors.dim('────────────────────────────────────────'));
54
+ // 3) Wait confirmation (if tx returned and user wants it)
55
+ if (opts.noWait || !res.tx_hash) {
56
+ if (!res.tx_hash)
57
+ console.log(colors.dim('Note: no tx hash returned (revocation may be purely off-chain or queued).'));
58
+ return;
59
+ }
60
+ const confTarget = Math.max(1, Number(opts.confirmations ?? 1));
61
+ try {
62
+ await waitForTxConfirmation({
63
+ txHash: res.tx_hash,
64
+ confirmations: confTarget,
65
+ timeoutMs: opts.timeoutMs,
66
+ });
67
+ console.log(colors.success(`✓ Confirmed on-chain (${confTarget} confirmation${confTarget > 1 ? 's' : ''}).`));
68
+ }
69
+ catch (e) {
70
+ console.error(colors.error(String(e?.message || e)));
71
+ process.exitCode = 1;
72
+ }
73
+ }
74
+ export function registerRevokeCommand(program) {
75
+ program
76
+ .command('revoke <attestationId>')
77
+ .description('Revoke an attestation (records revocation; does not delete).')
78
+ .option('--reason <text>', 'Human-readable reason (stored off-chain)')
79
+ .option('--replacement <attestationId>', 'Replacement attestation UUID (stored off-chain)')
80
+ .option('--note-cid <cid>', 'Optional public CID with revocation note')
81
+ .option('--onchain-reason <n>', 'Optional on-chain reason code (uint8)', (v) => parseInt(v, 10))
82
+ .option('--confirmations <n>', 'Wait for N confirmations (default: 1)', (v) => parseInt(v, 10))
83
+ .option('--timeout <ms>', 'Timeout waiting for confirmation (ms)', (v) => parseInt(v, 10))
84
+ .option('--no-wait', 'Do not wait for confirmation', false)
85
+ .action(async (attestationId, options) => {
86
+ await handleRevoke(attestationId, {
87
+ reason: options.reason,
88
+ replacement: options.replacement,
89
+ noteCid: options.noteCid,
90
+ onchainReason: Number.isFinite(options.onchainReason) ? options.onchainReason : undefined,
91
+ confirmations: options.confirmations,
92
+ timeoutMs: options.timeout,
93
+ noWait: !!options.noWait,
94
+ });
95
+ });
96
+ }
97
+ //# sourceMappingURL=revoke.js.map