openpond 0.0.36 → 0.0.38

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 (137) hide show
  1. package/README.md +4 -3
  2. package/dist/api/types.d.ts +0 -50
  3. package/dist/api.d.ts +2 -8
  4. package/dist/chunks/{app-layer-4AA4YYGK.js → app-layer-DPUJRNO2.js} +6 -3
  5. package/dist/chunks/{apps-V2JTB5MD.js → apps-AKBI6AS7.js} +16 -132
  6. package/dist/chunks/chunk-275WCETC.js +668 -0
  7. package/dist/chunks/{chunk-3DOOLZZM.js → chunk-43YI36NA.js} +1 -1
  8. package/dist/chunks/{chunk-NWQTF6O4.js → chunk-AHNFNWUN.js} +28 -3
  9. package/dist/chunks/{chunk-3JJBNVNX.js → chunk-AHPQTEIJ.js} +23 -19
  10. package/dist/chunks/chunk-FWLOFUPU.js +864 -0
  11. package/dist/chunks/{chunk-JAS6QZ2W.js → chunk-GB6VUZUA.js} +1 -1
  12. package/dist/chunks/{chunk-NVTC3XOA.js → chunk-GDZYDLEL.js} +8 -10
  13. package/dist/chunks/{chunk-G6WW2656.js → chunk-HLCTINEP.js} +1 -1
  14. package/dist/chunks/{chunk-MJT7EW5Q.js → chunk-HS2AGRDV.js} +1 -1
  15. package/dist/chunks/{chunk-CJSD5ADV.js → chunk-JWF37O5E.js} +2 -2
  16. package/dist/chunks/chunk-KSRWKXRB.js +12 -0
  17. package/dist/chunks/{chunk-7IPF4X3K.js → chunk-LZZM3IHS.js} +1004 -89
  18. package/dist/chunks/{chunk-TYYR7KWY.js → chunk-MPGSHXGF.js} +7 -5
  19. package/dist/chunks/chunk-MUMPWI4O.js +92 -0
  20. package/dist/chunks/{chunk-MSX2J653.js → chunk-QRM7XMAO.js} +5 -36
  21. package/dist/chunks/{chunk-65BVQIHR.js → chunk-SLMP353Q.js} +6 -6
  22. package/dist/chunks/chunk-T4QXKU5Y.js +1 -0
  23. package/dist/chunks/{chunk-GALAW74P.js → chunk-V35STJF4.js} +30 -11
  24. package/dist/chunks/{chunk-YLULZMWE.js → chunk-XCATKTK3.js} +51 -139
  25. package/dist/chunks/{chunk-LHYK6QO2.js → chunk-XEJ7XXUQ.js} +1 -0
  26. package/dist/chunks/{chunk-YRFQKUZD.js → chunk-XERQHYBO.js} +89 -27
  27. package/dist/chunks/{chunk-6L5WJF7T.js → chunk-YTJL6XPU.js} +2 -2
  28. package/dist/chunks/{chunk-NWVIUBJ3.js → chunk-ZI4GDAUB.js} +573 -1217
  29. package/dist/chunks/cli-2KBVNDRY.js +23 -0
  30. package/dist/chunks/{cli-RJHEE4FA.js → cli-7BKDWFNU.js} +5 -5
  31. package/dist/chunks/{core-commands-CQSPCVC4.js → core-commands-YN4RMWA3.js} +7 -4
  32. package/dist/chunks/{extend-4MZ75SHV.js → extend-REGNTBK3.js} +18 -13
  33. package/dist/chunks/extension-7K77DAVL.js +121 -0
  34. package/dist/chunks/{harness-YVZU42S7.js → harness-BHQRMXJR.js} +6 -3
  35. package/dist/chunks/{help-6SULYXVS.js → help-VREQNA4I.js} +2 -1
  36. package/dist/chunks/{opchat-XGS4AXHA.js → opchat-D63YTNSX.js} +12 -7
  37. package/dist/chunks/{organizations-4GFQ3NT2.js → organizations-I46KG7TC.js} +8 -5
  38. package/dist/chunks/{profile-VWMBIHIE.js → profile-WKZJHEPG.js} +11 -8
  39. package/dist/chunks/{project-agent-SQ6ODALG.js → project-agent-ZUC3YMCT.js} +10 -7
  40. package/dist/chunks/{sandbox-command-34S2V7BN.js → sandbox-command-AAOPFTI5.js} +7 -4
  41. package/dist/chunks/{sandbox-template-VP5HMGQI.js → sandbox-template-GKNVR4C5.js} +11 -7
  42. package/dist/chunks/{src-X3R3XIJT.js → src-MWDIK56B.js} +1997 -1247
  43. package/dist/chunks/{src-YHUMH6W6.js → src-RPW5TOPI.js} +3 -3
  44. package/dist/chunks/{teams-bot-EIVRNO5S.js → teams-bot-PSL3ZO6Z.js} +6 -3
  45. package/dist/chunks/{workspaces-2N52V3BI.js → workspaces-BPXC2DHT.js} +6 -2
  46. package/dist/cli.js +14 -11
  47. package/dist/client-types.d.ts +1 -9
  48. package/dist/client.d.ts +3 -3
  49. package/dist/index.js +27 -55
  50. package/dist/profile/local-profile-types.d.ts +1 -0
  51. package/dist/profile/profile-skills.d.ts +2 -0
  52. package/dist/web/assets/{AppDialog-j4N-gIi3.js → AppDialog-DrwJb_wG.js} +1 -1
  53. package/dist/web/assets/{AppsView-YiK3pqNb.js → AppsView-DPagLMsc.js} +1 -1
  54. package/dist/web/assets/{BrowserSidebar-BWFLEQ8j.js → BrowserSidebar-DMn2V8RV.js} +1 -1
  55. package/dist/web/assets/{CloudWorkView-3sS_1bhN.js → CloudWorkView-Cl_7mM3c.js} +1 -1
  56. package/dist/web/assets/{CommandMenu-B11OrTCq.js → CommandMenu-CHMQLez_.js} +1 -1
  57. package/dist/web/assets/{CommunityView-DXyXTWhP.js → CommunityView-DcHVDUk0.js} +1 -1
  58. package/dist/web/assets/{ComposerCreateImproveStrip-3NoRiJJq.js → ComposerCreateImproveStrip-BZ3Dgzmo.js} +1 -1
  59. package/dist/web/assets/{GetStartedView-CPV5lgVH.js → GetStartedView-DTRotFqz.js} +1 -1
  60. package/dist/web/assets/LabSkillSidebar-CVxtS9pd.css +1 -0
  61. package/dist/web/assets/LabSkillSidebar-D-PqFe1T.js +1 -0
  62. package/dist/web/assets/LabsRoute-BrJkBNig.css +1 -0
  63. package/dist/web/assets/LabsRoute-Dew1BwK5.js +3 -0
  64. package/dist/web/assets/MainChatThread-BaPxxzrw.js +2 -0
  65. package/dist/web/assets/{MakeAgentTutorialLearningPanel-C6F-kJQd.js → MakeAgentTutorialLearningPanel-CBsfnONQ.js} +2 -2
  66. package/dist/web/assets/{MarkdownText-CkVkr3P1.js → MarkdownText-DGLfAM_Z.js} +4 -4
  67. package/dist/web/assets/Messages-CIX9uTjX.js +10 -0
  68. package/dist/web/assets/NativeSkillSidebar-AP_uHn6g.js +1 -0
  69. package/dist/web/assets/{NewProjectDialog-DBMhkTvD.js → NewProjectDialog-C6lHkafU.js} +1 -1
  70. package/dist/web/assets/{PostTrainingLearningPanel-B1Rp7iIL.js → PostTrainingLearningPanel-CZEgPc8O.js} +2 -2
  71. package/dist/web/assets/{PostTrainingStatusPill-BGZ9h5eW.js → PostTrainingStatusPill-CeEpwUDB.js} +1 -1
  72. package/dist/web/assets/{ProfileSettingsSection-2NOHEz2b.js → ProfileSettingsSection-EumMLlEp.js} +1 -1
  73. package/dist/web/assets/RightChatPanelStack-MXBcx3zO.js +1 -0
  74. package/dist/web/assets/{SettingsView-uHhQnazW.css → SettingsView-Caljbns2.css} +1 -1
  75. package/dist/web/assets/SettingsView-DyURG_Uh.js +6 -0
  76. package/dist/web/assets/{TeamChatView-qVscSedQ.js → TeamChatView-D3v6aqJ3.js} +1 -1
  77. package/dist/web/assets/{TerminalOverlay-Bkw7XqMy.js → TerminalOverlay-BKl0p8pa.js} +1 -1
  78. package/dist/web/assets/{TrainingCreationPanel-COg1wvw8.js → TrainingCreationPanel-CfZQTuT5.js} +1 -1
  79. package/dist/web/assets/{TrainingDraftPanel-BNK2znmI.js → TrainingDraftPanel-DslRPSDW.js} +1 -1
  80. package/dist/web/assets/{UsageSettingsSection-CUxBaohC.js → UsageSettingsSection-zDAwzTGl.js} +1 -1
  81. package/dist/web/assets/WorkspaceDiffPanel-C_MZPPlL.js +14 -0
  82. package/dist/web/assets/{WorkspaceEnvironmentMenu-C0-mH7oF.js → WorkspaceEnvironmentMenu-BUAnn80j.js} +1 -1
  83. package/dist/web/assets/{WorkspaceGitDialogs-VvC2px0X.js → WorkspaceGitDialogs-Drbf4ujA.js} +1 -1
  84. package/dist/web/assets/{WorkspaceMonacoEditor-CUIwoHv1.js → WorkspaceMonacoEditor-DPGcG8fy.js} +3 -3
  85. package/dist/web/assets/{activity-BhqHgkfJ.js → activity-Dnr3jqb3.js} +1 -1
  86. package/dist/web/assets/{boxes-BpqUKFIm.js → boxes-BinC8UPn.js} +1 -1
  87. package/dist/web/assets/{chevron-up-BTn9DVRP.js → chevron-up-Bjp_-_Cb.js} +1 -1
  88. package/dist/web/assets/{circle-x-B9Qa8o5a.js → circle-x-ubnvEYuE.js} +1 -1
  89. package/dist/web/assets/{copy-BsYs6wBI.js → copy-B_ZCCUMz.js} +1 -1
  90. package/dist/web/assets/{create-pipeline-request-vxgKoAvv.js → create-pipeline-request-D6uLUxe9.js} +3 -3
  91. package/dist/web/assets/{cssMode-mw8RI2fR.js → cssMode-CKN9CcfG.js} +1 -1
  92. package/dist/web/assets/file-8HAMlTmQ.js +1 -0
  93. package/dist/web/assets/{git-branch-C7qQYFIs.js → git-branch-l2Zih3Bv.js} +1 -1
  94. package/dist/web/assets/{git-commit-horizontal-CbX4pTOA.js → git-commit-horizontal-Bxi8YPep.js} +1 -1
  95. package/dist/web/assets/{htmlMode-Cc4Czh_M.js → htmlMode-CeUcNhBZ.js} +1 -1
  96. package/dist/web/assets/index-BMFyOFRU.css +1 -0
  97. package/dist/web/assets/index-BzwcDzbT.js +1 -0
  98. package/dist/web/assets/index-KoQSSt_f.js +177 -0
  99. package/dist/web/assets/{info-BNGbwgtq.js → info-JTbDQxHx.js} +1 -1
  100. package/dist/web/assets/{jsonMode-CbqbqGVz.js → jsonMode-97z0Yz9u.js} +1 -1
  101. package/dist/web/assets/{lspLanguageFeatures-DKiKr5tH.js → lspLanguageFeatures-D4Tp-JmI.js} +1 -1
  102. package/dist/web/assets/{make-agent-tutorial-KKauJpB9.js → make-agent-tutorial-D6nBCgv-.js} +1 -1
  103. package/dist/web/assets/{monaco.contribution-Dxc4IxFM.js → monaco.contribution-B3j6oown.js} +2 -2
  104. package/dist/web/assets/{monaco.contribution-CNgwz_pw.js → monaco.contribution-BXHxPPWL.js} +2 -2
  105. package/dist/web/assets/{monaco.contribution-D_-wu578.js → monaco.contribution-C2P5zIzh.js} +2 -2
  106. package/dist/web/assets/{monaco.contribution-CdUAX47Q.js → monaco.contribution-C8c6OtGi.js} +2 -2
  107. package/dist/web/assets/{monitor-CNdx_GTg.js → monitor-kzHtxHnA.js} +1 -1
  108. package/dist/web/assets/{play-BLRANWaV.js → play-C-37dnR1.js} +1 -1
  109. package/dist/web/assets/{python-DYgDMu2R.js → python-CGpDXY7_.js} +1 -1
  110. package/dist/web/assets/{refresh-cw-BFjjwYNf.js → refresh-cw-BAaaPCXl.js} +1 -1
  111. package/dist/web/assets/{reply-D012cuZl.js → reply-9rehU13k.js} +1 -1
  112. package/dist/web/assets/{rotate-cw-CTfjlR4G.js → rotate-cw-C1Z_Xs23.js} +1 -1
  113. package/dist/web/assets/{save-B1zYlRyN.js → save-Cvxs3XyC.js} +1 -1
  114. package/dist/web/assets/{toggleHighContrast-D9XFH7EA.js → toggleHighContrast-CD42jH4g.js} +1 -1
  115. package/dist/web/assets/{tsMode-BU-tuKsY.js → tsMode-ZROIxEjv.js} +1 -1
  116. package/dist/web/assets/{upload-DU_81jvL.js → upload-DvCSGERK.js} +1 -1
  117. package/dist/web/assets/{wifi-off-TPsBnbGW.js → wifi-off-BIb94PkS.js} +1 -1
  118. package/dist/web/assets/{workers-NhWySRdT.js → workers-oYqbrVYG.js} +1 -1
  119. package/dist/web/assets/{yaml-DWXa_3ZL.js → yaml-WqBjNgOO.js} +1 -1
  120. package/dist/web/index.html +2 -2
  121. package/docs/command-reference.md +16 -1
  122. package/package.json +1 -1
  123. package/dist/chunks/cli-4JA3SIDE.js +0 -19
  124. package/dist/web/assets/LabsRoute-B_nsEZXy.js +0 -3
  125. package/dist/web/assets/LabsRoute-dNN-odU0.css +0 -1
  126. package/dist/web/assets/MainChatThread-Dg7p3R2O.js +0 -2
  127. package/dist/web/assets/Messages-C7uHGoFw.js +0 -10
  128. package/dist/web/assets/NativeSkillSidebar-BPpoHjEW.js +0 -1
  129. package/dist/web/assets/RightChatPanelStack-CLK7_zKe.js +0 -1
  130. package/dist/web/assets/SettingsView-BAqea_KX.js +0 -6
  131. package/dist/web/assets/WorkspaceDiffPanel-qfFj8IRq.js +0 -14
  132. package/dist/web/assets/credit-card-BCePAwMI.js +0 -1
  133. package/dist/web/assets/index-9tbdqUau.css +0 -1
  134. package/dist/web/assets/index-B_3z_lxq.js +0 -1
  135. package/dist/web/assets/index-Cr_RZ7GD.js +0 -177
  136. package/dist/web/tokens/eth.svg +0 -1
  137. package/dist/web/tokens/usdc.svg +0 -1
@@ -5,7 +5,7 @@ import {
5
5
  SandboxTemplateManifestSchema,
6
6
  SandboxTemplateValidationDiagnosticSchema,
7
7
  validateConnectedAppToolCallRequest
8
- } from "./chunk-LHYK6QO2.js";
8
+ } from "./chunk-XEJ7XXUQ.js";
9
9
  import {
10
10
  external_exports,
11
11
  yaml
@@ -113,7 +113,9 @@ async function readProfileSkill(input) {
113
113
  path: skill.path,
114
114
  sourcePath: skill.sourcePath,
115
115
  sourceHash: skill.sourceHash,
116
- charCount: skill.charCount
116
+ charCount: skill.charCount,
117
+ packagePath: path.dirname(absolutePath),
118
+ resourceFiles: skill.resourceFiles
117
119
  };
118
120
  }
119
121
  function emptyProfileSkillCatalogState(input = {}) {
@@ -128,12 +130,8 @@ async function loadProfileSkillDirectory(profileSourcePath2, directoryName) {
128
130
  const relativePath = path.join(PROFILE_SKILLS_DIR, directoryName, PROFILE_SKILL_FILE).replace(/\\/g, "/");
129
131
  const absolutePath = path.join(profileSourcePath2, relativePath);
130
132
  const messages = [];
131
- const entries = await readdir(path.join(profileSourcePath2, PROFILE_SKILLS_DIR, directoryName), { withFileTypes: true });
132
- for (const entry of entries) {
133
- if (entry.name === PROFILE_SKILL_FILE && entry.isFile())
134
- continue;
135
- messages.push(`Profile skills only support ${PROFILE_SKILL_FILE}; unsupported entry: ${entry.name}`);
136
- }
133
+ const packageRoot = path.join(profileSourcePath2, PROFILE_SKILLS_DIR, directoryName);
134
+ const packageFiles = await listPackageFiles(packageRoot);
137
135
  let contents = "";
138
136
  if (!existsSync(absolutePath)) {
139
137
  messages.push(`Missing ${PROFILE_SKILL_FILE}.`);
@@ -163,9 +161,26 @@ async function loadProfileSkillDirectory(profileSourcePath2, directoryName) {
163
161
  charCount: contents.length,
164
162
  sourceHash: sha256Hex(contents),
165
163
  validationStatus: messages.length > 0 ? "error" : "valid",
166
- validationMessages: messages
164
+ validationMessages: messages,
165
+ resourceFiles: packageFiles.filter((file) => file !== PROFILE_SKILL_FILE)
167
166
  };
168
167
  }
168
+ async function listPackageFiles(root) {
169
+ const files = [];
170
+ async function visit(directory, prefix) {
171
+ const entries = await readdir(directory, { withFileTypes: true });
172
+ await Promise.all(entries.map(async (entry) => {
173
+ const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
174
+ if (entry.isDirectory()) {
175
+ await visit(path.join(directory, entry.name), relativePath);
176
+ } else if (entry.isFile()) {
177
+ files.push(relativePath);
178
+ }
179
+ }));
180
+ }
181
+ await visit(root, "");
182
+ return files.sort();
183
+ }
169
184
  function markDuplicateSkillNames(skills) {
170
185
  const counts = /* @__PURE__ */ new Map();
171
186
  for (const skill of skills) {
@@ -185,10 +200,14 @@ function markDuplicateSkillNames(skills) {
185
200
  async function latestSkillMtime(profileSourcePath2, skills) {
186
201
  let latest = 0;
187
202
  for (const skill of skills) {
188
- const fileStat = await stat(path.join(profileSourcePath2, skill.path)).catch(() => null);
189
- if (!fileStat?.isFile())
190
- continue;
191
- latest = Math.max(latest, fileStat.mtimeMs);
203
+ const packageRoot = path.dirname(path.join(profileSourcePath2, skill.path));
204
+ const packageFiles = [PROFILE_SKILL_FILE, ...skill.resourceFiles];
205
+ for (const file of packageFiles) {
206
+ const fileStat = await stat(path.join(packageRoot, file)).catch(() => null);
207
+ if (!fileStat?.isFile())
208
+ continue;
209
+ latest = Math.max(latest, fileStat.mtimeMs);
210
+ }
192
211
  }
193
212
  return latest > 0 ? new Date(latest).toISOString() : null;
194
213
  }
@@ -2899,11 +2918,11 @@ function parseProfileSkillCommand(prompt) {
2899
2918
  if (subcommand === "create") {
2900
2919
  if (!args)
2901
2920
  return { action: "help" };
2902
- const named = splitOptionalSkillName(args);
2921
+ const named2 = splitOptionalSkillName(args);
2903
2922
  return {
2904
2923
  action: "create",
2905
- objective: named.objective,
2906
- requestedName: named.name
2924
+ objective: named2.objective,
2925
+ requestedName: named2.name
2907
2926
  };
2908
2927
  }
2909
2928
  if (subcommand === "edit") {
@@ -2914,7 +2933,12 @@ function parseProfileSkillCommand(prompt) {
2914
2933
  return { action: "help" };
2915
2934
  return { action: "edit", name, changeRequest };
2916
2935
  }
2917
- return { action: "help" };
2936
+ const named = splitOptionalSkillName(rest);
2937
+ return {
2938
+ action: "create",
2939
+ objective: named.objective,
2940
+ requestedName: named.name
2941
+ };
2918
2942
  }
2919
2943
  return null;
2920
2944
  }
@@ -2931,7 +2955,7 @@ function profileSkillHelp(profile) {
2931
2955
  "- /skill create --name <skill-name> <what the skill should help with>",
2932
2956
  "- /skill edit <skill-name> <change request>",
2933
2957
  "",
2934
- "Create/edit starts a profile-skill goal in the active profile repo. Skills are single-file profile instructions. If the workflow needs scripts, references, tools, or assets, create an agent instead."
2958
+ "Create/edit starts a profile-skill goal in the active profile repo. Skills may include SKILL.md plus focused scripts, references, and assets. Use an agent when the workflow needs durable autonomy, schedules, identity, or its own model loop."
2935
2959
  ].join("\n")
2936
2960
  };
2937
2961
  }
@@ -3053,10 +3077,11 @@ function profileSkillGoalPrompt(goal) {
3053
3077
  "",
3054
3078
  "Rules:",
3055
3079
  modeLine,
3056
- "- Keep the skill package single-file: only SKILL.md.",
3080
+ "- Keep SKILL.md as the required entry point. Add only scripts, references, assets, or agents/openai.yaml that directly support the workflow.",
3057
3081
  "- SKILL.md must include YAML frontmatter with required name and description fields, followed by a markdown body.",
3058
3082
  "- The body should describe the reusable workflow clearly enough for future chats to apply it.",
3059
- "- Do not add references, scripts, assets, tool dependencies, or setup files. If those are needed, explain that this should be an agent instead.",
3083
+ "- Use scripts for deterministic repeated operations, references for detailed knowledge, and assets for files consumed by outputs.",
3084
+ "- Do not add README, changelog, installation guide, or other auxiliary documentation.",
3060
3085
  "- Validate the resulting file by reading it back and checking name, description, body, and path consistency.",
3061
3086
  "- Report the final skill name, path, validation status, and explicit invocation such as $skill-name only after the file is written or updated.",
3062
3087
  "- Ask only for missing details that materially change the skill.",
@@ -3297,16 +3322,6 @@ async function getOpenPondAccount(baseUrl, token) {
3297
3322
  }
3298
3323
  return await response.json();
3299
3324
  }
3300
- async function getOpenPondAccountBalance(baseUrl, token) {
3301
- const response = await apiFetch(baseUrl, token, "/account/balance", {
3302
- method: "GET"
3303
- });
3304
- if (!response.ok) {
3305
- const text5 = await response.text().catch(() => "");
3306
- throw new Error(`Account balance lookup failed: ${response.status} ${text5}`);
3307
- }
3308
- return await response.json();
3309
- }
3310
3325
  async function checkOpenPondApiHealth(baseUrl, token) {
3311
3326
  const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
3312
3327
  const started = Date.now();
@@ -3543,13 +3558,13 @@ function createSandboxRuntimeHandle(client, runtimeId, initial = null) {
3543
3558
  keepAlive,
3544
3559
  checkpoint: (input) => client.checkpointSandboxRuntime(runtimeId, input),
3545
3560
  files: {
3546
- write: async (path11, contents) => client.uploadFile((await resume()).id, path11, contents),
3547
- read: async (path11) => client.downloadFile((await resume()).id, path11),
3561
+ write: async (path13, contents) => client.uploadFile((await resume()).id, path13, contents),
3562
+ read: async (path13) => client.downloadFile((await resume()).id, path13),
3548
3563
  readResponse: async (input) => client.downloadFileResponse((await resume()).id, input),
3549
3564
  list: async (input = {}) => client.listFiles((await resume()).id, input),
3550
- delete: async (path11, input = {}) => client.deleteFile((await resume()).id, path11, input),
3565
+ delete: async (path13, input = {}) => client.deleteFile((await resume()).id, path13, input),
3551
3566
  search: async (input) => client.searchFiles((await resume()).id, input),
3552
- stat: async (path11) => client.statFile((await resume()).id, path11),
3567
+ stat: async (path13) => client.statFile((await resume()).id, path13),
3553
3568
  mkdir: async (input) => client.mkdir((await resume()).id, input),
3554
3569
  move: async (input) => client.moveFile((await resume()).id, input)
3555
3570
  },
@@ -4053,20 +4068,20 @@ var OpenPondSandboxInstanceClient = class {
4053
4068
  path: `/${encodeURIComponent(sandboxId)}/pty/${encodeURIComponent(ptyId)}/stream${query.size > 0 ? `?${query.toString()}` : ""}`
4054
4069
  });
4055
4070
  }
4056
- uploadFile(sandboxId, path11, contents) {
4057
- return this.uploadFileBase64(sandboxId, path11, Buffer.from(contents, "utf-8").toString("base64"));
4071
+ uploadFile(sandboxId, path13, contents) {
4072
+ return this.uploadFileBase64(sandboxId, path13, Buffer.from(contents, "utf-8").toString("base64"));
4058
4073
  }
4059
- uploadFileBase64(sandboxId, path11, contentsBase64) {
4074
+ uploadFileBase64(sandboxId, path13, contentsBase64) {
4060
4075
  return this.request(`/${encodeURIComponent(sandboxId)}/files`, {
4061
4076
  method: "POST",
4062
4077
  body: JSON.stringify({
4063
- path: path11,
4078
+ path: path13,
4064
4079
  contentsBase64
4065
4080
  })
4066
4081
  });
4067
4082
  }
4068
- async downloadFile(sandboxId, path11) {
4069
- const payload = await this.downloadFileResponse(sandboxId, path11);
4083
+ async downloadFile(sandboxId, path13) {
4084
+ const payload = await this.downloadFileResponse(sandboxId, path13);
4070
4085
  return Buffer.from(payload.file.contentsBase64, "base64").toString("utf-8");
4071
4086
  }
4072
4087
  downloadFileResponse(sandboxId, input) {
@@ -4090,16 +4105,16 @@ var OpenPondSandboxInstanceClient = class {
4090
4105
  query.set("maxEntries", String(input.maxEntries));
4091
4106
  return this.request(`/${encodeURIComponent(sandboxId)}/files?${query.toString()}`);
4092
4107
  }
4093
- deleteFile(sandboxId, path11, input = {}) {
4094
- const query = new URLSearchParams({ path: path11 });
4108
+ deleteFile(sandboxId, path13, input = {}) {
4109
+ const query = new URLSearchParams({ path: path13 });
4095
4110
  if (input.recursive !== void 0)
4096
4111
  query.set("recursive", String(input.recursive));
4097
4112
  return this.request(`/${encodeURIComponent(sandboxId)}/files?${query.toString()}`, {
4098
4113
  method: "DELETE"
4099
4114
  });
4100
4115
  }
4101
- statFile(sandboxId, path11) {
4102
- const query = new URLSearchParams({ stat: "1", path: path11 });
4116
+ statFile(sandboxId, path13) {
4117
+ const query = new URLSearchParams({ stat: "1", path: path13 });
4103
4118
  return this.request(`/${encodeURIComponent(sandboxId)}/files?${query.toString()}`);
4104
4119
  }
4105
4120
  mkdir(sandboxId, input) {
@@ -4275,12 +4290,12 @@ var OpenPondSandboxInstanceClient = class {
4275
4290
  body: JSON.stringify({ leaseId })
4276
4291
  });
4277
4292
  }
4278
- async request(path11, init = {}) {
4279
- const response = await apiFetch(this.sandboxApiUrl, this.apiKey, path11, init);
4293
+ async request(path13, init = {}) {
4294
+ const response = await apiFetch(this.sandboxApiUrl, this.apiKey, path13, init);
4280
4295
  return readApiJson(response, "Sandbox request");
4281
4296
  }
4282
- async requestApiRoot(path11, init = {}) {
4283
- const response = await apiFetch(this.apiRootUrl, this.apiKey, path11, init);
4297
+ async requestApiRoot(path13, init = {}) {
4298
+ const response = await apiFetch(this.apiRootUrl, this.apiKey, path13, init);
4284
4299
  return readApiJson(response, "OpenPond API request");
4285
4300
  }
4286
4301
  };
@@ -5019,8 +5034,841 @@ function responsePayloadData(payload) {
5019
5034
  return null;
5020
5035
  }
5021
5036
 
5037
+ // ../../packages/cloud/dist/extensions/types.js
5038
+ var GithubExtensionError = class extends Error {
5039
+ code;
5040
+ status;
5041
+ constructor(message, options) {
5042
+ super(message);
5043
+ this.name = "GithubExtensionError";
5044
+ this.code = options.code;
5045
+ this.status = options.status ?? 400;
5046
+ }
5047
+ };
5048
+
5049
+ // ../../packages/cloud/dist/extensions/github-source.js
5050
+ import { createHash as createHash3 } from "node:crypto";
5051
+ import path10 from "node:path";
5052
+ var DEFAULT_REF = "HEAD";
5053
+ var MAX_EXTENSION_SKILLS = 64;
5054
+ var MAX_EXTENSION_FILES = 512;
5055
+ var MAX_EXTENSION_BYTES = 20 * 1024 * 1024;
5056
+ var MAX_EXTENSION_FILE_BYTES = 5 * 1024 * 1024;
5057
+ var DOWNLOAD_CONCURRENCY = 8;
5058
+ var SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
5059
+ var GITHUB_REPOSITORY_PATTERN = /^[A-Za-z0-9_.-]+$/;
5060
+ var ROOT_SKILL_RESOURCE_DIRECTORIES = /* @__PURE__ */ new Set(["agents", "assets", "references", "scripts"]);
5061
+ function createGithubSourceClient(options = {}) {
5062
+ const fetchImpl = options.fetch ?? fetch;
5063
+ const githubToken = options.githubToken?.trim() || process.env.GITHUB_TOKEN?.trim() || process.env.GH_TOKEN?.trim() || null;
5064
+ return {
5065
+ async resolve(request) {
5066
+ const source = await resolveSource(request, fetchImpl, githubToken);
5067
+ const preview = await buildPreview(source, fetchImpl, githubToken);
5068
+ return {
5069
+ preview,
5070
+ files: filesToDownload(source)
5071
+ };
5072
+ },
5073
+ async download(resolution, writeFile5) {
5074
+ await downloadFiles({
5075
+ resolution,
5076
+ fetchImpl,
5077
+ githubToken,
5078
+ writeFile: writeFile5
5079
+ });
5080
+ }
5081
+ };
5082
+ }
5083
+ function parseGithubExtensionSource(source) {
5084
+ const trimmed = source.trim();
5085
+ let owner = "";
5086
+ let repo = "";
5087
+ if (/^(?:https?:\/\/)?github\.com\//i.test(trimmed)) {
5088
+ const url = new URL(trimmed.startsWith("http") ? trimmed : `https://${trimmed}`);
5089
+ if (url.hostname.toLowerCase() !== "github.com") {
5090
+ throw invalidSource(source);
5091
+ }
5092
+ const segments = url.pathname.replace(/^\/+|\/+$/g, "").split("/");
5093
+ if (segments.length !== 2)
5094
+ throw invalidSource(source);
5095
+ [owner = "", repo = ""] = segments;
5096
+ } else {
5097
+ const normalized = trimmed.replace(/^github:/i, "").replace(/^\/+|\/+$/g, "");
5098
+ const segments = normalized.split("/");
5099
+ if (segments.length !== 2)
5100
+ throw invalidSource(source);
5101
+ [owner = "", repo = ""] = segments;
5102
+ }
5103
+ repo = repo.replace(/\.git$/i, "");
5104
+ if (!GITHUB_REPOSITORY_PATTERN.test(owner) || !GITHUB_REPOSITORY_PATTERN.test(repo)) {
5105
+ throw invalidSource(source);
5106
+ }
5107
+ const normalizedOwner = owner.toLowerCase();
5108
+ const normalizedRepo = repo.toLowerCase();
5109
+ return {
5110
+ id: `github:${normalizedOwner}/${normalizedRepo}`,
5111
+ owner: normalizedOwner,
5112
+ repo: normalizedRepo,
5113
+ repositoryUrl: `https://github.com/${normalizedOwner}/${normalizedRepo}`
5114
+ };
5115
+ }
5116
+ async function resolveSource(request, fetchImpl, githubToken) {
5117
+ const identity = parseGithubExtensionSource(request.source);
5118
+ const requestedRef = request.ref?.trim() || DEFAULT_REF;
5119
+ const repository = await githubJson(fetchImpl, githubToken, `/repos/${identity.owner}/${identity.repo}`);
5120
+ const resolvedRef = requestedRef === DEFAULT_REF ? repository.default_branch?.trim() || "main" : requestedRef;
5121
+ const commit = await githubJson(fetchImpl, githubToken, `/repos/${identity.owner}/${identity.repo}/commits/${encodeURIComponent(resolvedRef)}`);
5122
+ const resolvedCommit = commit.sha?.trim();
5123
+ const treeSha = commit.commit?.tree?.sha?.trim();
5124
+ if (!resolvedCommit || !treeSha) {
5125
+ throw new GithubExtensionError("GitHub returned an incomplete commit response.", {
5126
+ code: "github_invalid_commit",
5127
+ status: 502
5128
+ });
5129
+ }
5130
+ const treePayload = await githubJson(fetchImpl, githubToken, `/repos/${identity.owner}/${identity.repo}/git/trees/${treeSha}?recursive=1`);
5131
+ if (treePayload.truncated) {
5132
+ throw new GithubExtensionError("The GitHub repository tree is too large to install safely.", {
5133
+ code: "github_tree_truncated"
5134
+ });
5135
+ }
5136
+ const tree = (treePayload.tree ?? []).filter(validTreeEntry);
5137
+ const skillPackages = discoverSkillPackages(tree);
5138
+ if (skillPackages.length === 0) {
5139
+ throw new GithubExtensionError("No skills found. Add SKILL.md at the repository root or use a standard agent skills directory.", { code: "extension_no_skills" });
5140
+ }
5141
+ if (skillPackages.length > MAX_EXTENSION_SKILLS) {
5142
+ throw new GithubExtensionError(`Extension contains more than ${MAX_EXTENSION_SKILLS} skills.`, {
5143
+ code: "extension_too_many_skills"
5144
+ });
5145
+ }
5146
+ validateDownloadLimits(skillPackages);
5147
+ const readme = tree.find((entry) => entry.type === "blob" && /^readme(?:\.[^/]+)?$/i.test(entry.path)) ?? null;
5148
+ return { identity, requestedRef, resolvedCommit, tree, skillPackages, readme };
5149
+ }
5150
+ async function buildPreview(source, fetchImpl, githubToken) {
5151
+ const skills = await mapConcurrent(source.skillPackages, DOWNLOAD_CONCURRENCY, async (skillPackage) => {
5152
+ const contents = await downloadText(source, skillPackage.entry, fetchImpl, githubToken);
5153
+ return previewSkill(skillPackage, contents);
5154
+ });
5155
+ const duplicateNames = duplicateValues(skills.map((skill) => skill.name));
5156
+ for (const skill of skills) {
5157
+ if (!duplicateNames.has(skill.name))
5158
+ continue;
5159
+ skill.validationStatus = "error";
5160
+ skill.validationMessages = [...skill.validationMessages, `Duplicate skill name: ${skill.name}`];
5161
+ }
5162
+ const validationMessages = skills.flatMap((skill) => skill.validationMessages.map((message) => `${skill.relativePath}: ${message}`));
5163
+ const packageFiles = filesToDownload(source);
5164
+ return {
5165
+ ...source.identity,
5166
+ source: "github",
5167
+ requestedRef: source.requestedRef,
5168
+ resolvedCommit: source.resolvedCommit,
5169
+ sourcePath: null,
5170
+ readmePath: source.readme?.path ?? null,
5171
+ packageHash: hashTree(packageFiles),
5172
+ skills: skills.sort((left, right) => left.name.localeCompare(right.name)),
5173
+ validationStatus: validationMessages.length === 0 ? "valid" : "error",
5174
+ validationMessages
5175
+ };
5176
+ }
5177
+ function previewSkill(skillPackage, contents) {
5178
+ const parsed = parseProfileSkillMarkdown(contents);
5179
+ const directoryName = skillPackage.root === "." ? null : path10.posix.basename(skillPackage.root);
5180
+ const name = parsed.name ?? directoryName ?? "invalid-skill";
5181
+ const messages = [...parsed.messages];
5182
+ if (!SKILL_NAME_PATTERN.test(name))
5183
+ messages.push("Skill name must be lowercase kebab-case.");
5184
+ if (directoryName && name !== directoryName) {
5185
+ messages.push(`Skill name must match its directory name (${directoryName}).`);
5186
+ }
5187
+ const resourceFiles = skillPackage.files.filter((file) => file.path !== skillPackage.entry.path).map((file) => relativeSkillPath(skillPackage.root, file.path)).sort();
5188
+ return {
5189
+ name,
5190
+ description: parsed.description ?? "",
5191
+ relativePath: skillPackage.root === "." ? "SKILL.md" : `${skillPackage.root}/SKILL.md`,
5192
+ sourcePath: "",
5193
+ charCount: contents.length,
5194
+ sourceHash: createHash3("sha256").update(contents).digest("hex"),
5195
+ resourceFiles,
5196
+ validationStatus: messages.length === 0 ? "valid" : "error",
5197
+ validationMessages: [...new Set(messages)]
5198
+ };
5199
+ }
5200
+ function discoverSkillPackages(tree) {
5201
+ const entries = [];
5202
+ const rootEntry = tree.find((entry) => entry.type === "blob" && entry.path === "SKILL.md");
5203
+ if (rootEntry)
5204
+ entries.push({ root: ".", entry: rootEntry });
5205
+ const skillEntries = tree.filter((entry) => entry.type === "blob" && entry.path.endsWith("/SKILL.md"));
5206
+ const standardEntries = skillEntries.filter((entry) => isStandardAgentSkillsPath(entry.path));
5207
+ const discoveredEntries = standardEntries.length > 0 ? standardEntries : skillEntries;
5208
+ const roots = new Set(discoveredEntries.map((entry) => path10.posix.dirname(entry.path)));
5209
+ for (const entry of discoveredEntries) {
5210
+ const root = path10.posix.dirname(entry.path);
5211
+ if ([...roots].some((candidate) => candidate !== root && root.startsWith(`${candidate}/`)))
5212
+ continue;
5213
+ entries.push({ root, entry });
5214
+ }
5215
+ return entries.map(({ root, entry }) => {
5216
+ const files = tree.filter((candidate) => {
5217
+ if (candidate.type !== "blob")
5218
+ return false;
5219
+ if (root !== ".")
5220
+ return candidate.path.startsWith(`${root}/`);
5221
+ if (candidate.path === "SKILL.md")
5222
+ return true;
5223
+ const firstSegment = candidate.path.split("/", 1)[0] ?? "";
5224
+ return ROOT_SKILL_RESOURCE_DIRECTORIES.has(firstSegment);
5225
+ });
5226
+ const unsafe = tree.find((candidate) => candidate.type !== "blob" && candidate.type !== "tree" && (root === "." ? candidate.path === "SKILL.md" || ROOT_SKILL_RESOURCE_DIRECTORIES.has(candidate.path.split("/", 1)[0] ?? "") : candidate.path.startsWith(`${root}/`)));
5227
+ const symlink2 = files.find((candidate) => candidate.mode === "120000");
5228
+ if (unsafe || symlink2) {
5229
+ throw new GithubExtensionError(`Skill package ${root} contains a symlink or submodule.`, {
5230
+ code: "extension_unsafe_entry"
5231
+ });
5232
+ }
5233
+ return { root, entry, files };
5234
+ });
5235
+ }
5236
+ function isStandardAgentSkillsPath(skillPath) {
5237
+ const segments = skillPath.split("/");
5238
+ if (segments.at(-1) !== "SKILL.md")
5239
+ return false;
5240
+ const skillDirectorySegments = segments.slice(0, -1);
5241
+ if (skillDirectorySegments.length < 2)
5242
+ return false;
5243
+ const skillsIndex = skillDirectorySegments.lastIndexOf("skills");
5244
+ if (skillsIndex < 0 || skillsIndex > 2)
5245
+ return false;
5246
+ const containerPrefix = skillDirectorySegments.slice(0, skillsIndex);
5247
+ const nestedSkillPath = skillDirectorySegments.slice(skillsIndex + 1);
5248
+ if (nestedSkillPath.length < 1 || nestedSkillPath.length > 2)
5249
+ return false;
5250
+ if (skillsIndex === 0)
5251
+ return true;
5252
+ const first = containerPrefix[0] ?? "";
5253
+ return first.startsWith(".") || first === "agent" || first === "data";
5254
+ }
5255
+ function filesToDownload(source) {
5256
+ const byPath = /* @__PURE__ */ new Map();
5257
+ if (source.readme)
5258
+ byPath.set(source.readme.path, source.readme);
5259
+ for (const skillPackage of source.skillPackages) {
5260
+ for (const file of skillPackage.files)
5261
+ byPath.set(file.path, file);
5262
+ }
5263
+ return [...byPath.values()].sort((left, right) => left.path.localeCompare(right.path));
5264
+ }
5265
+ async function downloadFiles(input) {
5266
+ let downloadedBytes = 0;
5267
+ await mapConcurrent(input.resolution.files, DOWNLOAD_CONCURRENCY, async (file) => {
5268
+ const bytes = await downloadBytes({
5269
+ owner: input.resolution.preview.owner,
5270
+ repo: input.resolution.preview.repo,
5271
+ commit: input.resolution.preview.resolvedCommit,
5272
+ file,
5273
+ fetchImpl: input.fetchImpl,
5274
+ githubToken: input.githubToken
5275
+ });
5276
+ downloadedBytes += bytes.byteLength;
5277
+ if (downloadedBytes > MAX_EXTENSION_BYTES) {
5278
+ throw new GithubExtensionError("Extension download exceeds the maximum allowed size.", {
5279
+ code: "extension_too_large"
5280
+ });
5281
+ }
5282
+ await input.writeFile(file.path, bytes, file.mode === "100755");
5283
+ });
5284
+ }
5285
+ async function downloadText(source, file, fetchImpl, githubToken) {
5286
+ const bytes = await downloadBytes({
5287
+ owner: source.identity.owner,
5288
+ repo: source.identity.repo,
5289
+ commit: source.resolvedCommit,
5290
+ file,
5291
+ fetchImpl,
5292
+ githubToken
5293
+ });
5294
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
5295
+ }
5296
+ async function downloadBytes(input) {
5297
+ const encodedPath = input.file.path.split("/").map(encodeURIComponent).join("/");
5298
+ const url = `https://raw.githubusercontent.com/${input.owner}/${input.repo}/${input.commit}/${encodedPath}`;
5299
+ const response = await input.fetchImpl(url, {
5300
+ headers: githubHeaders(input.githubToken, "application/vnd.github.raw"),
5301
+ redirect: "follow"
5302
+ });
5303
+ if (!response.ok) {
5304
+ throw new GithubExtensionError(`GitHub file download failed (${response.status}): ${input.file.path}`, {
5305
+ code: "github_download_failed",
5306
+ status: response.status
5307
+ });
5308
+ }
5309
+ const contentLength = Number(response.headers.get("content-length"));
5310
+ if (Number.isFinite(contentLength) && contentLength > MAX_EXTENSION_FILE_BYTES) {
5311
+ throw new GithubExtensionError(`Extension file is too large: ${input.file.path}`, {
5312
+ code: "extension_file_too_large"
5313
+ });
5314
+ }
5315
+ const bytes = new Uint8Array(await response.arrayBuffer());
5316
+ if (bytes.byteLength > MAX_EXTENSION_FILE_BYTES) {
5317
+ throw new GithubExtensionError(`Extension file is too large: ${input.file.path}`, {
5318
+ code: "extension_file_too_large"
5319
+ });
5320
+ }
5321
+ return bytes;
5322
+ }
5323
+ async function githubJson(fetchImpl, githubToken, pathname) {
5324
+ const response = await fetchImpl(`https://api.github.com${pathname}`, {
5325
+ headers: githubHeaders(githubToken, "application/vnd.github+json")
5326
+ });
5327
+ if (!response.ok) {
5328
+ const details = await response.json().catch(() => null);
5329
+ const detail = typeof details?.message === "string" ? `: ${details.message}` : "";
5330
+ throw new GithubExtensionError(`GitHub request failed (${response.status})${detail}`, {
5331
+ code: response.status === 404 ? "github_repository_not_found" : "github_request_failed",
5332
+ status: response.status
5333
+ });
5334
+ }
5335
+ return await response.json();
5336
+ }
5337
+ function githubHeaders(token, accept) {
5338
+ const headers = new Headers({
5339
+ Accept: accept,
5340
+ "User-Agent": "openpond-extension-installer",
5341
+ "X-GitHub-Api-Version": "2022-11-28"
5342
+ });
5343
+ if (token)
5344
+ headers.set("Authorization", `Bearer ${token}`);
5345
+ return headers;
5346
+ }
5347
+ function validateDownloadLimits(skillPackages) {
5348
+ const files = /* @__PURE__ */ new Map();
5349
+ for (const skillPackage of skillPackages) {
5350
+ for (const file of skillPackage.files)
5351
+ files.set(file.path, file);
5352
+ }
5353
+ if (files.size > MAX_EXTENSION_FILES) {
5354
+ throw new GithubExtensionError(`Extension contains more than ${MAX_EXTENSION_FILES} skill files.`, {
5355
+ code: "extension_too_many_files"
5356
+ });
5357
+ }
5358
+ let totalBytes = 0;
5359
+ for (const file of files.values()) {
5360
+ if ((file.size ?? 0) > MAX_EXTENSION_FILE_BYTES) {
5361
+ throw new GithubExtensionError(`Extension file is too large: ${file.path}`, {
5362
+ code: "extension_file_too_large"
5363
+ });
5364
+ }
5365
+ totalBytes += file.size ?? 0;
5366
+ }
5367
+ if (totalBytes > MAX_EXTENSION_BYTES) {
5368
+ throw new GithubExtensionError("Extension exceeds the maximum allowed size.", {
5369
+ code: "extension_too_large"
5370
+ });
5371
+ }
5372
+ }
5373
+ function validTreeEntry(value) {
5374
+ if (!value || typeof value !== "object")
5375
+ return false;
5376
+ const entry = value;
5377
+ return typeof entry.path === "string" && !entry.path.startsWith("/") && !entry.path.split("/").includes("..") && typeof entry.mode === "string" && (entry.type === "blob" || entry.type === "tree" || entry.type === "commit") && typeof entry.sha === "string";
5378
+ }
5379
+ function hashTree(files) {
5380
+ const hash = createHash3("sha256");
5381
+ for (const file of files)
5382
+ hash.update(`${file.path}\0${file.sha}\0${file.size ?? ""}
5383
+ `);
5384
+ return hash.digest("hex");
5385
+ }
5386
+ function relativeSkillPath(root, filePath) {
5387
+ return root === "." ? filePath : filePath.slice(root.length + 1);
5388
+ }
5389
+ function duplicateValues(values) {
5390
+ const seen = /* @__PURE__ */ new Set();
5391
+ const duplicates = /* @__PURE__ */ new Set();
5392
+ for (const value of values) {
5393
+ if (seen.has(value))
5394
+ duplicates.add(value);
5395
+ seen.add(value);
5396
+ }
5397
+ return duplicates;
5398
+ }
5399
+ async function mapConcurrent(values, concurrency, mapper) {
5400
+ const results = new Array(values.length);
5401
+ let nextIndex = 0;
5402
+ async function worker() {
5403
+ while (nextIndex < values.length) {
5404
+ const index = nextIndex;
5405
+ nextIndex += 1;
5406
+ results[index] = await mapper(values[index]);
5407
+ }
5408
+ }
5409
+ await Promise.all(Array.from({ length: Math.min(concurrency, values.length) }, worker));
5410
+ return results;
5411
+ }
5412
+ function invalidSource(source) {
5413
+ return new GithubExtensionError(`Invalid GitHub extension source: ${source}. Use owner/repo or https://github.com/owner/repo.`, { code: "github_invalid_source" });
5414
+ }
5415
+
5416
+ // ../../packages/cloud/dist/extensions/extension-manager.js
5417
+ import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
5418
+ import { existsSync as existsSync6 } from "node:fs";
5419
+ import { mkdir as mkdir2, readFile as readFile6, rename, rm, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
5420
+ import path11 from "node:path";
5421
+ var REGISTRY_SCHEMA_VERSION = 1;
5422
+ var OPERATION_LOCK_STALE_MS = 2 * 60 * 1e3;
5423
+ var OPERATION_LOCK_TIMEOUT_MS = 15e3;
5424
+ function createGithubExtensionManager(options = {}) {
5425
+ const rootPath = path11.resolve(options.rootPath ?? path11.join(openPondConfigDirectory(), "extensions"));
5426
+ const registryPath = path11.join(rootPath, "registry.json");
5427
+ const github = createGithubSourceClient({
5428
+ fetch: options.fetch,
5429
+ githubToken: options.githubToken
5430
+ });
5431
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
5432
+ async function list() {
5433
+ try {
5434
+ const registry = await readRegistry(registryPath);
5435
+ const extensions = await Promise.all(registry.extensions.map((extension) => hydrateExtension(rootPath, extension)));
5436
+ markInstalledSkillConflicts(extensions, await reservedSkillNames(options.reservedSkillNames));
5437
+ return {
5438
+ rootPath,
5439
+ registryPath,
5440
+ extensions: extensions.sort(extensionSort),
5441
+ error: null
5442
+ };
5443
+ } catch (error) {
5444
+ return {
5445
+ rootPath,
5446
+ registryPath,
5447
+ extensions: [],
5448
+ error: error instanceof Error ? error.message : String(error)
5449
+ };
5450
+ }
5451
+ }
5452
+ async function preview(request) {
5453
+ const resolution = await github.resolve(request);
5454
+ const registry = await readRegistry(registryPath);
5455
+ const existing = registry.extensions.find((extension) => extension.id === resolution.preview.id) ?? null;
5456
+ assertSkillNamesAvailable(resolution.preview, registry.extensions.filter((extension) => extension.id !== existing?.id), await reservedSkillNames(options.reservedSkillNames));
5457
+ return resolution.preview;
5458
+ }
5459
+ async function add(request) {
5460
+ const identity = parseGithubExtensionSource(request.source);
5461
+ return withExtensionLock(rootPath, identity.id, async () => {
5462
+ const registry = await readRegistry(registryPath);
5463
+ if (registry.extensions.some((extension) => extension.id === identity.id)) {
5464
+ throw new GithubExtensionError(`${identity.owner}/${identity.repo} is already installed.`, {
5465
+ code: "extension_already_installed",
5466
+ status: 409
5467
+ });
5468
+ }
5469
+ const resolution = await github.resolve(request);
5470
+ assertInstallable(resolution.preview);
5471
+ assertSkillNamesAvailable(resolution.preview, registry.extensions, await reservedSkillNames(options.reservedSkillNames));
5472
+ const timestamp = now().toISOString();
5473
+ const installed = await materializeExtension({
5474
+ rootPath,
5475
+ resolution,
5476
+ installedAt: timestamp,
5477
+ updatedAt: timestamp,
5478
+ github
5479
+ });
5480
+ try {
5481
+ const reserved = await reservedSkillNames(options.reservedSkillNames);
5482
+ await writeRegistry(registryPath, now, (current) => ({
5483
+ ...current,
5484
+ extensions: appendInstalledExtension(current, installed, reserved)
5485
+ }));
5486
+ await finalizeMaterialization(rootPath, installed.id);
5487
+ return installed;
5488
+ } catch (error) {
5489
+ await rollbackMaterialization(rootPath, installed.id);
5490
+ throw error;
5491
+ }
5492
+ });
5493
+ }
5494
+ async function update(request) {
5495
+ const identity = parseGithubExtensionSource(request.source);
5496
+ return withExtensionLock(rootPath, identity.id, async () => {
5497
+ const registry = await readRegistry(registryPath);
5498
+ const existing = requireInstalled(registry, identity.id);
5499
+ const resolution = await github.resolve({
5500
+ source: existing.repositoryUrl,
5501
+ ref: request.ref?.trim() || existing.requestedRef
5502
+ });
5503
+ assertInstallable(resolution.preview);
5504
+ assertSkillNamesAvailable(resolution.preview, registry.extensions.filter((extension) => extension.id !== existing.id), await reservedSkillNames(options.reservedSkillNames));
5505
+ if (existing.resolvedCommit === resolution.preview.resolvedCommit && existing.packageHash === resolution.preview.packageHash && existing.requestedRef === resolution.preview.requestedRef) {
5506
+ return hydrateExtension(rootPath, existing);
5507
+ }
5508
+ const installed = await materializeExtension({
5509
+ rootPath,
5510
+ resolution,
5511
+ installedAt: existing.installedAt,
5512
+ updatedAt: now().toISOString(),
5513
+ github
5514
+ });
5515
+ try {
5516
+ const reserved = await reservedSkillNames(options.reservedSkillNames);
5517
+ await writeRegistry(registryPath, now, (current) => ({
5518
+ ...current,
5519
+ extensions: replaceInstalledExtension(current, installed, reserved)
5520
+ }));
5521
+ await finalizeMaterialization(rootPath, installed.id);
5522
+ return installed;
5523
+ } catch (error) {
5524
+ await rollbackMaterialization(rootPath, installed.id);
5525
+ throw error;
5526
+ }
5527
+ });
5528
+ }
5529
+ async function updateAll() {
5530
+ const catalog = await list();
5531
+ if (catalog.error)
5532
+ throw new GithubExtensionError(catalog.error, { code: "extension_registry_error" });
5533
+ const result = { updated: [], unchanged: [], failed: [] };
5534
+ for (const extension of catalog.extensions) {
5535
+ try {
5536
+ const next = await update({ source: extension.repositoryUrl, ref: extension.requestedRef });
5537
+ if (next.resolvedCommit === extension.resolvedCommit && next.packageHash === extension.packageHash) {
5538
+ result.unchanged.push(next);
5539
+ } else {
5540
+ result.updated.push(next);
5541
+ }
5542
+ } catch (error) {
5543
+ result.failed.push({
5544
+ id: extension.id,
5545
+ error: error instanceof Error ? error.message : String(error)
5546
+ });
5547
+ }
5548
+ }
5549
+ return result;
5550
+ }
5551
+ async function inspect(source) {
5552
+ const identity = parseGithubExtensionSource(source);
5553
+ const registry = await readRegistry(registryPath);
5554
+ return hydrateExtension(rootPath, requireInstalled(registry, identity.id));
5555
+ }
5556
+ async function remove(source) {
5557
+ const identity = parseGithubExtensionSource(source);
5558
+ return withExtensionLock(rootPath, identity.id, async () => {
5559
+ const registry = await readRegistry(registryPath);
5560
+ const existing = requireInstalled(registry, identity.id);
5561
+ const target = extensionDirectory(rootPath, identity.owner, identity.repo);
5562
+ const trash = `${target}.${randomUUID3()}.remove`;
5563
+ if (existsSync6(target))
5564
+ await rename(target, trash);
5565
+ try {
5566
+ await writeRegistry(registryPath, now, (current) => ({
5567
+ ...current,
5568
+ extensions: current.extensions.filter((extension) => extension.id !== existing.id)
5569
+ }));
5570
+ await rm(trash, { recursive: true, force: true });
5571
+ return existing;
5572
+ } catch (error) {
5573
+ if (existsSync6(trash) && !existsSync6(target))
5574
+ await rename(trash, target);
5575
+ throw error;
5576
+ }
5577
+ });
5578
+ }
5579
+ async function readSkill(nameInput) {
5580
+ const name = nameInput.trim();
5581
+ if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name)) {
5582
+ throw new GithubExtensionError("Extension skill name must be lowercase kebab-case.", {
5583
+ code: "extension_skill_invalid_name"
5584
+ });
5585
+ }
5586
+ const catalog = await list();
5587
+ if (catalog.error) {
5588
+ throw new GithubExtensionError(catalog.error, { code: "extension_registry_error" });
5589
+ }
5590
+ const matches = catalog.extensions.flatMap((extension) => extension.skills.filter((skill) => skill.name === name).map((skill) => ({ extension, skill })));
5591
+ if (matches.length === 0) {
5592
+ throw new GithubExtensionError(`Extension skill not found: ${name}`, {
5593
+ code: "extension_skill_not_found",
5594
+ status: 404
5595
+ });
5596
+ }
5597
+ if (matches.length > 1) {
5598
+ throw new GithubExtensionError(`Extension skill name is ambiguous: ${name}`, {
5599
+ code: "extension_skill_conflict",
5600
+ status: 409
5601
+ });
5602
+ }
5603
+ const match = matches[0];
5604
+ if (match.extension.validationStatus !== "valid" || match.skill.validationStatus !== "valid") {
5605
+ throw new GithubExtensionError(`Extension skill ${name} is not valid.`, {
5606
+ code: "extension_skill_invalid"
5607
+ });
5608
+ }
5609
+ const absolutePath = safeDestination(match.extension.sourcePath, match.skill.relativePath);
5610
+ const markdown = await readFile6(absolutePath, "utf8");
5611
+ const sourceHash = createHash4("sha256").update(markdown).digest("hex");
5612
+ if (sourceHash !== match.skill.sourceHash) {
5613
+ throw new GithubExtensionError(`Extension skill ${name} changed on disk. Update or reinstall its extension before using it.`, { code: "extension_skill_modified" });
5614
+ }
5615
+ const parsed = parseProfileSkillMarkdown(markdown);
5616
+ if (parsed.messages.length > 0 || parsed.name !== name || !parsed.description) {
5617
+ throw new GithubExtensionError(`Extension skill ${name} is not valid. ${parsed.messages.join(" ")}`.trim(), { code: "extension_skill_invalid" });
5618
+ }
5619
+ return {
5620
+ name,
5621
+ description: parsed.description,
5622
+ body: parsed.body,
5623
+ path: match.skill.relativePath,
5624
+ sourcePath: match.extension.sourcePath,
5625
+ sourceHash,
5626
+ charCount: markdown.length,
5627
+ packagePath: path11.dirname(absolutePath),
5628
+ resourceFiles: match.skill.resourceFiles
5629
+ };
5630
+ }
5631
+ return { rootPath, registryPath, list, preview, add, update, updateAll, inspect, remove, readSkill };
5632
+ }
5633
+ async function materializeExtension(input) {
5634
+ const preview = input.resolution.preview;
5635
+ const target = extensionDirectory(input.rootPath, preview.owner, preview.repo);
5636
+ const temporary = `${target}.${randomUUID3()}.install`;
5637
+ const backup = backupDirectory(input.rootPath, preview.id);
5638
+ const current = path11.join(temporary, "current");
5639
+ await rm(temporary, { recursive: true, force: true });
5640
+ await rm(backup, { recursive: true, force: true });
5641
+ await mkdir2(current, { recursive: true, mode: 448 });
5642
+ try {
5643
+ await input.github.download(input.resolution, async (relativePath, bytes, executable) => {
5644
+ const destination = safeDestination(current, relativePath);
5645
+ await mkdir2(path11.dirname(destination), { recursive: true, mode: 448 });
5646
+ await writeFile3(destination, bytes, { mode: executable ? 448 : 384 });
5647
+ });
5648
+ const extension = installedExtension(preview, target, input.installedAt, input.updatedAt);
5649
+ await writeFile3(path11.join(temporary, "extension.json"), `${JSON.stringify(extension, null, 2)}
5650
+ `, { mode: 384 });
5651
+ await mkdir2(path11.dirname(target), { recursive: true, mode: 448 });
5652
+ if (existsSync6(target))
5653
+ await rename(target, backup);
5654
+ await rename(temporary, target);
5655
+ return extension;
5656
+ } catch (error) {
5657
+ await rm(temporary, { recursive: true, force: true });
5658
+ if (existsSync6(backup) && !existsSync6(target))
5659
+ await rename(backup, target);
5660
+ throw error;
5661
+ }
5662
+ }
5663
+ function installedExtension(preview, target, installedAt, updatedAt) {
5664
+ const sourcePath = path11.join(target, "current");
5665
+ return {
5666
+ ...preview,
5667
+ sourcePath,
5668
+ readmePath: preview.readmePath ? path11.join(sourcePath, preview.readmePath) : null,
5669
+ installedAt,
5670
+ updatedAt,
5671
+ skills: preview.skills.map((skill) => ({
5672
+ ...skill,
5673
+ sourcePath: path11.join(sourcePath, skill.relativePath)
5674
+ }))
5675
+ };
5676
+ }
5677
+ async function finalizeMaterialization(rootPath, id) {
5678
+ await rm(backupDirectory(rootPath, id), { recursive: true, force: true });
5679
+ }
5680
+ async function rollbackMaterialization(rootPath, id) {
5681
+ const identity = parseGithubExtensionSource(id.replace(/^github:/, ""));
5682
+ const target = extensionDirectory(rootPath, identity.owner, identity.repo);
5683
+ const backup = backupDirectory(rootPath, id);
5684
+ await rm(target, { recursive: true, force: true });
5685
+ if (existsSync6(backup))
5686
+ await rename(backup, target);
5687
+ }
5688
+ async function hydrateExtension(rootPath, extension) {
5689
+ const target = extensionDirectory(rootPath, extension.owner, extension.repo);
5690
+ const sourcePath = path11.join(target, "current");
5691
+ const present = (await stat4(path11.join(target, "extension.json")).catch(() => null))?.isFile() ?? false;
5692
+ const validationMessages = extension.validationMessages.filter((message) => message !== "Installed files are missing.");
5693
+ if (!present)
5694
+ validationMessages.push("Installed files are missing.");
5695
+ return {
5696
+ ...extension,
5697
+ sourcePath,
5698
+ readmePath: extension.readmePath ? path11.join(sourcePath, path11.basename(extension.readmePath)) : null,
5699
+ skills: extension.skills.map((skill) => ({
5700
+ ...skill,
5701
+ sourcePath: path11.join(sourcePath, skill.relativePath)
5702
+ })),
5703
+ validationStatus: validationMessages.length === 0 ? "valid" : "error",
5704
+ validationMessages
5705
+ };
5706
+ }
5707
+ function assertInstallable(preview) {
5708
+ if (preview.validationStatus === "valid")
5709
+ return;
5710
+ throw new GithubExtensionError(`Extension contains invalid skills: ${preview.validationMessages.join(" ")}`, { code: "extension_invalid" });
5711
+ }
5712
+ function assertSkillNamesAvailable(preview, installed, reserved) {
5713
+ const owners = /* @__PURE__ */ new Map();
5714
+ for (const name of reserved)
5715
+ owners.set(name, "a shipped OpenPond skill");
5716
+ for (const extension of installed) {
5717
+ for (const skill of extension.skills)
5718
+ owners.set(skill.name, extension.id);
5719
+ }
5720
+ const conflicts = preview.skills.map((skill) => ({ name: skill.name, owner: owners.get(skill.name) })).filter((entry) => Boolean(entry.owner));
5721
+ if (conflicts.length === 0)
5722
+ return;
5723
+ throw new GithubExtensionError(`Skill name conflict: ${conflicts.map((entry) => `${entry.name} (${entry.owner})`).join(", ")}.`, { code: "extension_skill_conflict", status: 409 });
5724
+ }
5725
+ function appendInstalledExtension(registry, installed, reserved) {
5726
+ if (registry.extensions.some((extension) => extension.id === installed.id)) {
5727
+ throw new GithubExtensionError(`${installed.owner}/${installed.repo} is already installed.`, {
5728
+ code: "extension_already_installed",
5729
+ status: 409
5730
+ });
5731
+ }
5732
+ assertSkillNamesAvailable(installed, registry.extensions, reserved);
5733
+ return [...registry.extensions, installed].sort(extensionSort);
5734
+ }
5735
+ function replaceInstalledExtension(registry, installed, reserved) {
5736
+ requireInstalled(registry, installed.id);
5737
+ assertSkillNamesAvailable(installed, registry.extensions.filter((extension) => extension.id !== installed.id), reserved);
5738
+ return registry.extensions.map((extension) => extension.id === installed.id ? installed : extension).sort(extensionSort);
5739
+ }
5740
+ function markInstalledSkillConflicts(extensions, reserved) {
5741
+ const owners = /* @__PURE__ */ new Map();
5742
+ for (const name of reserved)
5743
+ owners.set(name, "built-in");
5744
+ for (const extension of extensions) {
5745
+ for (const skill of extension.skills) {
5746
+ const owner = owners.get(skill.name);
5747
+ if (!owner) {
5748
+ owners.set(skill.name, extension.id);
5749
+ continue;
5750
+ }
5751
+ const message = `Skill name conflicts with ${owner}: ${skill.name}`;
5752
+ skill.validationStatus = "error";
5753
+ skill.validationMessages = [.../* @__PURE__ */ new Set([...skill.validationMessages, message])];
5754
+ extension.validationStatus = "error";
5755
+ extension.validationMessages = [.../* @__PURE__ */ new Set([...extension.validationMessages, message])];
5756
+ }
5757
+ }
5758
+ }
5759
+ async function reservedSkillNames(source) {
5760
+ const values = typeof source === "function" ? await source() : source ?? [];
5761
+ return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
5762
+ }
5763
+ function requireInstalled(registry, id) {
5764
+ const extension = registry.extensions.find((candidate) => candidate.id === id);
5765
+ if (extension)
5766
+ return extension;
5767
+ throw new GithubExtensionError(`${id.replace(/^github:/, "")} is not installed.`, {
5768
+ code: "extension_not_installed",
5769
+ status: 404
5770
+ });
5771
+ }
5772
+ async function readRegistry(registryPath) {
5773
+ try {
5774
+ const parsed = JSON.parse(await readFile6(registryPath, "utf8"));
5775
+ if (parsed.schemaVersion !== REGISTRY_SCHEMA_VERSION || !Array.isArray(parsed.extensions)) {
5776
+ throw new Error("Extension registry has an unsupported format.");
5777
+ }
5778
+ return {
5779
+ schemaVersion: REGISTRY_SCHEMA_VERSION,
5780
+ updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : null,
5781
+ extensions: parsed.extensions.filter(isStoredExtension)
5782
+ };
5783
+ } catch (error) {
5784
+ if (error.code === "ENOENT")
5785
+ return emptyRegistry();
5786
+ throw error;
5787
+ }
5788
+ }
5789
+ async function writeRegistry(registryPath, now, update) {
5790
+ await updatePrivateJsonFile(registryPath, emptyRegistry, (current) => ({
5791
+ ...update(normalizeRegistry(current)),
5792
+ schemaVersion: REGISTRY_SCHEMA_VERSION,
5793
+ updatedAt: now().toISOString()
5794
+ }));
5795
+ }
5796
+ function normalizeRegistry(value) {
5797
+ return {
5798
+ schemaVersion: REGISTRY_SCHEMA_VERSION,
5799
+ updatedAt: typeof value?.updatedAt === "string" ? value.updatedAt : null,
5800
+ extensions: Array.isArray(value?.extensions) ? value.extensions.filter(isStoredExtension) : []
5801
+ };
5802
+ }
5803
+ function emptyRegistry() {
5804
+ return { schemaVersion: REGISTRY_SCHEMA_VERSION, updatedAt: null, extensions: [] };
5805
+ }
5806
+ function isStoredExtension(value) {
5807
+ if (!value || typeof value !== "object")
5808
+ return false;
5809
+ const extension = value;
5810
+ return extension.source === "github" && typeof extension.id === "string" && typeof extension.owner === "string" && typeof extension.repo === "string" && typeof extension.repositoryUrl === "string" && typeof extension.requestedRef === "string" && typeof extension.resolvedCommit === "string" && Array.isArray(extension.skills);
5811
+ }
5812
+ function safeDestination(root, relativePath) {
5813
+ if (path11.isAbsolute(relativePath) || relativePath.split(/[\\/]/).includes("..")) {
5814
+ throw new GithubExtensionError(`Unsafe extension path: ${relativePath}`, {
5815
+ code: "extension_unsafe_path"
5816
+ });
5817
+ }
5818
+ const destination = path11.resolve(root, ...relativePath.split("/"));
5819
+ const prefix = `${path11.resolve(root)}${path11.sep}`;
5820
+ if (!destination.startsWith(prefix)) {
5821
+ throw new GithubExtensionError(`Unsafe extension path: ${relativePath}`, {
5822
+ code: "extension_unsafe_path"
5823
+ });
5824
+ }
5825
+ return destination;
5826
+ }
5827
+ function extensionDirectory(rootPath, owner, repo) {
5828
+ return path11.join(rootPath, "github", owner, repo);
5829
+ }
5830
+ function backupDirectory(rootPath, id) {
5831
+ const identity = parseGithubExtensionSource(id.replace(/^github:/, ""));
5832
+ return `${extensionDirectory(rootPath, identity.owner, identity.repo)}.previous`;
5833
+ }
5834
+ async function withExtensionLock(rootPath, id, operation) {
5835
+ const safeId = id.replace(/[^a-z0-9.-]+/gi, "-");
5836
+ const lockPath = path11.join(rootPath, ".locks", `${safeId}.lock`);
5837
+ await mkdir2(path11.dirname(lockPath), { recursive: true, mode: 448 });
5838
+ const deadline = Date.now() + OPERATION_LOCK_TIMEOUT_MS;
5839
+ while (true) {
5840
+ try {
5841
+ await mkdir2(lockPath, { mode: 448 });
5842
+ break;
5843
+ } catch (error) {
5844
+ if (error.code !== "EEXIST")
5845
+ throw error;
5846
+ const lockStat = await stat4(lockPath).catch(() => null);
5847
+ if (lockStat && Date.now() - lockStat.mtimeMs > OPERATION_LOCK_STALE_MS) {
5848
+ await rm(lockPath, { recursive: true, force: true });
5849
+ continue;
5850
+ }
5851
+ if (Date.now() >= deadline) {
5852
+ throw new GithubExtensionError(`Timed out waiting for extension operation: ${id}`, {
5853
+ code: "extension_operation_busy",
5854
+ status: 409
5855
+ });
5856
+ }
5857
+ await new Promise((resolve) => setTimeout(resolve, 30));
5858
+ }
5859
+ }
5860
+ try {
5861
+ return await operation();
5862
+ } finally {
5863
+ await rm(lockPath, { recursive: true, force: true });
5864
+ }
5865
+ }
5866
+ function extensionSort(left, right) {
5867
+ return left.id.localeCompare(right.id);
5868
+ }
5869
+
5022
5870
  // ../../packages/cloud/dist/profile/hosted-run-idempotency.js
5023
- import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
5871
+ import { createHash as createHash5, randomUUID as randomUUID4 } from "node:crypto";
5024
5872
  function buildHostedRunIdempotencyKey(input) {
5025
5873
  const explicit = input.explicitKey?.trim();
5026
5874
  if (explicit)
@@ -5031,10 +5879,10 @@ function buildHostedRunIdempotencyKey(input) {
5031
5879
  const base = `profile-push-run:${input.localHead}:${sourceHead}:${input.runtimeAgentId}:${targetProjectId}:${inputHash}`;
5032
5880
  if (!input.retry)
5033
5881
  return base;
5034
- return `${base}:retry:${(input.randomId ?? randomUUID3)()}`;
5882
+ return `${base}:retry:${(input.randomId ?? randomUUID4)()}`;
5035
5883
  }
5036
5884
  function hashStableJson(value) {
5037
- return createHash3("sha256").update(stableJsonStringify(value)).digest("hex");
5885
+ return createHash5("sha256").update(stableJsonStringify(value)).digest("hex");
5038
5886
  }
5039
5887
  function stableJsonStringify(value) {
5040
5888
  if (value === void 0)
@@ -5048,9 +5896,9 @@ function stableJsonStringify(value) {
5048
5896
  }
5049
5897
 
5050
5898
  // ../../packages/cloud/dist/profile/profile-skill-goal-executor.js
5051
- import { existsSync as existsSync6 } from "node:fs";
5052
- import { mkdir as mkdir2, readFile as readFile6, writeFile as writeFile3 } from "node:fs/promises";
5053
- import path10 from "node:path";
5899
+ import { existsSync as existsSync7 } from "node:fs";
5900
+ import { mkdir as mkdir3, readFile as readFile7, writeFile as writeFile4 } from "node:fs/promises";
5901
+ import path12 from "node:path";
5054
5902
  async function executeProfileSkillGoalRequest(goal) {
5055
5903
  if (goal.operation === "edit")
5056
5904
  return executeProfileSkillEdit(goal);
@@ -5061,9 +5909,9 @@ async function executeProfileSkillCreate(goal) {
5061
5909
  const existingNames = new Set(existing.skills.map((skill) => skill.name));
5062
5910
  const skillName = uniqueSkillName(goal.targetSkillName ?? goal.requestedName ?? inferSkillName(goal.userObjective), existingNames, goal.profileSourcePath);
5063
5911
  const skillPath = profileSkillPath(skillName);
5064
- const absolutePath = path10.join(goal.profileSourcePath, skillPath);
5065
- await mkdir2(path10.dirname(absolutePath), { recursive: true });
5066
- await writeFile3(absolutePath, renderSkillMarkdown({
5912
+ const absolutePath = path12.join(goal.profileSourcePath, skillPath);
5913
+ await mkdir3(path12.dirname(absolutePath), { recursive: true });
5914
+ await writeFile4(absolutePath, renderSkillMarkdown({
5067
5915
  name: skillName,
5068
5916
  description: descriptionForObjective(goal.userObjective),
5069
5917
  body: bodyForObjective(goal.userObjective)
@@ -5075,10 +5923,10 @@ async function executeProfileSkillEdit(goal) {
5075
5923
  if (!skillName)
5076
5924
  throw new Error("Profile skill edit requires skillName.");
5077
5925
  const skillPath = profileSkillPath(skillName);
5078
- const absolutePath = path10.join(goal.profileSourcePath, skillPath);
5079
- if (!existsSync6(absolutePath))
5926
+ const absolutePath = path12.join(goal.profileSourcePath, skillPath);
5927
+ if (!existsSync7(absolutePath))
5080
5928
  throw new Error(`Profile skill not found: ${skillName}`);
5081
- const current = await readFile6(absolutePath, "utf8");
5929
+ const current = await readFile7(absolutePath, "utf8");
5082
5930
  const parsed = parseProfileSkillMarkdown(current);
5083
5931
  if (parsed.messages.length > 0 || !parsed.name || !parsed.description) {
5084
5932
  throw new Error(`Profile skill ${skillName} is not valid. ${parsed.messages.join(" ")}`);
@@ -5092,7 +5940,7 @@ async function executeProfileSkillEdit(goal) {
5092
5940
  change,
5093
5941
  ""
5094
5942
  ].join("\n");
5095
- await writeFile3(absolutePath, renderSkillMarkdown({
5943
+ await writeFile4(absolutePath, renderSkillMarkdown({
5096
5944
  name: parsed.name,
5097
5945
  description: parsed.description,
5098
5946
  body
@@ -5108,7 +5956,7 @@ async function validateExecutedGoal(goal, skillName) {
5108
5956
  ...goal,
5109
5957
  status: "completed",
5110
5958
  targetSkillName: skillName,
5111
- targetSkillPath: path10.join(goal.profileSourceRelativePath, PROFILE_SKILLS_DIR, skillName, PROFILE_SKILL_FILE).replace(/\\/g, "/")
5959
+ targetSkillPath: path12.join(goal.profileSourceRelativePath, PROFILE_SKILLS_DIR, skillName, PROFILE_SKILL_FILE).replace(/\\/g, "/")
5112
5960
  };
5113
5961
  const validationStatus = skill.validationStatus === "valid" ? "valid" : "error";
5114
5962
  if (validationStatus !== "valid") {
@@ -5241,14 +6089,14 @@ function uniqueSkillName(baseName, existingNames, profileSourcePath2) {
5241
6089
  const base = normalizeSkillName2(baseName) ?? "profile-skill";
5242
6090
  let candidate = base;
5243
6091
  let suffix = 2;
5244
- while (existingNames.has(candidate) || existsSync6(path10.join(profileSourcePath2, PROFILE_SKILLS_DIR, candidate))) {
6092
+ while (existingNames.has(candidate) || existsSync7(path12.join(profileSourcePath2, PROFILE_SKILLS_DIR, candidate))) {
5245
6093
  candidate = `${base}-${suffix}`;
5246
6094
  suffix += 1;
5247
6095
  }
5248
6096
  return candidate;
5249
6097
  }
5250
6098
  function profileSkillPath(skillName) {
5251
- return path10.join(PROFILE_SKILLS_DIR, skillName, PROFILE_SKILL_FILE).replace(/\\/g, "/");
6099
+ return path12.join(PROFILE_SKILLS_DIR, skillName, PROFILE_SKILL_FILE).replace(/\\/g, "/");
5252
6100
  }
5253
6101
  function normalizeSkillName2(value) {
5254
6102
  const normalized = value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-");
@@ -7945,31 +8793,12 @@ var AccountProfileSchema = external_exports.object({
7945
8793
  isVerified: external_exports.boolean().nullable(),
7946
8794
  dailyAgentAppId: external_exports.string().nullable(),
7947
8795
  dailyAgentDeploymentId: external_exports.string().nullable(),
7948
- credits: external_exports.string().nullable(),
7949
- turnkeyWalletAddress: external_exports.string().nullable(),
7950
- turnkeyOperatingWalletAddress: external_exports.string().nullable()
8796
+ credits: external_exports.string().nullable()
7951
8797
  });
7952
8798
  var ActiveProfileSelectorSchema = external_exports.object({
7953
8799
  handle: external_exports.string(),
7954
8800
  baseUrl: external_exports.string().nullable().optional()
7955
8801
  });
7956
- var AccountBalanceSchema = external_exports.object({
7957
- balanceKind: external_exports.string(),
7958
- balanceUsd: external_exports.string().nullable(),
7959
- balanceUsdCents: external_exports.number().nullable(),
7960
- currency: external_exports.string(),
7961
- asOf: external_exports.string(),
7962
- stale: external_exports.boolean(),
7963
- error: external_exports.string().nullable(),
7964
- breakdown: external_exports.array(external_exports.object({
7965
- wallet: external_exports.string(),
7966
- chain: external_exports.string(),
7967
- chainId: external_exports.number().nullable(),
7968
- asset: external_exports.string(),
7969
- amount: external_exports.string().nullable(),
7970
- usdValue: external_exports.string().nullable()
7971
- }).passthrough())
7972
- }).passthrough();
7973
8802
  var AccountStateSchema = external_exports.object({
7974
8803
  state: external_exports.enum(["signed_out", "signed_in", "loading", "switching", "auth_error"]),
7975
8804
  activeProfile: ActiveProfileSelectorSchema.nullable(),
@@ -7980,8 +8809,6 @@ var AccountStateSchema = external_exports.object({
7980
8809
  baseUrl: external_exports.string().nullable(),
7981
8810
  apiBaseUrl: external_exports.string().nullable(),
7982
8811
  chatApiBaseUrl: external_exports.string().nullable().optional().default(null),
7983
- balanceLabel: external_exports.string(),
7984
- balance: AccountBalanceSchema.nullable().optional().default(null),
7985
8812
  creditsLabel: external_exports.string().nullable(),
7986
8813
  profile: AccountProfileSchema.nullable(),
7987
8814
  products: external_exports.array(AccountProductSchema),
@@ -8100,7 +8927,8 @@ var OpenPondProfileSkillSchema = external_exports.object({
8100
8927
  charCount: external_exports.number(),
8101
8928
  sourceHash: external_exports.string(),
8102
8929
  validationStatus: external_exports.enum(["valid", "warning", "error"]),
8103
- validationMessages: external_exports.array(external_exports.string())
8930
+ validationMessages: external_exports.array(external_exports.string()),
8931
+ resourceFiles: external_exports.array(external_exports.string()).optional().default([])
8104
8932
  });
8105
8933
  var OpenPondProfileEvalSchema = external_exports.object({
8106
8934
  id: external_exports.string(),
@@ -8371,6 +9199,82 @@ function emptyOpenPondProfileState() {
8371
9199
  };
8372
9200
  }
8373
9201
 
9202
+ // ../../packages/contracts/dist/skills.js
9203
+ var CodexPersonalSkillSchema = external_exports.object({
9204
+ name: external_exports.string(),
9205
+ description: external_exports.string(),
9206
+ path: external_exports.string(),
9207
+ sourcePath: external_exports.string(),
9208
+ enabled: external_exports.boolean(),
9209
+ charCount: external_exports.number().int().nonnegative(),
9210
+ sourceHash: external_exports.string(),
9211
+ validationStatus: external_exports.enum(["valid", "error"]),
9212
+ validationMessages: external_exports.array(external_exports.string()),
9213
+ resourceFiles: external_exports.array(external_exports.string()),
9214
+ updatedAt: external_exports.string().nullable()
9215
+ });
9216
+ var SkillSourceScopeSchema = external_exports.enum(["codex", "profile", "extension"]);
9217
+ var SkillSourceFileSchema = external_exports.object({
9218
+ skillName: external_exports.string(),
9219
+ scope: SkillSourceScopeSchema,
9220
+ path: external_exports.string(),
9221
+ byteSize: external_exports.number().int().nonnegative(),
9222
+ isBinary: external_exports.boolean(),
9223
+ content: external_exports.string().nullable()
9224
+ });
9225
+
9226
+ // ../../packages/contracts/dist/extensions.js
9227
+ var SHIPPED_OPENPOND_SKILL_NAMES = [
9228
+ "openpond-cli",
9229
+ "openpond-desktop-harness",
9230
+ "openpond-taskset-authoring"
9231
+ ];
9232
+ var OpenPondExtensionSkillSchema = external_exports.object({
9233
+ name: external_exports.string(),
9234
+ description: external_exports.string(),
9235
+ relativePath: external_exports.string(),
9236
+ sourcePath: external_exports.string(),
9237
+ charCount: external_exports.number().int().nonnegative(),
9238
+ sourceHash: external_exports.string(),
9239
+ resourceFiles: external_exports.array(external_exports.string()),
9240
+ validationStatus: external_exports.enum(["valid", "error"]),
9241
+ validationMessages: external_exports.array(external_exports.string())
9242
+ });
9243
+ var OpenPondExtensionSchema = external_exports.object({
9244
+ id: external_exports.string(),
9245
+ source: external_exports.literal("github"),
9246
+ owner: external_exports.string(),
9247
+ repo: external_exports.string(),
9248
+ repositoryUrl: external_exports.string().url(),
9249
+ requestedRef: external_exports.string(),
9250
+ resolvedCommit: external_exports.string(),
9251
+ sourcePath: external_exports.string(),
9252
+ readmePath: external_exports.string().nullable(),
9253
+ installedAt: external_exports.string(),
9254
+ updatedAt: external_exports.string(),
9255
+ packageHash: external_exports.string(),
9256
+ skills: external_exports.array(OpenPondExtensionSkillSchema),
9257
+ validationStatus: external_exports.enum(["valid", "error"]),
9258
+ validationMessages: external_exports.array(external_exports.string())
9259
+ });
9260
+ var OpenPondExtensionPreviewSchema = OpenPondExtensionSchema.omit({
9261
+ installedAt: true,
9262
+ updatedAt: true,
9263
+ sourcePath: true
9264
+ }).extend({
9265
+ sourcePath: external_exports.null()
9266
+ });
9267
+ var OpenPondExtensionCatalogSchema = external_exports.object({
9268
+ rootPath: external_exports.string(),
9269
+ registryPath: external_exports.string(),
9270
+ extensions: external_exports.array(OpenPondExtensionSchema),
9271
+ error: external_exports.string().nullable()
9272
+ });
9273
+ var OpenPondExtensionSourceRequestSchema = external_exports.object({
9274
+ source: external_exports.string().trim().min(1),
9275
+ ref: external_exports.string().trim().min(1).optional()
9276
+ });
9277
+
8374
9278
  // ../../packages/contracts/dist/bootstrap.js
8375
9279
  var BootstrapEventWindowSchema = external_exports.object({
8376
9280
  latestSequence: external_exports.number().int().nonnegative(),
@@ -8394,6 +9298,13 @@ var BootstrapPayloadSchema = external_exports.object({
8394
9298
  localProjects: external_exports.array(LocalProjectSchema).optional().default([]),
8395
9299
  cloudProjects: external_exports.array(CloudProjectSchema).optional().default([]),
8396
9300
  profile: OpenPondProfileStateSchema.optional().default(emptyOpenPondProfileState),
9301
+ codexPersonalSkills: external_exports.array(CodexPersonalSkillSchema).optional().default([]),
9302
+ extensionCatalog: OpenPondExtensionCatalogSchema.optional().default({
9303
+ rootPath: "",
9304
+ registryPath: "",
9305
+ extensions: [],
9306
+ error: null
9307
+ }),
8397
9308
  codexHistorySessions: external_exports.array(SessionSchema).optional().default([]),
8398
9309
  sidebarAppPreferences: SidebarAppPreferencesSchema,
8399
9310
  sidebarFileBookmarks: external_exports.array(SidebarFileBookmarkSchema).optional().default([]),
@@ -11583,7 +12494,6 @@ export {
11583
12494
  createRepo,
11584
12495
  getAppEnvironment,
11585
12496
  getOpenPondAccount,
11586
- getOpenPondAccountBalance,
11587
12497
  checkOpenPondApiHealth,
11588
12498
  loadGlobalConfig,
11589
12499
  listConfiguredProfiles,
@@ -11594,8 +12504,11 @@ export {
11594
12504
  normalizeSandboxApiUrl,
11595
12505
  createOpenPondSandboxClient,
11596
12506
  executeConnectedAppToolCall,
11597
- buildHostedRunIdempotencyKey,
12507
+ GithubExtensionError,
12508
+ parseProfileSkillMarkdown,
11598
12509
  readProfileSkill,
12510
+ createGithubExtensionManager,
12511
+ buildHostedRunIdempotencyKey,
11599
12512
  buildOpenPondProfileSetupGate,
11600
12513
  formatOpenPondProfileSetupRequirement,
11601
12514
  readSourceUploadCache,
@@ -11731,6 +12644,8 @@ export {
11731
12644
  SwitchOpenPondAccountRequestSchema,
11732
12645
  SaveOpenPondAccountRequestSchema,
11733
12646
  UpdateOpenPondAccountConfigRequestSchema,
12647
+ SHIPPED_OPENPOND_SKILL_NAMES,
12648
+ OpenPondExtensionSourceRequestSchema,
11734
12649
  BootstrapPayloadSchema,
11735
12650
  WorkspaceTemplateConfigViewSchema,
11736
12651
  WorkspaceToolRequestSchema,