@c956180462/awbs 0.0.1

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 (50) hide show
  1. package/AWBS_CORE_DESIGN.md +983 -0
  2. package/AWBS_CURRENT_FEATURES.md +463 -0
  3. package/LICENSE +21 -0
  4. package/README.md +265 -0
  5. package/TASK_001_VIEW_AUTHORITY.md +446 -0
  6. package/TASK_003_AUTHORITY_LEDGER_AND_DB_AUDIT.md +268 -0
  7. package/TASK_004_TRUSTED_AUTHORITY_LAYER.md +547 -0
  8. package/TASK_005_AUTHORITY_SESSION.md +218 -0
  9. package/TASK_006_TRUST_BOUNDARY_HARDENING.md +381 -0
  10. package/TASK_007_TRUSTED_OPERATION_ENTRY.md +129 -0
  11. package/bin/awbs.js +2 -0
  12. package/docs/DEVELOPMENT_LEARNING.md +319 -0
  13. package/docs/FULL_CHAIN.md +295 -0
  14. package/docs/PRODUCT.md +188 -0
  15. package/docs/USAGE.md +294 -0
  16. package/package.json +45 -0
  17. package/src/adapters/file-summary-store.ts +88 -0
  18. package/src/adapters/git-cli.ts +107 -0
  19. package/src/adapters/local-authority-session.ts +606 -0
  20. package/src/adapters/local-file-database.ts +199 -0
  21. package/src/adapters/sealed-authority.ts +725 -0
  22. package/src/adapters/session-authority-client.ts +176 -0
  23. package/src/adapters/sqlite-index-store.ts +176 -0
  24. package/src/cli.ts +491 -0
  25. package/src/domain/authority-types.ts +194 -0
  26. package/src/domain/constants.ts +11 -0
  27. package/src/domain/errors.ts +6 -0
  28. package/src/domain/hash.ts +27 -0
  29. package/src/domain/path-policy.ts +36 -0
  30. package/src/domain/paths.ts +65 -0
  31. package/src/domain/session-proof.ts +140 -0
  32. package/src/domain/session-types.ts +101 -0
  33. package/src/domain/types.ts +94 -0
  34. package/src/ports/authority-session.ts +8 -0
  35. package/src/ports/authority.ts +26 -0
  36. package/src/ports/file-database.ts +18 -0
  37. package/src/ports/git.ts +23 -0
  38. package/src/ports/index-store.ts +7 -0
  39. package/src/ports/summary-store.ts +16 -0
  40. package/src/runtime.ts +56 -0
  41. package/src/session-entry.ts +1 -0
  42. package/src/usecases/authority.ts +53 -0
  43. package/src/usecases/changeset.ts +437 -0
  44. package/src/usecases/db.ts +192 -0
  45. package/src/usecases/index.ts +136 -0
  46. package/src/usecases/init.ts +48 -0
  47. package/src/usecases/ledger.ts +146 -0
  48. package/src/usecases/session.ts +48 -0
  49. package/src/usecases/trusted-chain.ts +56 -0
  50. package/src/usecases/view.ts +166 -0
package/src/cli.ts ADDED
@@ -0,0 +1,491 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { AwbsError } from "./domain/errors.ts";
4
+ import { createDefaultRuntime } from "./runtime.ts";
5
+ import { runAuthoritySessionDaemon, runAuthoritySessionRequest } from "./session-entry.ts";
6
+
7
+ type ParsedArgs = {
8
+ positionals: string[];
9
+ flags: Map<string, string[]>;
10
+ };
11
+
12
+ async function main(): Promise<void> {
13
+ const [, , ...argv] = process.argv;
14
+ if (argv[0] === "__session-daemon") {
15
+ await runAuthoritySessionDaemon();
16
+ return;
17
+ }
18
+ if (argv[0] === "__session-request") {
19
+ await runAuthoritySessionRequest();
20
+ return;
21
+ }
22
+
23
+ if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) {
24
+ printHelp();
25
+ return;
26
+ }
27
+
28
+ const [domain, action, ...rest] = argv;
29
+ const parsed = parseArgs(rest);
30
+ const cwd = process.cwd();
31
+ const cliPath = process.argv[1];
32
+
33
+ if (domain === "init") {
34
+ const runtime = createDefaultRuntime({ cliPath });
35
+ runtime.usecases.init.initProject(cwd);
36
+ console.log("AWBS project initialized.");
37
+ return;
38
+ }
39
+
40
+ if (domain === "index" && action === "rebuild") {
41
+ const runtime = createDefaultRuntime({ cliPath });
42
+ const result = runtime.usecases.index.rebuildIndex(cwd);
43
+ console.log(`Index rebuilt: ${result.active} active, ${result.removed} removed -> ${result.path}`);
44
+ return;
45
+ }
46
+
47
+ if (domain === "index" && action === "query") {
48
+ const runtime = createDefaultRuntime({ cliPath });
49
+ const json = parsed.flags.has("json");
50
+ const status = singleFlag(parsed, "status") ?? "active";
51
+ if (!["active", "removed", "all"].includes(status)) {
52
+ throw new AwbsError("--status must be active, removed, or all.");
53
+ }
54
+ const entries = runtime.usecases.index.queryIndex(cwd, parsed.positionals[0] ?? null, { json, status: status as "active" | "removed" | "all" });
55
+ if (json) {
56
+ console.log(JSON.stringify(entries, null, 2));
57
+ } else {
58
+ for (const entry of entries) {
59
+ console.log(`${entry.status.padEnd(7)} ${entry.kind.padEnd(9)} ${entry.path} :: ${entry.summary}`);
60
+ }
61
+ }
62
+ return;
63
+ }
64
+
65
+ if (domain === "summary" && action === "set") {
66
+ const runtime = createDefaultRuntime({ cliPath });
67
+ const target = parsed.positionals[0];
68
+ if (!target) {
69
+ throw new AwbsError("summary set requires a path.");
70
+ }
71
+ const inlineText = singleFlag(parsed, "text");
72
+ const filePath = singleFlag(parsed, "file");
73
+ if ((inlineText && filePath) || (!inlineText && !filePath)) {
74
+ throw new AwbsError("summary set requires exactly one of --text or --file.");
75
+ }
76
+ const summary = inlineText ?? readFileSync(filePath!, "utf8");
77
+ const entry = runtime.usecases.index.setSummary(cwd, { path: target, summary });
78
+ console.log(`Summary set: ${entry.path}`);
79
+ return;
80
+ }
81
+
82
+ if (domain === "summary" && action === "get") {
83
+ const runtime = createDefaultRuntime({ cliPath });
84
+ const target = parsed.positionals[0];
85
+ if (!target) {
86
+ throw new AwbsError("summary get requires a path.");
87
+ }
88
+ const entry = runtime.usecases.index.getSummary(cwd, target);
89
+ if (parsed.flags.has("json")) {
90
+ console.log(JSON.stringify(entry, null, 2));
91
+ } else if (entry) {
92
+ console.log(entry.summary);
93
+ } else {
94
+ console.log("No external summary found.");
95
+ process.exitCode = 1;
96
+ }
97
+ return;
98
+ }
99
+
100
+ if (domain === "summary" && action === "list") {
101
+ const runtime = createDefaultRuntime({ cliPath });
102
+ const entries = runtime.usecases.index.listSummaries(cwd);
103
+ if (parsed.flags.has("json")) {
104
+ console.log(JSON.stringify(entries, null, 2));
105
+ } else {
106
+ for (const entry of entries) {
107
+ console.log(`${entry.path} :: ${entry.summary}`);
108
+ }
109
+ }
110
+ return;
111
+ }
112
+
113
+ if (domain === "view" && action === "create") {
114
+ const runtime = createDefaultRuntime({ cliPath, authorityMode: "session", controllerToken: requiredControllerToken(parsed) });
115
+ const out = requiredFlag(parsed, "out");
116
+ const readPaths = multiFlag(parsed, "read");
117
+ const writePaths = multiFlag(parsed, "write");
118
+ const manifest = runtime.usecases.view.createView(cwd, { out, readPaths, writePaths });
119
+ console.log(`View created: ${manifest.viewId}`);
120
+ console.log(`Workspace: ${manifest.workspacePath}`);
121
+ return;
122
+ }
123
+
124
+ if (domain === "view" && action === "inspect") {
125
+ const runtime = createDefaultRuntime({ cliPath, authorityMode: "auto" });
126
+ const viewId = parsed.positionals[0];
127
+ if (!viewId) {
128
+ throw new AwbsError("view inspect requires a view id.");
129
+ }
130
+ const result = runtime.usecases.view.inspectView(cwd, viewId);
131
+ if (parsed.flags.has("json")) {
132
+ console.log(JSON.stringify(result, null, 2));
133
+ } else {
134
+ console.log(`View: ${result.contract.viewId}`);
135
+ console.log(`Status: ${result.catalogView.status}`);
136
+ console.log(`Base commit: ${result.contract.baseCommit}`);
137
+ console.log(`Read: ${result.contract.readPaths.join(", ") || "(none)"}`);
138
+ console.log(`Write: ${result.contract.writePaths.join(", ") || "(none)"}`);
139
+ if (result.catalogView.revokedAt) {
140
+ console.log(`Revoked at: ${result.catalogView.revokedAt}`);
141
+ }
142
+ }
143
+ return;
144
+ }
145
+
146
+ if (domain === "view" && action === "revoke") {
147
+ const runtime = createDefaultRuntime({ cliPath, authorityMode: "session", controllerToken: requiredControllerToken(parsed) });
148
+ const viewId = parsed.positionals[0];
149
+ if (!viewId) {
150
+ throw new AwbsError("view revoke requires a view id.");
151
+ }
152
+ runtime.usecases.view.revokeView(cwd, viewId);
153
+ console.log(`View revoked: ${viewId}`);
154
+ return;
155
+ }
156
+
157
+ if (domain === "changeset" && action === "collect") {
158
+ const runtime = createDefaultRuntime({ cliPath, authorityMode: "auto" });
159
+ const workspace = requiredFlag(parsed, "workspace");
160
+ const manifest = runtime.usecases.changeset.collectChangeset(cwd, workspace);
161
+ console.log(`Changeset collected: ${manifest.changesetId}`);
162
+ console.log(`Status: ${manifest.status}`);
163
+ console.log(`Added: ${manifest.summary.added}, modified: ${manifest.summary.modified}, deleted: ${manifest.summary.deleted}, violations: ${manifest.summary.violations}`);
164
+ return;
165
+ }
166
+
167
+ if (domain === "changeset" && action === "inspect") {
168
+ const runtime = createDefaultRuntime({ cliPath });
169
+ const target = parsed.positionals[0];
170
+ if (!target) {
171
+ throw new AwbsError("changeset inspect requires a changeset path or id.");
172
+ }
173
+ const manifest = runtime.usecases.changeset.inspectChangeset(cwd, target);
174
+ if (parsed.flags.has("json")) {
175
+ console.log(JSON.stringify(manifest, null, 2));
176
+ } else {
177
+ console.log(runtime.usecases.changeset.formatChangesetSummary(manifest));
178
+ }
179
+ return;
180
+ }
181
+
182
+ if (domain === "changeset" && action === "apply") {
183
+ const runtime = createDefaultRuntime({ cliPath, authorityMode: "session", controllerToken: requiredControllerToken(parsed) });
184
+ const target = parsed.positionals[0];
185
+ if (!target) {
186
+ throw new AwbsError("changeset apply requires a changeset path or id.");
187
+ }
188
+ const adapter = singleFlag(parsed, "adapter") ?? "same-path";
189
+ const result = runtime.usecases.changeset.applyChangeset(cwd, target, adapter);
190
+ if (result.commit) {
191
+ console.log(`Changeset applied: ${result.applied} change(s), commit ${result.commit}`);
192
+ } else {
193
+ console.log("Changeset contained no applicable changes.");
194
+ }
195
+ return;
196
+ }
197
+
198
+ if (domain === "ledger" && action === "bootstrap") {
199
+ const runtime = createDefaultRuntime({ cliPath, authorityMode: "session", controllerToken: requiredControllerToken(parsed) });
200
+ const result = runtime.usecases.ledger.bootstrapLedger(cwd);
201
+ if (parsed.flags.has("json")) {
202
+ console.log(JSON.stringify(result, null, 2));
203
+ } else {
204
+ console.log(`Trusted chain bootstrapped: ${result.currentTrustedCommit}`);
205
+ console.log(`Parent: ${result.parentTrustedCommit}`);
206
+ console.log(`Entry: ${result.headEntryId}`);
207
+ }
208
+ return;
209
+ }
210
+
211
+ if (domain === "ledger" && (action === "inspect" || action === "verify")) {
212
+ const runtime = createDefaultRuntime({ cliPath, authorityMode: "auto" });
213
+ const report = action === "inspect" ? runtime.usecases.ledger.inspectLedger(cwd) : runtime.usecases.ledger.verifyLedger(cwd);
214
+ if (parsed.flags.has("json")) {
215
+ console.log(JSON.stringify(report, null, 2));
216
+ } else {
217
+ console.log(runtime.usecases.ledger.formatLedgerReport(report));
218
+ }
219
+ if (!report.ok) {
220
+ process.exitCode = 1;
221
+ }
222
+ return;
223
+ }
224
+
225
+ if (domain === "db" && action === "audit") {
226
+ const runtime = createDefaultRuntime({ cliPath, authorityMode: "auto" });
227
+ const report = runtime.usecases.db.auditDatabase(cwd);
228
+ if (parsed.flags.has("json")) {
229
+ console.log(JSON.stringify(report, null, 2));
230
+ } else {
231
+ console.log(runtime.usecases.db.formatAuditReport(report));
232
+ }
233
+ if (!report.ok) {
234
+ process.exitCode = 1;
235
+ }
236
+ return;
237
+ }
238
+
239
+ if (domain === "db" && action === "clean-rebuild") {
240
+ const runtime = createDefaultRuntime({ cliPath });
241
+ const session = runtime.usecases.session.statusSession(cwd);
242
+ if (session.active) {
243
+ throw new AwbsError("Stop the authority session before running db clean-rebuild.");
244
+ }
245
+ const report = runtime.usecases.db.cleanRebuild(cwd);
246
+ if (parsed.flags.has("json")) {
247
+ console.log(JSON.stringify(report, null, 2));
248
+ } else {
249
+ console.log(runtime.usecases.db.formatCleanRebuildReport(report));
250
+ }
251
+ return;
252
+ }
253
+
254
+ if (domain === "db" && action === "backups" && parsed.positionals[0] === "list") {
255
+ const runtime = createDefaultRuntime({ cliPath });
256
+ const backups = runtime.usecases.db.listBackups(cwd);
257
+ if (parsed.flags.has("json")) {
258
+ console.log(JSON.stringify(backups, null, 2));
259
+ } else if (backups.length === 0) {
260
+ console.log("No AWBS database backups found.");
261
+ } else {
262
+ for (const backup of backups) {
263
+ console.log(backup);
264
+ }
265
+ }
266
+ return;
267
+ }
268
+
269
+ if (domain === "authority" && action === "session") {
270
+ const runtime = createDefaultRuntime({ cliPath });
271
+ const subaction = parsed.positionals[0];
272
+ if (subaction === "start") {
273
+ if (!parsed.flags.has("control-stdin")) {
274
+ throw new AwbsError("authority session start requires --control-stdin.");
275
+ }
276
+ const result = await runtime.usecases.session.startSession(cwd, readControlInput());
277
+ if (parsed.flags.has("json")) {
278
+ console.log(JSON.stringify(result, null, 2));
279
+ } else {
280
+ console.log(runtime.usecases.session.formatStatus(result));
281
+ console.log(`Recovery seal: ${result.recoverySealPath}`);
282
+ }
283
+ return;
284
+ }
285
+ if (subaction === "status") {
286
+ const result = runtime.usecases.session.statusSession(cwd);
287
+ if (parsed.flags.has("json")) {
288
+ console.log(JSON.stringify(result, null, 2));
289
+ } else {
290
+ console.log(runtime.usecases.session.formatStatus(result));
291
+ }
292
+ if (result.status === "stale" || result.status === "unavailable") {
293
+ process.exitCode = 1;
294
+ }
295
+ return;
296
+ }
297
+ if (subaction === "stop") {
298
+ if (!parsed.flags.has("control-token-stdin")) {
299
+ throw new AwbsError("authority session stop requires --control-token-stdin.");
300
+ }
301
+ const result = runtime.usecases.session.stopSession(cwd, readControllerTokenFromStdin());
302
+ if (parsed.flags.has("json")) {
303
+ console.log(JSON.stringify(result, null, 2));
304
+ } else {
305
+ console.log(`Authority session stopped. Local restored: ${result.localRestored ? "yes" : "no"}`);
306
+ }
307
+ return;
308
+ }
309
+ if (subaction === "recover") {
310
+ if (!parsed.flags.has("recovery-secret-stdin")) {
311
+ throw new AwbsError("authority session recover requires --recovery-secret-stdin.");
312
+ }
313
+ const result = runtime.usecases.session.recoverSession(cwd, readRecoverySecretFromStdin());
314
+ if (parsed.flags.has("json")) {
315
+ console.log(JSON.stringify(result, null, 2));
316
+ } else {
317
+ console.log(`Authority local material recovered: ${result.recovered ? "yes" : "already present"}`);
318
+ }
319
+ return;
320
+ }
321
+ throw new AwbsError("authority session requires start, status, stop, or recover.");
322
+ }
323
+
324
+ if (domain === "authority" && action === "verify") {
325
+ const runtime = createDefaultRuntime({ cliPath, authorityMode: "auto" });
326
+ const report = runtime.usecases.authority.verifyAuthority(cwd);
327
+ if (parsed.flags.has("json")) {
328
+ console.log(JSON.stringify(report, null, 2));
329
+ } else {
330
+ console.log(runtime.usecases.authority.formatVerifyReport(report));
331
+ }
332
+ if (!report.ok) {
333
+ process.exitCode = 1;
334
+ }
335
+ return;
336
+ }
337
+
338
+ if (domain === "authority" && action === "repair-mirrors") {
339
+ const runtime = createDefaultRuntime({ cliPath, authorityMode: "session", controllerToken: requiredControllerToken(parsed) });
340
+ const report = runtime.usecases.authority.repairMirrors(cwd);
341
+ if (parsed.flags.has("json")) {
342
+ console.log(JSON.stringify(report, null, 2));
343
+ } else {
344
+ console.log(runtime.usecases.authority.formatRepairReport(report));
345
+ }
346
+ return;
347
+ }
348
+
349
+ throw new AwbsError(`Unknown command: ${argv.join(" ")}`);
350
+ }
351
+
352
+ function parseArgs(argv: string[]): ParsedArgs {
353
+ const positionals: string[] = [];
354
+ const flags = new Map<string, string[]>();
355
+
356
+ for (let index = 0; index < argv.length; index += 1) {
357
+ const token = argv[index];
358
+ if (token.startsWith("--")) {
359
+ const [rawName, inlineValue] = token.slice(2).split("=", 2);
360
+ const values = flags.get(rawName) ?? [];
361
+ if (inlineValue !== undefined) {
362
+ values.push(inlineValue);
363
+ } else if (argv[index + 1] && !argv[index + 1].startsWith("--")) {
364
+ values.push(argv[index + 1]);
365
+ index += 1;
366
+ } else {
367
+ values.push("true");
368
+ }
369
+ flags.set(rawName, values);
370
+ } else {
371
+ positionals.push(token);
372
+ }
373
+ }
374
+
375
+ return { positionals, flags };
376
+ }
377
+
378
+ function requiredFlag(args: ParsedArgs, name: string): string {
379
+ const value = singleFlag(args, name);
380
+ if (!value || value === "true") {
381
+ throw new AwbsError(`Missing required --${name} value.`);
382
+ }
383
+ return value;
384
+ }
385
+
386
+ function singleFlag(args: ParsedArgs, name: string): string | undefined {
387
+ return args.flags.get(name)?.at(-1);
388
+ }
389
+
390
+ function multiFlag(args: ParsedArgs, name: string): string[] {
391
+ const values = args.flags.get(name) ?? [];
392
+ return values.filter((value) => value !== "true");
393
+ }
394
+
395
+ function requiredControllerToken(args: ParsedArgs): string {
396
+ if (!args.flags.has("control-token-stdin")) {
397
+ throw new AwbsError("This trusted write command requires --control-token-stdin.");
398
+ }
399
+ return readSecretFromStdin("controllerToken", "Expected a controller token on stdin.");
400
+ }
401
+
402
+ function readControlInput(): { recoverySecret: string; controllerToken: string } {
403
+ const value = readStdinText();
404
+ let parsed: unknown;
405
+ try {
406
+ parsed = JSON.parse(value);
407
+ } catch {
408
+ throw new AwbsError("--control-stdin must provide JSON with recoverySecret and controllerToken.");
409
+ }
410
+ if (!parsed || typeof parsed !== "object") {
411
+ throw new AwbsError("--control-stdin must provide JSON with recoverySecret and controllerToken.");
412
+ }
413
+ const input = parsed as Record<string, unknown>;
414
+ if (typeof input.recoverySecret !== "string" || typeof input.controllerToken !== "string") {
415
+ throw new AwbsError("--control-stdin must include string recoverySecret and controllerToken.");
416
+ }
417
+ return {
418
+ recoverySecret: input.recoverySecret,
419
+ controllerToken: input.controllerToken
420
+ };
421
+ }
422
+
423
+ function readControllerTokenFromStdin(): string {
424
+ return readSecretFromStdin("controllerToken", "Expected a controller token on stdin.");
425
+ }
426
+
427
+ function readRecoverySecretFromStdin(): string {
428
+ return readSecretFromStdin("recoverySecret", "Expected a recovery secret on stdin.");
429
+ }
430
+
431
+ function readSecretFromStdin(jsonField: "controllerToken" | "recoverySecret", emptyMessage: string): string {
432
+ const value = readStdinText().trim();
433
+ if (!value) {
434
+ throw new AwbsError(emptyMessage);
435
+ }
436
+ try {
437
+ const parsed = JSON.parse(value) as unknown;
438
+ if (parsed && typeof parsed === "object" && typeof (parsed as Record<string, unknown>)[jsonField] === "string") {
439
+ return (parsed as Record<string, string>)[jsonField];
440
+ }
441
+ } catch {
442
+ // Raw secret input is expected for most callers.
443
+ }
444
+ return value;
445
+ }
446
+
447
+ function readStdinText(): string {
448
+ return readFileSync(0, "utf8");
449
+ }
450
+
451
+ function printHelp(): void {
452
+ console.log(`AWBS CLI
453
+
454
+ Commands:
455
+ awbs init
456
+ awbs index rebuild
457
+ awbs index query [term] [--status active|removed|all] [--json]
458
+ awbs summary set <path> (--text <summary> | --file <file>)
459
+ awbs summary get <path> [--json]
460
+ awbs summary list [--json]
461
+ awbs view create --out <workspace> [--read A] [--write B] --control-token-stdin
462
+ awbs view inspect <viewId> [--json]
463
+ awbs view revoke <viewId> --control-token-stdin
464
+ awbs changeset collect --workspace <workspace>
465
+ awbs changeset inspect <changesetDir|id> [--json]
466
+ awbs changeset apply <changesetDir|id> --control-token-stdin
467
+ awbs ledger bootstrap [--json] --control-token-stdin
468
+ awbs ledger inspect [--json]
469
+ awbs ledger verify [--json]
470
+ awbs db audit [--json]
471
+ awbs db clean-rebuild [--json]
472
+ awbs db backups list [--json]
473
+ awbs authority session start --control-stdin [--json]
474
+ awbs authority session status [--json]
475
+ awbs authority session stop --control-token-stdin [--json]
476
+ awbs authority session recover --recovery-secret-stdin [--json]
477
+ awbs authority verify [--json]
478
+ awbs authority repair-mirrors --control-token-stdin [--json]
479
+ `);
480
+ }
481
+
482
+ main().catch((error: unknown) => {
483
+ if (error instanceof AwbsError) {
484
+ console.error(`awbs: ${error.message}`);
485
+ } else if (error instanceof Error) {
486
+ console.error(error.stack ?? error.message);
487
+ } else {
488
+ console.error(String(error));
489
+ }
490
+ process.exitCode = 1;
491
+ });
@@ -0,0 +1,194 @@
1
+ import type { IndexKind } from "./types.ts";
2
+
3
+ export type AuthorityViewStatus = "active" | "revoked";
4
+ export type AuthorityTrustMode = "repo-local-sealed-key-v1" | "ephemeral-local-key-v1";
5
+ export type AuthorityEventType =
6
+ | "AUTHORITY_INITIALIZED"
7
+ | "VIEW_CREATED"
8
+ | "VIEW_REVOKED"
9
+ | "CATALOG_RESEALED"
10
+ | "MIRROR_REBUILT"
11
+ | "LEDGER_BOOTSTRAPPED"
12
+ | "LEDGER_ENTRY_APPENDED";
13
+ export type AuthorityPayloadType = "authority.catalog" | "authority.viewContract" | "authority.ledger" | "authority.changesetReceipt";
14
+
15
+ export type AuthorityRepo = {
16
+ schemaVersion: 1;
17
+ repoId: string;
18
+ authoritySalt: string;
19
+ algorithm: "AWBS-AES-256-GCM-v1";
20
+ kdf: "scrypt-repo-local-runtime-v1";
21
+ trustMode?: AuthorityTrustMode;
22
+ createdAt: string;
23
+ };
24
+
25
+ export type AuthorityLocal = {
26
+ schemaVersion: 1;
27
+ installationId: string;
28
+ localSealSeed: string;
29
+ createdAt: string;
30
+ };
31
+
32
+ export type AuthorityResource = {
33
+ resourceId: string;
34
+ path: string;
35
+ kind: IndexKind;
36
+ parent: string | null;
37
+ defaultMode: "read";
38
+ ext: Record<string, unknown>;
39
+ };
40
+
41
+ export type AuthorityCatalogView = {
42
+ viewId: string;
43
+ status: AuthorityViewStatus;
44
+ baseCommit: string;
45
+ readPaths: string[];
46
+ writePaths: string[];
47
+ createdAt: string;
48
+ revokedAt?: string;
49
+ ext: Record<string, unknown>;
50
+ };
51
+
52
+ export type AuthorityCatalog = {
53
+ schemaVersion: 1;
54
+ repoId: string;
55
+ catalogVersion: number;
56
+ createdAt: string;
57
+ updatedAt: string;
58
+ resources: AuthorityResource[];
59
+ views: AuthorityCatalogView[];
60
+ ext: Record<string, unknown>;
61
+ };
62
+
63
+ export type AuthorityViewSource = {
64
+ path: string;
65
+ sourcePath: string;
66
+ workspacePath: string;
67
+ baselinePath: string;
68
+ kind: IndexKind;
69
+ sha256: string | null;
70
+ mode: "read" | "write";
71
+ ext: Record<string, unknown>;
72
+ };
73
+
74
+ export type AuthorityViewContract = {
75
+ schemaVersion: 1;
76
+ viewId: string;
77
+ baseCommit: string;
78
+ createdAt: string;
79
+ readPaths: string[];
80
+ writePaths: string[];
81
+ sources: AuthorityViewSource[];
82
+ ext: Record<string, unknown>;
83
+ };
84
+
85
+ export type SealEnvelope = {
86
+ schemaVersion: 1;
87
+ sealType: "awbs.seal.v1";
88
+ payloadType: AuthorityPayloadType;
89
+ aad: Record<string, unknown>;
90
+ nonce: string;
91
+ ciphertext: string;
92
+ tag: string;
93
+ contentHash: string;
94
+ };
95
+
96
+ export type AuthorityReceipt = {
97
+ schemaVersion: 1;
98
+ viewId: string;
99
+ payloadType: "authority.viewContract";
100
+ algorithm: "AWBS-AES-256-GCM-v1";
101
+ contentHash: string;
102
+ createdAt: string;
103
+ ext: Record<string, unknown>;
104
+ };
105
+
106
+ export type AuthorityChangesetReceipt = {
107
+ schemaVersion: 1;
108
+ changesetId: string;
109
+ viewId: string;
110
+ baseCommit: string;
111
+ createdAt: string;
112
+ payloadHash: string;
113
+ operationHash: string;
114
+ manifestHash: string;
115
+ ext: Record<string, unknown>;
116
+ };
117
+
118
+ export type AuthorityEvent = {
119
+ schemaVersion: 1;
120
+ event: AuthorityEventType;
121
+ eventId: string;
122
+ createdAt: string;
123
+ viewId?: string;
124
+ details?: Record<string, unknown>;
125
+ };
126
+
127
+ export type AuthorityVerifyReport = {
128
+ ok: boolean;
129
+ mirrorMismatches: string[];
130
+ errors: string[];
131
+ catalog: {
132
+ views: number;
133
+ resources: number;
134
+ };
135
+ };
136
+
137
+ export type AuthorityRepairReport = {
138
+ repairedMirrors: string[];
139
+ };
140
+
141
+ export type AuthorityLedgerEntryKind = "bootstrap" | "changeset";
142
+
143
+ export type AuthorityChangesetApplyOperation = {
144
+ schemaVersion: 1;
145
+ parentTrustedCommit: string;
146
+ baseCommit: string;
147
+ changesetId: string;
148
+ viewId: string;
149
+ appliedPaths: string[];
150
+ changesetManifestHash: string;
151
+ changesetPayloadHash: string;
152
+ authorityContractHash: string;
153
+ createdAt?: string;
154
+ ext: Record<string, unknown>;
155
+ };
156
+
157
+ export type AuthorityLedgerEntry = {
158
+ schemaVersion: 1;
159
+ entryId: string;
160
+ kind: AuthorityLedgerEntryKind;
161
+ previousEntryHash: string | null;
162
+ entryHash: string;
163
+ parentTrustedCommit: string;
164
+ baseCommit: string;
165
+ changesetId: string | null;
166
+ viewId: string | null;
167
+ createdAt: string;
168
+ appliedPaths: string[];
169
+ changesetManifestHash: string | null;
170
+ changesetPayloadHash: string | null;
171
+ authorityContractHash: string | null;
172
+ operationHash: string;
173
+ ext: Record<string, unknown>;
174
+ };
175
+
176
+ export type AuthorityLedger = {
177
+ schemaVersion: 1;
178
+ repoId: string;
179
+ ledgerVersion: number;
180
+ createdAt: string;
181
+ updatedAt: string;
182
+ headEntryId: string | null;
183
+ entries: AuthorityLedgerEntry[];
184
+ ext: Record<string, unknown>;
185
+ };
186
+
187
+ export type AuthorityLedgerInspectReport = {
188
+ ok: boolean;
189
+ currentTrustedCommit: string | null;
190
+ headEntryId: string | null;
191
+ entries: number;
192
+ errors: string[];
193
+ ledger: AuthorityLedger | null;
194
+ };
@@ -0,0 +1,11 @@
1
+ export const AWBS_DIR = ".awbs";
2
+ export const INDEX_PATH = ".awbs/index/files.sqlite";
3
+ export const SUMMARY_PATH = ".awbs/summaries/files.jsonl";
4
+ export const VIEW_MANIFEST = ".awbs-view.json";
5
+ export const TRUSTED_REF = "refs/awbs/trusted";
6
+
7
+ export const INDEX_EXCLUDED_PATHS = [
8
+ ".git",
9
+ "node_modules",
10
+ ".awbs"
11
+ ];
@@ -0,0 +1,6 @@
1
+ export class AwbsError extends Error {
2
+ constructor(message: string) {
3
+ super(message);
4
+ this.name = "AwbsError";
5
+ }
6
+ }