@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
@@ -0,0 +1,199 @@
1
+ import { createHash } from "node:crypto";
2
+ import { cpSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { INDEX_EXCLUDED_PATHS, VIEW_MANIFEST } from "../domain/constants.ts";
5
+ import { AwbsError } from "../domain/errors.ts";
6
+ import type { FileEntry, IndexKind, SnapshotEntry } from "../domain/types.ts";
7
+ import type { FileDatabasePort } from "../ports/file-database.ts";
8
+
9
+ export class LocalFileDatabaseAdapter implements FileDatabasePort {
10
+ findProjectRoot(cwd: string): string {
11
+ let current = cwd;
12
+ while (true) {
13
+ if (existsSync(join(current, ".awbs", "config.json"))) {
14
+ return current;
15
+ }
16
+ const parent = dirname(current);
17
+ if (parent === current) {
18
+ throw new AwbsError("No AWBS project found. Run `awbs init` first.");
19
+ }
20
+ current = parent;
21
+ }
22
+ }
23
+
24
+ pathExists(path: string): boolean {
25
+ return existsSync(path);
26
+ }
27
+
28
+ isDirectory(path: string): boolean {
29
+ return statSync(path).isDirectory();
30
+ }
31
+
32
+ ensureDir(path: string): void {
33
+ assertSafeDirectoryTarget(path);
34
+ mkdirSync(path, { recursive: true });
35
+ }
36
+
37
+ assertSafeOutputDirectory(path: string): void {
38
+ if (existsSync(path) && readdirSync(path).length > 0) {
39
+ throw new AwbsError(`Output directory already exists and is not empty: ${path}`);
40
+ }
41
+ }
42
+
43
+ copyPath(source: string, destination: string): void {
44
+ assertNoSymlinkTree(source);
45
+ assertSafeFileTarget(destination);
46
+ this.ensureDir(dirname(destination));
47
+ cpSync(source, destination, { recursive: true, force: true, errorOnExist: false });
48
+ }
49
+
50
+ removePath(path: string): void {
51
+ assertSafeFileTarget(path);
52
+ if (existsSync(path)) {
53
+ assertNotSymlink(path);
54
+ rmSync(path, { recursive: true, force: true });
55
+ }
56
+ }
57
+
58
+ readText(path: string): string {
59
+ assertSafeFileTarget(path);
60
+ return readFileSync(path, "utf8");
61
+ }
62
+
63
+ writeText(path: string, value: string): void {
64
+ assertSafeFileTarget(path);
65
+ this.ensureDir(dirname(path));
66
+ writeFileSync(path, value, "utf8");
67
+ }
68
+
69
+ readJson<T>(path: string): T {
70
+ assertSafeFileTarget(path);
71
+ return JSON.parse(readFileSync(path, "utf8")) as T;
72
+ }
73
+
74
+ writeJson(path: string, value: unknown): void {
75
+ assertSafeFileTarget(path);
76
+ this.ensureDir(dirname(path));
77
+ writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, "utf8");
78
+ }
79
+
80
+ sha256File(path: string): string {
81
+ assertSafeFileTarget(path);
82
+ return createHash("sha256").update(readFileSync(path)).digest("hex");
83
+ }
84
+
85
+ walkIndexableEntries(root: string): FileEntry[] {
86
+ const results: FileEntry[] = [];
87
+ const visit = (absPath: string, relPath: string): void => {
88
+ if (shouldExclude(relPath)) {
89
+ return;
90
+ }
91
+ const lstat = lstatSync(absPath);
92
+ if (lstat.isSymbolicLink()) {
93
+ throw new AwbsError(`Symbolic links are not supported by AWBS file database paths: ${absPath}`);
94
+ }
95
+ const stats = statSync(absPath);
96
+ if (relPath) {
97
+ const kind: IndexKind = stats.isDirectory() ? "directory" : "file";
98
+ results.push({
99
+ path: relPath,
100
+ kind,
101
+ sha256: kind === "file" ? this.sha256File(absPath) : null,
102
+ size: kind === "file" ? stats.size : null,
103
+ mtime: stats.mtime.toISOString()
104
+ });
105
+ }
106
+ if (stats.isDirectory()) {
107
+ const children = readdirSync(absPath).sort((a, b) => a.localeCompare(b));
108
+ for (const child of children) {
109
+ const childRel = relPath ? `${relPath}/${child}` : child;
110
+ visit(join(absPath, child), childRel);
111
+ }
112
+ }
113
+ };
114
+ visit(root, "");
115
+ return results;
116
+ }
117
+
118
+ snapshotFiles(root: string, options: { ignoreAwbsViewManifest: boolean }): Map<string, SnapshotEntry> {
119
+ const entries = new Map<string, SnapshotEntry>();
120
+ if (!existsSync(root)) {
121
+ return entries;
122
+ }
123
+
124
+ const visit = (absPath: string, relPath: string): void => {
125
+ if (options.ignoreAwbsViewManifest && relPath === VIEW_MANIFEST) {
126
+ return;
127
+ }
128
+ const lstat = lstatSync(absPath);
129
+ if (lstat.isSymbolicLink()) {
130
+ throw new AwbsError(`Symbolic links are not supported by AWBS snapshots: ${absPath}`);
131
+ }
132
+ const stats = statSync(absPath);
133
+ if (stats.isDirectory()) {
134
+ const children = readdirSync(absPath).sort((a, b) => a.localeCompare(b));
135
+ for (const child of children) {
136
+ const childRel = relPath ? `${relPath}/${child}` : child;
137
+ visit(join(absPath, child), childRel);
138
+ }
139
+ return;
140
+ }
141
+ entries.set(relPath, {
142
+ path: relPath,
143
+ sha256: this.sha256File(absPath),
144
+ size: stats.size
145
+ });
146
+ };
147
+
148
+ visit(root, "");
149
+ return entries;
150
+ }
151
+ }
152
+
153
+ function assertNoSymlinkTree(path: string): void {
154
+ assertNotSymlink(path);
155
+ if (!statSync(path).isDirectory()) {
156
+ return;
157
+ }
158
+ const children = readdirSync(path);
159
+ for (const child of children) {
160
+ assertNoSymlinkTree(join(path, child));
161
+ }
162
+ }
163
+
164
+ function assertNotSymlink(path: string): void {
165
+ if (lstatSync(path).isSymbolicLink()) {
166
+ throw new AwbsError(`Symbolic links are not supported by AWBS file database paths: ${path}`);
167
+ }
168
+ }
169
+
170
+ function assertNoSymlinkInExistingAncestors(path: string): void {
171
+ let current = dirname(path);
172
+ while (current && current !== dirname(current)) {
173
+ if (existsSync(current)) {
174
+ assertNotSymlink(current);
175
+ }
176
+ current = dirname(current);
177
+ }
178
+ }
179
+
180
+ function assertSafeFileTarget(path: string): void {
181
+ assertNoSymlinkInExistingAncestors(path);
182
+ if (existsSync(path)) {
183
+ assertNotSymlink(path);
184
+ }
185
+ }
186
+
187
+ function assertSafeDirectoryTarget(path: string): void {
188
+ assertNoSymlinkInExistingAncestors(path);
189
+ if (existsSync(path)) {
190
+ assertNotSymlink(path);
191
+ }
192
+ }
193
+
194
+ function shouldExclude(relPath: string): boolean {
195
+ if (!relPath) {
196
+ return false;
197
+ }
198
+ return INDEX_EXCLUDED_PATHS.some((excluded) => relPath === excluded || relPath.startsWith(`${excluded}/`));
199
+ }