@ultrst-armada/kloks 1.6.0 → 1.7.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.
Files changed (29) hide show
  1. package/.krusbl-release-attestation.json +3 -3
  2. package/package.json +1 -1
  3. package/packages/backend/dist/{BaseStorageAdapter-tosOoSUg.d.ts → BaseStorageAdapter-6x_BQiB3.d.ts} +6 -1
  4. package/packages/backend/dist/{chunk-OZDYAEH4.js → chunk-3IUA66RS.js} +219 -3
  5. package/packages/backend/dist/{chunk-E72GXBXF.js → chunk-6K75XXFD.js} +9 -200
  6. package/packages/backend/dist/{chunk-GPXV4GBD.js → chunk-6W7OAGNV.js} +59 -75
  7. package/packages/backend/dist/{chunk-GQUNN7SA.js → chunk-7ZT2ZPPH.js} +7 -5
  8. package/packages/backend/dist/{chunk-DBZVGMJ7.js → chunk-F6IDQLC2.js} +2 -2
  9. package/packages/backend/dist/chunk-JUPWFW7V.js +134 -0
  10. package/packages/backend/dist/{chunk-J2J24JVC.js → chunk-R45CEV46.js} +210 -153
  11. package/packages/backend/dist/{chunk-3HZYAZF4.js → chunk-SQGBAWZN.js} +97 -7
  12. package/packages/backend/dist/chunk-VAFCR2MS.js +203 -0
  13. package/packages/backend/dist/{chunk-VDROUXFT.js → chunk-XHADDA75.js} +19 -13
  14. package/packages/backend/dist/development/index.d.ts +54 -1
  15. package/packages/backend/dist/development/index.js +7 -1
  16. package/packages/backend/dist/index.d.ts +5 -5
  17. package/packages/backend/dist/index.js +38 -211
  18. package/packages/backend/dist/krnl-services.js +6 -5
  19. package/packages/backend/dist/services/index.js +4 -3
  20. package/packages/backend/dist/srkl/index.d.ts +55 -2
  21. package/packages/backend/dist/srkl/index.js +3 -2
  22. package/packages/backend/dist/storage/index.d.ts +35 -3
  23. package/packages/backend/dist/storage/index.js +12 -3
  24. package/packages/backend/dist/workspace/index.d.ts +27 -33
  25. package/packages/backend/dist/workspace/index.js +3 -2
  26. package/packages/backend/kloks.manifest.json +25 -0
  27. package/packages/client/dist/index.d.ts +34 -1
  28. package/packages/client/dist/index.js +116 -0
  29. package/packages/backend/dist/chunk-LS3HWJBX.js +0 -0
@@ -143,9 +143,9 @@ var LocalFSAdapter = class extends BaseStorageAdapter {
143
143
  async function ensureS3DirectoryMarker(s3, bucketName, folderPrefix) {
144
144
  const clean = folderPrefix.replace(/^\/+|\/+$/g, "");
145
145
  if (!clean) return;
146
- const { PutObjectCommand: PutObjectCommand3 } = await import("@aws-sdk/client-s3");
146
+ const { PutObjectCommand: PutObjectCommand2 } = await import("@aws-sdk/client-s3");
147
147
  try {
148
- await s3.send(new PutObjectCommand3({
148
+ await s3.send(new PutObjectCommand2({
149
149
  Bucket: bucketName,
150
150
  Key: `${clean}/`,
151
151
  Body: Buffer.alloc(0),
@@ -197,7 +197,7 @@ async function permanentDeleteS3Folder(s3, bucketName, targetPrefix) {
197
197
  const bare = targetPrefix.replace(/\/+$/, "");
198
198
  const isMatch = (k) => k === bare || k === `${bare}/` || k.startsWith(`${bare}/`);
199
199
  try {
200
- const { ListObjectVersionsCommand, DeleteObjectsCommand, DeleteObjectCommand, ListObjectsV2Command: ListObjectsV2Command3 } = await import("@aws-sdk/client-s3");
200
+ const { ListObjectVersionsCommand, DeleteObjectsCommand, DeleteObjectCommand, ListObjectsV2Command: ListObjectsV2Command2 } = await import("@aws-sdk/client-s3");
201
201
  let keyMarker;
202
202
  let versionMarker;
203
203
  let isTruncated = true;
@@ -237,7 +237,7 @@ async function permanentDeleteS3Folder(s3, bucketName, targetPrefix) {
237
237
  let contToken;
238
238
  let more = true;
239
239
  while (more) {
240
- const v2Res = await s3.send(new ListObjectsV2Command3({ Bucket: bucketName, Prefix: bare, ContinuationToken: contToken }));
240
+ const v2Res = await s3.send(new ListObjectsV2Command2({ Bucket: bucketName, Prefix: bare, ContinuationToken: contToken }));
241
241
  for (const obj of v2Res.Contents || []) {
242
242
  if (obj.Key && isMatch(obj.Key)) {
243
243
  await permanentDeleteS3Object(s3, bucketName, obj.Key);
@@ -262,12 +262,12 @@ async function renameS3Folder(s3, bucketName, oldPrefix, newPrefix) {
262
262
  const newDir = `${newClean}/`;
263
263
  let movedCount = 0;
264
264
  try {
265
- const { ListObjectsV2Command: ListObjectsV2Command3, GetObjectCommand: GetObjectCommand3, PutObjectCommand: PutObjectCommand3 } = await import("@aws-sdk/client-s3");
265
+ const { ListObjectsV2Command: ListObjectsV2Command2, GetObjectCommand: GetObjectCommand2, PutObjectCommand: PutObjectCommand2 } = await import("@aws-sdk/client-s3");
266
266
  let contToken;
267
267
  let more = true;
268
268
  const items = [];
269
269
  while (more) {
270
- const res = await s3.send(new ListObjectsV2Command3({ Bucket: bucketName, Prefix: oldFolderKey, ContinuationToken: contToken }));
270
+ const res = await s3.send(new ListObjectsV2Command2({ Bucket: bucketName, Prefix: oldFolderKey, ContinuationToken: contToken }));
271
271
  for (const obj of res.Contents || []) {
272
272
  if (!obj.Key) continue;
273
273
  if (obj.Key === oldFolderKey || obj.Key === oldDir) items.push({ Key: obj.Key, isDir: true, subRel: "" });
@@ -283,10 +283,10 @@ async function renameS3Folder(s3, bucketName, oldPrefix, newPrefix) {
283
283
  continue;
284
284
  }
285
285
  const newKey = `${newDir}${item.subRel}`;
286
- const getRes = await s3.send(new GetObjectCommand3({ Bucket: bucketName, Key: item.Key }));
286
+ const getRes = await s3.send(new GetObjectCommand2({ Bucket: bucketName, Key: item.Key }));
287
287
  if (getRes.Body) {
288
288
  const bytes = await getRes.Body.transformToByteArray();
289
- await s3.send(new PutObjectCommand3({ Bucket: bucketName, Key: newKey, Body: bytes, ContentType: getRes.ContentType || "application/octet-stream" }));
289
+ await s3.send(new PutObjectCommand2({ Bucket: bucketName, Key: newKey, Body: bytes, ContentType: getRes.ContentType || "application/octet-stream" }));
290
290
  movedCount++;
291
291
  }
292
292
  }
@@ -298,129 +298,6 @@ async function renameS3Folder(s3, bucketName, oldPrefix, newPrefix) {
298
298
  }
299
299
  }
300
300
 
301
- // src/storage/S3Adapter.ts
302
- var S3Client;
303
- var PutObjectCommand;
304
- var GetObjectCommand;
305
- var ListObjectsV2Command;
306
- var HeadObjectCommand;
307
- var S3Adapter = class extends BaseStorageAdapter {
308
- client;
309
- bucket;
310
- constructor(config) {
311
- super(config);
312
- this.bucket = config.bucket || "";
313
- }
314
- async ensureClient() {
315
- if (this.client) return;
316
- try {
317
- const aws = await import("@aws-sdk/client-s3");
318
- S3Client = aws.S3Client;
319
- PutObjectCommand = aws.PutObjectCommand;
320
- GetObjectCommand = aws.GetObjectCommand;
321
- ListObjectsV2Command = aws.ListObjectsV2Command;
322
- HeadObjectCommand = aws.HeadObjectCommand;
323
- this.client = new S3Client({
324
- region: this.config.region || "us-east-1",
325
- endpoint: this.config.endpoint,
326
- credentials: {
327
- accessKeyId: this.config.accessKey,
328
- secretAccessKey: this.config.secretKey
329
- },
330
- forcePathStyle: Boolean(this.config.endpoint)
331
- });
332
- } catch (e) {
333
- throw new Error(`@aws-sdk/client-s3 failed to initialize: ${e.message}`);
334
- }
335
- }
336
- async read(pathStr) {
337
- await this.ensureClient();
338
- const command = new GetObjectCommand({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
339
- const response = await this.client.send(command);
340
- return response.Body ? await response.Body.transformToByteArray() : new Uint8Array();
341
- }
342
- async write(pathStr, data, contentType = "application/octet-stream") {
343
- await this.ensureClient();
344
- const body = typeof data === "string" ? Buffer.from(data, "utf-8") : Buffer.from(data);
345
- const command = new PutObjectCommand({
346
- Bucket: this.bucket,
347
- Key: this.normalizePath(pathStr),
348
- Body: body,
349
- ContentType: contentType
350
- });
351
- await this.client.send(command);
352
- }
353
- async delete(pathStr) {
354
- await this.ensureClient();
355
- await permanentDeleteS3Object(this.client, this.bucket, this.normalizePath(pathStr));
356
- }
357
- async deleteFolder(pathStr) {
358
- await this.ensureClient();
359
- return await permanentDeleteS3Folder(this.client, this.bucket, this.normalizePath(pathStr));
360
- }
361
- async renameFolder(oldPath, newPath) {
362
- await this.ensureClient();
363
- return await renameS3Folder(this.client, this.bucket, this.normalizePath(oldPath), this.normalizePath(newPath));
364
- }
365
- async ensureDirectory(pathStr) {
366
- await this.ensureClient();
367
- await ensureS3DirectoryMarker(this.client, this.bucket, this.normalizePath(pathStr));
368
- }
369
- async exists(pathStr) {
370
- await this.ensureClient();
371
- try {
372
- const command = new HeadObjectCommand({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
373
- await this.client.send(command);
374
- return true;
375
- } catch (e) {
376
- if (e.name === "NotFound" || e.$metadata?.httpStatusCode === 404) return false;
377
- throw e;
378
- }
379
- }
380
- async list(pathStr = "") {
381
- await this.ensureClient();
382
- const prefix = pathStr ? this.normalizePath(pathStr).replace(/\/+$/, "") + "/" : "";
383
- const command = new ListObjectsV2Command({ Bucket: this.bucket, Prefix: prefix });
384
- const response = await this.client.send(command);
385
- return (response.Contents || []).map((item) => ({
386
- path: item.Key,
387
- size: item.Size || 0,
388
- modifiedAt: item.LastModified ? item.LastModified.getTime() : 0
389
- }));
390
- }
391
- async stat(pathStr) {
392
- await this.ensureClient();
393
- const command = new HeadObjectCommand({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
394
- const response = await this.client.send(command);
395
- return {
396
- path: pathStr,
397
- size: response.ContentLength || 0,
398
- modifiedAt: response.LastModified ? response.LastModified.getTime() : 0
399
- };
400
- }
401
- async mkdir(pathStr) {
402
- await this.ensureDirectory(pathStr);
403
- }
404
- async testConnection() {
405
- const start = performance.now();
406
- try {
407
- await this.ensureClient();
408
- const res = await this.client.send(new ListObjectsV2Command({ Bucket: this.bucket, MaxKeys: 1 }));
409
- return {
410
- ok: true,
411
- latencyMs: Math.round(performance.now() - start),
412
- details: { bucket: this.bucket, keyCount: res.KeyCount ?? 0 }
413
- };
414
- } catch (e) {
415
- return {
416
- ok: false,
417
- latencyMs: Math.round(performance.now() - start),
418
- error: e.message
419
- };
420
- }
421
- }
422
- };
423
-
424
301
  // src/storage/b2Endpoint.ts
425
302
  function isSecretMasked(str) {
426
303
  return Boolean(str && (str.includes("\u2022") || str.includes("***")));
@@ -486,11 +363,11 @@ ${appKey}`;
486
363
  }
487
364
 
488
365
  // src/storage/BackblazeB2Adapter.ts
489
- var S3Client2;
490
- var PutObjectCommand2;
491
- var GetObjectCommand2;
492
- var ListObjectsV2Command2;
493
- var HeadObjectCommand2;
366
+ var S3Client;
367
+ var PutObjectCommand;
368
+ var GetObjectCommand;
369
+ var ListObjectsV2Command;
370
+ var HeadObjectCommand;
494
371
  var BackblazeB2Adapter = class extends BaseStorageAdapter {
495
372
  client;
496
373
  bucket;
@@ -502,17 +379,17 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
502
379
  if (this.client) return;
503
380
  try {
504
381
  const aws = await import("@aws-sdk/client-s3");
505
- S3Client2 = aws.S3Client;
506
- PutObjectCommand2 = aws.PutObjectCommand;
507
- GetObjectCommand2 = aws.GetObjectCommand;
508
- ListObjectsV2Command2 = aws.ListObjectsV2Command;
509
- HeadObjectCommand2 = aws.HeadObjectCommand;
382
+ S3Client = aws.S3Client;
383
+ PutObjectCommand = aws.PutObjectCommand;
384
+ GetObjectCommand = aws.GetObjectCommand;
385
+ ListObjectsV2Command = aws.ListObjectsV2Command;
386
+ HeadObjectCommand = aws.HeadObjectCommand;
510
387
  const rawKeyId = this.config.b2KeyId || this.config.accessKey || this.config.keyId;
511
388
  const rawAppKey = this.config.b2ApplicationKey || this.config.secretKey || this.config.applicationKey;
512
389
  const { keyId, appKey } = normalizeBackblazeCredentials(rawKeyId, rawAppKey);
513
390
  const rawEndpoint = this.config.b2Endpoint || this.config.endpoint || this.config.b2Region || this.config.region;
514
391
  const { endpoint, region } = resolveBackblazeEndpoint(rawEndpoint, keyId);
515
- this.client = new S3Client2({
392
+ this.client = new S3Client({
516
393
  region,
517
394
  endpoint,
518
395
  forcePathStyle: true,
@@ -527,14 +404,14 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
527
404
  }
528
405
  async read(pathStr) {
529
406
  await this.ensureClient();
530
- const command = new GetObjectCommand2({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
407
+ const command = new GetObjectCommand({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
531
408
  const response = await this.client.send(command);
532
409
  return response.Body ? await response.Body.transformToByteArray() : new Uint8Array();
533
410
  }
534
411
  async write(pathStr, data, contentType = "text/plain") {
535
412
  await this.ensureClient();
536
413
  const body = typeof data === "string" ? Buffer.from(data, "utf-8") : Buffer.from(data);
537
- const command = new PutObjectCommand2({
414
+ const command = new PutObjectCommand({
538
415
  Bucket: this.bucket,
539
416
  Key: this.normalizePath(pathStr),
540
417
  Body: body,
@@ -566,7 +443,7 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
566
443
  async exists(pathStr) {
567
444
  await this.ensureClient();
568
445
  try {
569
- const command = new HeadObjectCommand2({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
446
+ const command = new HeadObjectCommand({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
570
447
  await this.client.send(command);
571
448
  return true;
572
449
  } catch (e) {
@@ -577,7 +454,7 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
577
454
  async list(pathStr = "") {
578
455
  await this.ensureClient();
579
456
  const prefix = pathStr ? this.normalizePath(pathStr).replace(/\/+$/, "") + "/" : "";
580
- const command = new ListObjectsV2Command2({ Bucket: this.bucket, Prefix: prefix });
457
+ const command = new ListObjectsV2Command({ Bucket: this.bucket, Prefix: prefix });
581
458
  const response = await this.client.send(command);
582
459
  return (response.Contents || []).map((item) => ({
583
460
  path: item.Key,
@@ -587,7 +464,7 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
587
464
  }
588
465
  async stat(pathStr) {
589
466
  await this.ensureClient();
590
- const command = new HeadObjectCommand2({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
467
+ const command = new HeadObjectCommand({ Bucket: this.bucket, Key: this.normalizePath(pathStr) });
591
468
  const response = await this.client.send(command);
592
469
  return {
593
470
  path: pathStr,
@@ -602,7 +479,7 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
602
479
  const start = performance.now();
603
480
  try {
604
481
  await this.ensureClient();
605
- const res = await this.client.send(new ListObjectsV2Command2({ Bucket: this.bucket, MaxKeys: 1 }));
482
+ const res = await this.client.send(new ListObjectsV2Command({ Bucket: this.bucket, MaxKeys: 1 }));
606
483
  return {
607
484
  ok: true,
608
485
  latencyMs: Math.round(performance.now() - start),
@@ -618,6 +495,185 @@ var BackblazeB2Adapter = class extends BaseStorageAdapter {
618
495
  }
619
496
  };
620
497
 
498
+ // src/storage/GoogleDriveOAuth.ts
499
+ var AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
500
+ var TOKEN_URL = "https://oauth2.googleapis.com/token";
501
+ function createGoogleDriveAuthorizationUrl(config, state, codeChallenge) {
502
+ const params = new URLSearchParams({
503
+ client_id: config.clientId,
504
+ redirect_uri: config.redirectUri,
505
+ response_type: "code",
506
+ access_type: "offline",
507
+ prompt: "consent",
508
+ scope: (config.scopes || ["https://www.googleapis.com/auth/drive.file"]).join(" "),
509
+ state
510
+ });
511
+ if (codeChallenge) {
512
+ params.set("code_challenge", codeChallenge);
513
+ params.set("code_challenge_method", "S256");
514
+ }
515
+ return `${AUTH_URL}?${params.toString()}`;
516
+ }
517
+ async function exchangeGoogleDriveCode(config, code, codeVerifier) {
518
+ const body = new URLSearchParams({
519
+ client_id: config.clientId,
520
+ redirect_uri: config.redirectUri,
521
+ code,
522
+ grant_type: "authorization_code"
523
+ });
524
+ if (config.clientSecret) body.set("client_secret", config.clientSecret);
525
+ if (codeVerifier) body.set("code_verifier", codeVerifier);
526
+ const response = await fetch(TOKEN_URL, {
527
+ method: "POST",
528
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
529
+ body
530
+ });
531
+ if (!response.ok) throw new Error(`Google OAuth token exchange failed: ${response.status}`);
532
+ const data = await response.json();
533
+ return {
534
+ accessToken: data.access_token,
535
+ refreshToken: data.refresh_token,
536
+ expiresAt: data.expires_in ? Date.now() + Number(data.expires_in) * 1e3 : void 0,
537
+ tokenType: data.token_type
538
+ };
539
+ }
540
+ async function refreshGoogleDriveAccessToken(clientId, refreshToken) {
541
+ const body = new URLSearchParams({
542
+ client_id: clientId,
543
+ refresh_token: refreshToken,
544
+ grant_type: "refresh_token"
545
+ });
546
+ const response = await fetch(TOKEN_URL, {
547
+ method: "POST",
548
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
549
+ body
550
+ });
551
+ if (!response.ok) throw new Error(`Google OAuth refresh failed: ${response.status}`);
552
+ const data = await response.json();
553
+ return {
554
+ accessToken: data.access_token,
555
+ expiresAt: data.expires_in ? Date.now() + Number(data.expires_in) * 1e3 : void 0,
556
+ tokenType: data.token_type
557
+ };
558
+ }
559
+
560
+ // src/storage/GoogleDriveAdapter.ts
561
+ var GoogleDriveAdapter = class extends BaseStorageAdapter {
562
+ async token() {
563
+ const accessToken = this.config.googleAccessToken || this.config.accessKey;
564
+ const expiresAt = Number(this.config.googleAccessTokenExpiresAt || 0);
565
+ if (accessToken && (!expiresAt || expiresAt > Date.now() + 6e4)) return accessToken;
566
+ const refreshToken = this.config.googleRefreshToken;
567
+ const clientId = this.config.googleClientId;
568
+ if (!refreshToken || !clientId) throw new Error("Google Drive OAuth credentials are incomplete.");
569
+ const refreshed = await refreshGoogleDriveAccessToken(clientId, refreshToken);
570
+ this.config.googleAccessToken = refreshed.accessToken;
571
+ this.config.googleAccessTokenExpiresAt = refreshed.expiresAt;
572
+ return refreshed.accessToken;
573
+ }
574
+ async request(url, init = {}) {
575
+ const headers = new Headers(init.headers);
576
+ headers.set("Authorization", `Bearer ${await this.token()}`);
577
+ return fetch(url, { ...init, headers });
578
+ }
579
+ async findChild(parentId, name) {
580
+ const q = `'${parentId}' in parents and name = '${name.replace(/'/g, "\\'")}' and trashed = false`;
581
+ const res = await this.request(`https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=files(id,name,size,modifiedTime,mimeType)&pageSize=10`);
582
+ if (!res.ok) throw new Error(`Google Drive lookup failed: ${res.status}`);
583
+ const data = await res.json();
584
+ return data.files?.[0] || null;
585
+ }
586
+ async resolveParent(relativeDir, create = false) {
587
+ let parent = this.config.googleRootFolderId || this.config.rootFolderId || "root";
588
+ for (const part of this.normalizePath(relativeDir).split("/").filter(Boolean)) {
589
+ let child = await this.findChild(parent, part);
590
+ if (!child && create) {
591
+ const res = await this.request("https://www.googleapis.com/drive/v3/files", {
592
+ method: "POST",
593
+ headers: { "Content-Type": "application/json" },
594
+ body: JSON.stringify({ name: part, mimeType: "application/vnd.google-apps.folder", parents: [parent] })
595
+ });
596
+ if (!res.ok) throw new Error(`Google Drive folder creation failed: ${res.status}`);
597
+ child = await res.json();
598
+ }
599
+ if (!child) throw new Error(`Google Drive directory not found: ${part}`);
600
+ parent = child.id;
601
+ }
602
+ return parent;
603
+ }
604
+ split(pathStr) {
605
+ const key = this.normalizePath(pathStr);
606
+ const i = key.lastIndexOf("/");
607
+ return i < 0 ? { dir: "", name: key } : { dir: key.slice(0, i), name: key.slice(i + 1) };
608
+ }
609
+ async read(pathStr) {
610
+ const { dir, name } = this.split(pathStr);
611
+ const parent = await this.resolveParent(dir);
612
+ const file = await this.findChild(parent, name);
613
+ if (!file) throw new Error(`Google Drive file not found: ${pathStr}`);
614
+ const res = await this.request(`https://www.googleapis.com/drive/v3/files/${file.id}?alt=media`);
615
+ if (!res.ok) throw new Error(`Google Drive download failed: ${res.status}`);
616
+ return new Uint8Array(await res.arrayBuffer());
617
+ }
618
+ async write(pathStr, data, contentType = "application/octet-stream") {
619
+ const { dir, name } = this.split(pathStr);
620
+ const parent = await this.resolveParent(dir, true);
621
+ const existing = await this.findChild(parent, name);
622
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
623
+ const form = new FormData();
624
+ form.append("metadata", new Blob([JSON.stringify({ name, mimeType: contentType, ...existing ? {} : { parents: [parent] } })], { type: "application/json" }));
625
+ form.append("file", new Blob([bytes], { type: contentType }));
626
+ const url = existing ? `https://www.googleapis.com/upload/drive/v3/files/${existing.id}?uploadType=multipart` : "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart";
627
+ const res = await this.request(url, { method: existing ? "PATCH" : "POST", body: form });
628
+ if (!res.ok) throw new Error(`Google Drive upload failed: ${res.status}`);
629
+ }
630
+ async delete(pathStr) {
631
+ const { dir, name } = this.split(pathStr);
632
+ const parent = await this.resolveParent(dir);
633
+ const file = await this.findChild(parent, name);
634
+ if (!file) return;
635
+ const res = await this.request(`https://www.googleapis.com/drive/v3/files/${file.id}`, { method: "DELETE" });
636
+ if (!res.ok && res.status !== 404) throw new Error(`Google Drive delete failed: ${res.status}`);
637
+ }
638
+ async exists(pathStr) {
639
+ try {
640
+ await this.stat(pathStr);
641
+ return true;
642
+ } catch {
643
+ return false;
644
+ }
645
+ }
646
+ async list(pathStr = "") {
647
+ const parent = await this.resolveParent(pathStr);
648
+ const q = `'${parent}' in parents and trashed = false`;
649
+ const res = await this.request(`https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=files(id,name,size,modifiedTime,mimeType)&pageSize=1000`);
650
+ if (!res.ok) throw new Error(`Google Drive list failed: ${res.status}`);
651
+ const data = await res.json();
652
+ return (data.files || []).map((f) => ({ path: this.normalizePath(pathStr ? `${pathStr}/${f.name}` : f.name), size: Number(f.size || 0), modifiedAt: f.modifiedTime ? Date.parse(f.modifiedTime) : 0 }));
653
+ }
654
+ async stat(pathStr) {
655
+ const { dir, name } = this.split(pathStr);
656
+ const parent = await this.resolveParent(dir);
657
+ const file = await this.findChild(parent, name);
658
+ if (!file) throw new Error(`Google Drive file not found: ${pathStr}`);
659
+ return { path: pathStr, size: Number(file.size || 0), modifiedAt: file.modifiedTime ? Date.parse(file.modifiedTime) : 0 };
660
+ }
661
+ async mkdir(pathStr) {
662
+ await this.resolveParent(pathStr, true);
663
+ }
664
+ async testConnection() {
665
+ const start = performance.now();
666
+ try {
667
+ const res = await this.request("https://www.googleapis.com/drive/v3/about?fields=user");
668
+ if (!res.ok) throw new Error(`Google Drive authorization failed: ${res.status}`);
669
+ const data = await res.json();
670
+ return { ok: true, latencyMs: Math.round(performance.now() - start), details: { email: data.user?.emailAddress } };
671
+ } catch (e) {
672
+ return { ok: false, latencyMs: Math.round(performance.now() - start), error: e.message };
673
+ }
674
+ }
675
+ };
676
+
621
677
  // src/storage/SupabaseStorageAdapter.ts
622
678
  var createClient;
623
679
  var SupabaseStorageAdapter = class extends BaseStorageAdapter {
@@ -699,15 +755,13 @@ var StorageAdapterFactory = class {
699
755
  switch (config.provider) {
700
756
  case "local_fs":
701
757
  return new LocalFSAdapter(config);
702
- case "s3":
703
- case "cloudflare_r2":
704
- case "r2":
705
- return new S3Adapter(config);
706
758
  case "backblaze_b2":
707
759
  case "b2":
708
760
  return new BackblazeB2Adapter(config);
709
761
  case "supabase":
710
762
  return new SupabaseStorageAdapter(config);
763
+ case "google_drive":
764
+ return new GoogleDriveAdapter(config);
711
765
  default:
712
766
  throw new Error(`Unsupported storage provider: ${config.provider}`);
713
767
  }
@@ -721,11 +775,14 @@ export {
721
775
  permanentDeleteS3Object,
722
776
  permanentDeleteS3Folder,
723
777
  renameS3Folder,
724
- S3Adapter,
725
778
  isSecretMasked,
726
779
  resolveBackblazeEndpoint,
727
780
  normalizeBackblazeCredentials,
728
781
  BackblazeB2Adapter,
782
+ createGoogleDriveAuthorizationUrl,
783
+ exchangeGoogleDriveCode,
784
+ refreshGoogleDriveAccessToken,
785
+ GoogleDriveAdapter,
729
786
  SupabaseStorageAdapter,
730
787
  StorageAdapterFactory
731
788
  };
@@ -245,6 +245,7 @@ var DevelopmentServiceDefinition = createServiceDefinition({
245
245
  providers: [
246
246
  { id: "webcontainer", capabilities: ["install", "lint", "test", "build", "validate", "check", "process-host"] },
247
247
  { id: "typescript-language-server", capabilities: ["lsp", "diagnostics", "completion", "hover", "definition", "references", "rename", "symbols"] },
248
+ { id: "agent-harness", capabilities: ["deepseek", "openai", "google", "headless", "sdk", "acp"] },
248
249
  { id: "github-actions", capabilities: ["dispatch", "observe", "rerun", "cancel"] }
249
250
  ]
250
251
  })
@@ -301,8 +302,8 @@ var COMMANDS2 = {
301
302
  var DEFAULT_LAYERS = ["syntax", "lint", "krnl", "frnl"];
302
303
  var commandText = (command, args) => [command, ...args].join(" ");
303
304
  var CodeValidationRuntime = class {
304
- constructor(runtime4 = new WebContainerRuntime()) {
305
- this.runtime = runtime4;
305
+ constructor(runtime5 = new WebContainerRuntime()) {
306
+ this.runtime = runtime5;
306
307
  }
307
308
  runtime;
308
309
  async validate(input = {}) {
@@ -356,8 +357,8 @@ var CodeValidationServiceFacade = {
356
357
 
357
358
  // src/development/codeDiagnosticsService.ts
358
359
  var CodeDiagnosticsService = class {
359
- constructor(runtime4 = new WebContainerRuntime()) {
360
- this.runtime = runtime4;
360
+ constructor(runtime5 = new WebContainerRuntime()) {
361
+ this.runtime = runtime5;
361
362
  }
362
363
  runtime;
363
364
  async diagnostics(input = {}) {
@@ -375,8 +376,8 @@ var TYPESCRIPT_LANGUAGE_SERVER_VERSION = "6.0.2";
375
376
  var PACKAGE = TYPESCRIPT_LANGUAGE_SERVER_PACKAGE;
376
377
  var DEFAULT_VERSION = TYPESCRIPT_LANGUAGE_SERVER_VERSION;
377
378
  var TypeScriptLanguageServerRuntime = class {
378
- constructor(runtime4 = new WebContainerRuntime()) {
379
- this.runtime = runtime4;
379
+ constructor(runtime5 = new WebContainerRuntime()) {
380
+ this.runtime = runtime5;
380
381
  }
381
382
  runtime;
382
383
  process = null;
@@ -502,6 +503,92 @@ var TypeScriptLanguageServerServiceFacade = {
502
503
  }
503
504
  };
504
505
 
506
+ // src/development/agentHarnessService.ts
507
+ var PROVIDERS = [
508
+ {
509
+ id: "deepseek",
510
+ name: "DeepSeek Harness",
511
+ package: "@deepseek-ai/dsh",
512
+ capabilities: ["headless", "sdk", "acp", "web"],
513
+ implemented: true
514
+ },
515
+ {
516
+ id: "openai",
517
+ name: "OpenAI Agents SDK",
518
+ package: "@openai/agents",
519
+ capabilities: ["agents", "tools", "handoffs", "guardrails", "sessions", "tracing"],
520
+ implemented: false
521
+ },
522
+ {
523
+ id: "google",
524
+ name: "Google ADK",
525
+ package: "@google/adk",
526
+ capabilities: ["agents", "tools", "multi-agent", "evaluation", "deployment"],
527
+ implemented: false
528
+ }
529
+ ];
530
+ var AgentHarnessRuntime = class {
531
+ constructor(runtime5 = new WebContainerRuntime()) {
532
+ this.runtime = runtime5;
533
+ }
534
+ runtime;
535
+ providers() {
536
+ return PROVIDERS.map((provider) => ({ ...provider, capabilities: [...provider.capabilities] }));
537
+ }
538
+ async run(input) {
539
+ if (input.provider !== "deepseek") {
540
+ throw new Error(
541
+ `Agent harness provider "${input.provider}" is registered but not yet executable; install and register its adapter before running it.`
542
+ );
543
+ }
544
+ const started = Date.now();
545
+ const profile = input.profile ?? "headless";
546
+ const command = "pnpm";
547
+ const args = ["exec", "dsh", "--profile", profile, input.prompt];
548
+ const result = await this.runtime.runCommand(command, args, input.cwd ?? ".", input.env);
549
+ return {
550
+ provider: input.provider,
551
+ ok: result.exitCode === 0,
552
+ exitCode: result.exitCode,
553
+ output: result.output,
554
+ durationMs: Date.now() - started,
555
+ command: [command, ...args].join(" ")
556
+ };
557
+ }
558
+ };
559
+ var runtime4 = new AgentHarnessRuntime();
560
+ var AgentHarnessServiceDefinition = createServiceDefinition({
561
+ id: "kloks.backend.agentHarness",
562
+ name: "AgentHarnessService",
563
+ version: "1.0.0",
564
+ operations: {
565
+ providers: {
566
+ id: "AgentHarnessService.providers",
567
+ name: "providers",
568
+ handler: async () => runtime4.providers()
569
+ },
570
+ run: {
571
+ id: "AgentHarnessService.run",
572
+ name: "run",
573
+ handler: async (input) => runtime4.run(input)
574
+ }
575
+ }
576
+ });
577
+ var AgentHarnessServiceFacade = {
578
+ id: AgentHarnessServiceDefinition.id,
579
+ name: AgentHarnessServiceDefinition.name,
580
+ version: AgentHarnessServiceDefinition.version,
581
+ runtime: "client",
582
+ deployment: "local",
583
+ definition: AgentHarnessServiceDefinition,
584
+ createInstance: () => createService(AgentHarnessServiceDefinition),
585
+ execute: async (op, input) => {
586
+ const instance = createService(AgentHarnessServiceDefinition);
587
+ await instance.start();
588
+ return instance.call(op, input);
589
+ }
590
+ };
591
+
505
592
  export {
506
593
  GitHubActionsClient,
507
594
  GitHubActionsServiceDefinition,
@@ -521,5 +608,8 @@ export {
521
608
  TYPESCRIPT_LANGUAGE_SERVER_PACKAGE,
522
609
  TYPESCRIPT_LANGUAGE_SERVER_VERSION,
523
610
  TypeScriptLanguageServerServiceDefinition,
524
- TypeScriptLanguageServerServiceFacade
611
+ TypeScriptLanguageServerServiceFacade,
612
+ AgentHarnessRuntime,
613
+ AgentHarnessServiceDefinition,
614
+ AgentHarnessServiceFacade
525
615
  };