@dotobokuri/fleet-console 1.23.0 → 1.24.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 (69) hide show
  1. package/AGENTS.md +41 -257
  2. package/README.md +8 -0
  3. package/dist/cli.d.ts +11 -1
  4. package/dist/cli.mjs +1738 -453
  5. package/dist/client/assets/{_baseUniq-BjOe5yYF.js → _baseUniq-yooYbTgN.js} +1 -1
  6. package/dist/client/assets/{arc-bFUuO3jf.js → arc-D4mme5Ts.js} +1 -1
  7. package/dist/client/assets/{architectureDiagram-Q4EWVU46-Ba7nimQq.js → architectureDiagram-Q4EWVU46-BAJOviEX.js} +1 -1
  8. package/dist/client/assets/{blockDiagram-DXYQGD6D-CQGf47hl.js → blockDiagram-DXYQGD6D-DuObpxQ3.js} +1 -1
  9. package/dist/client/assets/{c4Diagram-AHTNJAMY-DZF_cAK4.js → c4Diagram-AHTNJAMY-BOT-SD34.js} +1 -1
  10. package/dist/client/assets/channel-TZYyAq1v.js +1 -0
  11. package/dist/client/assets/{chunk-4BX2VUAB-DjUUHSQ5.js → chunk-4BX2VUAB-BF_aMTes.js} +1 -1
  12. package/dist/client/assets/{chunk-4TB4RGXK-Dvqti8bd.js → chunk-4TB4RGXK-M4brBcnD.js} +1 -1
  13. package/dist/client/assets/{chunk-55IACEB6-2BxiBvkp.js → chunk-55IACEB6-CrG-4b2Z.js} +1 -1
  14. package/dist/client/assets/{chunk-EDXVE4YY-CqCjol5O.js → chunk-EDXVE4YY-BxDSygH1.js} +1 -1
  15. package/dist/client/assets/{chunk-FMBD7UC4-eoCfIbly.js → chunk-FMBD7UC4-Bh7MEX7E.js} +1 -1
  16. package/dist/client/assets/{chunk-OYMX7WX6-CoC86V_1.js → chunk-OYMX7WX6-DBnBwxer.js} +1 -1
  17. package/dist/client/assets/{chunk-QZHKN3VN-CJQA5mlQ.js → chunk-QZHKN3VN-bjAogQwW.js} +1 -1
  18. package/dist/client/assets/{chunk-YZCP3GAM-C5C4kbLu.js → chunk-YZCP3GAM-l4FGlk_c.js} +1 -1
  19. package/dist/client/assets/classDiagram-6PBFFD2Q-Dh6hZUl4.js +1 -0
  20. package/dist/client/assets/classDiagram-v2-HSJHXN6E-Dh6hZUl4.js +1 -0
  21. package/dist/client/assets/clone-DgWGnVWH.js +1 -0
  22. package/dist/client/assets/{cose-bilkent-S5V4N54A-CahuunpL.js → cose-bilkent-S5V4N54A-Bm5QA4zo.js} +1 -1
  23. package/dist/client/assets/{dagre-KV5264BT-Cbv5kSi5.js → dagre-KV5264BT-PzXQN-5Q.js} +1 -1
  24. package/dist/client/assets/{diagram-5BDNPKRD-CNm40ZGB.js → diagram-5BDNPKRD-KhaAKPtX.js} +1 -1
  25. package/dist/client/assets/{diagram-G4DWMVQ6-DrlGNT3i.js → diagram-G4DWMVQ6-DBbjfiR8.js} +1 -1
  26. package/dist/client/assets/{diagram-MMDJMWI5-r8Y2oqmw.js → diagram-MMDJMWI5-QWro7PRX.js} +1 -1
  27. package/dist/client/assets/{diagram-TYMM5635-CMzEhXup.js → diagram-TYMM5635-B9LqWrbF.js} +1 -1
  28. package/dist/client/assets/{erDiagram-SMLLAGMA-UFjUUMPz.js → erDiagram-SMLLAGMA-b0VkMMN4.js} +1 -1
  29. package/dist/client/assets/{flowDiagram-DWJPFMVM-Dd1STmYc.js → flowDiagram-DWJPFMVM-edxBAbe6.js} +1 -1
  30. package/dist/client/assets/{ganttDiagram-T4ZO3ILL-CHHU0hVd.js → ganttDiagram-T4ZO3ILL-ks2Gg1_V.js} +1 -1
  31. package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-vj2HukAF.js → gitGraphDiagram-UUTBAWPF-DymUyYNl.js} +1 -1
  32. package/dist/client/assets/{graph-DhjfEbEb.js → graph-B-B_mqfh.js} +1 -1
  33. package/dist/client/assets/index-BgLzfg-v.css +1 -0
  34. package/dist/client/assets/index-pDnb-q6f.js +380 -0
  35. package/dist/client/assets/{infoDiagram-42DDH7IO-CC7AEgDm.js → infoDiagram-42DDH7IO-B5iLIYAc.js} +1 -1
  36. package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-DlRw2B9G.js → ishikawaDiagram-UXIWVN3A-DnztLLn7.js} +1 -1
  37. package/dist/client/assets/{journeyDiagram-VCZTEJTY-BbRXANKQ.js → journeyDiagram-VCZTEJTY-BKDRfH1Y.js} +1 -1
  38. package/dist/client/assets/{kanban-definition-6JOO6SKY-DtvdCxGN.js → kanban-definition-6JOO6SKY-DPB3Phvr.js} +1 -1
  39. package/dist/client/assets/{layout-Dg5cvw5v.js → layout-BEeRhYTG.js} +1 -1
  40. package/dist/client/assets/{linear-BvVlQLqF.js → linear-QzmfWKSq.js} +1 -1
  41. package/dist/client/assets/{mermaid.core-DzrV8sC-.js → mermaid.core-BVka5dgm.js} +4 -4
  42. package/dist/client/assets/{min-DNGQ1Ciz.js → min-CfXk9kSN.js} +1 -1
  43. package/dist/client/assets/{mindmap-definition-QFDTVHPH-DxJCNZbg.js → mindmap-definition-QFDTVHPH-tGrGhr6Z.js} +1 -1
  44. package/dist/client/assets/{pieDiagram-DEJITSTG-B75XHG-s.js → pieDiagram-DEJITSTG-ZRBqRiRK.js} +1 -1
  45. package/dist/client/assets/{quadrantDiagram-34T5L4WZ-CL4yoF0m.js → quadrantDiagram-34T5L4WZ-VCINZgct.js} +1 -1
  46. package/dist/client/assets/{requirementDiagram-MS252O5E-kGV4vcr1.js → requirementDiagram-MS252O5E-DFLzADh3.js} +1 -1
  47. package/dist/client/assets/{sankeyDiagram-XADWPNL6-DoA4u7wI.js → sankeyDiagram-XADWPNL6-BbouN8Ji.js} +1 -1
  48. package/dist/client/assets/{sequenceDiagram-FGHM5R23-ZpNDf1bS.js → sequenceDiagram-FGHM5R23-B58_LF0R.js} +1 -1
  49. package/dist/client/assets/{stateDiagram-FHFEXIEX-BzgKcVAG.js → stateDiagram-FHFEXIEX-pk-OHHuL.js} +1 -1
  50. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-xsN122JA.js +1 -0
  51. package/dist/client/assets/{timeline-definition-GMOUNBTQ-B_DkUDsD.js → timeline-definition-GMOUNBTQ-4jQdCvaj.js} +1 -1
  52. package/dist/client/assets/{vennDiagram-DHZGUBPP-MCUnnsKb.js → vennDiagram-DHZGUBPP-CUr1fH6N.js} +1 -1
  53. package/dist/client/assets/{wardley-RL74JXVD-D_JAMSxj.js → wardley-RL74JXVD-D0cfvvNA.js} +1 -1
  54. package/dist/client/assets/{wardleyDiagram-NUSXRM2D-BHCwZGLq.js → wardleyDiagram-NUSXRM2D-D0l_Rp_Z.js} +1 -1
  55. package/dist/client/assets/{xychartDiagram-5P7HB3ND-FbGwbD3V.js → xychartDiagram-5P7HB3ND-BdR8OEuJ.js} +1 -1
  56. package/dist/client/index.html +3 -3
  57. package/dist/desktop-protocol.d.ts +49 -0
  58. package/dist/desktop-protocol.mjs +99 -0
  59. package/dist/fleet-plugins/diff/routes.mjs +124 -225
  60. package/dist/fleet-plugins/skills/routes.mjs +218 -82
  61. package/dist/fleet-plugins/terminal/routes.mjs +190 -176
  62. package/package.json +7 -2
  63. package/dist/client/assets/channel-D2BahVp1.js +0 -1
  64. package/dist/client/assets/classDiagram-6PBFFD2Q-DsDAVLhS.js +0 -1
  65. package/dist/client/assets/classDiagram-v2-HSJHXN6E-DsDAVLhS.js +0 -1
  66. package/dist/client/assets/clone-CdZy2Xzf.js +0 -1
  67. package/dist/client/assets/index-Dq9EKm2G.css +0 -1
  68. package/dist/client/assets/index-DtzbOdd7.js +0 -380
  69. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-yRK5hzZ4.js +0 -1
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import path from 'path';
2
+ import path5 from 'path';
3
3
  import { execFile } from 'child_process';
4
- import fs3 from 'fs/promises';
4
+ import fs4 from 'fs/promises';
5
5
  import os2 from 'os';
6
6
  import crypto4 from 'crypto';
7
7
  import 'http';
@@ -18,12 +18,12 @@ var __export = (target, all) => {
18
18
  function definePlugin(definition) {
19
19
  return definition;
20
20
  }
21
- function registerRouter(ctx, path7, handler) {
22
- ctx.registerRouter(normalizePath(path7), handler);
21
+ function registerRouter(ctx, path8, handler) {
22
+ ctx.registerRouter(normalizePath(path8), handler);
23
23
  }
24
- function normalizePath(path7) {
25
- if (path7.length === 0 || path7 === "/") return "/";
26
- return path7;
24
+ function normalizePath(path8) {
25
+ if (path8.length === 0 || path8 === "/") return "/";
26
+ return path8;
27
27
  }
28
28
 
29
29
  // ../../node_modules/.pnpm/@agentclientprotocol+sdk@1.2.1_zod@4.4.1/node_modules/@agentclientprotocol/sdk/dist/schema/index.js
@@ -832,10 +832,10 @@ function mergeDefs(...defs) {
832
832
  function cloneDef(schema) {
833
833
  return mergeDefs(schema._zod.def);
834
834
  }
835
- function getElementAtPath(obj, path7) {
836
- if (!path7)
835
+ function getElementAtPath(obj, path8) {
836
+ if (!path8)
837
837
  return obj;
838
- return path7.reduce((acc, key) => acc?.[key], obj);
838
+ return path8.reduce((acc, key) => acc?.[key], obj);
839
839
  }
840
840
  function promiseAllObject(promisesObj) {
841
841
  const keys = Object.keys(promisesObj);
@@ -1244,11 +1244,11 @@ function explicitlyAborted(x, startIndex = 0) {
1244
1244
  }
1245
1245
  return false;
1246
1246
  }
1247
- function prefixIssues(path7, issues) {
1247
+ function prefixIssues(path8, issues) {
1248
1248
  return issues.map((iss) => {
1249
1249
  var _a3;
1250
1250
  (_a3 = iss).path ?? (_a3.path = []);
1251
- iss.path.unshift(path7);
1251
+ iss.path.unshift(path8);
1252
1252
  return iss;
1253
1253
  });
1254
1254
  }
@@ -1395,16 +1395,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1395
1395
  }
1396
1396
  function formatError(error51, mapper = (issue2) => issue2.message) {
1397
1397
  const fieldErrors = { _errors: [] };
1398
- const processError = (error52, path7 = []) => {
1398
+ const processError = (error52, path8 = []) => {
1399
1399
  for (const issue2 of error52.issues) {
1400
1400
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1401
- issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
1401
+ issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
1402
1402
  } else if (issue2.code === "invalid_key") {
1403
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
1403
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
1404
1404
  } else if (issue2.code === "invalid_element") {
1405
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
1405
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
1406
1406
  } else {
1407
- const fullpath = [...path7, ...issue2.path];
1407
+ const fullpath = [...path8, ...issue2.path];
1408
1408
  if (fullpath.length === 0) {
1409
1409
  fieldErrors._errors.push(mapper(issue2));
1410
1410
  } else {
@@ -1431,17 +1431,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1431
1431
  }
1432
1432
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1433
1433
  const result = { errors: [] };
1434
- const processError = (error52, path7 = []) => {
1434
+ const processError = (error52, path8 = []) => {
1435
1435
  var _a3, _b;
1436
1436
  for (const issue2 of error52.issues) {
1437
1437
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1438
- issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
1438
+ issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
1439
1439
  } else if (issue2.code === "invalid_key") {
1440
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
1440
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
1441
1441
  } else if (issue2.code === "invalid_element") {
1442
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
1442
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
1443
1443
  } else {
1444
- const fullpath = [...path7, ...issue2.path];
1444
+ const fullpath = [...path8, ...issue2.path];
1445
1445
  if (fullpath.length === 0) {
1446
1446
  result.errors.push(mapper(issue2));
1447
1447
  continue;
@@ -1473,8 +1473,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
1473
1473
  }
1474
1474
  function toDotPath(_path) {
1475
1475
  const segs = [];
1476
- const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1477
- for (const seg of path7) {
1476
+ const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1477
+ for (const seg of path8) {
1478
1478
  if (typeof seg === "number")
1479
1479
  segs.push(`[${seg}]`);
1480
1480
  else if (typeof seg === "symbol")
@@ -14138,13 +14138,13 @@ function resolveRef(ref, ctx) {
14138
14138
  if (!ref.startsWith("#")) {
14139
14139
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14140
14140
  }
14141
- const path7 = ref.slice(1).split("/").filter(Boolean);
14142
- if (path7.length === 0) {
14141
+ const path8 = ref.slice(1).split("/").filter(Boolean);
14142
+ if (path8.length === 0) {
14143
14143
  return ctx.rootSchema;
14144
14144
  }
14145
14145
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14146
- if (path7[0] === defsKey) {
14147
- const key = path7[1];
14146
+ if (path8[0] === defsKey) {
14147
+ const key = path8[1];
14148
14148
  if (!key || !ctx.defs[key]) {
14149
14149
  throw new Error(`Reference not found: ${ref}`);
14150
14150
  }
@@ -16312,7 +16312,7 @@ function findBinaryPath(command, env, options = {}) {
16312
16312
  return findOnPath(command, pathValue, pathExts, platform);
16313
16313
  }
16314
16314
  function wrapWindowsShim(resolved, env, platform) {
16315
- if (platform !== "win32" || !WINDOWS_SHIM_EXTENSIONS.has(path.extname(resolved).toLowerCase())) {
16315
+ if (platform !== "win32" || !WINDOWS_SHIM_EXTENSIONS.has(path5.extname(resolved).toLowerCase())) {
16316
16316
  return { bin: resolved, prefixArgs: [] };
16317
16317
  }
16318
16318
  rejectCmdExpansionSensitiveShim(resolved);
@@ -16330,13 +16330,13 @@ function forceWindowsArgQuoting(value) {
16330
16330
  return `${value} `;
16331
16331
  }
16332
16332
  function findOnPath(bin, pathValue, pathExts, platform) {
16333
- const pathSeparator = platform === "win32" ? WINDOWS_PATH_SEPARATOR : path.delimiter;
16334
- if (hasPathSeparator(bin, platform) || path.isAbsolute(bin)) {
16333
+ const pathSeparator = platform === "win32" ? WINDOWS_PATH_SEPARATOR : path5.delimiter;
16334
+ if (hasPathSeparator(bin, platform) || path5.isAbsolute(bin)) {
16335
16335
  return resolveWithExtensions(bin, pathExts, platform);
16336
16336
  }
16337
16337
  for (const entry of pathValue.split(pathSeparator)) {
16338
16338
  const searchDir = entry.length === 0 ? "." : entry;
16339
- const candidate = resolveWithExtensions(path.join(searchDir, bin), pathExts, platform);
16339
+ const candidate = resolveWithExtensions(path5.join(searchDir, bin), pathExts, platform);
16340
16340
  if (candidate) {
16341
16341
  return candidate;
16342
16342
  }
@@ -16344,7 +16344,7 @@ function findOnPath(bin, pathValue, pathExts, platform) {
16344
16344
  return void 0;
16345
16345
  }
16346
16346
  function resolveWithExtensions(candidate, pathExts, platform) {
16347
- if (platform !== "win32" || path.extname(candidate).length > 0) {
16347
+ if (platform !== "win32" || path5.extname(candidate).length > 0) {
16348
16348
  return isAccessibleExecutable(candidate, platform) ? candidate : void 0;
16349
16349
  }
16350
16350
  for (const ext of pathExts) {
@@ -16663,18 +16663,18 @@ async function ensureCliMjs(cliHome, onBootstrap) {
16663
16663
  if (_cliMjsPath) return _cliMjsPath;
16664
16664
  if (_bootstrapPromise) return _bootstrapPromise;
16665
16665
  _bootstrapPromise = (async () => {
16666
- const mjsPath = path.join(cliHome, "node_modules", SKILLS_PACKAGE, "bin", "cli.mjs");
16667
- const pkgPath = path.join(cliHome, "node_modules", SKILLS_PACKAGE, "package.json");
16666
+ const mjsPath = path5.join(cliHome, "node_modules", SKILLS_PACKAGE, "bin", "cli.mjs");
16667
+ const pkgPath = path5.join(cliHome, "node_modules", SKILLS_PACKAGE, "package.json");
16668
16668
  let needsInstall = true;
16669
16669
  try {
16670
- const raw = await fs3.readFile(pkgPath, "utf-8");
16670
+ const raw = await fs4.readFile(pkgPath, "utf-8");
16671
16671
  const pkg = JSON.parse(raw);
16672
16672
  if (pkg.version === SKILLS_VERSION) needsInstall = false;
16673
16673
  } catch {
16674
16674
  }
16675
16675
  if (needsInstall) {
16676
16676
  onBootstrap?.(WARMUP_LINE);
16677
- await fs3.mkdir(cliHome, { recursive: true });
16677
+ await fs4.mkdir(cliHome, { recursive: true });
16678
16678
  await runNpmInstall(cliHome);
16679
16679
  }
16680
16680
  _cliMjsPath = mjsPath;
@@ -16799,6 +16799,61 @@ function getJobResult(id, cursor) {
16799
16799
  exitCode: job.exitCode
16800
16800
  };
16801
16801
  }
16802
+ var ProjectPathError = class extends Error {
16803
+ code;
16804
+ constructor(code) {
16805
+ super(code);
16806
+ this.name = "ProjectPathError";
16807
+ this.code = code;
16808
+ }
16809
+ };
16810
+ async function resolveProjectCwd(theaterRoot, relPath) {
16811
+ if (relPath !== null && !isSafeRelativePath(relPath)) {
16812
+ throw new ProjectPathError("invalid_rel_path");
16813
+ }
16814
+ const lexicalRoot = path5.resolve(theaterRoot);
16815
+ const lexicalTarget = path5.resolve(lexicalRoot, relPath ?? ".");
16816
+ if (!isContainedBy(lexicalRoot, lexicalTarget)) {
16817
+ throw new ProjectPathError("path_outside_theater");
16818
+ }
16819
+ let realRoot;
16820
+ let realTarget;
16821
+ try {
16822
+ [realRoot, realTarget] = await Promise.all([
16823
+ fs4.realpath(lexicalRoot),
16824
+ fs4.realpath(lexicalTarget)
16825
+ ]);
16826
+ } catch (error51) {
16827
+ throw mapFilesystemError(error51);
16828
+ }
16829
+ if (!isContainedBy(realRoot, realTarget)) {
16830
+ throw new ProjectPathError("path_outside_theater");
16831
+ }
16832
+ try {
16833
+ if (!(await fs4.stat(realTarget)).isDirectory()) {
16834
+ throw new ProjectPathError("invalid_rel_path");
16835
+ }
16836
+ } catch (error51) {
16837
+ if (error51 instanceof ProjectPathError) throw error51;
16838
+ throw mapFilesystemError(error51);
16839
+ }
16840
+ return realTarget;
16841
+ }
16842
+ function isSafeRelativePath(value) {
16843
+ if (!value || value.includes("\0") || path5.isAbsolute(value) || path5.posix.isAbsolute(value) || path5.win32.isAbsolute(value)) {
16844
+ return false;
16845
+ }
16846
+ return value.split(/[\\/]/).every((segment) => segment !== "" && segment !== "." && segment !== "..");
16847
+ }
16848
+ function isContainedBy(root, target) {
16849
+ return target === root || target.startsWith(root.endsWith(path5.sep) ? root : root + path5.sep);
16850
+ }
16851
+ function mapFilesystemError(error51) {
16852
+ const code = error51.code;
16853
+ if (code === "EACCES" || code === "EPERM") return new ProjectPathError("path_outside_theater");
16854
+ if (code === "ENOENT" || code === "ENOTDIR") return new ProjectPathError("not_found");
16855
+ return new ProjectPathError("invalid_rel_path");
16856
+ }
16802
16857
 
16803
16858
  // ../fleet-plugins/skills/server/registry-search.ts
16804
16859
  var DEFAULT_SKILLS_API_URL = "https://skills.sh";
@@ -16873,10 +16928,12 @@ function validateScope(scope) {
16873
16928
  // ../fleet-plugins/skills/server/handlers.ts
16874
16929
  var PREVIEW_TIMEOUT_MS = 3e4;
16875
16930
  var CLI_TIMEOUT_MS = 12e4;
16931
+ var USERINFO_URL_RE = /\b[a-z][a-z0-9+.-]*:\/\/[^\s/@]+@[^\s]+/gi;
16932
+ var TOKEN_URL_PARAM_RE = /([?&](?:access_?token|token|api_?key|apikey|auth(?:orization)?|password|secret|credential)=)[^&#\s]*/gi;
16876
16933
  async function readSkillSources(cwd) {
16877
16934
  const sources = /* @__PURE__ */ new Map();
16878
16935
  try {
16879
- const raw = await fs3.readFile(path.join(cwd, "skills-lock.json"), "utf-8");
16936
+ const raw = await fs4.readFile(path5.join(cwd, "skills-lock.json"), "utf-8");
16880
16937
  const parsed = JSON.parse(raw);
16881
16938
  if (typeof parsed === "object" && parsed !== null) {
16882
16939
  for (const [name, entry] of Object.entries(parsed)) {
@@ -16887,7 +16944,7 @@ async function readSkillSources(cwd) {
16887
16944
  } catch {
16888
16945
  }
16889
16946
  try {
16890
- const raw = await fs3.readFile(path.join(cwd, ".agents", ".skill-lock.json"), "utf-8");
16947
+ const raw = await fs4.readFile(path5.join(cwd, ".agents", ".skill-lock.json"), "utf-8");
16891
16948
  const parsed = JSON.parse(raw);
16892
16949
  if (typeof parsed === "object" && parsed !== null) {
16893
16950
  for (const [name, entry] of Object.entries(parsed)) {
@@ -16913,6 +16970,21 @@ async function runListCommand(args, cwd, executor) {
16913
16970
  function buildDisplayPath(scope, name) {
16914
16971
  return scope === "global" ? `~/.agents/skills/${name}` : `.agents/skills/${name}`;
16915
16972
  }
16973
+ function parseOptionalRelPath(value) {
16974
+ if (value === void 0 || value === null) return null;
16975
+ return typeof value === "string" ? value : void 0;
16976
+ }
16977
+ async function resolveProjectScopeCwd(ctx, theaterId, relPath) {
16978
+ if (!theaterId) return null;
16979
+ if (relPath === void 0) throw new ProjectPathError("invalid_rel_path");
16980
+ const theaterRoot = ctx.host.paths.resolveTheaterPath(theaterId);
16981
+ return theaterRoot ? resolveProjectCwd(theaterRoot, relPath) : null;
16982
+ }
16983
+ function writeProjectPathError(res, ctx, error51) {
16984
+ if (!(error51 instanceof ProjectPathError)) throw error51;
16985
+ const status = error51.code === "path_outside_theater" ? 403 : error51.code === "not_found" ? 404 : 400;
16986
+ ctx.host.http.writeJson(res, status, { error: error51.code });
16987
+ }
16916
16988
  function extractSkillMarkdown(raw) {
16917
16989
  const text = stripAnsi(raw);
16918
16990
  const openTag = "<SKILL.md>";
@@ -16924,13 +16996,28 @@ function extractSkillMarkdown(raw) {
16924
16996
  }
16925
16997
  return text.trim();
16926
16998
  }
16927
- function spawnJobAsync(jobId, args, cwd, executor) {
16999
+ function redactJobOutput(chunk, paths) {
17000
+ let redacted = chunk.replace(USERINFO_URL_RE, "[redacted credential URL]").replace(TOKEN_URL_PARAM_RE, "$1[redacted]");
17001
+ const sensitivePaths = [.../* @__PURE__ */ new Set([paths.cwd, paths.homeDir, paths.pluginDataDir])].filter(Boolean).sort((a, b) => b.length - a.length);
17002
+ for (const sensitivePath of sensitivePaths) {
17003
+ redacted = redacted.replaceAll(sensitivePath, "[redacted path]");
17004
+ }
17005
+ return redacted;
17006
+ }
17007
+ function getJobOutputRedactionPaths(ctx, cwd) {
17008
+ return {
17009
+ cwd,
17010
+ homeDir: os2.homedir(),
17011
+ pluginDataDir: ctx.host.paths.pluginDataDir("skills")
17012
+ };
17013
+ }
17014
+ function spawnJobAsync(jobId, args, cwd, redactionPaths, executor) {
16928
17015
  setImmediate(() => {
16929
17016
  void executor(args, {
16930
17017
  cwd,
16931
17018
  timeout: CLI_TIMEOUT_MS,
16932
- onChunk: (chunk) => appendChunk(jobId, chunk),
16933
- onBootstrap: (line) => appendChunk(jobId, line + "\n")
17019
+ onChunk: (chunk) => appendChunk(jobId, redactJobOutput(chunk, redactionPaths)),
17020
+ onBootstrap: (line) => appendChunk(jobId, redactJobOutput(line + "\n", redactionPaths))
16934
17021
  }).then((result) => finishJob(jobId, result.exitCode)).catch(() => finishJob(jobId, 1));
16935
17022
  });
16936
17023
  }
@@ -16945,13 +17032,26 @@ async function handleList(req, res, ctx, executor) {
16945
17032
  }
16946
17033
  const url2 = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
16947
17034
  const theaterId = url2.searchParams.get("theaterId") ?? void 0;
16948
- const theaterPath = theaterId ? ctx.host.paths.resolveTheaterPath(theaterId) : null;
17035
+ const relPath = url2.searchParams.has("relPath") ? url2.searchParams.get("relPath") || null : null;
17036
+ let projectCwd = null;
17037
+ if (theaterId) {
17038
+ try {
17039
+ projectCwd = await resolveProjectScopeCwd(ctx, theaterId, relPath);
17040
+ } catch (error51) {
17041
+ writeProjectPathError(res, ctx, error51);
17042
+ return;
17043
+ }
17044
+ if (!projectCwd) {
17045
+ ctx.host.http.writeJson(res, 404, { error: "theater_not_found" });
17046
+ return;
17047
+ }
17048
+ }
16949
17049
  try {
16950
- if (theaterPath) {
17050
+ if (projectCwd) {
16951
17051
  const [projectRaw, globalRaw, projectSources, globalSources] = await Promise.all([
16952
- runListCommand(["list", "--json"], theaterPath, executor),
17052
+ runListCommand(["list", "--json"], projectCwd, executor),
16953
17053
  runListCommand(["list", "-g", "--json"], os2.homedir(), executor),
16954
- readSkillSources(theaterPath),
17054
+ readSkillSources(projectCwd),
16955
17055
  readSkillSources(os2.homedir())
16956
17056
  ]);
16957
17057
  const projectSkills = projectRaw.map((entry) => ({
@@ -17025,8 +17125,9 @@ async function handleInstall(req, res, ctx, executor) {
17025
17125
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17026
17126
  return;
17027
17127
  }
17028
- const { source, skill, scope, agents, theaterId: rawTheaterId } = body;
17128
+ const { source, skill, scope, agents, theaterId: rawTheaterId, relPath: rawRelPath } = body;
17029
17129
  const theaterId = typeof rawTheaterId === "string" ? rawTheaterId : void 0;
17130
+ const relPath = parseOptionalRelPath(rawRelPath);
17030
17131
  if (!validateSource(source)) {
17031
17132
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17032
17133
  return;
@@ -17049,12 +17150,16 @@ async function handleInstall(req, res, ctx, executor) {
17049
17150
  return;
17050
17151
  }
17051
17152
  }
17052
- const theaterPath = scope === "project" ? theaterId ? ctx.host.paths.resolveTheaterPath(theaterId) : null : null;
17053
- if (scope === "project" && !theaterPath) {
17054
- ctx.host.http.writeJson(res, 404, { error: "theater_not_found" });
17055
- return;
17153
+ let projectCwd = null;
17154
+ if (scope === "project") {
17155
+ try {
17156
+ projectCwd = await resolveProjectScopeCwd(ctx, theaterId, relPath);
17157
+ } catch (error51) {
17158
+ writeProjectPathError(res, ctx, error51);
17159
+ return;
17160
+ }
17056
17161
  }
17057
- const cwd = scope === "global" ? defaultCwd() : theaterPath;
17162
+ const cwd = scope === "global" ? defaultCwd() : projectCwd;
17058
17163
  if (!cwd) {
17059
17164
  ctx.host.http.writeJson(res, 404, { error: "theater_not_found" });
17060
17165
  return;
@@ -17067,7 +17172,7 @@ async function handleInstall(req, res, ctx, executor) {
17067
17172
  const agentArgs = agents.flatMap((a) => ["--agent", a]);
17068
17173
  const scopeFlag = scope === "global" ? ["-g"] : [];
17069
17174
  const args = ["add", source, "-y", "--skill", skill, ...scopeFlag, ...agentArgs];
17070
- spawnJobAsync(jobId, args, cwd, executor);
17175
+ spawnJobAsync(jobId, args, cwd, getJobOutputRedactionPaths(ctx, cwd), executor);
17071
17176
  ctx.host.http.writeJson(res, 202, { jobId });
17072
17177
  }
17073
17178
  async function handleUpdate(req, res, ctx, executor) {
@@ -17084,18 +17189,23 @@ async function handleUpdate(req, res, ctx, executor) {
17084
17189
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17085
17190
  return;
17086
17191
  }
17087
- const { scope, theaterId: rawTheaterId } = body;
17192
+ const { scope, theaterId: rawTheaterId, relPath: rawRelPath } = body;
17088
17193
  const theaterId = typeof rawTheaterId === "string" ? rawTheaterId : void 0;
17194
+ const relPath = parseOptionalRelPath(rawRelPath);
17089
17195
  if (!validateScope(scope)) {
17090
17196
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17091
17197
  return;
17092
17198
  }
17093
- const theaterPath = scope === "project" ? theaterId ? ctx.host.paths.resolveTheaterPath(theaterId) : null : null;
17094
- if (scope === "project" && !theaterPath) {
17095
- ctx.host.http.writeJson(res, 404, { error: "theater_not_found" });
17096
- return;
17199
+ let projectCwd = null;
17200
+ if (scope === "project") {
17201
+ try {
17202
+ projectCwd = await resolveProjectScopeCwd(ctx, theaterId, relPath);
17203
+ } catch (error51) {
17204
+ writeProjectPathError(res, ctx, error51);
17205
+ return;
17206
+ }
17097
17207
  }
17098
- const cwd = scope === "global" ? defaultCwd() : theaterPath;
17208
+ const cwd = scope === "global" ? defaultCwd() : projectCwd;
17099
17209
  if (!cwd) {
17100
17210
  ctx.host.http.writeJson(res, 404, { error: "theater_not_found" });
17101
17211
  return;
@@ -17107,7 +17217,7 @@ async function handleUpdate(req, res, ctx, executor) {
17107
17217
  }
17108
17218
  const scopeFlag = scope === "global" ? "-g" : "-p";
17109
17219
  const args = ["update", "-y", scopeFlag];
17110
- spawnJobAsync(jobId, args, cwd, executor);
17220
+ spawnJobAsync(jobId, args, cwd, getJobOutputRedactionPaths(ctx, cwd), executor);
17111
17221
  ctx.host.http.writeJson(res, 202, { jobId });
17112
17222
  }
17113
17223
  async function handleGetJob(req, res, ctx) {
@@ -17148,8 +17258,9 @@ async function handleRemove(req, res, ctx, executor) {
17148
17258
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17149
17259
  return;
17150
17260
  }
17151
- const { scope, skill, theaterId: rawTheaterId } = body;
17261
+ const { scope, skill, theaterId: rawTheaterId, relPath: rawRelPath } = body;
17152
17262
  const theaterId = typeof rawTheaterId === "string" ? rawTheaterId : void 0;
17263
+ const relPath = parseOptionalRelPath(rawRelPath);
17153
17264
  if (!validateScope(scope)) {
17154
17265
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17155
17266
  return;
@@ -17158,12 +17269,16 @@ async function handleRemove(req, res, ctx, executor) {
17158
17269
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17159
17270
  return;
17160
17271
  }
17161
- const theaterPath = scope === "project" ? theaterId ? ctx.host.paths.resolveTheaterPath(theaterId) : null : null;
17162
- if (scope === "project" && !theaterPath) {
17163
- ctx.host.http.writeJson(res, 404, { error: "theater_not_found" });
17164
- return;
17272
+ let projectCwd = null;
17273
+ if (scope === "project") {
17274
+ try {
17275
+ projectCwd = await resolveProjectScopeCwd(ctx, theaterId, relPath);
17276
+ } catch (error51) {
17277
+ writeProjectPathError(res, ctx, error51);
17278
+ return;
17279
+ }
17165
17280
  }
17166
- const cwd = scope === "global" ? defaultCwd() : theaterPath;
17281
+ const cwd = scope === "global" ? defaultCwd() : projectCwd;
17167
17282
  if (!cwd) {
17168
17283
  ctx.host.http.writeJson(res, 404, { error: "theater_not_found" });
17169
17284
  return;
@@ -17193,7 +17308,9 @@ async function handlePreview(req, res, ctx, executor) {
17193
17308
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17194
17309
  return;
17195
17310
  }
17196
- const { source, skill } = body;
17311
+ const { source, skill, theaterId: rawTheaterId, relPath: rawRelPath } = body;
17312
+ const theaterId = typeof rawTheaterId === "string" ? rawTheaterId : void 0;
17313
+ const relPath = parseOptionalRelPath(rawRelPath);
17197
17314
  if (!validateSource(source)) {
17198
17315
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17199
17316
  return;
@@ -17202,8 +17319,22 @@ async function handlePreview(req, res, ctx, executor) {
17202
17319
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17203
17320
  return;
17204
17321
  }
17322
+ let cwd = defaultCwd();
17323
+ if (theaterId) {
17324
+ try {
17325
+ const projectCwd = await resolveProjectScopeCwd(ctx, theaterId, relPath);
17326
+ if (!projectCwd) {
17327
+ ctx.host.http.writeJson(res, 404, { error: "theater_not_found" });
17328
+ return;
17329
+ }
17330
+ cwd = projectCwd;
17331
+ } catch (error51) {
17332
+ writeProjectPathError(res, ctx, error51);
17333
+ return;
17334
+ }
17335
+ }
17205
17336
  try {
17206
- const result = await executor([`use`, `${source}@${skill}`], { cwd: defaultCwd(), timeout: PREVIEW_TIMEOUT_MS });
17337
+ const result = await executor([`use`, `${source}@${skill}`], { cwd, timeout: PREVIEW_TIMEOUT_MS });
17207
17338
  ctx.host.http.writeJson(res, 200, { markdown: extractSkillMarkdown(result.stdout) });
17208
17339
  } catch {
17209
17340
  ctx.host.http.writeJson(res, 502, { error: "preview_failed" });
@@ -17223,8 +17354,9 @@ async function handleInstalledFile(req, res, ctx, executor) {
17223
17354
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17224
17355
  return;
17225
17356
  }
17226
- const { scope, skill, theaterId: rawTheaterId } = body;
17357
+ const { scope, skill, theaterId: rawTheaterId, relPath: rawRelPath } = body;
17227
17358
  const theaterId = typeof rawTheaterId === "string" ? rawTheaterId : void 0;
17359
+ const relPath = parseOptionalRelPath(rawRelPath);
17228
17360
  if (!validateScope(scope)) {
17229
17361
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17230
17362
  return;
@@ -17233,12 +17365,16 @@ async function handleInstalledFile(req, res, ctx, executor) {
17233
17365
  ctx.host.http.writeJson(res, 400, { error: "invalid_argument" });
17234
17366
  return;
17235
17367
  }
17236
- const theaterPath = scope === "project" ? theaterId ? ctx.host.paths.resolveTheaterPath(theaterId) : null : null;
17237
- if (scope === "project" && !theaterPath) {
17238
- ctx.host.http.writeJson(res, 404, { error: "theater_not_found" });
17239
- return;
17368
+ let projectCwd = null;
17369
+ if (scope === "project") {
17370
+ try {
17371
+ projectCwd = await resolveProjectScopeCwd(ctx, theaterId, relPath);
17372
+ } catch (error51) {
17373
+ writeProjectPathError(res, ctx, error51);
17374
+ return;
17375
+ }
17240
17376
  }
17241
- const cwd = scope === "global" ? defaultCwd() : theaterPath;
17377
+ const cwd = scope === "global" ? defaultCwd() : projectCwd;
17242
17378
  if (!cwd) {
17243
17379
  ctx.host.http.writeJson(res, 404, { error: "theater_not_found" });
17244
17380
  return;
@@ -17252,28 +17388,28 @@ async function handleInstalledFile(req, res, ctx, executor) {
17252
17388
  return;
17253
17389
  }
17254
17390
  const skillRoot = entry.path;
17255
- const skillMdPath = path.join(skillRoot, "SKILL.md");
17391
+ const skillMdPath = path5.join(skillRoot, "SKILL.md");
17256
17392
  const [realAllowedRoot, realRoot, realMd] = await Promise.all([
17257
17393
  // CLI가 보고한 skillRoot 자체도 신뢰하지 않는다 — scope의 정당한 상위 경계
17258
17394
  // (project=theater 루트, global=홈)를 벗어나면 읽지 않는다. `.agents/skills`로
17259
17395
  // 고정하지 않는 이유: claude 단독 설치는 `.claude/skills` 아래에 놓인다.
17260
- fs3.realpath(cwd),
17261
- fs3.realpath(skillRoot),
17262
- fs3.realpath(skillMdPath).catch(() => null)
17396
+ fs4.realpath(cwd),
17397
+ fs4.realpath(skillRoot),
17398
+ fs4.realpath(skillMdPath).catch(() => null)
17263
17399
  ]);
17264
17400
  if (!realMd) {
17265
17401
  ctx.host.http.writeJson(res, 404, { error: "skill_not_found" });
17266
17402
  return;
17267
17403
  }
17268
- if (realRoot !== realAllowedRoot && !realRoot.startsWith(realAllowedRoot + path.sep)) {
17404
+ if (realRoot !== realAllowedRoot && !realRoot.startsWith(realAllowedRoot + path5.sep)) {
17269
17405
  ctx.host.http.writeJson(res, 403, { error: "path_outside_theater" });
17270
17406
  return;
17271
17407
  }
17272
- if (realMd !== realRoot && !realMd.startsWith(realRoot + path.sep)) {
17408
+ if (realMd !== realRoot && !realMd.startsWith(realRoot + path5.sep)) {
17273
17409
  ctx.host.http.writeJson(res, 403, { error: "path_outside_theater" });
17274
17410
  return;
17275
17411
  }
17276
- const markdown = await fs3.readFile(realMd, "utf-8");
17412
+ const markdown = await fs4.readFile(realMd, "utf-8");
17277
17413
  ctx.host.http.writeJson(res, 200, { markdown });
17278
17414
  } catch {
17279
17415
  ctx.host.http.writeJson(res, 502, { error: "read_failed" });
@@ -17284,7 +17420,7 @@ async function handleInstalledFile(req, res, ctx, executor) {
17284
17420
  var routes_default = definePlugin({
17285
17421
  id: "skills",
17286
17422
  register(ctx) {
17287
- const cliHome = path.join(ctx.host.paths.pluginDataDir("skills"), "cli");
17423
+ const cliHome = path5.join(ctx.host.paths.pluginDataDir("skills"), "cli");
17288
17424
  const executor = createDefaultExecutor(cliHome);
17289
17425
  registerRouter(ctx, "list", async ({ req, res }) => {
17290
17426
  await handleList(req, res, ctx, executor);