@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,80 @@
1
+ const SAFE_METHODS = new Set(['GET', 'HEAD']);
2
+ export function isLoopbackHostname(hostname) {
3
+ if (hostname === 'localhost' || hostname === '[::1]')
4
+ return true;
5
+ const parts = hostname.split('.');
6
+ return parts.length === 4 && parts[0] === '127'
7
+ && parts.every(part => /^\d{1,3}$/.test(part) && Number(part) <= 255);
8
+ }
9
+ /** Return why a request must be rejected, or undefined when it may reach the handler. */
10
+ export function localRouteRejection(request) {
11
+ const host = singleHeader(request.headers.host);
12
+ const hostUrl = host === undefined ? undefined : parseAuthority(host);
13
+ if (hostUrl === undefined || !isLoopbackHostname(hostUrl.hostname))
14
+ return 'untrusted-host';
15
+ if (singleHeader(request.headers['sec-fetch-site'])?.toLowerCase() === 'cross-site') {
16
+ return 'cross-site-request';
17
+ }
18
+ const origin = singleHeader(request.headers.origin);
19
+ if (origin === undefined) {
20
+ return SAFE_METHODS.has((request.method ?? 'GET').toUpperCase()) ? undefined : 'origin-rejected';
21
+ }
22
+ try {
23
+ const originUrl = new URL(origin);
24
+ if (originUrl.protocol !== 'http:' && originUrl.protocol !== 'https:')
25
+ return 'origin-rejected';
26
+ return originUrl.host === hostUrl.host ? undefined : 'origin-rejected';
27
+ }
28
+ catch {
29
+ return 'origin-rejected';
30
+ }
31
+ }
32
+ /** Wrap a route handler so untrusted browser requests get a 403 before any handler code runs. */
33
+ export function guardLocalRoute(handler) {
34
+ return async (request, response) => {
35
+ if (rejectUntrustedRequest(request, response))
36
+ return;
37
+ await handler(request, response);
38
+ };
39
+ }
40
+ /** Write the standard 403 response and return true when the request fails the fence. */
41
+ export function rejectUntrustedRequest(request, response) {
42
+ const rejection = localRouteRejection(request);
43
+ if (rejection === undefined)
44
+ return false;
45
+ response.setHeader('Cache-Control', 'no-store');
46
+ response.setHeader('Content-Type', 'application/json; charset=utf-8');
47
+ response.setHeader('X-Content-Type-Options', 'nosniff');
48
+ response.statusCode = 403;
49
+ response.end(JSON.stringify({ error: { code: rejection, message: REJECTION_MESSAGES[rejection] } }));
50
+ return true;
51
+ }
52
+ const REJECTION_MESSAGES = {
53
+ 'untrusted-host': 'This endpoint only serves the local loopback DSH origin.',
54
+ 'cross-site-request': 'Cross-site requests are not accepted.',
55
+ 'origin-rejected': 'Mutation requests must come from this DSH origin.',
56
+ };
57
+ function singleHeader(value) {
58
+ return typeof value === 'string' ? value : undefined;
59
+ }
60
+ /** Parse a bare `host[:port]` authority; anything with userinfo, a path, query, or fragment is refused. */
61
+ function parseAuthority(authority) {
62
+ if (authority.length === 0 || /[\s/?#@\\]/u.test(authority))
63
+ return undefined;
64
+ try {
65
+ const url = new URL(`http://${authority}`);
66
+ return url.username === '' && url.password === '' && url.pathname === '/' ? url : undefined;
67
+ }
68
+ catch {
69
+ return undefined;
70
+ }
71
+ }
72
+ /**
73
+ * DSH's browser login, looked up per request. DSH 0.2 Web provides it as the `connection`
74
+ * service; hosts without it get only the loopback fence above.
75
+ */
76
+ export function dshOperatorAuthentication(ctx) {
77
+ const candidate = ctx.get('connection');
78
+ return typeof candidate?.requestRejection === 'function' ? candidate : undefined;
79
+ }
80
+ //# sourceMappingURL=route-guard.js.map
@@ -0,0 +1,24 @@
1
+ export interface RegularFileIdentity {
2
+ dev: number;
3
+ ino: number;
4
+ }
5
+ export interface ReadRegularFileOptions {
6
+ /** Reject files larger than this many bytes, checked on the open handle. */
7
+ maxBytes?: number;
8
+ /** Require the opened file to be this exact inode, e.g. one validated by an earlier path check. */
9
+ expected?: RegularFileIdentity;
10
+ }
11
+ /**
12
+ * Read one file without following a final symlink and without a check-then-read race: the file
13
+ * is opened with O_NOFOLLOW (O_NONBLOCK keeps a FIFO from blocking the open), then the open
14
+ * handle is checked to be a regular file and read. Platforms without O_NOFOLLOW fall back to an
15
+ * lstat check plus the same handle checks.
16
+ */
17
+ export declare function readRegularFileNoFollow(path: string, options?: ReadRegularFileOptions): Promise<Buffer>;
18
+ /**
19
+ * Replace a file so that a crash or power loss leaves either the old or the new contents, never an
20
+ * empty file: write a private temporary file, fsync it, rename it over the target, then fsync the
21
+ * directory so the rename itself is durable (best effort where directories cannot be fsynced).
22
+ */
23
+ export declare function writeFileDurably(path: string, contents: string | Uint8Array): Promise<void>;
24
+ //# sourceMappingURL=safe-file.d.ts.map
@@ -0,0 +1,93 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { constants } from 'node:fs';
3
+ import { lstat, mkdir, open, rename, unlink } from 'node:fs/promises';
4
+ import { dirname } from 'node:path';
5
+ /**
6
+ * Read one file without following a final symlink and without a check-then-read race: the file
7
+ * is opened with O_NOFOLLOW (O_NONBLOCK keeps a FIFO from blocking the open), then the open
8
+ * handle is checked to be a regular file and read. Platforms without O_NOFOLLOW fall back to an
9
+ * lstat check plus the same handle checks.
10
+ */
11
+ export async function readRegularFileNoFollow(path, options = {}) {
12
+ if (constants.O_NOFOLLOW === undefined) {
13
+ const info = await lstat(path);
14
+ if (info.isSymbolicLink())
15
+ throw new Error(`refusing to follow a symlink: ${path}`);
16
+ }
17
+ const flags = constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0);
18
+ let handle;
19
+ try {
20
+ handle = await open(path, flags);
21
+ }
22
+ catch (error) {
23
+ if (isErrno(error, 'ELOOP'))
24
+ throw new Error(`refusing to follow a symlink: ${path}`, { cause: error });
25
+ throw error;
26
+ }
27
+ try {
28
+ const info = await handle.stat();
29
+ if (!info.isFile())
30
+ throw new Error(`not a regular file: ${path}`);
31
+ if (options.expected !== undefined
32
+ && (info.dev !== options.expected.dev || info.ino !== options.expected.ino)) {
33
+ throw new Error(`file changed while it was being opened: ${path}`);
34
+ }
35
+ if (options.maxBytes !== undefined && info.size > options.maxBytes) {
36
+ throw new Error(`file exceeds ${options.maxBytes} bytes: ${path}`);
37
+ }
38
+ const bytes = await handle.readFile();
39
+ if (options.maxBytes !== undefined && bytes.length > options.maxBytes) {
40
+ throw new Error(`file exceeds ${options.maxBytes} bytes: ${path}`);
41
+ }
42
+ return bytes;
43
+ }
44
+ finally {
45
+ await handle.close();
46
+ }
47
+ }
48
+ function isErrno(error, code) {
49
+ return typeof error === 'object' && error !== null && 'code' in error && error.code === code;
50
+ }
51
+ /**
52
+ * Replace a file so that a crash or power loss leaves either the old or the new contents, never an
53
+ * empty file: write a private temporary file, fsync it, rename it over the target, then fsync the
54
+ * directory so the rename itself is durable (best effort where directories cannot be fsynced).
55
+ */
56
+ export async function writeFileDurably(path, contents) {
57
+ const directory = dirname(path);
58
+ await mkdir(directory, { recursive: true });
59
+ const temporary = `${path}.${process.pid}.${randomUUID()}.tmp`;
60
+ const handle = await open(temporary, 'wx', 0o600);
61
+ try {
62
+ await handle.writeFile(contents);
63
+ await handle.sync();
64
+ }
65
+ catch (error) {
66
+ await handle.close().catch(() => undefined);
67
+ await unlink(temporary).catch(() => undefined);
68
+ throw error;
69
+ }
70
+ await handle.close();
71
+ try {
72
+ await rename(temporary, path);
73
+ }
74
+ catch (error) {
75
+ await unlink(temporary).catch(() => undefined);
76
+ throw error;
77
+ }
78
+ await syncDirectory(directory);
79
+ }
80
+ async function syncDirectory(directory) {
81
+ let handle;
82
+ try {
83
+ handle = await open(directory, constants.O_RDONLY);
84
+ await handle.sync();
85
+ }
86
+ catch {
87
+ // Some platforms and filesystems cannot fsync a directory; the file itself is already synced.
88
+ }
89
+ finally {
90
+ await handle?.close().catch(() => undefined);
91
+ }
92
+ }
93
+ //# sourceMappingURL=safe-file.js.map
@@ -0,0 +1,10 @@
1
+ import type { CreateOrganizationInput } from './home-store.js';
2
+ /** A small growth team with real data to work on, so every BizAgent loop can be tried in minutes. */
3
+ export declare const SAMPLE_ORGANIZATION: Omit<CreateOrganizationInput, 'owner'>;
4
+ /** Files placed in sample Home directories. Existing files are never overwritten. */
5
+ export declare const SAMPLE_FILES: ReadonlyArray<{
6
+ home: string;
7
+ path: string;
8
+ content: string;
9
+ }>;
10
+ //# sourceMappingURL=sample-organization.d.ts.map
@@ -0,0 +1,46 @@
1
+ import { BIZAGENT_SAMPLE_ORGANIZATION_ID } from './ui-contract.js';
2
+ /** A small growth team with real data to work on, so every BizAgent loop can be tried in minutes. */
3
+ export const SAMPLE_ORGANIZATION = {
4
+ id: BIZAGENT_SAMPLE_ORGANIZATION_ID,
5
+ name: 'Sample Shop',
6
+ mission: 'grow repeat purchases with numbers everyone on the team can trust.',
7
+ members: [
8
+ {
9
+ id: 'growth-lead',
10
+ displayName: 'Growth lead',
11
+ roleId: 'growth',
12
+ roleName: 'Growth',
13
+ responsibility: 'Decide where the team spends its effort, run Projects, and sign off on results.',
14
+ },
15
+ {
16
+ id: 'data-analyst',
17
+ displayName: 'Data analyst',
18
+ roleId: 'analytics',
19
+ roleName: 'Analytics',
20
+ responsibility: 'Own metric definitions and compute numbers from the shop data in your workspace.',
21
+ },
22
+ ],
23
+ capabilities: [{
24
+ id: 'metrics',
25
+ displayName: 'Metric definitions',
26
+ responsibility: 'Keep the agreed definitions of GMV, retention, and other shared metrics.',
27
+ }],
28
+ };
29
+ /** Files placed in sample Home directories. Existing files are never overwritten. */
30
+ export const SAMPLE_FILES = [
31
+ {
32
+ home: 'personal:data-analyst',
33
+ path: 'orders.csv',
34
+ content: [
35
+ 'order_id,status,amount',
36
+ 'A1,paid,120.50',
37
+ 'A2,cancelled,80.00',
38
+ 'A3,paid,45.25',
39
+ 'A4,refunded,60.00',
40
+ 'A5,paid,200.00',
41
+ 'A6,shipped,34.75',
42
+ '',
43
+ ].join('\n'),
44
+ },
45
+ ];
46
+ //# sourceMappingURL=sample-organization.js.map