@slashfi/agents-sdk 0.69.12 → 0.70.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/adk-check.ts CHANGED
@@ -13,10 +13,16 @@
13
13
  * adk run --no-check -e "code" Execute inline without type-checking
14
14
  */
15
15
 
16
- import { join, dirname, basename, resolve } from "node:path";
17
- import { homedir } from "node:os";
18
- import { existsSync, writeFileSync, readFileSync, unlinkSync, copyFileSync } from "node:fs";
19
16
  import { spawnSync } from "node:child_process";
17
+ import {
18
+ copyFileSync,
19
+ existsSync,
20
+ readFileSync,
21
+ unlinkSync,
22
+ writeFileSync,
23
+ } from "node:fs";
24
+ import { homedir } from "node:os";
25
+ import { basename, dirname, join, resolve } from "node:path";
20
26
 
21
27
  export interface CheckOptions {
22
28
  file?: string;
@@ -26,62 +32,94 @@ export interface CheckOptions {
26
32
  configDir?: string;
27
33
  }
28
34
 
29
- const INLINE_PREAMBLE_CHECK = (
30
- `import "./.adk_types";\n` +
31
- `import { createAdk, createLocalFsStore } from "@slashfi/agents-sdk";\n` +
32
- `import { join } from "node:path";\n` +
33
- `import { homedir } from "node:os";\n` +
34
- `const adk = createAdk(\n` +
35
- ` createLocalFsStore(process.env.ADK_CONFIG_DIR ?? join(homedir(), ".adk")),\n` +
36
- ` { token: process.env.ATLAS_TOKEN ?? process.env.ADK_TOKEN ?? "" },\n` +
37
- `);\n`
38
- );
39
-
40
- const INLINE_PREAMBLE_RUN = (
41
- `import { createAdk, createLocalFsStore } from "@slashfi/agents-sdk";\n` +
42
- `import { join } from "node:path";\n` +
43
- `import { homedir } from "node:os";\n` +
44
- `const adk = createAdk(\n` +
45
- ` createLocalFsStore(process.env.ADK_CONFIG_DIR ?? join(homedir(), ".adk")),\n` +
46
- ` { token: process.env.ATLAS_TOKEN ?? process.env.ADK_TOKEN ?? "" },\n` +
47
- `);\n`
48
- );
49
-
50
- export async function adkCheck(opts: CheckOptions): Promise<{ ok: boolean; exitCode: number }> {
51
- const configDir = opts.configDir ?? process.env.ADK_CONFIG_DIR ?? join(homedir(), ".adk");
35
+ /**
36
+ * Resolve the absolute path to the @slashfi/agents-sdk package.
37
+ * This ensures the preamble works regardless of the script's working directory,
38
+ * since bare specifiers like "@slashfi/agents-sdk" may not resolve from arbitrary cwds.
39
+ */
40
+ function resolveAgentsSdkPath(): string {
41
+ try {
42
+ // require.resolve gives us the main entry point, e.g.
43
+ // /root/.bun/install/global/node_modules/@slashfi/agents-sdk/dist/index.js
44
+ const resolved = require.resolve("@slashfi/agents-sdk");
45
+ // Extract package root path
46
+ const marker = "@slashfi/agents-sdk";
47
+ const idx = resolved.indexOf(marker);
48
+ if (idx !== -1) {
49
+ return resolved.substring(0, idx + marker.length);
50
+ }
51
+ return "@slashfi/agents-sdk";
52
+ } catch {
53
+ return "@slashfi/agents-sdk";
54
+ }
55
+ }
56
+
57
+ function makePreambleCheck(sdkPath: string): string {
58
+ return `import "./.adk_types";\nimport { createAdk, createLocalFsStore } from "${sdkPath}";\nimport { join } from "node:path";\nimport { homedir } from "node:os";\nconst adk = createAdk(\n createLocalFsStore(process.env.ADK_CONFIG_DIR ?? join(homedir(), ".adk")),\n { token: process.env.ATLAS_TOKEN ?? process.env.ADK_TOKEN ?? "" },\n);\n`;
59
+ }
60
+
61
+ function makePreambleRun(sdkPath: string): string {
62
+ return `import { createAdk, createLocalFsStore } from "${sdkPath}";\nimport { join } from "node:path";\nimport { homedir } from "node:os";\nconst adk = createAdk(\n createLocalFsStore(process.env.ADK_CONFIG_DIR ?? join(homedir(), ".adk")),\n { token: process.env.ATLAS_TOKEN ?? process.env.ADK_TOKEN ?? "" },\n);\n`;
63
+ }
64
+
65
+ /**
66
+ * Create a run wrapper file that injects the adk preamble before the user's code.
67
+ * Works for both inline (-e) and file mode.
68
+ */
69
+ function writeRunWrapper(
70
+ tmpFile: string,
71
+ preamble: string,
72
+ userCode: string,
73
+ ): void {
74
+ writeFileSync(tmpFile, preamble + userCode);
75
+ }
76
+
77
+ export async function adkCheck(
78
+ opts: CheckOptions,
79
+ ): Promise<{ ok: boolean; exitCode: number }> {
80
+ const configDir =
81
+ opts.configDir ?? process.env.ADK_CONFIG_DIR ?? join(homedir(), ".adk");
52
82
  const adkTypes = join(configDir, "adk.d.ts");
53
83
  const hasTypes = existsSync(adkTypes);
54
84
  const isInline = !!opts.code;
85
+ const sdkPath = resolveAgentsSdkPath();
86
+ const PREAMBLE_RUN = makePreambleRun(sdkPath);
55
87
 
56
88
  // --no-check: skip typecheck, just run
57
89
  if (opts.noCheck && opts.run) {
58
- if (isInline) {
59
- const tmpFile = join(process.cwd(), ".adk_run.ts");
60
- writeFileSync(tmpFile, INLINE_PREAMBLE_RUN + opts.code);
61
- const r = spawnSync("bun", ["run", tmpFile], { cwd: process.cwd(), stdio: "inherit", env: process.env });
62
- try { unlinkSync(tmpFile); } catch {}
63
- return { ok: r.status === 0, exitCode: r.status ?? 1 };
64
- } else {
65
- const r = spawnSync("bun", ["run", resolve(opts.file!)], {
66
- cwd: dirname(resolve(opts.file!)), stdio: "inherit", env: process.env,
67
- });
68
- return { ok: r.status === 0, exitCode: r.status ?? 1 };
69
- }
90
+ const cwd = isInline ? process.cwd() : dirname(resolve(opts.file!));
91
+ const userCode = isInline
92
+ ? opts.code!
93
+ : readFileSync(resolve(opts.file!), "utf-8");
94
+ const tmpFile = join(cwd, ".adk_run.ts");
95
+ writeRunWrapper(tmpFile, PREAMBLE_RUN, userCode);
96
+ const r = spawnSync("bun", ["run", tmpFile], {
97
+ cwd,
98
+ stdio: "inherit",
99
+ env: process.env,
100
+ });
101
+ try {
102
+ unlinkSync(tmpFile);
103
+ } catch {}
104
+ return { ok: r.status === 0, exitCode: r.status ?? 1 };
70
105
  }
71
106
 
72
107
  if (!hasTypes) {
73
- console.error("\x1b[33m\u26a0\x1b[0m No adk.d.ts found. Run `adk sync` first to generate agent types.");
108
+ console.error(
109
+ "\x1b[33m\u26a0\x1b[0m No adk.d.ts found. Run `adk sync` first to generate agent types.",
110
+ );
74
111
  }
75
112
 
76
113
  let cwd: string;
77
114
  let checkFile: string;
78
115
  let originalFile: string | undefined;
79
116
  const cleanup: string[] = [];
117
+ const PREAMBLE_CHECK = makePreambleCheck("@slashfi/agents-sdk");
80
118
 
81
119
  if (isInline) {
82
120
  cwd = process.cwd();
83
121
  checkFile = join(cwd, ".adk_check.ts");
84
- writeFileSync(checkFile, INLINE_PREAMBLE_CHECK + opts.code);
122
+ writeFileSync(checkFile, PREAMBLE_CHECK + opts.code);
85
123
  cleanup.push(checkFile);
86
124
  } else if (opts.file) {
87
125
  originalFile = resolve(opts.file);
@@ -91,8 +129,16 @@ export async function adkCheck(opts: CheckOptions): Promise<{ ok: boolean; exitC
91
129
  }
92
130
  cwd = dirname(originalFile);
93
131
  checkFile = join(cwd, `.adk_check_${basename(originalFile)}`);
132
+ // File mode: inject preamble so `adk` is typed and available
94
133
  const typesImport = hasTypes ? `import "./.adk_types";\n` : "";
95
- writeFileSync(checkFile, typesImport + readFileSync(originalFile, "utf-8"));
134
+ const preambleNoTypes = PREAMBLE_CHECK.replace(
135
+ `import "./.adk_types";\n`,
136
+ "",
137
+ );
138
+ writeFileSync(
139
+ checkFile,
140
+ typesImport + preambleNoTypes + readFileSync(originalFile, "utf-8"),
141
+ );
96
142
  cleanup.push(checkFile);
97
143
  } else {
98
144
  console.error('Usage: adk check <file> | adk check -e "<code>"');
@@ -108,31 +154,74 @@ export async function adkCheck(opts: CheckOptions): Promise<{ ok: boolean; exitC
108
154
 
109
155
  // Write minimal tsconfig
110
156
  const tsconfigFile = join(cwd, ".adk_tsconfig.json");
111
- writeFileSync(tsconfigFile, JSON.stringify({
112
- compilerOptions: {
113
- target: "ES2022",
114
- module: "ESNext",
115
- moduleResolution: "bundler",
116
- esModuleInterop: true,
117
- strict: true,
118
- noEmit: true,
119
- skipLibCheck: true,
120
- types: ["node"],
121
- },
122
- include: [basename(checkFile)],
123
- }));
157
+ writeFileSync(
158
+ tsconfigFile,
159
+ JSON.stringify({
160
+ compilerOptions: {
161
+ target: "ES2022",
162
+ module: "ESNext",
163
+ moduleResolution: "bundler",
164
+ esModuleInterop: true,
165
+ strict: true,
166
+ noEmit: true,
167
+ skipLibCheck: true,
168
+ types: ["node"],
169
+ },
170
+ include: [basename(checkFile)],
171
+ }),
172
+ );
124
173
  cleanup.push(tsconfigFile);
125
174
 
126
175
  // Find type checker
127
176
  const checker = findTypeChecker();
128
177
 
178
+ if (!checker) {
179
+ console.error(
180
+ "\x1b[33m\u26a0\x1b[0m No TypeScript type checker found (tsgo or tsc). Skipping type check.",
181
+ );
182
+ for (const f of cleanup) {
183
+ try {
184
+ unlinkSync(f);
185
+ } catch {}
186
+ }
187
+
188
+ // Still run if requested
189
+ if (opts.run) {
190
+ const userCode = isInline
191
+ ? opts.code!
192
+ : readFileSync(originalFile!, "utf-8");
193
+ const tmpFile = join(cwd, ".adk_run.ts");
194
+ writeRunWrapper(tmpFile, PREAMBLE_RUN, userCode);
195
+ const r = spawnSync("bun", ["run", tmpFile], {
196
+ cwd,
197
+ stdio: "inherit",
198
+ env: process.env,
199
+ });
200
+ try {
201
+ unlinkSync(tmpFile);
202
+ } catch {}
203
+ return { ok: r.status === 0, exitCode: r.status ?? 1 };
204
+ }
205
+ return { ok: true, exitCode: 0 };
206
+ }
207
+
129
208
  // Type-check
130
- const result = spawnSync(checker.cmd, [...checker.args, "--project", tsconfigFile], {
131
- cwd, stdio: "inherit", env: process.env,
132
- });
209
+ const result = spawnSync(
210
+ checker.cmd,
211
+ [...checker.args, "--project", tsconfigFile],
212
+ {
213
+ cwd,
214
+ stdio: "inherit",
215
+ env: process.env,
216
+ },
217
+ );
133
218
 
134
219
  // Clean up
135
- for (const f of cleanup) { try { unlinkSync(f); } catch {} }
220
+ for (const f of cleanup) {
221
+ try {
222
+ unlinkSync(f);
223
+ } catch {}
224
+ }
136
225
 
137
226
  if (result.status !== 0) {
138
227
  return { ok: false, exitCode: result.status ?? 1 };
@@ -142,25 +231,73 @@ export async function adkCheck(opts: CheckOptions): Promise<{ ok: boolean; exitC
142
231
 
143
232
  // Run
144
233
  if (opts.run) {
145
- let runResult;
146
- if (isInline) {
147
- const tmpFile = join(cwd, ".adk_run.ts");
148
- writeFileSync(tmpFile, INLINE_PREAMBLE_RUN + opts.code);
149
- runResult = spawnSync("bun", ["run", tmpFile], { cwd, stdio: "inherit", env: process.env });
150
- try { unlinkSync(tmpFile); } catch {}
151
- } else {
152
- runResult = spawnSync("bun", ["run", originalFile!], { cwd, stdio: "inherit", env: process.env });
153
- }
234
+ const userCode = isInline
235
+ ? opts.code!
236
+ : readFileSync(originalFile!, "utf-8");
237
+ const tmpFile = join(cwd, ".adk_run.ts");
238
+ writeRunWrapper(tmpFile, PREAMBLE_RUN, userCode);
239
+ const runResult = spawnSync("bun", ["run", tmpFile], {
240
+ cwd,
241
+ stdio: "inherit",
242
+ env: process.env,
243
+ });
244
+ try {
245
+ unlinkSync(tmpFile);
246
+ } catch {}
154
247
  return { ok: runResult.status === 0, exitCode: runResult.status ?? 1 };
155
248
  }
156
249
 
157
250
  return { ok: true, exitCode: 0 };
158
251
  }
159
252
 
160
- function findTypeChecker(): { cmd: string; args: string[] } {
253
+ /**
254
+ * Find a working TypeScript type checker.
255
+ * Returns null if none found — callers should skip type checking gracefully.
256
+ *
257
+ * Checks:
258
+ * 1. tsgo binary (fastest — native TypeScript compiler)
259
+ * 2. npx tsgo (if installed as a package)
260
+ * 3. tsc binary (standard TypeScript compiler, verified via --version)
261
+ * 4. npx tsc — but ONLY if it's the real TypeScript compiler, not the
262
+ * unrelated `tsc` npm package that prints "This is not the tsc command
263
+ * you are looking for"
264
+ */
265
+ function findTypeChecker(): { cmd: string; args: string[] } | null {
266
+ // 1. tsgo binary
161
267
  const tsgo = spawnSync("which", ["tsgo"], { stdio: "pipe" });
162
268
  if (tsgo.status === 0) return { cmd: "tsgo", args: [] };
163
- const npxTsgo = spawnSync("npx", ["tsgo", "--version"], { stdio: "pipe", timeout: 5000 });
269
+
270
+ // 2. npx tsgo
271
+ const npxTsgo = spawnSync("npx", ["tsgo", "--version"], {
272
+ stdio: "pipe",
273
+ timeout: 5000,
274
+ });
164
275
  if (npxTsgo.status === 0) return { cmd: "npx", args: ["tsgo"] };
165
- return { cmd: "npx", args: ["tsc"] };
276
+
277
+ // 3. tsc binary (e.g. from `npm install -g typescript`)
278
+ const tscWhich = spawnSync("which", ["tsc"], { stdio: "pipe" });
279
+ if (tscWhich.status === 0) {
280
+ // Verify it's the real TypeScript compiler, not the bogus `tsc` npm package
281
+ const tscVersion = spawnSync("tsc", ["--version"], {
282
+ stdio: "pipe",
283
+ timeout: 5000,
284
+ });
285
+ const output = tscVersion.stdout?.toString() ?? "";
286
+ if (tscVersion.status === 0 && output.includes("Version")) {
287
+ return { cmd: "tsc", args: [] };
288
+ }
289
+ }
290
+
291
+ // 4. npx tsc — validate it's actually TypeScript
292
+ const npxTsc = spawnSync("npx", ["--no-install", "tsc", "--version"], {
293
+ stdio: "pipe",
294
+ timeout: 10000,
295
+ });
296
+ const npxOutput = npxTsc.stdout?.toString() ?? "";
297
+ if (npxTsc.status === 0 && npxOutput.includes("Version")) {
298
+ return { cmd: "npx", args: ["tsc"] };
299
+ }
300
+
301
+ // No type checker found
302
+ return null;
166
303
  }
@@ -128,9 +128,21 @@ async function resolveTemplates<T>(
128
128
  // Registry Auth Headers
129
129
  // ============================================
130
130
 
131
+ /**
132
+ * Expand `$VAR` and `${VAR}` references in a string using process.env.
133
+ * Unresolved variables are left as-is (no silent empty-string replacement).
134
+ */
135
+ function expandEnvVars(value: string): string {
136
+ return value.replace(/\$\{([^}]+)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g, (match, braced, bare) => {
137
+ const varName = braced ?? bare;
138
+ return process.env[varName] ?? match;
139
+ });
140
+ }
141
+
131
142
  /**
132
143
  * Build auth headers for a registry based on its auth config and custom headers.
133
144
  * Merges typed auth (bearer, api-key) with arbitrary custom headers.
145
+ * Environment variable references ($VAR or ${VAR}) in header values are expanded.
134
146
  */
135
147
  function buildRegistryAuthHeaders(
136
148
  registry: ResolvedRegistry,
@@ -171,8 +183,11 @@ function buildRegistryAuthHeaders(
171
183
  }
172
184
 
173
185
  // Merge custom headers (these override auth-generated headers)
186
+ // Expand $VAR / ${VAR} env references in header values
174
187
  if (registry.headers) {
175
- Object.assign(headers, registry.headers);
188
+ for (const [key, value] of Object.entries(registry.headers)) {
189
+ headers[key] = expandEnvVars(value);
190
+ }
176
191
  }
177
192
 
178
193
  return headers;