@amalgm/core 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 (87) hide show
  1. package/PURPOSE.md +94 -0
  2. package/README.md +30 -0
  3. package/dist/adapters/index.d.ts +13 -0
  4. package/dist/adapters/index.d.ts.map +1 -0
  5. package/dist/adapters/index.js +11 -0
  6. package/dist/adapters/index.js.map +1 -0
  7. package/dist/identity/auth-records.d.ts +147 -0
  8. package/dist/identity/auth-records.d.ts.map +1 -0
  9. package/dist/identity/auth-records.js +354 -0
  10. package/dist/identity/auth-records.js.map +1 -0
  11. package/dist/identity/ids.d.ts +57 -0
  12. package/dist/identity/ids.d.ts.map +1 -0
  13. package/dist/identity/ids.js +80 -0
  14. package/dist/identity/ids.js.map +1 -0
  15. package/dist/identity/index.d.ts +14 -0
  16. package/dist/identity/index.d.ts.map +1 -0
  17. package/dist/identity/index.js +14 -0
  18. package/dist/identity/index.js.map +1 -0
  19. package/dist/identity/labels.d.ts +115 -0
  20. package/dist/identity/labels.d.ts.map +1 -0
  21. package/dist/identity/labels.js +154 -0
  22. package/dist/identity/labels.js.map +1 -0
  23. package/dist/identity/layout.d.ts +188 -0
  24. package/dist/identity/layout.d.ts.map +1 -0
  25. package/dist/identity/layout.js +233 -0
  26. package/dist/identity/layout.js.map +1 -0
  27. package/dist/identity/ports.d.ts +31 -0
  28. package/dist/identity/ports.d.ts.map +1 -0
  29. package/dist/identity/ports.js +9 -0
  30. package/dist/identity/ports.js.map +1 -0
  31. package/dist/identity/product-state.d.ts +49 -0
  32. package/dist/identity/product-state.d.ts.map +1 -0
  33. package/dist/identity/product-state.js +55 -0
  34. package/dist/identity/product-state.js.map +1 -0
  35. package/dist/index.d.ts +19 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +19 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/supervision/app-health.d.ts +148 -0
  40. package/dist/supervision/app-health.d.ts.map +1 -0
  41. package/dist/supervision/app-health.js +165 -0
  42. package/dist/supervision/app-health.js.map +1 -0
  43. package/dist/supervision/app-restart.d.ts +105 -0
  44. package/dist/supervision/app-restart.d.ts.map +1 -0
  45. package/dist/supervision/app-restart.js +97 -0
  46. package/dist/supervision/app-restart.js.map +1 -0
  47. package/dist/supervision/health.d.ts +218 -0
  48. package/dist/supervision/health.d.ts.map +1 -0
  49. package/dist/supervision/health.js +227 -0
  50. package/dist/supervision/health.js.map +1 -0
  51. package/dist/supervision/index.d.ts +17 -0
  52. package/dist/supervision/index.d.ts.map +1 -0
  53. package/dist/supervision/index.js +17 -0
  54. package/dist/supervision/index.js.map +1 -0
  55. package/dist/supervision/service-registration.d.ts +343 -0
  56. package/dist/supervision/service-registration.d.ts.map +1 -0
  57. package/dist/supervision/service-registration.js +543 -0
  58. package/dist/supervision/service-registration.js.map +1 -0
  59. package/dist/supervision/update.d.ts +231 -0
  60. package/dist/supervision/update.d.ts.map +1 -0
  61. package/dist/supervision/update.js +336 -0
  62. package/dist/supervision/update.js.map +1 -0
  63. package/dist/transport/admission.d.ts +235 -0
  64. package/dist/transport/admission.d.ts.map +1 -0
  65. package/dist/transport/admission.js +313 -0
  66. package/dist/transport/admission.js.map +1 -0
  67. package/dist/transport/auth.d.ts +232 -0
  68. package/dist/transport/auth.d.ts.map +1 -0
  69. package/dist/transport/auth.js +266 -0
  70. package/dist/transport/auth.js.map +1 -0
  71. package/dist/transport/index.d.ts +21 -0
  72. package/dist/transport/index.d.ts.map +1 -0
  73. package/dist/transport/index.js +21 -0
  74. package/dist/transport/index.js.map +1 -0
  75. package/dist/transport/ingress.d.ts +94 -0
  76. package/dist/transport/ingress.d.ts.map +1 -0
  77. package/dist/transport/ingress.js +171 -0
  78. package/dist/transport/ingress.js.map +1 -0
  79. package/dist/transport/routing.d.ts +235 -0
  80. package/dist/transport/routing.d.ts.map +1 -0
  81. package/dist/transport/routing.js +288 -0
  82. package/dist/transport/routing.js.map +1 -0
  83. package/dist/transport/shipped-routes.d.ts +21 -0
  84. package/dist/transport/shipped-routes.d.ts.map +1 -0
  85. package/dist/transport/shipped-routes.js +53 -0
  86. package/dist/transport/shipped-routes.js.map +1 -0
  87. package/package.json +51 -0
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Filesystem-layout grammar — the names, manifests, and path shapes of
3
+ * `~/amalgm` (engine runtime/scripts/amalgm-mcp/lib/layout.js, mirrored
4
+ * byte-for-byte in packages/amalgm/lib/layout.js modulo one comment; and
5
+ * runtime/scripts/lib/runtime-paths.js). PURE laws only: every function
6
+ * here is a string/record computation. Reading, writing, migrating, and
7
+ * resolving against the real filesystem stay host-side.
8
+ *
9
+ * The layout's own law: the folder name is presentation, the manifest is
10
+ * identity. `.amalgm-user.json`'s userId is authoritative; a renamed folder
11
+ * is recovered by manifest scan, never by trusting its name.
12
+ *
13
+ * Path joins here are POSIX (`/`). DELIBERATE DEVIATION: the engine joins
14
+ * with `path.join`, so on Windows it emits `\` — identical bytes on
15
+ * macOS/Linux, where every shipped runtime lives. The grammar (segment
16
+ * names and nesting) is the law; the separator belongs to the host.
17
+ */
18
+ import type { ClockIsoPort, RandomHexPort } from './ports.js';
19
+ /** Installation identity + user-folder index, at the amalgm root
20
+ * (layout.js:32). */
21
+ export declare const ROOT_MANIFEST_NAME = ".amalgm-root.json";
22
+ /** Stable user identity inside a user folder (layout.js:33). */
23
+ export declare const USER_MANIFEST_NAME = ".amalgm-user.json";
24
+ /** Root/user manifest schema version (layout.js:34). */
25
+ export declare const LAYOUT_VERSION = 1;
26
+ /** Basename of the user-home manifest (layout.js:35). The file itself lives
27
+ * at `system/home.json` inside the user dir — the `home-manifest` entry of
28
+ * {@link shippedUserHomeDeclaration}. */
29
+ export declare const USER_HOME_MANIFEST_NAME = "home.json";
30
+ /** User-home graph schema version (layout.js:38). Changing the declared
31
+ * exact graph changes the identity contract: a client must never accept a
32
+ * prior graph and silently invent a new managed child. */
33
+ export declare const USER_HOME_SCHEMA_VERSION = 2;
34
+ /** Stable per-user product namespaces (layout.js:43-50). Their authority is
35
+ * NOT inferred from their path: user content and exact platform-managed
36
+ * targets are declared separately in the user-home declaration.
37
+ * DELIBERATE DEVIATION: `browser` is an SDK-side ADDITION ahead of the
38
+ * engine — the browser brick keeps per-user state and needs a declared
39
+ * namespace to resolve it into ({@link resolveProductStateDir}). Additive
40
+ * only (axiom 7): the engine's six keep their bytes and order; it does NOT
41
+ * join the shipped user-home graph until the browser product declares it. */
42
+ export declare const PRIMITIVE_DIRS: readonly string[];
43
+ /**
44
+ * ONE sanitizer, two engine homes: runtime-identity.js:59-65
45
+ * (`sanitizeScopeSegment`) and layout.js:161-167 (`sanitizeFolderSegment`)
46
+ * carry the deliberately identical charset `[^A-Za-z0-9_.@-] → _`, trimmed
47
+ * of leading/trailing underscores, falling back to `'local'` — kept in
48
+ * lockstep so legacy uuid folders resolve to the exact names they were
49
+ * created with. Ported once; {@link sanitizeFolderSegment} is the same
50
+ * function under its layout-side name.
51
+ */
52
+ export declare function sanitizeScopeSegment(value: unknown, fallback?: string): string;
53
+ /** The shared sanitizer under its layout.js name — the same function, not a
54
+ * copy, so the two names can never drift. */
55
+ export declare const sanitizeFolderSegment: typeof sanitizeScopeSegment;
56
+ /** Folder name for a user identified by email (layout.js:170-172):
57
+ * lowercased, same charset, and — unlike a scope — an empty email yields
58
+ * `''`, never the `'local'` fallback. */
59
+ export declare function emailFolderName(email: unknown): string;
60
+ /** A root under the user dir that holds user content. */
61
+ export interface UserHomeRootDeclaration {
62
+ readonly key: string;
63
+ readonly relativePath: string;
64
+ }
65
+ /** An exact platform-managed node. Management is an exact-node fact — it
66
+ * deliberately does not cascade from `system/`. */
67
+ export interface UserHomeExactManagedDeclaration {
68
+ readonly key: string;
69
+ readonly relativePath: string;
70
+ readonly rootKey: string;
71
+ readonly toolId?: string;
72
+ }
73
+ /** What a user home contains: content roots plus the exact managed graph. */
74
+ export interface UserHomeDeclaration {
75
+ readonly roots: readonly UserHomeRootDeclaration[];
76
+ readonly exactManaged: readonly UserHomeExactManagedDeclaration[];
77
+ }
78
+ export interface ShippedUserHomeDeclaration extends UserHomeDeclaration {
79
+ readonly systemToolArtifacts: readonly UserHomeExactManagedDeclaration[];
80
+ }
81
+ /**
82
+ * The user-home graph the engine ships today (layout.js:52-87): the six
83
+ * roots, one `<key>-root` managed node per root, the home manifest at
84
+ * `system/home.json`, `system/defaults`, `system/policy`, and the seven
85
+ * system tool artifacts. These CONTENTS are PRODUCT declarations, not
86
+ * kernel law — the builder ({@link buildUserHomeManifest}) takes any
87
+ * declaration as input. The shipped set lives here only until the products
88
+ * register their own declarations.
89
+ */
90
+ export declare const shippedUserHomeDeclaration: ShippedUserHomeDeclaration;
91
+ /** The persisted `system/home.json` contents (layout.js:137-146). */
92
+ export interface UserHomeManifest {
93
+ readonly schemaVersion: number;
94
+ readonly kind: 'amalgm-user-home';
95
+ readonly roots: readonly {
96
+ readonly key: string;
97
+ readonly path: string;
98
+ }[];
99
+ readonly exactManaged: readonly {
100
+ readonly key: string;
101
+ readonly path: string;
102
+ readonly scope: 'exact';
103
+ }[];
104
+ }
105
+ /**
106
+ * The user-home manifest for a declaration (engine ensureUserHome's
107
+ * `manifestContents`, layout.js:137-146): schemaVersion 2, kind
108
+ * `amalgm-user-home`, and the declaration's entries with each
109
+ * `relativePath` published under the key name `path` — relative, so the
110
+ * manifest survives a moved or renamed user folder — and every managed
111
+ * node stamped `scope: 'exact'`.
112
+ */
113
+ export declare function buildUserHomeManifest(declaration: UserHomeDeclaration): UserHomeManifest;
114
+ /** `.amalgm-root.json` — installation identity plus the user-folder index
115
+ * (a cache; user-manifest scans stay authoritative). */
116
+ export interface RootManifest {
117
+ readonly schemaVersion: number;
118
+ readonly installationId: string;
119
+ readonly createdAt: string;
120
+ readonly users: Record<string, unknown>;
121
+ }
122
+ /**
123
+ * The root manifest an installation should hold (engine ensureRootManifest,
124
+ * layout.js:234-245, minus the write): an existing manifest that already
125
+ * carries an installationId is returned untouched — installation identity
126
+ * is minted once, never re-rolled — otherwise a fresh manifest is built,
127
+ * preserving any partial `createdAt`/`users`, with an 8-byte hex
128
+ * installationId from the injected randomness.
129
+ */
130
+ export declare function buildRootManifest(existing: Partial<RootManifest> | null | undefined, ports: ClockIsoPort & RandomHexPort): RootManifest;
131
+ /** `.amalgm-user.json` — the stable identity of a user folder. */
132
+ export interface UserManifest {
133
+ readonly schemaVersion: number;
134
+ readonly userId: string;
135
+ readonly canonicalEmail: string;
136
+ readonly emailHistory: readonly unknown[];
137
+ readonly createdAt: string;
138
+ readonly updatedAt: string;
139
+ }
140
+ /**
141
+ * The next user manifest (engine writeUserManifest, layout.js:262-277,
142
+ * minus the write): userId trimmed, canonicalEmail lowercased with the
143
+ * existing email as fallback, and emailHistory APPEND-ONLY — a new
144
+ * canonical email joins the history, nothing ever leaves it, so every name
145
+ * this user has worn stays resolvable. `createdAt` is preserved;
146
+ * `updatedAt` is stamped now.
147
+ */
148
+ export declare function buildUserManifest(identity: {
149
+ readonly userId: string;
150
+ readonly email?: unknown;
151
+ }, existing: Partial<UserManifest> | null | undefined, ports: ClockIsoPort): UserManifest;
152
+ /** THE path join of this grammar: segments glued with `/`, nothing
153
+ * normalized (see the header's deliberate-deviation note on separators).
154
+ * Exported so callers composing onto these paths use the same law instead
155
+ * of reaching for `node:path`, which axiom 6 forbids them anyway. */
156
+ export declare function joinPathSegments(...segments: string[]): string;
157
+ /**
158
+ * The name-derived user dir: `<homeDir>/users/<sanitized scope>` (engine
159
+ * scopedAmalgmDir, runtime-identity.js:137-142). DELIBERATE DEVIATION: the
160
+ * engine signature takes a third `label` parameter it asserts and then
161
+ * IGNORES — vestigial since manifest identity won over label-scoped
162
+ * folders — so the honest signature drops it. This is only the fallback
163
+ * path grammar: manifest-based resolution (find-by-userId across
164
+ * `.amalgm-user.json` files) reads the filesystem and stays host-side.
165
+ */
166
+ export declare function scopedAmalgmDir(homeDir: string, userScope: unknown): string;
167
+ /** Per-label runtime state: `<userDir>/runtimes/<label>` (engine
168
+ * scopedRuntimeDir runtime-identity.js:144-146, runtime-paths.js:81-86).
169
+ * The label must be one of the three — junk never names a state dir. */
170
+ export declare function runtimeStateDir(userDir: string, label: string): string;
171
+ /** `runtime-state.json` inside a runtime state dir (runtime-paths.js:88-90). */
172
+ export declare function runtimeStateFile(stateDir: string): string;
173
+ /** `runtime-token.json` inside a runtime state dir (runtime-paths.js:92-94). */
174
+ export declare function runtimeTokenFile(stateDir: string): string;
175
+ /** `logs/` inside a runtime state dir (runtime-paths.js:96-98). */
176
+ export declare function runtimeLogDir(stateDir: string): string;
177
+ /** `computer.json` — the public computer record beside a state or user dir
178
+ * (engine config.js:37-40, proxy-token-store.js:25-28). */
179
+ export declare function computerRecordFile(dir: string): string;
180
+ /** `auth.json` — the secret auth envelope beside a state or user dir
181
+ * (engine config.js:37-40, proxy-token-store.js:25-28). */
182
+ export declare function computerAuthFile(dir: string): string;
183
+ /**
184
+ * A primitive root under the user dir (layout.js:414-419). Only the six
185
+ * declared namespaces exist; the refusal string is the ratified text.
186
+ */
187
+ export declare function userPrimitiveRoot(userDir: string, kind: string): string;
188
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/identity/layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Filesystem-layout grammar — the names, manifests, and path shapes of
3
+ * `~/amalgm` (engine runtime/scripts/amalgm-mcp/lib/layout.js, mirrored
4
+ * byte-for-byte in packages/amalgm/lib/layout.js modulo one comment; and
5
+ * runtime/scripts/lib/runtime-paths.js). PURE laws only: every function
6
+ * here is a string/record computation. Reading, writing, migrating, and
7
+ * resolving against the real filesystem stay host-side.
8
+ *
9
+ * The layout's own law: the folder name is presentation, the manifest is
10
+ * identity. `.amalgm-user.json`'s userId is authoritative; a renamed folder
11
+ * is recovered by manifest scan, never by trusting its name.
12
+ *
13
+ * Path joins here are POSIX (`/`). DELIBERATE DEVIATION: the engine joins
14
+ * with `path.join`, so on Windows it emits `\` — identical bytes on
15
+ * macOS/Linux, where every shipped runtime lives. The grammar (segment
16
+ * names and nesting) is the law; the separator belongs to the host.
17
+ */
18
+ import { assertRuntimeLabel } from './labels.js';
19
+ /** Installation identity + user-folder index, at the amalgm root
20
+ * (layout.js:32). */
21
+ export const ROOT_MANIFEST_NAME = '.amalgm-root.json';
22
+ /** Stable user identity inside a user folder (layout.js:33). */
23
+ export const USER_MANIFEST_NAME = '.amalgm-user.json';
24
+ /** Root/user manifest schema version (layout.js:34). */
25
+ export const LAYOUT_VERSION = 1;
26
+ /** Basename of the user-home manifest (layout.js:35). The file itself lives
27
+ * at `system/home.json` inside the user dir — the `home-manifest` entry of
28
+ * {@link shippedUserHomeDeclaration}. */
29
+ export const USER_HOME_MANIFEST_NAME = 'home.json';
30
+ /** User-home graph schema version (layout.js:38). Changing the declared
31
+ * exact graph changes the identity contract: a client must never accept a
32
+ * prior graph and silently invent a new managed child. */
33
+ export const USER_HOME_SCHEMA_VERSION = 2;
34
+ /** Stable per-user product namespaces (layout.js:43-50). Their authority is
35
+ * NOT inferred from their path: user content and exact platform-managed
36
+ * targets are declared separately in the user-home declaration.
37
+ * DELIBERATE DEVIATION: `browser` is an SDK-side ADDITION ahead of the
38
+ * engine — the browser brick keeps per-user state and needs a declared
39
+ * namespace to resolve it into ({@link resolveProductStateDir}). Additive
40
+ * only (axiom 7): the engine's six keep their bytes and order; it does NOT
41
+ * join the shipped user-home graph until the browser product declares it. */
42
+ export const PRIMITIVE_DIRS = Object.freeze([
43
+ 'agents',
44
+ 'apps',
45
+ 'automations',
46
+ 'toolbox',
47
+ 'workspaces',
48
+ 'system',
49
+ 'browser',
50
+ ]);
51
+ /**
52
+ * ONE sanitizer, two engine homes: runtime-identity.js:59-65
53
+ * (`sanitizeScopeSegment`) and layout.js:161-167 (`sanitizeFolderSegment`)
54
+ * carry the deliberately identical charset `[^A-Za-z0-9_.@-] → _`, trimmed
55
+ * of leading/trailing underscores, falling back to `'local'` — kept in
56
+ * lockstep so legacy uuid folders resolve to the exact names they were
57
+ * created with. Ported once; {@link sanitizeFolderSegment} is the same
58
+ * function under its layout-side name.
59
+ */
60
+ export function sanitizeScopeSegment(value, fallback = 'local') {
61
+ const clean = String(value || '')
62
+ .trim()
63
+ .replace(/[^A-Za-z0-9_.@-]/g, '_')
64
+ .replace(/^_+|_+$/g, '');
65
+ return clean || fallback;
66
+ }
67
+ /** The shared sanitizer under its layout.js name — the same function, not a
68
+ * copy, so the two names can never drift. */
69
+ export const sanitizeFolderSegment = sanitizeScopeSegment;
70
+ /** Folder name for a user identified by email (layout.js:170-172):
71
+ * lowercased, same charset, and — unlike a scope — an empty email yields
72
+ * `''`, never the `'local'` fallback. */
73
+ export function emailFolderName(email) {
74
+ return sanitizeFolderSegment(String(email || '').trim().toLowerCase(), '');
75
+ }
76
+ const USER_HOME_ROOTS = Object.freeze([
77
+ { key: 'agents', relativePath: 'agents' },
78
+ { key: 'apps', relativePath: 'apps' },
79
+ { key: 'automations', relativePath: 'automations' },
80
+ { key: 'toolbox', relativePath: 'toolbox' },
81
+ { key: 'workspaces', relativePath: 'workspaces' },
82
+ { key: 'system', relativePath: 'system' },
83
+ ]);
84
+ // A Toolbox tool is one complete entity: its definition and actions travel
85
+ // in the same file. These names are deliberately stable and human-readable.
86
+ const SYSTEM_TOOL_ARTIFACTS = Object.freeze([
87
+ { key: 'amalgm-automations', toolId: 'automations', relativePath: 'toolbox/amalgm-automations.json', rootKey: 'toolbox' },
88
+ { key: 'amalgm-notifications', toolId: 'notifications', relativePath: 'toolbox/amalgm-notifications.json', rootKey: 'toolbox' },
89
+ { key: 'amalgm-memories', toolId: 'memories', relativePath: 'toolbox/amalgm-memories.json', rootKey: 'toolbox' },
90
+ { key: 'amalgm-agents', toolId: 'agents', relativePath: 'toolbox/amalgm-agents.json', rootKey: 'toolbox' },
91
+ { key: 'amalgm-apps', toolId: 'apps', relativePath: 'toolbox/amalgm-apps.json', rootKey: 'toolbox' },
92
+ { key: 'amalgm-cua', toolId: 'computer-use', relativePath: 'toolbox/amalgm-cua.json', rootKey: 'toolbox' },
93
+ { key: 'amalgm-browser', toolId: 'browser', relativePath: 'toolbox/amalgm-browser.json', rootKey: 'toolbox' },
94
+ ]);
95
+ /**
96
+ * The user-home graph the engine ships today (layout.js:52-87): the six
97
+ * roots, one `<key>-root` managed node per root, the home manifest at
98
+ * `system/home.json`, `system/defaults`, `system/policy`, and the seven
99
+ * system tool artifacts. These CONTENTS are PRODUCT declarations, not
100
+ * kernel law — the builder ({@link buildUserHomeManifest}) takes any
101
+ * declaration as input. The shipped set lives here only until the products
102
+ * register their own declarations.
103
+ */
104
+ export const shippedUserHomeDeclaration = Object.freeze({
105
+ roots: USER_HOME_ROOTS,
106
+ systemToolArtifacts: SYSTEM_TOOL_ARTIFACTS,
107
+ exactManaged: Object.freeze([
108
+ ...USER_HOME_ROOTS.map(({ key, relativePath }) => ({
109
+ key: `${key}-root`, relativePath, rootKey: key,
110
+ })),
111
+ { key: 'home-manifest', relativePath: 'system/home.json', rootKey: 'system' },
112
+ { key: 'defaults', relativePath: 'system/defaults', rootKey: 'system' },
113
+ { key: 'policy', relativePath: 'system/policy', rootKey: 'system' },
114
+ ...SYSTEM_TOOL_ARTIFACTS,
115
+ ]),
116
+ });
117
+ /**
118
+ * The user-home manifest for a declaration (engine ensureUserHome's
119
+ * `manifestContents`, layout.js:137-146): schemaVersion 2, kind
120
+ * `amalgm-user-home`, and the declaration's entries with each
121
+ * `relativePath` published under the key name `path` — relative, so the
122
+ * manifest survives a moved or renamed user folder — and every managed
123
+ * node stamped `scope: 'exact'`.
124
+ */
125
+ export function buildUserHomeManifest(declaration) {
126
+ return {
127
+ schemaVersion: USER_HOME_SCHEMA_VERSION,
128
+ kind: 'amalgm-user-home',
129
+ roots: declaration.roots.map(({ key, relativePath }) => ({ key, path: relativePath })),
130
+ exactManaged: declaration.exactManaged.map(({ key, relativePath }) => ({
131
+ key, path: relativePath, scope: 'exact',
132
+ })),
133
+ };
134
+ }
135
+ /**
136
+ * The root manifest an installation should hold (engine ensureRootManifest,
137
+ * layout.js:234-245, minus the write): an existing manifest that already
138
+ * carries an installationId is returned untouched — installation identity
139
+ * is minted once, never re-rolled — otherwise a fresh manifest is built,
140
+ * preserving any partial `createdAt`/`users`, with an 8-byte hex
141
+ * installationId from the injected randomness.
142
+ */
143
+ export function buildRootManifest(existing, ports) {
144
+ if (existing?.installationId)
145
+ return existing;
146
+ return {
147
+ schemaVersion: LAYOUT_VERSION,
148
+ installationId: existing?.installationId || ports.randomHex(8),
149
+ createdAt: existing?.createdAt || ports.nowIso(),
150
+ users: existing?.users || {},
151
+ };
152
+ }
153
+ /**
154
+ * The next user manifest (engine writeUserManifest, layout.js:262-277,
155
+ * minus the write): userId trimmed, canonicalEmail lowercased with the
156
+ * existing email as fallback, and emailHistory APPEND-ONLY — a new
157
+ * canonical email joins the history, nothing ever leaves it, so every name
158
+ * this user has worn stays resolvable. `createdAt` is preserved;
159
+ * `updatedAt` is stamped now.
160
+ */
161
+ export function buildUserManifest(identity, existing, ports) {
162
+ const canonicalEmail = String(identity.email || existing?.canonicalEmail || '').trim().toLowerCase();
163
+ const emailHistory = Array.isArray(existing?.emailHistory) ? [...existing.emailHistory] : [];
164
+ if (canonicalEmail && !emailHistory.includes(canonicalEmail))
165
+ emailHistory.push(canonicalEmail);
166
+ return {
167
+ schemaVersion: LAYOUT_VERSION,
168
+ userId: String(identity.userId).trim(),
169
+ canonicalEmail,
170
+ emailHistory,
171
+ createdAt: existing?.createdAt || ports.nowIso(),
172
+ updatedAt: ports.nowIso(),
173
+ };
174
+ }
175
+ /** THE path join of this grammar: segments glued with `/`, nothing
176
+ * normalized (see the header's deliberate-deviation note on separators).
177
+ * Exported so callers composing onto these paths use the same law instead
178
+ * of reaching for `node:path`, which axiom 6 forbids them anyway. */
179
+ export function joinPathSegments(...segments) {
180
+ return segments.join('/');
181
+ }
182
+ const join = joinPathSegments;
183
+ /**
184
+ * The name-derived user dir: `<homeDir>/users/<sanitized scope>` (engine
185
+ * scopedAmalgmDir, runtime-identity.js:137-142). DELIBERATE DEVIATION: the
186
+ * engine signature takes a third `label` parameter it asserts and then
187
+ * IGNORES — vestigial since manifest identity won over label-scoped
188
+ * folders — so the honest signature drops it. This is only the fallback
189
+ * path grammar: manifest-based resolution (find-by-userId across
190
+ * `.amalgm-user.json` files) reads the filesystem and stays host-side.
191
+ */
192
+ export function scopedAmalgmDir(homeDir, userScope) {
193
+ return join(homeDir, 'users', sanitizeScopeSegment(userScope));
194
+ }
195
+ /** Per-label runtime state: `<userDir>/runtimes/<label>` (engine
196
+ * scopedRuntimeDir runtime-identity.js:144-146, runtime-paths.js:81-86).
197
+ * The label must be one of the three — junk never names a state dir. */
198
+ export function runtimeStateDir(userDir, label) {
199
+ return join(userDir, 'runtimes', assertRuntimeLabel(label));
200
+ }
201
+ /** `runtime-state.json` inside a runtime state dir (runtime-paths.js:88-90). */
202
+ export function runtimeStateFile(stateDir) {
203
+ return join(stateDir, 'runtime-state.json');
204
+ }
205
+ /** `runtime-token.json` inside a runtime state dir (runtime-paths.js:92-94). */
206
+ export function runtimeTokenFile(stateDir) {
207
+ return join(stateDir, 'runtime-token.json');
208
+ }
209
+ /** `logs/` inside a runtime state dir (runtime-paths.js:96-98). */
210
+ export function runtimeLogDir(stateDir) {
211
+ return join(stateDir, 'logs');
212
+ }
213
+ /** `computer.json` — the public computer record beside a state or user dir
214
+ * (engine config.js:37-40, proxy-token-store.js:25-28). */
215
+ export function computerRecordFile(dir) {
216
+ return join(dir, 'computer.json');
217
+ }
218
+ /** `auth.json` — the secret auth envelope beside a state or user dir
219
+ * (engine config.js:37-40, proxy-token-store.js:25-28). */
220
+ export function computerAuthFile(dir) {
221
+ return join(dir, 'auth.json');
222
+ }
223
+ /**
224
+ * A primitive root under the user dir (layout.js:414-419). Only the six
225
+ * declared namespaces exist; the refusal string is the ratified text.
226
+ */
227
+ export function userPrimitiveRoot(userDir, kind) {
228
+ if (!PRIMITIVE_DIRS.includes(kind)) {
229
+ throw new Error(`Unknown primitive root "${kind}". Use one of: ${PRIMITIVE_DIRS.join(', ')}`);
230
+ }
231
+ return join(userDir, kind);
232
+ }
233
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/identity/layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Effect ports — axiom 6: a host supplies its own effects. Nothing in src/
3
+ * reads a clock, randomness source, hash, path resolver, or environment
4
+ * variable; each law that needs an effect names the narrow power here and
5
+ * receives it from the caller. The engine call each port replaces is cited
6
+ * so parity stays checkable.
7
+ */
8
+ /** Wall-clock as an ISO-8601 string — the engine's `new Date().toISOString()`. */
9
+ export interface ClockIsoPort {
10
+ nowIso(): string;
11
+ }
12
+ /** Wall-clock in epoch milliseconds — the engine's `Date.now()`. */
13
+ export interface ClockMsPort {
14
+ nowMs(): number;
15
+ }
16
+ /** Cryptographic randomness as lowercase hex over `byteCount` bytes — the
17
+ * engine's `crypto.randomBytes(byteCount).toString('hex')`. */
18
+ export interface RandomHexPort {
19
+ randomHex(byteCount: number): string;
20
+ }
21
+ /** SHA-256 of a UTF-8 string as lowercase hex — the engine's
22
+ * `crypto.createHash('sha256').update(input, 'utf8').digest('hex')`. */
23
+ export interface Sha256HexPort {
24
+ sha256Hex(input: string): string;
25
+ }
26
+ /** Absolute-path resolution — the engine's `path.resolve`. Injected because
27
+ * resolution consults the working directory, an ambient effect. */
28
+ export interface ResolvePathPort {
29
+ resolvePath(target: string): string;
30
+ }
31
+ //# sourceMappingURL=ports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../src/identity/ports.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC3B,MAAM,IAAI,MAAM,CAAC;CAClB;AAED,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,KAAK,IAAI,MAAM,CAAC;CACjB;AAED;+DAC+D;AAC/D,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CACtC;AAED;wEACwE;AACxE,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CAClC;AAED;mEACmE;AACnE,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CACrC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Effect ports — axiom 6: a host supplies its own effects. Nothing in src/
3
+ * reads a clock, randomness source, hash, path resolver, or environment
4
+ * variable; each law that needs an effect names the narrow power here and
5
+ * receives it from the caller. The engine call each port replaces is cited
6
+ * so parity stays checkable.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=ports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.js","sourceRoot":"","sources":["../../src/identity/ports.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Product state-dir resolution — where a product brick keeps its per-user
3
+ * state on disk, as ONE law. Hoisted from the four bricks (apps, tools,
4
+ * agents, browser) that each hand-rolled this resolution and drifted;
5
+ * axiom 2 says a second place that computes a home directory is a bug, so
6
+ * the bricks import this instead.
7
+ *
8
+ * PURE laws only (axiom 6): nothing here reads `process.env` or the
9
+ * filesystem — the caller injects the env bag and the home directory, and
10
+ * gets a path string back. Creating the directory stays host-side.
11
+ */
12
+ import type { EnvLike } from '../transport/auth.js';
13
+ /**
14
+ * The env var that overrides a product's state dir: the product name in
15
+ * upper-snake between `AMALGM_` and `_DIR` — `browser` →
16
+ * `AMALGM_BROWSER_DIR`, `design-canvas` → `AMALGM_DESIGN_CANVAS_DIR`.
17
+ * A name with no usable characters cannot name an env var and is refused.
18
+ */
19
+ export declare function productStateDirEnvVar(product: string): string;
20
+ /** The five facts the resolver needs — env and homedir injected, never read. */
21
+ export interface ProductStateDirInput {
22
+ /** The brick's name — only role: deriving {@link productStateDirEnvVar}. */
23
+ readonly product: string;
24
+ /** Which declared namespace the state lives under — one of {@link PRIMITIVE_DIRS}. */
25
+ readonly primitive: string;
26
+ /** An env-shaped bag of strings. The host passes process.env; tests pass literals. */
27
+ readonly env: EnvLike;
28
+ /** The amalgm root (the engine's `~/.amalgm`), resolved by the host. */
29
+ readonly homedir: string;
30
+ /** The user scope; absent falls to the sanitizer's `local`, as everywhere. */
31
+ readonly scope?: unknown;
32
+ }
33
+ /**
34
+ * The one resolution law, in precedence order:
35
+ *
36
+ * 1. `env[AMALGM_<PRODUCT>_DIR]` — the product-specific override, used
37
+ * VERBATIM (an operator pointing state somewhere means exactly there);
38
+ * 2. `env.AMALGM_DIR` + `/<primitive>` — the shared override, one
39
+ * namespace per primitive under it;
40
+ * 3. the ratified scoped layout — `<homedir>/users/<scope>/<primitive>`
41
+ * via {@link scopedAmalgmDir} and {@link userPrimitiveRoot}, the same
42
+ * grammar every other path in the kernel derives from.
43
+ *
44
+ * The primitive is validated against {@link PRIMITIVE_DIRS} on EVERY tier —
45
+ * an unknown primitive is a caller bug, and an env override must never
46
+ * mask it into a working path.
47
+ */
48
+ export declare function resolveProductStateDir(input: ProductStateDirInput): string;
49
+ //# sourceMappingURL=product-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-state.d.ts","sourceRoot":"","sources":["../../src/identity/product-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAGpD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAU7D;AAED,gFAAgF;AAChF,MAAM,WAAW,oBAAoB;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,sFAAsF;IACtF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAU1E"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Product state-dir resolution — where a product brick keeps its per-user
3
+ * state on disk, as ONE law. Hoisted from the four bricks (apps, tools,
4
+ * agents, browser) that each hand-rolled this resolution and drifted;
5
+ * axiom 2 says a second place that computes a home directory is a bug, so
6
+ * the bricks import this instead.
7
+ *
8
+ * PURE laws only (axiom 6): nothing here reads `process.env` or the
9
+ * filesystem — the caller injects the env bag and the home directory, and
10
+ * gets a path string back. Creating the directory stays host-side.
11
+ */
12
+ import { PRIMITIVE_DIRS, joinPathSegments, scopedAmalgmDir, userPrimitiveRoot } from './layout.js';
13
+ /**
14
+ * The env var that overrides a product's state dir: the product name in
15
+ * upper-snake between `AMALGM_` and `_DIR` — `browser` →
16
+ * `AMALGM_BROWSER_DIR`, `design-canvas` → `AMALGM_DESIGN_CANVAS_DIR`.
17
+ * A name with no usable characters cannot name an env var and is refused.
18
+ */
19
+ export function productStateDirEnvVar(product) {
20
+ const key = String(product || '')
21
+ .trim()
22
+ .replace(/[^A-Za-z0-9]+/g, '_')
23
+ .replace(/^_+|_+$/g, '')
24
+ .toUpperCase();
25
+ if (!key) {
26
+ throw new Error(`Unusable product name "${product}". Name the brick, e.g. "browser" -> AMALGM_BROWSER_DIR.`);
27
+ }
28
+ return `AMALGM_${key}_DIR`;
29
+ }
30
+ /**
31
+ * The one resolution law, in precedence order:
32
+ *
33
+ * 1. `env[AMALGM_<PRODUCT>_DIR]` — the product-specific override, used
34
+ * VERBATIM (an operator pointing state somewhere means exactly there);
35
+ * 2. `env.AMALGM_DIR` + `/<primitive>` — the shared override, one
36
+ * namespace per primitive under it;
37
+ * 3. the ratified scoped layout — `<homedir>/users/<scope>/<primitive>`
38
+ * via {@link scopedAmalgmDir} and {@link userPrimitiveRoot}, the same
39
+ * grammar every other path in the kernel derives from.
40
+ *
41
+ * The primitive is validated against {@link PRIMITIVE_DIRS} on EVERY tier —
42
+ * an unknown primitive is a caller bug, and an env override must never
43
+ * mask it into a working path.
44
+ */
45
+ export function resolveProductStateDir(input) {
46
+ const { product, primitive, env, homedir, scope } = input;
47
+ const scopedFallback = userPrimitiveRoot(scopedAmalgmDir(homedir, scope), primitive);
48
+ const productOverride = env[productStateDirEnvVar(product)];
49
+ if (productOverride)
50
+ return productOverride;
51
+ if (env.AMALGM_DIR)
52
+ return joinPathSegments(env.AMALGM_DIR, primitive);
53
+ return scopedFallback;
54
+ }
55
+ //# sourceMappingURL=product-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-state.js","sourceRoot":"","sources":["../../src/identity/product-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEnG;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;SAC9B,IAAI,EAAE;SACN,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC;SAC9B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,WAAW,EAAE,CAAC;IACjB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,0BAA0B,OAAO,0DAA0D,CAAC,CAAC;IAC/G,CAAC;IACD,OAAO,UAAU,GAAG,MAAM,CAAC;AAC7B,CAAC;AAgBD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAA2B;IAChE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IAC1D,MAAM,cAAc,GAAG,iBAAiB,CAAC,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC;IAErF,MAAM,eAAe,GAAG,GAAG,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5D,IAAI,eAAe;QAAE,OAAO,eAAe,CAAC;IAE5C,IAAI,GAAG,CAAC,UAAU;QAAE,OAAO,gBAAgB,CAAC,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAEvE,OAAO,cAAc,CAAC;AACxB,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @amalgm/core — the Amalgm kernel SDK.
3
+ *
4
+ * Three modules, one membership test (PURPOSE.md): needed to boot,
5
+ * supervise, or route to an app, and can't itself be an app.
6
+ *
7
+ * identity/ who this machine is: labels, layout, ids, auth records.
8
+ * transport/ the pipe: auth boundary, one routing table, admission,
9
+ * event-rail ingress.
10
+ * supervision/ the cascade: health contracts, restart policy, updater
11
+ * laws, service registration.
12
+ *
13
+ * Everything here is a pure contract or decision core; hosts inject their
14
+ * effects through the ports in `adapters/`.
15
+ */
16
+ export * from './identity/index.js';
17
+ export * from './transport/index.js';
18
+ export * from './supervision/index.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @amalgm/core — the Amalgm kernel SDK.
3
+ *
4
+ * Three modules, one membership test (PURPOSE.md): needed to boot,
5
+ * supervise, or route to an app, and can't itself be an app.
6
+ *
7
+ * identity/ who this machine is: labels, layout, ids, auth records.
8
+ * transport/ the pipe: auth boundary, one routing table, admission,
9
+ * event-rail ingress.
10
+ * supervision/ the cascade: health contracts, restart policy, updater
11
+ * laws, service registration.
12
+ *
13
+ * Everything here is a pure contract or decision core; hosts inject their
14
+ * effects through the ports in `adapters/`.
15
+ */
16
+ export * from './identity/index.js';
17
+ export * from './transport/index.js';
18
+ export * from './supervision/index.js';
19
+ //# sourceMappingURL=index.js.map