@bizagent/dsh 0.0.0-stage → 1.0.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 (181) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/LICENSE +21 -0
  3. package/README.md +61 -2
  4. package/cordis.patch.yml +14 -0
  5. package/docs/README.md +23 -0
  6. package/docs/architecture.md +154 -0
  7. package/docs/concepts.md +192 -0
  8. package/docs/configuration.md +154 -0
  9. package/docs/quickstart.md +103 -0
  10. package/docs/quickstart.zh-CN.md +86 -0
  11. package/docs/tools.md +607 -0
  12. package/docs/user-guide.zh-CN.md +132 -0
  13. package/docs/verification.md +69 -0
  14. package/examples/README.md +64 -0
  15. package/examples/demo-runtime.mjs +71 -0
  16. package/examples/learning-lab.mjs +263 -0
  17. package/examples/scenarios.mjs +45 -0
  18. package/lib/agent-preset.d.ts +20 -0
  19. package/lib/agent-preset.js +46 -0
  20. package/lib/agent-session-address.d.ts +14 -0
  21. package/lib/agent-session-address.js +15 -0
  22. package/lib/agent-session-coordinator.d.ts +24 -0
  23. package/lib/agent-session-coordinator.js +101 -0
  24. package/lib/cli.d.ts +3 -0
  25. package/lib/cli.js +142 -0
  26. package/lib/client-types/agent-session-address.d.ts +13 -0
  27. package/lib/client-types/client/agent-mentions.d.ts +3 -0
  28. package/lib/client-types/client/api.d.ts +180 -0
  29. package/lib/client-types/client/components.d.ts +22 -0
  30. package/lib/client-types/client/controller.d.ts +23 -0
  31. package/lib/client-types/client/frame-participants.d.ts +5 -0
  32. package/lib/client-types/client/home-name.d.ts +9 -0
  33. package/lib/client-types/client/human-inbox.d.ts +8 -0
  34. package/lib/client-types/client/index.d.ts +13 -0
  35. package/lib/client-types/client/locales.d.ts +796 -0
  36. package/lib/client-types/client/markdown.d.ts +12 -0
  37. package/lib/client-types/client/project-artifact-link.d.ts +10 -0
  38. package/lib/client-types/client/project-outcome-review-inbox.d.ts +13 -0
  39. package/lib/client-types/client/projects.d.ts +11 -0
  40. package/lib/client-types/client/sample-guide.d.ts +9 -0
  41. package/lib/client-types/client/session-resource.d.ts +34 -0
  42. package/lib/client-types/client/session-surfaces.d.ts +24 -0
  43. package/lib/client-types/client/styles.d.ts +1 -0
  44. package/lib/client-types/config.d.ts +55 -0
  45. package/lib/client-types/cron.d.ts +8 -0
  46. package/lib/client-types/domain.d.ts +818 -0
  47. package/lib/client-types/frame-reference.d.ts +4 -0
  48. package/lib/client-types/home-directory.d.ts +5 -0
  49. package/lib/client-types/home-space.d.ts +49 -0
  50. package/lib/client-types/home-store.d.ts +125 -0
  51. package/lib/client-types/inbox-stalled-topic.d.ts +15 -0
  52. package/lib/client-types/inbox-wake-policy.d.ts +18 -0
  53. package/lib/client-types/known-format.d.ts +2 -0
  54. package/lib/client-types/learning-scheduler.d.ts +36 -0
  55. package/lib/client-types/learning-session-runner.d.ts +49 -0
  56. package/lib/client-types/learning-trigger.d.ts +17 -0
  57. package/lib/client-types/learning-usage.d.ts +17 -0
  58. package/lib/client-types/ledger.d.ts +190 -0
  59. package/lib/client-types/local-owner.d.ts +7 -0
  60. package/lib/client-types/message-source.d.ts +9 -0
  61. package/lib/client-types/organization-location.d.ts +19 -0
  62. package/lib/client-types/project-ledger.d.ts +182 -0
  63. package/lib/client-types/project-seat-context.d.ts +17 -0
  64. package/lib/client-types/safe-file.d.ts +23 -0
  65. package/lib/client-types/sample-organization.d.ts +9 -0
  66. package/lib/client-types/service.d.ts +596 -0
  67. package/lib/client-types/shared-knowledge.d.ts +116 -0
  68. package/lib/client-types/ui-contract.d.ts +276 -0
  69. package/lib/client-types/untrusted-text.d.ts +15 -0
  70. package/lib/client-types/work-ledger.d.ts +108 -0
  71. package/lib/client-types/work-output-eval.d.ts +15 -0
  72. package/lib/client-types/worklog-ledger.d.ts +88 -0
  73. package/lib/client-types/worklog-snapshot.d.ts +33 -0
  74. package/lib/client.js +5463 -0
  75. package/lib/config.d.ts +56 -0
  76. package/lib/config.js +115 -0
  77. package/lib/cron.d.ts +9 -0
  78. package/lib/cron.js +127 -0
  79. package/lib/domain.d.ts +819 -0
  80. package/lib/domain.js +662 -0
  81. package/lib/frame-admission.d.ts +6 -0
  82. package/lib/frame-admission.js +39 -0
  83. package/lib/frame-reference.d.ts +5 -0
  84. package/lib/frame-reference.js +12 -0
  85. package/lib/home-archive.d.ts +17 -0
  86. package/lib/home-archive.js +177 -0
  87. package/lib/home-directory.d.ts +6 -0
  88. package/lib/home-directory.js +38 -0
  89. package/lib/home-space.d.ts +50 -0
  90. package/lib/home-space.js +120 -0
  91. package/lib/home-store.d.ts +126 -0
  92. package/lib/home-store.js +837 -0
  93. package/lib/host.d.ts +22 -0
  94. package/lib/host.js +15 -0
  95. package/lib/human-inbox-transport.d.ts +23 -0
  96. package/lib/human-inbox-transport.js +105 -0
  97. package/lib/human-notification-runner.d.ts +83 -0
  98. package/lib/human-notification-runner.js +138 -0
  99. package/lib/human-notification-webhook.d.ts +18 -0
  100. package/lib/human-notification-webhook.js +102 -0
  101. package/lib/human-turn-completion.d.ts +61 -0
  102. package/lib/human-turn-completion.js +157 -0
  103. package/lib/inbox-return-notifier.d.ts +46 -0
  104. package/lib/inbox-return-notifier.js +279 -0
  105. package/lib/inbox-stalled-escalation-runner.d.ts +31 -0
  106. package/lib/inbox-stalled-escalation-runner.js +68 -0
  107. package/lib/inbox-stalled-topic.d.ts +16 -0
  108. package/lib/inbox-stalled-topic.js +44 -0
  109. package/lib/inbox-wake-policy.d.ts +19 -0
  110. package/lib/inbox-wake-policy.js +28 -0
  111. package/lib/inbox-wake-runner.d.ts +45 -0
  112. package/lib/inbox-wake-runner.js +481 -0
  113. package/lib/index.d.ts +29 -0
  114. package/lib/index.js +480 -0
  115. package/lib/known-format.d.ts +3 -0
  116. package/lib/known-format.js +8 -0
  117. package/lib/learning-scheduler.d.ts +37 -0
  118. package/lib/learning-scheduler.js +182 -0
  119. package/lib/learning-session-runner.d.ts +50 -0
  120. package/lib/learning-session-runner.js +435 -0
  121. package/lib/learning-trigger.d.ts +18 -0
  122. package/lib/learning-trigger.js +92 -0
  123. package/lib/learning-usage.d.ts +18 -0
  124. package/lib/learning-usage.js +49 -0
  125. package/lib/ledger.d.ts +191 -0
  126. package/lib/ledger.js +752 -0
  127. package/lib/local-human-host.d.ts +11 -0
  128. package/lib/local-human-host.js +191 -0
  129. package/lib/local-human-token.d.ts +9 -0
  130. package/lib/local-human-token.js +32 -0
  131. package/lib/local-owner.d.ts +8 -0
  132. package/lib/local-owner.js +26 -0
  133. package/lib/message-source.d.ts +10 -0
  134. package/lib/message-source.js +2 -0
  135. package/lib/organization-location.d.ts +20 -0
  136. package/lib/organization-location.js +80 -0
  137. package/lib/organization-workspace.d.ts +22 -0
  138. package/lib/organization-workspace.js +32 -0
  139. package/lib/project-ledger.d.ts +183 -0
  140. package/lib/project-ledger.js +189 -0
  141. package/lib/project-review-transport.d.ts +23 -0
  142. package/lib/project-review-transport.js +155 -0
  143. package/lib/project-seat-context.d.ts +18 -0
  144. package/lib/project-seat-context.js +34 -0
  145. package/lib/proposal-review-transport.d.ts +26 -0
  146. package/lib/proposal-review-transport.js +104 -0
  147. package/lib/route-guard.d.ts +31 -0
  148. package/lib/route-guard.js +80 -0
  149. package/lib/safe-file.d.ts +24 -0
  150. package/lib/safe-file.js +93 -0
  151. package/lib/sample-organization.d.ts +10 -0
  152. package/lib/sample-organization.js +46 -0
  153. package/lib/service.d.ts +597 -0
  154. package/lib/service.js +4076 -0
  155. package/lib/session-surface.d.ts +11 -0
  156. package/lib/session-surface.js +109 -0
  157. package/lib/shared-knowledge-review-transport.d.ts +28 -0
  158. package/lib/shared-knowledge-review-transport.js +85 -0
  159. package/lib/shared-knowledge.d.ts +117 -0
  160. package/lib/shared-knowledge.js +240 -0
  161. package/lib/tools.d.ts +7 -0
  162. package/lib/tools.js +955 -0
  163. package/lib/ui-contract.d.ts +277 -0
  164. package/lib/ui-contract.js +12 -0
  165. package/lib/ui-host.d.ts +24 -0
  166. package/lib/ui-host.js +471 -0
  167. package/lib/untrusted-text.d.ts +16 -0
  168. package/lib/untrusted-text.js +50 -0
  169. package/lib/work-ledger.d.ts +109 -0
  170. package/lib/work-ledger.js +107 -0
  171. package/lib/work-output-eval.d.ts +16 -0
  172. package/lib/work-output-eval.js +58 -0
  173. package/lib/work-runner.d.ts +47 -0
  174. package/lib/work-runner.js +352 -0
  175. package/lib/worklog-ledger.d.ts +89 -0
  176. package/lib/worklog-ledger.js +91 -0
  177. package/lib/worklog-snapshot.d.ts +34 -0
  178. package/lib/worklog-snapshot.js +100 -0
  179. package/lib/writer-guard.d.ts +11 -0
  180. package/lib/writer-guard.js +207 -0
  181. package/package.json +172 -4
@@ -0,0 +1,39 @@
1
+ import { createUserMessage, freezeMessage } from '@deepseek-ai/dsh-llm';
2
+ import { selectedFrameAddresses, removeFrameReferences } from './frame-reference.js';
3
+ import './message-source.js';
4
+ /** Resolve selected references at DSH's admission boundary, before the model sees the step. */
5
+ export async function admitFrameReferences(service, agent, decision, signal) {
6
+ if (decision.kind !== 'enter')
7
+ return decision;
8
+ const messages = [];
9
+ for (const message of decision.messages) {
10
+ if (message.source.kind !== 'user') {
11
+ messages.push(message);
12
+ continue;
13
+ }
14
+ const text = message.content.filter(block => block.type === 'text').map(block => block.text).join('\n');
15
+ // The marker belongs to transport, not the visible transcript. Preserve message identity,
16
+ // user text and attachments while DSH logs the actual loaded context separately.
17
+ messages.push(freezeMessage({ ...message, content: message.content.map(block => block.type === 'text'
18
+ ? { ...block, text: removeFrameReferences(block.text) } : block) }));
19
+ for (const address of selectedFrameAddresses(text)) {
20
+ if (signal.aborted)
21
+ return { kind: 'reject' };
22
+ try {
23
+ // Admission can be cancelled after updating the Frame ledger. Always send a complete
24
+ // snapshot on retry, rather than assuming an earlier, uncommitted copy reached the log.
25
+ const result = await service.openFrame(agent, { address, forceSnapshot: true });
26
+ const context = String(result.context);
27
+ messages.push(createUserMessage({ content: [{ type: 'text', text: context }],
28
+ source: { kind: 'bizagent', form: 'snapshot', sections: [{ name: address, text: context }] } }));
29
+ }
30
+ catch (error) {
31
+ service.recordRuntimeError(`Frame reference ${String(agent.id)} ${address}`, error);
32
+ messages.push(createUserMessage({ content: [{ type: 'text', text: `The selected Home ${address} could not be loaded. Its context is unavailable; do not answer as if it was read.` }],
33
+ source: { kind: 'bizagent', form: 'notice', summary: `Home unavailable: ${address}` } }));
34
+ }
35
+ }
36
+ }
37
+ return signal.aborted ? { kind: 'reject' } : { ...decision, messages };
38
+ }
39
+ //# sourceMappingURL=frame-admission.js.map
@@ -0,0 +1,5 @@
1
+ /** A selected composer reference; only user-authored, admitted messages are resolved. */
2
+ export declare function frameReference(address: string): string;
3
+ export declare function selectedFrameAddresses(text: string): string[];
4
+ export declare function removeFrameReferences(text: string): string;
5
+ //# sourceMappingURL=frame-reference.d.ts.map
@@ -0,0 +1,12 @@
1
+ /** A selected composer reference; only user-authored, admitted messages are resolved. */
2
+ export function frameReference(address) {
3
+ return `[BIZAGENT_FRAME_REQUEST:${address}]`;
4
+ }
5
+ export function selectedFrameAddresses(text) {
6
+ return [...new Set([...text.matchAll(/^\[BIZAGENT_FRAME_REQUEST:((?:business|role|capability):[a-z0-9][a-z0-9._/-]*)\]/gm)]
7
+ .map(match => match[1]))].slice(0, 8);
8
+ }
9
+ export function removeFrameReferences(text) {
10
+ return text.replace(/\n?^\[BIZAGENT_FRAME_REQUEST:(?:business|role|capability):[a-z0-9][a-z0-9._/-]*\]/gm, '');
11
+ }
12
+ //# sourceMappingURL=frame-reference.js.map
@@ -0,0 +1,17 @@
1
+ import { z } from 'zod';
2
+ export declare const HomeArchiveManifestSchema: z.ZodObject<{
3
+ schemaVersion: z.ZodLiteral<1>;
4
+ kind: z.ZodLiteral<"bizagent-dsh-home-files">;
5
+ capturedAt: z.ZodString;
6
+ files: z.ZodArray<z.ZodObject<{
7
+ path: z.ZodString;
8
+ bytes: z.ZodNumber;
9
+ sha256: z.ZodString;
10
+ }, z.core.$strip>>;
11
+ rootDigest: z.ZodString;
12
+ }, z.core.$strip>;
13
+ export type HomeArchiveManifest = z.infer<typeof HomeArchiveManifestSchema>;
14
+ export declare function exportHomeArchive(sourceRoot: string, destination: string): Promise<HomeArchiveManifest>;
15
+ export declare function verifyHomeArchive(archiveRoot: string): Promise<HomeArchiveManifest>;
16
+ export declare function importHomeArchive(archiveRoot: string, destinationRoot: string): Promise<HomeArchiveManifest>;
17
+ //# sourceMappingURL=home-archive.d.ts.map
@@ -0,0 +1,177 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { copyFile, lstat, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, writeFile } from 'node:fs/promises';
3
+ import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
4
+ import { z } from 'zod';
5
+ import { HomeStore } from './home-store.js';
6
+ import { RUNTIME_WRITER_CLAIM_NAME, RUNTIME_WRITER_LOCK_NAME } from './writer-guard.js';
7
+ const MANIFEST = 'home-archive.json';
8
+ const ArchiveFileSchema = z.object({
9
+ path: z.string().min(1),
10
+ bytes: z.number().int().nonnegative(),
11
+ sha256: z.string().regex(/^[a-f0-9]{64}$/),
12
+ });
13
+ export const HomeArchiveManifestSchema = z.object({
14
+ schemaVersion: z.literal(1),
15
+ kind: z.literal('bizagent-dsh-home-files'),
16
+ capturedAt: z.string().datetime(),
17
+ files: z.array(ArchiveFileSchema).min(1),
18
+ rootDigest: z.string().regex(/^[a-f0-9]{64}$/),
19
+ }).superRefine((manifest, context) => {
20
+ const paths = manifest.files.map(file => file.path);
21
+ if (paths.some(path => !isSafePath(path) || path === MANIFEST
22
+ || path === RUNTIME_WRITER_LOCK_NAME || path === RUNTIME_WRITER_CLAIM_NAME)) {
23
+ context.addIssue({ code: 'custom', path: ['files'], message: 'unsafe archive path' });
24
+ }
25
+ if (new Set(paths).size !== paths.length || paths.join('\n') !== [...paths].sort(comparePath).join('\n')) {
26
+ context.addIssue({ code: 'custom', path: ['files'], message: 'archive paths must be unique and sorted' });
27
+ }
28
+ if (manifest.rootDigest !== digestFiles(manifest.files)) {
29
+ context.addIssue({ code: 'custom', path: ['rootDigest'], message: 'archive root digest mismatch' });
30
+ }
31
+ });
32
+ export async function exportHomeArchive(sourceRoot, destination) {
33
+ const source = resolve(sourceRoot);
34
+ const target = resolve(destination);
35
+ await requireRealDirectory(source);
36
+ requireOutside(source, target);
37
+ await requireAbsent(target);
38
+ await mkdir(dirname(target), { recursive: true });
39
+ const stage = await mkdtemp(join(dirname(target), `.${basename(target)}.stage-`));
40
+ try {
41
+ const files = await scanFiles(source, true);
42
+ if (files.length === 0)
43
+ throw new Error('Home root has no files to archive');
44
+ if (files.some(file => file.path === MANIFEST)) {
45
+ throw new Error(`Home root contains reserved archive filename: ${MANIFEST}`);
46
+ }
47
+ for (const file of files) {
48
+ const output = join(stage, file.path);
49
+ await mkdir(dirname(output), { recursive: true });
50
+ await copyFile(join(source, file.path), output);
51
+ }
52
+ const stagedFiles = await scanFiles(stage);
53
+ if (JSON.stringify(stagedFiles) !== JSON.stringify(files)
54
+ || JSON.stringify(await scanFiles(source, true)) !== JSON.stringify(files)) {
55
+ throw new Error('Home files changed during archive export');
56
+ }
57
+ const manifest = HomeArchiveManifestSchema.parse({
58
+ schemaVersion: 1, kind: 'bizagent-dsh-home-files', capturedAt: new Date().toISOString(),
59
+ files, rootDigest: digestFiles(files),
60
+ });
61
+ await writeFile(join(stage, MANIFEST), `${JSON.stringify(manifest, null, 2)}\n`, { flag: 'wx' });
62
+ await verifyHomeArchive(stage);
63
+ await requireAbsent(target);
64
+ await rename(stage, target);
65
+ return manifest;
66
+ }
67
+ catch (error) {
68
+ await rm(stage, { recursive: true, force: true });
69
+ throw error;
70
+ }
71
+ }
72
+ export async function verifyHomeArchive(archiveRoot) {
73
+ const root = resolve(archiveRoot);
74
+ await requireRealDirectory(root);
75
+ const manifest = HomeArchiveManifestSchema.parse(JSON.parse(await readFile(join(root, MANIFEST), 'utf8')));
76
+ const actual = (await scanFiles(root)).filter(file => file.path !== MANIFEST);
77
+ if (JSON.stringify(actual) !== JSON.stringify(manifest.files)) {
78
+ throw new Error('Home archive file list, size, or SHA-256 mismatch');
79
+ }
80
+ return manifest;
81
+ }
82
+ export async function importHomeArchive(archiveRoot, destinationRoot) {
83
+ const archive = resolve(archiveRoot);
84
+ const target = resolve(destinationRoot);
85
+ const manifest = await verifyHomeArchive(archive);
86
+ requireOutside(archive, target);
87
+ await requireAbsent(target);
88
+ await mkdir(dirname(target), { recursive: true });
89
+ const stage = await mkdtemp(join(dirname(target), `.${basename(target)}.stage-`));
90
+ try {
91
+ for (const file of manifest.files) {
92
+ const output = join(stage, file.path);
93
+ await mkdir(dirname(output), { recursive: true });
94
+ await copyFile(join(archive, file.path), output);
95
+ }
96
+ if (JSON.stringify(await scanFiles(stage)) !== JSON.stringify(manifest.files)) {
97
+ throw new Error('Home archive changed during import');
98
+ }
99
+ const store = new HomeStore(stage);
100
+ await store.initialize();
101
+ const report = await store.doctor();
102
+ if (!report.ok)
103
+ throw new Error(`Imported Home files failed doctor: ${report.issues.join('; ')}`);
104
+ await requireAbsent(target);
105
+ await rename(stage, target);
106
+ return manifest;
107
+ }
108
+ catch (error) {
109
+ await rm(stage, { recursive: true, force: true });
110
+ throw error;
111
+ }
112
+ }
113
+ async function scanFiles(root, excludeWriterLock = false) {
114
+ const files = [];
115
+ async function visit(directory) {
116
+ for (const entry of await readdir(directory, { withFileTypes: true })) {
117
+ if (excludeWriterLock && directory === root
118
+ && [RUNTIME_WRITER_LOCK_NAME, RUNTIME_WRITER_CLAIM_NAME].includes(entry.name))
119
+ continue;
120
+ const path = join(directory, entry.name);
121
+ const info = await lstat(path);
122
+ if (info.isSymbolicLink())
123
+ throw new Error(`Home archive rejects symlinks: ${relative(root, path)}`);
124
+ if (info.isDirectory()) {
125
+ await visit(path);
126
+ }
127
+ else if (info.isFile()) {
128
+ const name = relative(root, path).split('\\').join('/');
129
+ if (!isSafePath(name))
130
+ throw new Error(`unsafe Home archive path: ${name}`);
131
+ const bytes = await readFile(path);
132
+ files.push({ path: name, bytes: bytes.length, sha256: sha256(bytes) });
133
+ }
134
+ else {
135
+ throw new Error(`Home archive rejects non-file entry: ${relative(root, path)}`);
136
+ }
137
+ }
138
+ }
139
+ await visit(root);
140
+ return files.sort((a, b) => comparePath(a.path, b.path));
141
+ }
142
+ function comparePath(a, b) {
143
+ return a < b ? -1 : a > b ? 1 : 0;
144
+ }
145
+ function isSafePath(path) {
146
+ return !isAbsolute(path) && !path.includes('\\') && !path.includes('\0')
147
+ && path.split('/').every(part => part !== '' && part !== '.' && part !== '..');
148
+ }
149
+ function digestFiles(files) {
150
+ return sha256(JSON.stringify(files.map(file => [file.path, file.bytes, file.sha256])));
151
+ }
152
+ function sha256(bytes) {
153
+ return createHash('sha256').update(bytes).digest('hex');
154
+ }
155
+ async function requireRealDirectory(path) {
156
+ const info = await lstat(path);
157
+ if (!info.isDirectory() || await realpath(path) !== path)
158
+ throw new Error(`expected a real directory: ${path}`);
159
+ }
160
+ async function requireAbsent(path) {
161
+ try {
162
+ await lstat(path);
163
+ }
164
+ catch (error) {
165
+ if (error.code === 'ENOENT')
166
+ return;
167
+ throw error;
168
+ }
169
+ throw new Error(`destination already exists: ${path}`);
170
+ }
171
+ function requireOutside(source, target) {
172
+ const rel = relative(source, target);
173
+ if (rel === '' || (!rel.startsWith('..') && !isAbsolute(rel))) {
174
+ throw new Error('archive destination must be outside the source directory');
175
+ }
176
+ }
177
+ //# sourceMappingURL=home-archive.js.map
@@ -0,0 +1,6 @@
1
+ import { type AgentHome, type HomeAddress } from './domain.js';
2
+ export type HomeDirectoryEntry = Pick<AgentHome, 'address' | 'type' | 'displayName'>;
3
+ export declare function visibleHomeDirectory(homes: readonly AgentHome[], primaryHome: HomeAddress): HomeDirectoryEntry[];
4
+ export declare function searchHomeDirectory(homes: readonly AgentHome[], primaryHome: HomeAddress, query?: string, limit?: number): HomeDirectoryEntry[];
5
+ export declare function resolveHomeDirectoryTarget(homes: readonly AgentHome[], primaryHome: HomeAddress, target: string): HomeAddress;
6
+ //# sourceMappingURL=home-directory.d.ts.map
@@ -0,0 +1,38 @@
1
+ import { isHomeAddress } from './domain.js';
2
+ function normalize(value) {
3
+ return value.normalize('NFKC').trim().toLowerCase();
4
+ }
5
+ export function visibleHomeDirectory(homes, primaryHome) {
6
+ return homes
7
+ .filter(home => home.status === 'active' && (home.type !== 'personal' || home.address === primaryHome))
8
+ .map(({ address, type, displayName }) => ({ address, type, displayName }))
9
+ .sort((a, b) => a.address.localeCompare(b.address));
10
+ }
11
+ export function searchHomeDirectory(homes, primaryHome, query = '', limit = 20) {
12
+ const needle = normalize(query);
13
+ return visibleHomeDirectory(homes, primaryHome)
14
+ .filter(home => !needle || normalize(home.address).includes(needle)
15
+ || normalize(home.displayName).includes(needle) || normalize(home.type).includes(needle))
16
+ .slice(0, limit);
17
+ }
18
+ export function resolveHomeDirectoryTarget(homes, primaryHome, target) {
19
+ const visible = visibleHomeDirectory(homes, primaryHome);
20
+ const name = normalize(target);
21
+ if (!name)
22
+ throw new Error('Home not found or inaccessible');
23
+ // Canonical addresses take precedence over a Home with the same display name.
24
+ const address = target.trim();
25
+ if (isHomeAddress(address)) {
26
+ if (visible.some(home => home.address === address))
27
+ return address;
28
+ throw new Error('Home not found or inaccessible');
29
+ }
30
+ const matches = visible.filter(home => normalize(home.displayName) === name);
31
+ if (matches.length === 1)
32
+ return matches[0].address;
33
+ if (matches.length > 1) {
34
+ throw new Error(`ambiguous Home name; use a canonical address: ${matches.map(home => home.address).join(', ')}`);
35
+ }
36
+ throw new Error('Home not found or inaccessible');
37
+ }
38
+ //# sourceMappingURL=home-directory.js.map
@@ -0,0 +1,50 @@
1
+ import { type AgentHome, type AssetStatus, type ContextBudget, type Organization, type StoredAsset } from './domain.js';
2
+ import type { InboxWakePolicy } from './inbox-wake-policy.js';
3
+ import type { AssetSearchInput, CreateAssetInput, CreateHomeInput, DoctorReport, HomeStore, UpdateAssetInput } from './home-store.js';
4
+ /**
5
+ * Every Home this host can see: the person's own Homes in the data root (the personal space), and
6
+ * the active organization's Homes under `<data root>/orgs/<id>`. Each Home stays in the folder of
7
+ * the store that holds it. When both hold the same address, the organization's Home wins and the
8
+ * personal one is reported by `doctor`.
9
+ */
10
+ export declare class HomeSpace {
11
+ readonly personal: HomeStore;
12
+ readonly organizationStore?: HomeStore | undefined;
13
+ constructor(personal: HomeStore, organizationStore?: HomeStore | undefined);
14
+ /** Where organization-wide records live: the organization root, or the personal space without one. */
15
+ get root(): string;
16
+ get personalRoot(): string;
17
+ get organizationRoot(): string | undefined;
18
+ initialize(): Promise<void>;
19
+ reload(): Promise<void>;
20
+ /** The same personal space with another organization (or none) beside it. */
21
+ withOrganization(organizationStore: HomeStore | undefined): HomeSpace;
22
+ /** The root of the store that holds this Home; its snapshots and records belong there. */
23
+ rootFor(address: string): string;
24
+ /** A Home from the personal space, outside any organization. */
25
+ isPersonalHome(address: string): boolean;
26
+ listHomes(): AgentHome[];
27
+ hasHome(address: string): boolean;
28
+ getHome(address: string): AgentHome;
29
+ findHome(address: string): AgentHome | undefined;
30
+ homeWorkspacePath(address: string): string;
31
+ readInboxWakePolicy(address: string): Promise<InboxWakePolicy>;
32
+ getIdentity(address: string): string;
33
+ /** The active organization; before organizations had their own folder it could sit in the data root itself. */
34
+ getOrganization(): Organization | undefined;
35
+ /** New Homes join the active organization unless the personal space is asked for. */
36
+ createHome(input: CreateHomeInput, target?: 'organization' | 'personal'): Promise<AgentHome>;
37
+ listAssets(address: string, status?: AssetStatus): StoredAsset[];
38
+ searchAssets(address: string, input?: AssetSearchInput): StoredAsset[];
39
+ readAsset(address: string, id: string): StoredAsset;
40
+ findAssetByProposalId(address: string, proposalId: string): StoredAsset | undefined;
41
+ createAsset(input: CreateAssetInput): Promise<StoredAsset>;
42
+ updateAsset(address: string, id: string, input: UpdateAssetInput): Promise<StoredAsset>;
43
+ contextFor(address: string, budget: ContextBudget, episodeCount?: number): string;
44
+ contextForFrame(address: string, budget: ContextBudget): string;
45
+ doctor(): Promise<DoctorReport>;
46
+ private findStore;
47
+ /** Throws the store's own unknown-Home error when no store holds the address. */
48
+ private storeFor;
49
+ }
50
+ //# sourceMappingURL=home-space.d.ts.map
@@ -0,0 +1,120 @@
1
+ import { parseHomeAddress } from './domain.js';
2
+ /**
3
+ * Every Home this host can see: the person's own Homes in the data root (the personal space), and
4
+ * the active organization's Homes under `<data root>/orgs/<id>`. Each Home stays in the folder of
5
+ * the store that holds it. When both hold the same address, the organization's Home wins and the
6
+ * personal one is reported by `doctor`.
7
+ */
8
+ export class HomeSpace {
9
+ personal;
10
+ organizationStore;
11
+ constructor(personal, organizationStore) {
12
+ this.personal = personal;
13
+ this.organizationStore = organizationStore;
14
+ }
15
+ /** Where organization-wide records live: the organization root, or the personal space without one. */
16
+ get root() { return (this.organizationStore ?? this.personal).root; }
17
+ get personalRoot() { return this.personal.root; }
18
+ get organizationRoot() { return this.organizationStore?.root; }
19
+ async initialize() {
20
+ await this.personal.initialize();
21
+ await this.organizationStore?.initialize();
22
+ }
23
+ async reload() {
24
+ await this.personal.reload();
25
+ await this.organizationStore?.reload();
26
+ }
27
+ /** The same personal space with another organization (or none) beside it. */
28
+ withOrganization(organizationStore) {
29
+ return new HomeSpace(this.personal, organizationStore);
30
+ }
31
+ /** The root of the store that holds this Home; its snapshots and records belong there. */
32
+ rootFor(address) { return this.storeFor(address).root; }
33
+ /** A Home from the personal space, outside any organization. */
34
+ isPersonalHome(address) {
35
+ return this.findStore(address) === this.personal;
36
+ }
37
+ listHomes() {
38
+ const organizationHomes = this.organizationStore?.listHomes() ?? [];
39
+ const shadowed = new Set(organizationHomes.map(home => home.address));
40
+ return [...organizationHomes, ...this.personal.listHomes().filter(home => !shadowed.has(home.address))]
41
+ .sort((a, b) => a.address.localeCompare(b.address));
42
+ }
43
+ hasHome(address) { return this.findStore(address) !== undefined; }
44
+ getHome(address) { return this.storeFor(address).getHome(address); }
45
+ findHome(address) { return this.findStore(address)?.findHome(address); }
46
+ homeWorkspacePath(address) { return this.storeFor(address).homeWorkspacePath(address); }
47
+ readInboxWakePolicy(address) {
48
+ return this.storeFor(address).readInboxWakePolicy(address);
49
+ }
50
+ getIdentity(address) { return this.storeFor(address).getIdentity(address); }
51
+ /** The active organization; before organizations had their own folder it could sit in the data root itself. */
52
+ getOrganization() {
53
+ return (this.organizationStore ?? this.personal).getOrganization();
54
+ }
55
+ /** New Homes join the active organization unless the personal space is asked for. */
56
+ async createHome(input, target = 'organization') {
57
+ const store = target === 'personal' ? this.personal : this.organizationStore ?? this.personal;
58
+ const other = store === this.personal ? this.organizationStore : this.personal;
59
+ if (other?.hasHome(input.address)) {
60
+ throw new Error(`Agent Home already exists outside this ${target === 'personal' ? 'personal space' : 'organization'}: ${input.address}`);
61
+ }
62
+ return store.createHome(input);
63
+ }
64
+ listAssets(address, status) {
65
+ return this.storeFor(address).listAssets(address, status);
66
+ }
67
+ searchAssets(address, input = {}) {
68
+ return this.storeFor(address).searchAssets(address, input);
69
+ }
70
+ readAsset(address, id) { return this.storeFor(address).readAsset(address, id); }
71
+ findAssetByProposalId(address, proposalId) {
72
+ return this.storeFor(address).findAssetByProposalId(address, proposalId);
73
+ }
74
+ createAsset(input) {
75
+ return this.storeFor(input.ownerAddress).createAsset(input);
76
+ }
77
+ updateAsset(address, id, input) {
78
+ return this.storeFor(address).updateAsset(address, id, input);
79
+ }
80
+ contextFor(address, budget, episodeCount = 0) {
81
+ return this.storeFor(address).contextFor(address, budget, episodeCount);
82
+ }
83
+ contextForFrame(address, budget) {
84
+ return this.storeFor(address).contextForFrame(address, budget);
85
+ }
86
+ async doctor() {
87
+ const personal = await this.personal.doctor();
88
+ if (this.organizationStore === undefined)
89
+ return personal;
90
+ const organization = await this.organizationStore.doctor();
91
+ const shadowed = this.personal.listHomes()
92
+ .filter(home => this.organizationStore.hasHome(home.address))
93
+ .map(home => `personal Home ${home.address} is hidden by the organization Home with the same address`);
94
+ const issues = [...organization.issues, ...personal.issues.map(issue => `personal space: ${issue}`), ...shadowed];
95
+ return {
96
+ ok: issues.length === 0,
97
+ root: organization.root,
98
+ homeCount: this.listHomes().length,
99
+ assetCount: organization.assetCount + personal.assetCount,
100
+ issues,
101
+ };
102
+ }
103
+ findStore(address) {
104
+ let parsed;
105
+ try {
106
+ parsed = parseHomeAddress(address);
107
+ }
108
+ catch {
109
+ return undefined;
110
+ }
111
+ if (this.organizationStore?.hasHome(parsed))
112
+ return this.organizationStore;
113
+ return this.personal.hasHome(parsed) ? this.personal : undefined;
114
+ }
115
+ /** Throws the store's own unknown-Home error when no store holds the address. */
116
+ storeFor(address) {
117
+ return this.findStore(address) ?? this.organizationStore ?? this.personal;
118
+ }
119
+ }
120
+ //# sourceMappingURL=home-space.js.map
@@ -0,0 +1,126 @@
1
+ import { type AgentHome, type AssetKind, type AssetStatus, type ContextBudget, type EvidenceRef, type HomeAddress, type Organization, type StoredAsset } from './domain.js';
2
+ import { type InboxWakePolicy } from './inbox-wake-policy.js';
3
+ export interface CreateHomeInput {
4
+ address: string;
5
+ displayName?: string;
6
+ owner?: string;
7
+ identity?: string;
8
+ }
9
+ export interface CreateOrganizationInput {
10
+ id: string;
11
+ name: string;
12
+ mission: string;
13
+ /** Person who owns every Home in the organization. Defaults to each member id (members as people). */
14
+ owner?: string;
15
+ members: Array<{
16
+ id: string;
17
+ displayName: string;
18
+ roleId: string;
19
+ roleName: string;
20
+ responsibility: string;
21
+ }>;
22
+ capabilities: Array<{
23
+ id: string;
24
+ displayName: string;
25
+ responsibility: string;
26
+ }>;
27
+ }
28
+ export interface CreateAssetInput {
29
+ id: string;
30
+ ownerAddress: HomeAddress;
31
+ kind: Exclude<AssetKind, 'identity'>;
32
+ title?: string;
33
+ description: string;
34
+ body: string;
35
+ tags?: string[];
36
+ sourceRefs: EvidenceRef[];
37
+ confidence?: number;
38
+ fitness?: number;
39
+ status?: AssetStatus;
40
+ proposalId?: string;
41
+ }
42
+ export interface UpdateAssetInput {
43
+ /** Checked inside the serialized mutation, before reading or writing a new revision. */
44
+ expectedRevision?: number;
45
+ description?: string;
46
+ body?: string;
47
+ tags?: string[];
48
+ sourceRefs?: EvidenceRef[];
49
+ status?: AssetStatus;
50
+ confidence?: number;
51
+ fitness?: number;
52
+ /** Internal recovery marker, persisted in the same file revision as a proposal replacement. */
53
+ appliedProposalId?: string;
54
+ }
55
+ export interface AssetSearchInput {
56
+ query?: string;
57
+ kind?: AssetKind;
58
+ status?: AssetStatus;
59
+ limit?: number;
60
+ }
61
+ export interface DoctorReport {
62
+ ok: boolean;
63
+ root: string;
64
+ homeCount: number;
65
+ assetCount: number;
66
+ issues: string[];
67
+ }
68
+ export declare class HomeStore {
69
+ readonly root: string;
70
+ readonly homesRoot: string;
71
+ readonly organizationFile: string;
72
+ private readonly homes;
73
+ private organization;
74
+ private organizationLoadError;
75
+ private integrityIssues;
76
+ private mutationTail;
77
+ constructor(root: string);
78
+ initialize(): Promise<void>;
79
+ reload(): Promise<void>;
80
+ listHomes(): AgentHome[];
81
+ hasHome(address: string): boolean;
82
+ getHome(address: string): AgentHome;
83
+ /** Any loaded Home, including an archived one, or undefined; never throws for an unknown address. */
84
+ findHome(address: string): AgentHome | undefined;
85
+ /** The Home's fixed DSH Workspace, shared by Principal, Project Main and Seats. */
86
+ homeWorkspacePath(address: string): string;
87
+ /** Home-local receipt policy. Missing or malformed files use the 15-minute batch default. */
88
+ readInboxWakePolicy(address: string): Promise<InboxWakePolicy>;
89
+ getIdentity(address: string): string;
90
+ getOrganization(): Organization | undefined;
91
+ createHome(input: CreateHomeInput): Promise<AgentHome>;
92
+ createOrganization(input: CreateOrganizationInput): Promise<Organization>;
93
+ listAssets(address: string, status?: AssetStatus): StoredAsset[];
94
+ searchAssets(address: string, input?: AssetSearchInput): StoredAsset[];
95
+ readAsset(address: string, id: string): StoredAsset;
96
+ findAssetByProposalId(address: string, proposalId: string): StoredAsset | undefined;
97
+ createAsset(input: CreateAssetInput): Promise<StoredAsset>;
98
+ updateAsset(address: string, id: string, input: UpdateAssetInput): Promise<StoredAsset>;
99
+ contextFor(address: string, budget: ContextBudget, episodeCount?: number): string;
100
+ contextForFrame(address: string, budget: ContextBudget): string;
101
+ private renderContext;
102
+ private relativePath;
103
+ /** Error text for issues, with absolute paths under the root shown relative to it. */
104
+ private relativeMessage;
105
+ doctor(): Promise<DoctorReport>;
106
+ /**
107
+ * Owners recorded in directory.yaml when this store last wrote it. The file sits at the store
108
+ * root, outside each Home's own Workspace directory, so an Agent working in its Home cannot
109
+ * change its owner by editing home.yaml alone.
110
+ */
111
+ private readRecordedOwners;
112
+ /** Refuse an owner change made in agent-writable home.yaml; keep the recorded owner and report it. */
113
+ private keepRecordedOwner;
114
+ private loadHome;
115
+ private loadOrganization;
116
+ private loadOrganizationFile;
117
+ private createHomeUnlocked;
118
+ private refreshHome;
119
+ private assetPath;
120
+ private requireHome;
121
+ private assertWithinRoot;
122
+ private writeDirectory;
123
+ private mutate;
124
+ }
125
+ export declare function pathExists(path: string): Promise<boolean>;
126
+ //# sourceMappingURL=home-store.d.ts.map