@inneranimalmedia/agentsam-sdk 2.6.0 → 2.6.2

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 (145) hide show
  1. package/docs/AUTH_IDENTITY_CONTRACT.md +25 -27
  2. package/docs/PLATFORM_RUNTIME_EVENTS.md +48 -0
  3. package/docs/RELEASES.md +7 -7
  4. package/docs/SDK_WORKER.md +4 -3
  5. package/docs/SOURCE_ARCHITECTURE.md +58 -0
  6. package/docs/TEST_TIERS.md +26 -0
  7. package/migrations/runtime/0001_cli_runtime.sql +298 -0
  8. package/package.json +28 -7
  9. package/packages/agentsam-repository/README.md +15 -0
  10. package/packages/agentsam-repository/package.json +25 -0
  11. package/packages/agentsam-repository/src/contracts.js +113 -0
  12. package/packages/agentsam-repository/src/index.js +3 -0
  13. package/{src/lib → packages/agentsam-repository/src}/merkle/cloudflare-persistence.js +14 -24
  14. package/{src/lib → packages/agentsam-repository/src}/merkle/index.js +1 -0
  15. package/{src/lib → packages/agentsam-repository/src}/merkle/persistence.js +6 -4
  16. package/{src/lib → packages/agentsam-repository/src}/merkle/policy.js +1 -0
  17. package/packages/agentsam-repository/test/contracts.test.mjs +40 -0
  18. package/packages/agentsam-repository/test/git-context.test.mjs +24 -0
  19. package/{test/merkle.test.mjs → packages/agentsam-repository/test/merkle-core.test.mjs} +2 -32
  20. package/{test → packages/agentsam-repository/test}/merkle-persistence.test.mjs +11 -6
  21. package/packages/identity/package.json +2 -2
  22. package/packages/identity/src/contracts/auth-config.js +23 -40
  23. package/packages/identity/tests/auth-config.test.mjs +14 -23
  24. package/protocol/COMPANY_REPOSITORY_GRAPH_V1.md +91 -0
  25. package/protocol/MERKLE_PERSISTENCE_V1.md +2 -0
  26. package/protocol/MERKLE_PERSISTENCE_V2.md +40 -0
  27. package/protocol/repository/repository-contract.schema.json +24 -0
  28. package/protocol/repository/repository-dependency.schema.json +24 -0
  29. package/protocol/repository/repository-identity.schema.json +17 -0
  30. package/protocol/rpc/v1/common.proto +16 -0
  31. package/protocol/rpc/v1/errors.proto +35 -0
  32. package/protocol/rpc/v1/knowledge.proto +77 -0
  33. package/services/knowledge/package-lock.json +333 -0
  34. package/services/knowledge/package.json +5 -1
  35. package/src/agent/responses-runner.js +63 -35
  36. package/src/capabilities/repository-snapshot.js +3 -3
  37. package/src/cli.js +36 -29
  38. package/src/commands/account-auth.js +1 -1
  39. package/src/commands/context-economics.js +17 -2
  40. package/src/commands/context.js +1 -1
  41. package/src/commands/db.js +20 -3
  42. package/src/commands/deploy.js +2 -2
  43. package/src/commands/env.js +90 -0
  44. package/src/commands/knowledge.js +12 -4
  45. package/src/commands/merkle-persist.js +30 -11
  46. package/src/commands/merkle.js +1 -1
  47. package/src/commands/models.js +123 -65
  48. package/src/commands/ollama.js +26 -0
  49. package/src/commands/preferences.js +53 -26
  50. package/src/commands/providers.js +308 -0
  51. package/src/commands/shell.js +240 -48
  52. package/src/commands/tunnel.js +8 -8
  53. package/src/commands/whoami.js +42 -21
  54. package/src/errors/contract.js +236 -0
  55. package/src/errors/diagnostic.js +1 -0
  56. package/src/errors/index.js +14 -0
  57. package/src/index.js +13 -1
  58. package/src/knowledge/service/auth.js +13 -0
  59. package/src/knowledge/service/grpc-client.js +115 -0
  60. package/src/knowledge/service/grpc-codec.js +237 -0
  61. package/src/knowledge/service/grpc-server.js +83 -0
  62. package/src/knowledge/service/job-engine.js +248 -0
  63. package/src/knowledge/service/server.js +87 -135
  64. package/src/knowledge/source.js +1 -1
  65. package/src/lib/account-session.js +94 -25
  66. package/src/lib/auth.js +314 -51
  67. package/src/lib/cli-preferences.js +31 -4
  68. package/src/lib/core-client.js +75 -30
  69. package/src/lib/deploy-receipt/index.js +2 -2
  70. package/src/lib/detect-context.js +14 -16
  71. package/src/lib/knowledge-docker.js +6 -3
  72. package/src/lib/local-sessions.js +23 -2
  73. package/src/lib/local-status.js +1 -1
  74. package/src/lib/project-config.js +1 -1
  75. package/src/lib/provider-credentials.js +230 -14
  76. package/src/lib/slash-commands.js +5 -3
  77. package/src/local/migrations.js +93 -0
  78. package/src/local/runtime-store.js +141 -0
  79. package/src/local/sqlite.js +2 -0
  80. package/src/local-pty/server.js +113 -51
  81. package/src/models/discovery.js +327 -0
  82. package/src/providers/anthropic-messages.js +192 -0
  83. package/src/providers/cloudflare-chat.js +183 -0
  84. package/src/providers/factory.js +69 -0
  85. package/src/providers/gemini-generate-content.js +208 -0
  86. package/src/providers/index.js +5 -0
  87. package/src/providers/ollama-chat.js +148 -0
  88. package/src/providers/openai-responses.js +226 -75
  89. package/src/repository/index.js +14 -2
  90. package/src/rpc/generated/common_grpc_pb.js +1 -0
  91. package/src/rpc/generated/common_pb.js +536 -0
  92. package/src/rpc/generated/errors_grpc_pb.js +1 -0
  93. package/src/rpc/generated/errors_pb.js +482 -0
  94. package/src/rpc/generated/knowledge_grpc_pb.js +135 -0
  95. package/src/rpc/generated/knowledge_pb.js +2168 -0
  96. package/src/rpc/generated/package.json +3 -0
  97. package/src/security/trust-boundary.js +2 -2
  98. package/src/telemetry/events.js +4 -1
  99. package/src/ui/cli/activity.js +76 -0
  100. package/src/ui/cli/compaction.js +15 -0
  101. package/src/ui/cli/footer.js +39 -0
  102. package/src/ui/cli/help.js +194 -0
  103. package/src/ui/cli/plan.js +20 -0
  104. package/src/ui/cli/runtime-events.js +110 -0
  105. package/src/ui/cli/waiting.js +16 -0
  106. package/src/ui/merkle/render.js +1 -1
  107. package/test/account-session.test.mjs +48 -11
  108. package/test/apps-scaffold-contract.test.mjs +43 -0
  109. package/test/cli/preferences-runtime.test.mjs +11 -0
  110. package/test/cli/runtime-ui.test.mjs +74 -0
  111. package/test/error-diagnostics.test.mjs +57 -1
  112. package/test/fixtures/knowledge-rpc-worker.mjs +16 -0
  113. package/test/integration/cli-help.test.mjs +37 -0
  114. package/test/integration/knowledge-rpc.test.mjs +112 -0
  115. package/test/integration/merkle-cli.test.mjs +61 -0
  116. package/test/integration/merkle-persistence-identity.test.mjs +48 -0
  117. package/test/integration/provider-env-cli.test.mjs +49 -0
  118. package/test/integration/provider-factory.test.mjs +197 -0
  119. package/test/integration/repository-company-graph.test.mjs +90 -0
  120. package/test/integration/runtime-migrations.test.mjs +82 -0
  121. package/test/knowledge-service.test.mjs +5 -0
  122. package/test/knowledge.test.mjs +16 -0
  123. package/test/live/terminal-transport.live.test.mjs +24 -0
  124. package/test/local-sessions.test.mjs +7 -1
  125. package/test/models.test.mjs +101 -4
  126. package/test/ollama.test.mjs +21 -0
  127. package/test/portable-context.test.mjs +1 -1
  128. package/test/provider-credentials.test.mjs +45 -1
  129. package/test/release-hygiene.test.mjs +13 -5
  130. package/test/responses-runner.test.mjs +3 -1
  131. package/test/sdk-worker-contract.test.mjs +5 -1
  132. package/test/shell.test.mjs +50 -8
  133. package/test/smoke.mjs +2 -1
  134. package/test/terminal/local-pty.mock.test.mjs +151 -0
  135. package/test/whoami-resume.test.mjs +6 -5
  136. package/src/lib/prompt-byok.js +0 -57
  137. package/src/lib/save-sdk-token.js +0 -19
  138. /package/{src/lib → packages/agentsam-repository/src}/git-context.js +0 -0
  139. /package/{src/lib → packages/agentsam-repository/src}/merkle/diff.js +0 -0
  140. /package/{src/lib → packages/agentsam-repository/src}/merkle/filemeta.js +0 -0
  141. /package/{src/lib → packages/agentsam-repository/src}/merkle/git-ignore.js +0 -0
  142. /package/{src/lib → packages/agentsam-repository/src}/merkle/hash.js +0 -0
  143. /package/{src/lib → packages/agentsam-repository/src}/merkle/semantic.js +0 -0
  144. /package/{src/lib → packages/agentsam-repository/src}/merkle/snapshot.js +0 -0
  145. /package/{src/lib → packages/agentsam-repository/src}/merkle/tree.js +0 -0
package/test/smoke.mjs CHANGED
@@ -56,6 +56,7 @@ assert.ok(SLASH_COMMANDS.some((c) => c.cmd === '/deploy'));
56
56
  assert.ok(SLASH_COMMANDS.some((c) => c.cmd === '/db'));
57
57
  assert.ok(SLASH_COMMANDS.some((c) => c.cmd === '/agent'));
58
58
  assert.ok(SLASH_COMMANDS.some((c) => c.cmd === '/model'));
59
+ assert.ok(SLASH_COMMANDS.some((c) => c.cmd === '/providers'));
59
60
  assert.ok(SLASH_COMMANDS.some((c) => c.cmd === '/reasoning'));
60
61
  assert.ok(SLASH_COMMANDS.some((c) => c.cmd === '/fast'));
61
62
  assert.deepEqual(
@@ -65,7 +66,7 @@ assert.deepEqual(
65
66
  );
66
67
 
67
68
  printContextSummary({
68
- iam: { ready: true, source: 'sdk-key', detail: 'AGENTSAM_SDK_KEY' },
69
+ iam: { ready: true, source: 'api_key', detail: 'AGENTSAM_API_KEY' },
69
70
  gcp: { source: 'vm-metadata', email: 'execos@project.iam.gserviceaccount.com' },
70
71
  gcp_vm: true,
71
72
  github: { source: 'gh-cli', account: 'user@example.com' },
@@ -0,0 +1,151 @@
1
+ import assert from 'node:assert/strict';
2
+ import { EventEmitter } from 'node:events';
3
+ import fs from 'node:fs';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import test from 'node:test';
7
+ import { pathToFileURL } from 'node:url';
8
+ import {
9
+ attachLocalPtySession,
10
+ ensureNodePtySpawnHelperExecutable,
11
+ startLocalPtyServer,
12
+ } from '../../src/local-pty/server.js';
13
+
14
+ function fakeTransports() {
15
+ const writes = [];
16
+ const resizes = [];
17
+ let killed = 0;
18
+ let dataHandler = null;
19
+ let exitHandler = null;
20
+
21
+ const pty = {
22
+ spawn(shell, args, options) {
23
+ assert.equal(Array.isArray(args), true);
24
+ assert.equal(options.env.AGENTSAM_LOCAL_PTY, '1');
25
+ return {
26
+ write(value) { writes.push(value); },
27
+ resize(cols, rows) { resizes.push([cols, rows]); },
28
+ kill() { killed += 1; },
29
+ onData(fn) { dataHandler = fn; },
30
+ onExit(fn) { exitHandler = fn; },
31
+ };
32
+ },
33
+ };
34
+
35
+ class FakeWs extends EventEmitter {
36
+ OPEN = 1;
37
+ readyState = 1;
38
+ sent = [];
39
+ send(value) { this.sent.push(String(value)); }
40
+ close() {
41
+ if (this.readyState !== this.OPEN) return;
42
+ this.readyState = 3;
43
+ this.emit('close');
44
+ }
45
+ }
46
+
47
+ const ws = new FakeWs();
48
+ return {
49
+ pty,
50
+ ws,
51
+ writes,
52
+ resizes,
53
+ killed: () => killed,
54
+ emitData(value) { dataHandler?.(value); },
55
+ emitExit() { exitHandler?.(); },
56
+ };
57
+ }
58
+
59
+ test('macOS node-pty helper is made executable before runtime import', (t) => {
60
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-node-pty-helper-'));
61
+ t.after(() => fs.rmSync(root, { recursive: true, force: true }));
62
+ const libDir = path.join(root, 'lib');
63
+ const helperDir = path.join(root, 'prebuilds', 'darwin-arm64');
64
+ fs.mkdirSync(libDir, { recursive: true });
65
+ fs.mkdirSync(helperDir, { recursive: true });
66
+ fs.writeFileSync(path.join(libDir, 'index.js'), '');
67
+ const helper = path.join(helperDir, 'spawn-helper');
68
+ fs.writeFileSync(helper, 'fake');
69
+ fs.chmodSync(helper, 0o644);
70
+
71
+ const result = ensureNodePtySpawnHelperExecutable({
72
+ platform: 'darwin',
73
+ arch: 'arm64',
74
+ resolveModule: () => pathToFileURL(path.join(libDir, 'index.js')).href,
75
+ });
76
+
77
+ assert.equal(result.checked, true);
78
+ assert.equal(result.changed, true);
79
+ assert.equal(result.path, helper);
80
+ assert.notEqual(fs.statSync(helper).mode & 0o111, 0);
81
+
82
+ const second = ensureNodePtySpawnHelperExecutable({
83
+ platform: 'darwin',
84
+ arch: 'arm64',
85
+ resolveModule: () => pathToFileURL(path.join(libDir, 'index.js')).href,
86
+ });
87
+ assert.equal(second.changed, false);
88
+ });
89
+
90
+ test('local PTY wire protocol is release-testable entirely in memory', () => {
91
+ const transport = fakeTransports();
92
+ const session = attachLocalPtySession({
93
+ ws: transport.ws,
94
+ pty: transport.pty,
95
+ shell: '/bin/test-shell',
96
+ cwd: '/tmp/test-project',
97
+ cols: 80,
98
+ rows: 24,
99
+ env: {},
100
+ sessionId: 'local_test',
101
+ });
102
+
103
+ assert.equal(session.session_id, 'local_test');
104
+ assert.deepEqual(JSON.parse(transport.ws.sent[0]), {
105
+ type: 'session_id',
106
+ session_id: 'local_test',
107
+ });
108
+
109
+ transport.ws.emit('message', Buffer.from(JSON.stringify({ type: 'resize', cols: 120, rows: 40 })));
110
+ transport.ws.emit('message', Buffer.from(JSON.stringify({ type: 'slash', line: '/pwd' })));
111
+ transport.ws.emit('message', Buffer.from('raw input'));
112
+
113
+ assert.deepEqual(transport.resizes, [[120, 40]]);
114
+ assert.deepEqual(transport.writes, ['/pwd\r', 'raw input']);
115
+
116
+ transport.emitData('terminal output');
117
+ assert.equal(transport.ws.sent.at(-1), 'terminal output');
118
+
119
+ transport.ws.close();
120
+ assert.equal(transport.killed(), 1);
121
+
122
+ // Cleanup is idempotent even when transport error/close paths race.
123
+ transport.ws.emit('error', new Error('synthetic transport close'));
124
+ session.cleanup();
125
+ assert.equal(transport.killed(), 1);
126
+ });
127
+
128
+ test('local PTY server health check uses an ephemeral local port and no ExecOS tunnel', async () => {
129
+ const transport = fakeTransports();
130
+ const server = await startLocalPtyServer({
131
+ cwd: process.cwd(),
132
+ host: '127.0.0.1',
133
+ port: 0,
134
+ pty: transport.pty,
135
+ });
136
+
137
+ try {
138
+ const health = await fetch(server.healthUrl);
139
+ assert.equal(health.status, 200);
140
+ const body = await health.json();
141
+ assert.equal(body.ok, true);
142
+ assert.equal(body.service, 'agentsam-local-pty');
143
+ assert.equal(body.port, server.port);
144
+ assert.equal(server.port > 0, true);
145
+ } finally {
146
+ await server.close();
147
+ }
148
+
149
+ // No WebSocket session was opened, so the PTY process was never spawned.
150
+ assert.equal(transport.killed(), 0);
151
+ });
@@ -14,9 +14,9 @@ function tempHome(t) {
14
14
  return home;
15
15
  }
16
16
 
17
- test('whoami validates persisted IAM identity while never returning the SDK or provider secret', async t => {
17
+ test('whoami validates persisted IAM browser identity while never returning account or provider secrets', async t => {
18
18
  const home = tempHome(t);
19
- saveAccountSession({ access_token: 'sdk_do_not_print', user_id: 'au_local' }, { home });
19
+ saveAccountSession({ access_token: 'browser_session_do_not_print', user_id: 'au_local' }, { home });
20
20
  const envDir = path.join(home, '.agentsam', 'env.d');
21
21
  fs.mkdirSync(envDir, { recursive: true });
22
22
  const openaiFile = path.join(envDir, 'openai.env');
@@ -26,16 +26,17 @@ test('whoami validates persisted IAM identity while never returning the SDK or p
26
26
  const status = await collectWhoami({
27
27
  env: {}, home,
28
28
  contextLoader: async token => {
29
- assert.equal(token, 'sdk_do_not_print');
29
+ assert.equal(token, 'browser_session_do_not_print');
30
30
  return { user_id: 'au_server', account_id: 'acct_server', email: 'dev@example.test', cloudflare: { ok: true }, byok: { openai: { configured: true, masked: 'secret' } } };
31
31
  },
32
32
  });
33
33
  assert.equal(status.authenticated, true);
34
34
  assert.equal(status.identity.account_id, 'acct_server');
35
- assert.equal(status.sdk_credential.source, 'agentsam_account_session');
35
+ assert.equal(status.active_auth.source, 'agentsam_browser_oauth');
36
+ assert.equal(status.active_auth.kind, 'browser_oauth');
36
37
  assert.equal(status.provider_credentials.find(row => row.provider === 'openai').configured, true);
37
38
  const serialized = JSON.stringify(status);
38
- assert.doesNotMatch(serialized, /sdk_do_not_print|sk-never-print-this|masked/);
39
+ assert.doesNotMatch(serialized, /browser_session_do_not_print|sk-never-print-this|masked/);
39
40
  });
40
41
 
41
42
  test('resume restores saved cwd and session through the canonical shell runtime', async t => {
@@ -1,57 +0,0 @@
1
- /**
2
- * Optional BYOK key paste during SDK init → CORE user_api_keys.
3
- */
4
- import { getJson, postJson } from './core-client.js';
5
-
6
- const PROVIDERS = [
7
- { id: 'openai', label: 'OpenAI' },
8
- { id: 'anthropic', label: 'Anthropic' },
9
- ];
10
-
11
- /**
12
- * @param {string} token SDK bearer
13
- * @param {{ ask: (q: string) => Promise<string> } | null} prompt
14
- */
15
- export async function promptOptionalByokKeys(token, prompt) {
16
- if (!token || !prompt) return;
17
-
18
- let ctx;
19
- try {
20
- ctx = await getJson('/api/sdk/context', token);
21
- } catch {
22
- console.log('\n ⚠ Could not load BYOK status — skip key paste or add keys in Dashboard → Settings → Keys\n');
23
- return;
24
- }
25
-
26
- const byok = ctx?.byok || {};
27
- console.log('\n Provider keys (BYOK — optional, stored in YOUR IAM account):\n');
28
-
29
- for (const p of PROVIDERS) {
30
- const slot = byok[p.id];
31
- if (slot?.configured) {
32
- console.log(` ${p.label.padEnd(12)} ✓ connected ${slot.masked || ''}`);
33
- continue;
34
- }
35
-
36
- const ans = await prompt.ask(` ${p.label} API key (Enter to skip): `);
37
- const key = ans.trim();
38
- if (!key) continue;
39
-
40
- try {
41
- await postJson(
42
- '/api/sdk/keys',
43
- {
44
- provider: p.id,
45
- api_key: key,
46
- label: `${p.label} (SDK init)`,
47
- validate: true,
48
- },
49
- token,
50
- );
51
- console.log(` ${p.label.padEnd(12)} ✓ saved to IAM BYOK`);
52
- } catch (e) {
53
- console.log(` ${p.label.padEnd(12)} ✗ ${e?.message || 'save failed'}`);
54
- }
55
- }
56
- console.log('');
57
- }
@@ -1,19 +0,0 @@
1
- /**
2
- * Persist SDK session token locally for repeat inits (user's machine only).
3
- */
4
- import fs from 'fs';
5
- import path from 'path';
6
-
7
- export function saveSdkTokenHint(cwd, token) {
8
- const t = String(token || '').trim();
9
- if (!t || !t.startsWith('sdk_')) return null;
10
- const dir = path.join(path.resolve(cwd), '.agentsam');
11
- fs.mkdirSync(dir, { recursive: true });
12
- const hintPath = path.join(dir, 'credentials.env.example');
13
- const content = `# Agent Sam SDK — add to your shell profile (optional)
14
- export AGENTSAM_SDK_KEY=${t}
15
- export USER_GCP_PROJECT=YOUR_GCP_PROJECT_ID
16
- `;
17
- fs.writeFileSync(hintPath, content, 'utf8');
18
- return hintPath;
19
- }