@jini-ai/platform 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 (66) hide show
  1. package/LICENSE +201 -0
  2. package/dist/asset-cache.d.ts +80 -0
  3. package/dist/asset-cache.d.ts.map +1 -0
  4. package/dist/asset-cache.js +423 -0
  5. package/dist/asset-cache.js.map +1 -0
  6. package/dist/aws-sigv4.d.ts +51 -0
  7. package/dist/aws-sigv4.d.ts.map +1 -0
  8. package/dist/aws-sigv4.js +104 -0
  9. package/dist/aws-sigv4.js.map +1 -0
  10. package/dist/blob-storage.d.ts +89 -0
  11. package/dist/blob-storage.d.ts.map +1 -0
  12. package/dist/blob-storage.js +315 -0
  13. package/dist/blob-storage.js.map +1 -0
  14. package/dist/command.d.ts +32 -0
  15. package/dist/command.d.ts.map +1 -0
  16. package/dist/command.js +101 -0
  17. package/dist/command.js.map +1 -0
  18. package/dist/download.d.ts +92 -0
  19. package/dist/download.d.ts.map +1 -0
  20. package/dist/download.js +856 -0
  21. package/dist/download.js.map +1 -0
  22. package/dist/fs.d.ts +55 -0
  23. package/dist/fs.d.ts.map +1 -0
  24. package/dist/fs.js +124 -0
  25. package/dist/fs.js.map +1 -0
  26. package/dist/home-expansion.d.ts +18 -0
  27. package/dist/home-expansion.d.ts.map +1 -0
  28. package/dist/home-expansion.js +58 -0
  29. package/dist/home-expansion.js.map +1 -0
  30. package/dist/http.d.ts +14 -0
  31. package/dist/http.d.ts.map +1 -0
  32. package/dist/http.js +39 -0
  33. package/dist/http.js.map +1 -0
  34. package/dist/index.d.ts +59 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +45 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/process.d.ts +159 -0
  39. package/dist/process.d.ts.map +1 -0
  40. package/dist/process.js +362 -0
  41. package/dist/process.js.map +1 -0
  42. package/dist/proxy-env.d.ts +50 -0
  43. package/dist/proxy-env.d.ts.map +1 -0
  44. package/dist/proxy-env.js +373 -0
  45. package/dist/proxy-env.js.map +1 -0
  46. package/dist/resource-paths.d.ts +68 -0
  47. package/dist/resource-paths.d.ts.map +1 -0
  48. package/dist/resource-paths.js +137 -0
  49. package/dist/resource-paths.js.map +1 -0
  50. package/dist/sandbox-env.d.ts +86 -0
  51. package/dist/sandbox-env.d.ts.map +1 -0
  52. package/dist/sandbox-env.js +215 -0
  53. package/dist/sandbox-env.js.map +1 -0
  54. package/dist/shell.d.ts +46 -0
  55. package/dist/shell.d.ts.map +1 -0
  56. package/dist/shell.js +78 -0
  57. package/dist/shell.js.map +1 -0
  58. package/dist/terminal.d.ts +137 -0
  59. package/dist/terminal.d.ts.map +1 -0
  60. package/dist/terminal.js +398 -0
  61. package/dist/terminal.js.map +1 -0
  62. package/dist/toolchain.d.ts +17 -0
  63. package/dist/toolchain.d.ts.map +1 -0
  64. package/dist/toolchain.js +251 -0
  65. package/dist/toolchain.js.map +1 -0
  66. package/package.json +47 -0
@@ -0,0 +1,89 @@
1
+ import { type SigV4Credentials } from './aws-sigv4.js';
2
+ /** Metadata for a single stored blob. */
3
+ export interface BlobFileMeta {
4
+ /** Path relative to the namespace root. Always uses forward slashes. */
5
+ path: string;
6
+ /** Total size in bytes. */
7
+ size: number;
8
+ /** Unix epoch milliseconds of last modification. */
9
+ mtimeMs: number;
10
+ }
11
+ /** The narrow contract every blob storage backend implements. */
12
+ export interface BlobStorage {
13
+ /** Reads `<namespace>/<relpath>` into a Buffer. Throws a `StorageError('NOT_FOUND', ...)` when missing. */
14
+ readFile(namespace: string, relpath: string): Promise<Buffer>;
15
+ /** Writes `<namespace>/<relpath>`, creating parent directories/prefixes as needed. */
16
+ writeFile(namespace: string, relpath: string, body: Buffer): Promise<BlobFileMeta>;
17
+ /**
18
+ * Lists every file under `<namespace>/` recursively. The order is implementation-defined;
19
+ * callers that need deterministic order sort by `path`.
20
+ */
21
+ listFiles(namespace: string): Promise<BlobFileMeta[]>;
22
+ /** Deletes a single file under `<namespace>/`. Idempotent — missing files do not throw. */
23
+ deleteFile(namespace: string, relpath: string): Promise<void>;
24
+ /** Reports metadata for a single file without reading its bytes. Returns `null` when missing. */
25
+ statFile(namespace: string, relpath: string): Promise<BlobFileMeta | null>;
26
+ }
27
+ /** Error thrown by {@link BlobStorage} implementations, distinguishing not-found/traversal/IO failures. */
28
+ export declare class StorageError extends Error {
29
+ readonly code: 'NOT_FOUND' | 'TRAVERSAL' | 'IO';
30
+ constructor(code: 'NOT_FOUND' | 'TRAVERSAL' | 'IO', message: string);
31
+ }
32
+ /**
33
+ * The local-disk default backend — a thin `fs/promises` wrapper rooted at a caller-supplied
34
+ * directory, with a traversal guard so a hostile `namespace`/`relpath` can never escape it.
35
+ */
36
+ export declare class LocalBlobStorage implements BlobStorage {
37
+ private readonly root;
38
+ constructor(root: string);
39
+ readFile(namespace: string, relpath: string): Promise<Buffer>;
40
+ writeFile(namespace: string, relpath: string, body: Buffer): Promise<BlobFileMeta>;
41
+ listFiles(namespace: string): Promise<BlobFileMeta[]>;
42
+ deleteFile(namespace: string, relpath: string): Promise<void>;
43
+ statFile(namespace: string, relpath: string): Promise<BlobFileMeta | null>;
44
+ private resolvePath;
45
+ }
46
+ /**
47
+ * An S3-compatible blob backend. Signs requests inline with AWS SigV4 (see `./aws-sigv4.js`)
48
+ * using only `node:crypto` — no `@aws-sdk/*` dependency — targeting AWS S3 and any
49
+ * S3-compatible endpoint (MinIO, Aliyun OSS, Tencent COS, Huawei OBS, ...).
50
+ *
51
+ * Five operations:
52
+ * readFile → GET /<key>
53
+ * writeFile → PUT /<key> (with x-amz-content-sha256)
54
+ * deleteFile → DELETE /<key>
55
+ * statFile → HEAD /<key>
56
+ * listFiles → GET /?list-type=2&prefix=<namespace>/...
57
+ *
58
+ * Network is pluggable: pass `fetchFn` in the constructor (tests inject a stub; production
59
+ * defaults to `globalThis.fetch`).
60
+ */
61
+ export interface S3BlobStorageOptions {
62
+ bucket: string;
63
+ region: string;
64
+ /** Optional path prefix inside the bucket. Lets multiple deployments share one bucket. */
65
+ prefix?: string;
66
+ /** S3-compatible endpoint URL (MinIO, Aliyun OSS, Tencent COS, Huawei OBS). Omit for AWS S3. */
67
+ endpoint?: string;
68
+ /** AWS access credentials. Callers typically resolve these from their own env/secret-manager convention. */
69
+ credentials: SigV4Credentials;
70
+ /** Pluggable fetch for tests. Defaults to `globalThis.fetch`. */
71
+ fetchFn?: typeof fetch;
72
+ /** Override for clock — tests pin signatures with this. Production leaves it undefined (`signSigV4` falls back to `new Date()`). */
73
+ now?: () => Date;
74
+ }
75
+ export declare class S3BlobStorage implements BlobStorage {
76
+ readonly options: S3BlobStorageOptions;
77
+ private readonly fetchFn;
78
+ constructor(options: S3BlobStorageOptions);
79
+ readFile(namespace: string, relpath: string): Promise<Buffer>;
80
+ writeFile(namespace: string, relpath: string, body: Buffer): Promise<BlobFileMeta>;
81
+ deleteFile(namespace: string, relpath: string): Promise<void>;
82
+ statFile(namespace: string, relpath: string): Promise<BlobFileMeta | null>;
83
+ listFiles(namespace: string): Promise<BlobFileMeta[]>;
84
+ /** Builds the canonical S3 key the impl uses. Exposed for tests so the prefix/namespace/relpath join is stable. */
85
+ keyFor(namespace: string, relpath: string): string;
86
+ private endpointBase;
87
+ private signedRequest;
88
+ }
89
+ //# sourceMappingURL=blob-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-storage.d.ts","sourceRoot":"","sources":["../src/blob-storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,315 @@
1
+ /**
2
+ * @module blob-storage
3
+ *
4
+ * A narrow, backend-agnostic blob storage port — `readFile`/`writeFile`/`listFiles`/
5
+ * `deleteFile`/`statFile` scoped under an opaque `namespace` string — plus two
6
+ * implementations: {@link LocalBlobStorage} (the local-disk default) and
7
+ * {@link S3BlobStorage} (an S3-compatible backend: AWS S3, and any endpoint-compatible
8
+ * store such as MinIO, Aliyun OSS, Tencent COS, or Huawei OBS, signed inline via
9
+ * `./aws-sigv4.js`).
10
+ *
11
+ * `namespace` is deliberately opaque here — a top-level grouping key (a tenant id, a
12
+ * workspace id, a project id, whatever the host application scopes storage by) — this
13
+ * module carries no domain meaning for what a namespace *is*, only that paths are
14
+ * grouped and traversal-guarded underneath one.
15
+ */
16
+ import path from 'node:path';
17
+ import { promises as fsp } from 'node:fs';
18
+ import { encodeS3PathSegment, signSigV4 } from './aws-sigv4.js';
19
+ /** Error thrown by {@link BlobStorage} implementations, distinguishing not-found/traversal/IO failures. */
20
+ export class StorageError extends Error {
21
+ code;
22
+ constructor(code, message) {
23
+ super(message);
24
+ this.code = code;
25
+ this.name = 'StorageError';
26
+ }
27
+ }
28
+ /**
29
+ * The local-disk default backend — a thin `fs/promises` wrapper rooted at a caller-supplied
30
+ * directory, with a traversal guard so a hostile `namespace`/`relpath` can never escape it.
31
+ */
32
+ export class LocalBlobStorage {
33
+ root;
34
+ constructor(root) {
35
+ this.root = root;
36
+ }
37
+ async readFile(namespace, relpath) {
38
+ const abs = this.resolvePath(namespace, relpath);
39
+ try {
40
+ return await fsp.readFile(abs);
41
+ }
42
+ catch (err) {
43
+ const e = err;
44
+ if (e.code === 'ENOENT')
45
+ throw new StorageError('NOT_FOUND', `${namespace}/${relpath} not found`);
46
+ throw new StorageError('IO', `read failed: ${e.message}`);
47
+ }
48
+ }
49
+ async writeFile(namespace, relpath, body) {
50
+ const abs = this.resolvePath(namespace, relpath);
51
+ await fsp.mkdir(path.dirname(abs), { recursive: true });
52
+ await fsp.writeFile(abs, body);
53
+ const stat = await fsp.stat(abs);
54
+ return { path: normalizeRel(relpath), size: stat.size, mtimeMs: stat.mtimeMs };
55
+ }
56
+ async listFiles(namespace) {
57
+ const root = path.join(this.root, namespace);
58
+ const out = [];
59
+ const queue = [root];
60
+ while (queue.length > 0) {
61
+ const dir = queue.pop();
62
+ let entries;
63
+ try {
64
+ entries = await fsp.readdir(dir, { withFileTypes: true });
65
+ }
66
+ catch (err) {
67
+ if (err.code === 'ENOENT')
68
+ return [];
69
+ throw new StorageError('IO', `list failed: ${err.message}`);
70
+ }
71
+ for (const entry of entries) {
72
+ const abs = path.join(dir, entry.name);
73
+ if (entry.isDirectory()) {
74
+ queue.push(abs);
75
+ continue;
76
+ }
77
+ if (!entry.isFile())
78
+ continue;
79
+ const stat = await fsp.stat(abs);
80
+ const rel = path.relative(root, abs).split(path.sep).join('/');
81
+ out.push({ path: rel, size: stat.size, mtimeMs: stat.mtimeMs });
82
+ }
83
+ }
84
+ return out;
85
+ }
86
+ async deleteFile(namespace, relpath) {
87
+ const abs = this.resolvePath(namespace, relpath);
88
+ try {
89
+ await fsp.rm(abs, { force: true });
90
+ }
91
+ catch (err) {
92
+ throw new StorageError('IO', `delete failed: ${err.message}`);
93
+ }
94
+ }
95
+ async statFile(namespace, relpath) {
96
+ const abs = this.resolvePath(namespace, relpath);
97
+ try {
98
+ const stat = await fsp.stat(abs);
99
+ if (!stat.isFile())
100
+ return null;
101
+ return { path: normalizeRel(relpath), size: stat.size, mtimeMs: stat.mtimeMs };
102
+ }
103
+ catch {
104
+ return null;
105
+ }
106
+ }
107
+ resolvePath(namespace, relpath) {
108
+ if (!namespace || namespace.includes('/') || namespace.includes('\\') || namespace.includes('\0') || namespace.includes('..')) {
109
+ throw new StorageError('TRAVERSAL', `invalid namespace ${namespace}`);
110
+ }
111
+ const normalized = normalizeRel(relpath);
112
+ if (!normalized)
113
+ throw new StorageError('TRAVERSAL', 'empty relpath');
114
+ if (normalized.split('/').some((seg) => seg === '..' || seg === '.')) {
115
+ throw new StorageError('TRAVERSAL', `unsafe relpath ${relpath}`);
116
+ }
117
+ return path.join(this.root, namespace, ...normalized.split('/'));
118
+ }
119
+ }
120
+ export class S3BlobStorage {
121
+ options;
122
+ fetchFn;
123
+ constructor(options) {
124
+ this.options = options;
125
+ if (!options.bucket)
126
+ throw new StorageError('IO', 'S3BlobStorage requires a bucket');
127
+ if (!options.region)
128
+ throw new StorageError('IO', 'S3BlobStorage requires a region');
129
+ if (!options.credentials?.accessKeyId)
130
+ throw new StorageError('IO', 'S3BlobStorage requires credentials.accessKeyId');
131
+ if (!options.credentials?.secretAccessKey)
132
+ throw new StorageError('IO', 'S3BlobStorage requires credentials.secretAccessKey');
133
+ const fn = options.fetchFn ?? globalThis.fetch;
134
+ if (!fn)
135
+ throw new StorageError('IO', 'S3BlobStorage requires a fetch implementation');
136
+ this.fetchFn = fn;
137
+ }
138
+ async readFile(namespace, relpath) {
139
+ const key = this.keyFor(namespace, relpath);
140
+ const res = await this.signedRequest({ method: 'GET', key });
141
+ if (res.status === 404)
142
+ throw new StorageError('NOT_FOUND', `${namespace}/${relpath} not found`);
143
+ if (!res.ok)
144
+ throw new StorageError('IO', `S3 GET ${key} → ${res.status} ${res.statusText}: ${await safeText(res)}`);
145
+ return Buffer.from(await res.arrayBuffer());
146
+ }
147
+ async writeFile(namespace, relpath, body) {
148
+ const key = this.keyFor(namespace, relpath);
149
+ const res = await this.signedRequest({ method: 'PUT', key, body });
150
+ if (!res.ok)
151
+ throw new StorageError('IO', `S3 PUT ${key} → ${res.status} ${res.statusText}: ${await safeText(res)}`);
152
+ return { path: normalizeRel(relpath), size: body.byteLength, mtimeMs: Date.now() };
153
+ }
154
+ async deleteFile(namespace, relpath) {
155
+ const key = this.keyFor(namespace, relpath);
156
+ const res = await this.signedRequest({ method: 'DELETE', key });
157
+ // S3 returns 204 on successful delete; idempotent if missing.
158
+ if (!res.ok && res.status !== 404) {
159
+ throw new StorageError('IO', `S3 DELETE ${key} → ${res.status} ${res.statusText}: ${await safeText(res)}`);
160
+ }
161
+ }
162
+ async statFile(namespace, relpath) {
163
+ const key = this.keyFor(namespace, relpath);
164
+ const res = await this.signedRequest({ method: 'HEAD', key });
165
+ if (res.status === 404)
166
+ return null;
167
+ if (!res.ok)
168
+ throw new StorageError('IO', `S3 HEAD ${key} → ${res.status} ${res.statusText}`);
169
+ const contentLength = Number(res.headers.get('content-length') ?? '0');
170
+ const lastModified = res.headers.get('last-modified');
171
+ return {
172
+ path: normalizeRel(relpath),
173
+ size: Number.isFinite(contentLength) ? contentLength : 0,
174
+ mtimeMs: lastModified ? Date.parse(lastModified) : Date.now(),
175
+ };
176
+ }
177
+ async listFiles(namespace) {
178
+ const namespacePrefix = this.keyFor(namespace, '');
179
+ const out = [];
180
+ let continuationToken;
181
+ // Cap iterations so a hostile bucket can't loop forever.
182
+ for (let pages = 0; pages < 1000; pages++) {
183
+ const params = [
184
+ ['list-type', '2'],
185
+ ['prefix', namespacePrefix],
186
+ ];
187
+ if (continuationToken)
188
+ params.push(['continuation-token', continuationToken]);
189
+ params.sort((a, b) => a[0].localeCompare(b[0]));
190
+ const query = params.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&');
191
+ const res = await this.signedRequest({ method: 'GET', key: '', extraQuery: query });
192
+ if (!res.ok) {
193
+ throw new StorageError('IO', `S3 LIST ${namespacePrefix} → ${res.status} ${res.statusText}: ${await safeText(res)}`);
194
+ }
195
+ const xml = await res.text();
196
+ const { entries, isTruncated, nextToken } = parseListBucketV2Xml(xml);
197
+ for (const e of entries) {
198
+ // Strip the per-bucket namespacePrefix to surface namespace-relative paths.
199
+ // `namespacePrefix` is `keyFor(namespace, '')`, which always includes at least the
200
+ // (non-empty, `keyFor`-validated) namespace segment and never a trailing slash — so it's
201
+ // always non-empty and the +1 separator always applies.
202
+ const relStart = namespacePrefix.length + 1;
203
+ const rel = e.key.slice(relStart).replace(/^\/+/, '');
204
+ if (!rel)
205
+ continue; // skip the prefix marker itself
206
+ out.push({ path: rel, size: e.size, mtimeMs: e.lastModifiedMs });
207
+ }
208
+ if (!isTruncated || !nextToken)
209
+ break;
210
+ continuationToken = nextToken;
211
+ }
212
+ return out;
213
+ }
214
+ /** Builds the canonical S3 key the impl uses. Exposed for tests so the prefix/namespace/relpath join is stable. */
215
+ keyFor(namespace, relpath) {
216
+ if (!namespace || namespace.includes('/') || namespace.includes('\\') || namespace.includes('..')) {
217
+ throw new StorageError('TRAVERSAL', `invalid namespace ${namespace}`);
218
+ }
219
+ const normalized = relpath ? normalizeRel(relpath) : '';
220
+ if (normalized.split('/').some((seg) => seg === '..' || seg === '.')) {
221
+ throw new StorageError('TRAVERSAL', `unsafe relpath ${relpath}`);
222
+ }
223
+ const segments = [this.options.prefix?.replace(/^\/+|\/+$/g, ''), namespace, normalized].filter((s) => typeof s === 'string' && s.length > 0);
224
+ return segments.join('/');
225
+ }
226
+ endpointBase() {
227
+ if (this.options.endpoint)
228
+ return this.options.endpoint.replace(/\/+$/, '');
229
+ return `https://${this.options.bucket}.s3.${this.options.region}.amazonaws.com`;
230
+ }
231
+ async signedRequest(args) {
232
+ const base = this.endpointBase();
233
+ const baseHost = new URL(base).host;
234
+ // Path-style for endpoint overrides (typical for S3-compat services + MinIO test setups);
235
+ // virtual-host-style when endpoint is omitted (default AWS S3).
236
+ let pathSegment;
237
+ const host = baseHost;
238
+ if (this.options.endpoint) {
239
+ const segments = [this.options.bucket, ...args.key.split('/').filter(Boolean).map(encodeS3PathSegment)];
240
+ pathSegment = '/' + segments.join('/');
241
+ }
242
+ else {
243
+ const segments = args.key.split('/').filter(Boolean).map(encodeS3PathSegment);
244
+ pathSegment = segments.length === 0 ? '/' : '/' + segments.join('/');
245
+ }
246
+ const headers = { host };
247
+ const body = args.body ?? Buffer.alloc(0);
248
+ const now = this.options.now ? this.options.now() : new Date();
249
+ signSigV4({
250
+ method: args.method,
251
+ path: pathSegment,
252
+ query: args.extraQuery ?? '',
253
+ headers,
254
+ body,
255
+ region: this.options.region,
256
+ service: 's3',
257
+ credentials: this.options.credentials,
258
+ now,
259
+ });
260
+ const url = `${base.replace(/\/+$/, '')}${pathSegment}${args.extraQuery ? `?${args.extraQuery}` : ''}`;
261
+ const init = {
262
+ method: args.method,
263
+ headers,
264
+ ...(args.body ? { body: args.body } : {}),
265
+ };
266
+ return this.fetchFn(url, init);
267
+ }
268
+ }
269
+ function parseListBucketV2Xml(xml) {
270
+ const entries = [];
271
+ // Lightweight XML scrape — accepts S3 / S3-compat shapes:
272
+ // <Contents><Key>...</Key><LastModified>2026-...</LastModified><Size>1234</Size></Contents>
273
+ // and a single <NextContinuationToken>...</NextContinuationToken> and <IsTruncated>true|false</IsTruncated>.
274
+ const contentsRe = /<Contents\b[^>]*>([\s\S]*?)<\/Contents>/g;
275
+ let m;
276
+ while ((m = contentsRe.exec(xml)) !== null) {
277
+ // `contentsRe`'s one capturing group is mandatory (not `(...)?`), so a successful `.exec()`
278
+ // always populates it — TypeScript's `RegExpExecArray` types every group as possibly
279
+ // `undefined` regardless, so this is a type-checker-only fallback with no real runtime path.
280
+ const block = m[1];
281
+ const key = pluckTag(block, 'Key');
282
+ const size = Number(pluckTag(block, 'Size') ?? '0');
283
+ const lastModifiedRaw = pluckTag(block, 'LastModified');
284
+ if (!key)
285
+ continue;
286
+ entries.push({
287
+ key,
288
+ size: Number.isFinite(size) ? size : 0,
289
+ lastModifiedMs: lastModifiedRaw ? Date.parse(lastModifiedRaw) : Date.now(),
290
+ });
291
+ }
292
+ const isTruncated = (pluckTag(xml, 'IsTruncated') ?? 'false').toLowerCase() === 'true';
293
+ const nextToken = pluckTag(xml, 'NextContinuationToken') ?? undefined;
294
+ return nextToken ? { entries, isTruncated, nextToken } : { entries, isTruncated };
295
+ }
296
+ function pluckTag(text, tag) {
297
+ const re = new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`);
298
+ const m = re.exec(text);
299
+ return m ? m[1] : undefined;
300
+ }
301
+ async function safeText(res) {
302
+ try {
303
+ return (await res.text()).slice(0, 256);
304
+ }
305
+ catch {
306
+ return '';
307
+ }
308
+ }
309
+ function normalizeRel(relpath) {
310
+ return String(relpath || '')
311
+ .replace(/^[\\/]+/, '')
312
+ .replace(/[\\]+/g, '/')
313
+ .replace(/\/+/g, '/');
314
+ }
315
+ //# sourceMappingURL=blob-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blob-storage.js","sourceRoot":"","sources":["../src/blob-storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ export type CommandInvocation = {
2
+ args: string[];
3
+ command: string;
4
+ windowsVerbatimArguments?: boolean;
5
+ };
6
+ export type CommandInvocationRequest = {
7
+ args?: string[];
8
+ command: string;
9
+ env?: NodeJS.ProcessEnv;
10
+ };
11
+ /**
12
+ * Resolve a command request into the concrete invocation to spawn. On Windows,
13
+ * `.bat` / `.cmd` targets are rewrapped as a `cmd.exe /d /s /c "..."` shim with
14
+ * `windowsVerbatimArguments` so quoting and percent-expansion behave safely;
15
+ * every other case passes the command and args straight through.
16
+ *
17
+ * @param request - The command, optional args, and env to base the invocation on.
18
+ * @returns The `{ command, args }` (plus `windowsVerbatimArguments` when a shim is used) to spawn.
19
+ */
20
+ export declare function createCommandInvocation({ args, command, env }: CommandInvocationRequest): CommandInvocation;
21
+ /**
22
+ * Build the invocation for re-entering the repo-pinned package manager. Prefers
23
+ * `npm_execpath` (routing Node-loadable managers through `process.execPath`),
24
+ * and otherwise falls back to `corepack pnpm …` so Corepack-only setups without
25
+ * a global `pnpm` on PATH still work. See #2438.
26
+ *
27
+ * @param args - Arguments to pass to the package manager.
28
+ * @param env - Environment to read `npm_execpath` / `ComSpec` from (defaults to `process.env`).
29
+ * @returns The `{ command, args }` invocation that runs the package manager.
30
+ */
31
+ export declare function createPackageManagerInvocation(args: string[], env?: NodeJS.ProcessEnv): CommandInvocation;
32
+ //# sourceMappingURL=command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAKhB,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,CAAC;AA+CF;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,IAAS,EAAE,OAAO,EAAE,GAAiB,EAAE,EAAE,wBAAwB,GAAG,iBAAiB,CAK9H;AAED;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,iBAAiB,CAkBtH"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * @module command
3
+ *
4
+ * Cross-platform command-invocation construction. Turns a requested
5
+ * `{ command, args, env }` into the concrete `{ command, args }` (plus the
6
+ * Windows-only `windowsVerbatimArguments` flag) that `child_process.spawn` /
7
+ * `execFile` must receive so `.bat` / `.cmd` shims and Corepack-only package
8
+ * managers launch correctly on every platform.
9
+ *
10
+ * Consumed by the `process` module's spawn helpers; owns no process lifecycle
11
+ * itself.
12
+ */
13
+ import { extname } from "node:path";
14
+ // `cmd.exe /s /c "..."` runs percent-expansion on the inner line *regardless*
15
+ // of whether the `%name%` pair sits inside a `"..."` quoted segment, so a
16
+ // `.cmd` / `.bat` shim spawn with an attacker-influenced argv (e.g. an LLM
17
+ // adapter that ships the user prompt as a positional argument) lets a stray
18
+ // `%DEEPSEEK_API_KEY%` substring substitute live env values into the line
19
+ // before the child sees it. Plain quote-doubling is not enough on its own.
20
+ //
21
+ // The fix is to break each potential `%var%` pair by toggling out of the
22
+ // outer quote with `"^%"`: cmd treats the `^` as the standard escape for the
23
+ // next char (here, `%`), making it literal and skipping percent-expansion;
24
+ // `CommandLineToArgvW` then concatenates the surrounding quote segments back
25
+ // into one literal arg with the `%` preserved. The two layers cancel, so the
26
+ // child receives the original arg byte-for-byte while cmd never has a chance
27
+ // to expand anything inside it.
28
+ function quoteWindowsCommandArg(value) {
29
+ if (!/[\s"&<>|^%]/.test(value))
30
+ return value;
31
+ const escaped = value.replace(/"/g, '""').replace(/%/g, '"^%"');
32
+ return `"${escaped}"`;
33
+ }
34
+ // Build the `cmd.exe /d /s /c "<line>"` invocation Node uses internally for
35
+ // `shell: true`. The outer `"..."` plus `windowsVerbatimArguments: true` is
36
+ // the only shape that survives both layers of quoting:
37
+ //
38
+ // 1. Node would otherwise escape each argv element with CommandLineToArgvW
39
+ // rules (turning `"path with space"` into `\"path with space\"`), which
40
+ // cmd.exe does not understand.
41
+ // 2. cmd.exe with `/s /c` strips exactly one leading and one trailing `"`
42
+ // from the rest of the command line. The outer wrap absorbs that strip
43
+ // so any inner per-arg quoting stays intact.
44
+ //
45
+ // Without this, paths containing spaces (`C:\Users\First Last\...\foo.cmd`)
46
+ // get split on the first space and cmd.exe reports "not recognized as an
47
+ // internal or external command" — see issue #315.
48
+ function buildCmdShimInvocation(command, args, env) {
49
+ const inner = [command, ...args].map(quoteWindowsCommandArg).join(" ");
50
+ return {
51
+ args: ["/d", "/s", "/c", `"${inner}"`],
52
+ command: env.ComSpec ?? process.env.ComSpec ?? "cmd.exe",
53
+ windowsVerbatimArguments: true,
54
+ };
55
+ }
56
+ const nodeLoadablePackageManagerExtensions = new Set([".js", ".cjs", ".mjs"]);
57
+ /**
58
+ * Resolve a command request into the concrete invocation to spawn. On Windows,
59
+ * `.bat` / `.cmd` targets are rewrapped as a `cmd.exe /d /s /c "..."` shim with
60
+ * `windowsVerbatimArguments` so quoting and percent-expansion behave safely;
61
+ * every other case passes the command and args straight through.
62
+ *
63
+ * @param request - The command, optional args, and env to base the invocation on.
64
+ * @returns The `{ command, args }` (plus `windowsVerbatimArguments` when a shim is used) to spawn.
65
+ */
66
+ export function createCommandInvocation({ args = [], command, env = process.env }) {
67
+ if (process.platform === "win32" && /\.(bat|cmd)$/i.test(command)) {
68
+ return buildCmdShimInvocation(command, args, env);
69
+ }
70
+ return { args, command };
71
+ }
72
+ /**
73
+ * Build the invocation for re-entering the repo-pinned package manager. Prefers
74
+ * `npm_execpath` (routing Node-loadable managers through `process.execPath`),
75
+ * and otherwise falls back to `corepack pnpm …` so Corepack-only setups without
76
+ * a global `pnpm` on PATH still work. See #2438.
77
+ *
78
+ * @param args - Arguments to pass to the package manager.
79
+ * @param env - Environment to read `npm_execpath` / `ComSpec` from (defaults to `process.env`).
80
+ * @returns The `{ command, args }` invocation that runs the package manager.
81
+ */
82
+ export function createPackageManagerInvocation(args, env = process.env) {
83
+ const execPath = env.npm_execpath;
84
+ if (execPath) {
85
+ if (nodeLoadablePackageManagerExtensions.has(extname(execPath).toLowerCase())) {
86
+ return { args: [execPath, ...args], command: process.execPath };
87
+ }
88
+ return createCommandInvocation({ args, command: execPath, env });
89
+ }
90
+ // No `npm_execpath` — common on Corepack-only setups (e.g. native Windows
91
+ // PowerShell where `corepack pnpm` works but no standalone `pnpm` lives on
92
+ // PATH). Route nested invocations through `corepack pnpm …` instead of
93
+ // assuming a global `pnpm` binary: `corepack pnpm …` runs the repo-pinned
94
+ // package manager out of the box, while a bare `pnpm` only resolves when a
95
+ // separate global install or a `corepack enable` shim is present. See #2438.
96
+ if (process.platform === "win32") {
97
+ return buildCmdShimInvocation("corepack", ["pnpm", ...args], env);
98
+ }
99
+ return { args: ["pnpm", ...args], command: "corepack" };
100
+ }
101
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"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"}