dorkos 0.96.0 → 0.97.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 (83) hide show
  1. package/dist/bin/cli.js +1047 -414
  2. package/dist/client/assets/{AboutPage-CQDWR_CW.js → AboutPage-CWoaA13a.js} +1 -1
  3. package/dist/client/assets/{AdapterIcon-D_Q0_ksW.js → AdapterIcon-Db7lEW1n.js} +1 -1
  4. package/dist/client/assets/{AppearancePage-DJvLkrYg.js → AppearancePage-BQop2sAD.js} +1 -1
  5. package/dist/client/assets/{BaseTanStackRouterDevtoolsPanel-B-iktbLX-TGWNDhsR.js → BaseTanStackRouterDevtoolsPanel-B-iktbLX-ClUUkZON.js} +1 -1
  6. package/dist/client/assets/{BlintzCanvas-C-qAjHZg.js → BlintzCanvas-BfbE8ros.js} +1 -1
  7. package/dist/client/assets/{CanvasCsvContent-Bvyxic2o.js → CanvasCsvContent-DV6mysH1.js} +1 -1
  8. package/dist/client/assets/{CanvasFileContent-C-rKH6uY.js → CanvasFileContent-C8XU7_MO.js} +2 -2
  9. package/dist/client/assets/{CanvasModel3dContent-BpnUUaOx.js → CanvasModel3dContent-C6A2qmkr.js} +2 -2
  10. package/dist/client/assets/{CodeMirrorDiff-BdPGSTiE.js → CodeMirrorDiff-BrFFqIV4.js} +1 -1
  11. package/dist/client/assets/{CodeMirrorEditor-DUfMVBQz.js → CodeMirrorEditor-BUB5U0uv.js} +1 -1
  12. package/dist/client/assets/{ConnectionAccessLists-CAQvUY7v.js → ConnectionAccessLists-1Bmcq0xR.js} +1 -1
  13. package/dist/client/assets/{ConnectionsPage-C4C6a5Et.js → ConnectionsPage-CUNSv306.js} +1 -1
  14. package/dist/client/assets/{ConventionPage-CRvvk4Qe.js → ConventionPage-DTJAt0Sp.js} +1 -1
  15. package/dist/client/assets/{FloatingTanStackRouterDevtools-CqogiFob-C9ccmgWP.js → FloatingTanStackRouterDevtools-CqogiFob-D5R29cqc.js} +1 -1
  16. package/dist/client/assets/HandlePage-RfcAq6uu.js +1 -0
  17. package/dist/client/assets/{LexicalField-BKd-Flft.js → LexicalField-DH3889OK.js} +1 -1
  18. package/dist/client/assets/{ManagesPage-B_EPlkAF.js → ManagesPage-C19BGsTp.js} +1 -1
  19. package/dist/client/assets/{Model3dViewer-DaeyTiBa.js → Model3dViewer-WnbVchBx.js} +1 -1
  20. package/dist/client/assets/NamePage-zpDnrdnz.js +1 -0
  21. package/dist/client/assets/{NotificationsPage-9Pdcf9DP.js → NotificationsPage-DADGn_vX.js} +1 -1
  22. package/dist/client/assets/{PermissionsPage-C5VJzedd.js → PermissionsPage-D8Z88oLC.js} +1 -1
  23. package/dist/client/assets/{PersonalityPopover-a9JmYsIW.js → PersonalityPopover-c5ON9SdE.js} +1 -1
  24. package/dist/client/assets/PhotoPage-uYiT1-eE.js +1 -0
  25. package/dist/client/assets/{RoomsPage-BJYv3Kaj.js → RoomsPage-GHRaJ9k4.js} +1 -1
  26. package/dist/client/assets/RunsOnPopover-nTs5qHGV.js +1 -0
  27. package/dist/client/assets/{SessionsPage-DpcnPOve.js → SessionsPage-CWnq2H20.js} +1 -1
  28. package/dist/client/assets/{SkillsPage-FL6RDxum.js → SkillsPage-8lrI4hoj.js} +1 -1
  29. package/dist/client/assets/{TasksPage-DqR1PQpa.js → TasksPage-DXongF60.js} +1 -1
  30. package/dist/client/assets/{ToolsPage-CpXFsPyH.js → ToolsPage-DrxIOSZf.js} +1 -1
  31. package/dist/client/assets/{TopologyGraph-BeN6x6Mm.js → TopologyGraph-CnWK6syY.js} +1 -1
  32. package/dist/client/assets/{agent-browser-B1NCMPht.js → agent-browser-gNhNTz4L.js} +1 -1
  33. package/dist/client/assets/{highlighted-body-KPVGNVTW-BNGgh4uP.js → highlighted-body-KPVGNVTW-lytxVOWz.js} +1 -1
  34. package/dist/client/assets/{index-B85zmEBa.js → index--WyZ4-gR.js} +2 -2
  35. package/dist/client/assets/{index-CuEgy9Wq.js → index-2cIvrU43.js} +1 -1
  36. package/dist/client/assets/{index-CObSbOzd.js → index-55_UkkTU.js} +1 -1
  37. package/dist/client/assets/{index-B-reC6-b.js → index-B1AKLpj8.js} +1 -1
  38. package/dist/client/assets/{index-37POLmTg.js → index-B6NLm3gG.js} +2 -2
  39. package/dist/client/assets/{index-DK1bT79O.js → index-B9PeUmdr.js} +1 -1
  40. package/dist/client/assets/{index-CRY9XOxF.js → index-BGZjR5La.js} +369 -369
  41. package/dist/client/assets/{index-DpUjbgEc.js → index-BJ9mBDId.js} +1 -1
  42. package/dist/client/assets/{index-D7gHbbw4.js → index-BlIq4rKs.js} +1 -1
  43. package/dist/client/assets/{index-D6HybUuP.js → index-BoV5qBxN.js} +1 -1
  44. package/dist/client/assets/{index-DfFVj9js.js → index-Bzzw4C1K.js} +1 -1
  45. package/dist/client/assets/{index-CK2joAPt.js → index-C6pLstnZ.js} +1 -1
  46. package/dist/client/assets/{index-D0qFwr0D.js → index-CDe45jXh.js} +1 -1
  47. package/dist/client/assets/{index-X5Xf2LYs.js → index-CKpYfE0E.js} +1 -1
  48. package/dist/client/assets/{index-DTp4DkGS.js → index-COO_I6YV.js} +1 -1
  49. package/dist/client/assets/{index-Cg0vlOFm.js → index-CWLEH11K.js} +1 -1
  50. package/dist/client/assets/{index-CtTX0prA.js → index-CXTwjHuI.js} +1 -1
  51. package/dist/client/assets/{index-BV7OFKdM.js → index-CclxGUXZ.js} +1 -1
  52. package/dist/client/assets/{index-BDRH3Ip7.js → index-CjTZR_Gw.js} +1 -1
  53. package/dist/client/assets/{index-CYRV7SWo.js → index-CoOJmgj_.js} +1 -1
  54. package/dist/client/assets/{index-D6QchtbQ.js → index-CoofrD9y.js} +1 -1
  55. package/dist/client/assets/{index-CVqGn1_t.js → index-CzLupb1M.js} +1 -1
  56. package/dist/client/assets/{index-DmszcvjB.js → index-D7aH0ku1.js} +1 -1
  57. package/dist/client/assets/{index-DFJyOvaR.js → index-DRWuPSOY.js} +1 -1
  58. package/dist/client/assets/{index-O-_zHvAT.js → index-DUYzoZHH.js} +3 -3
  59. package/dist/client/assets/{index-HJ9uFBTw.js → index-Db10wqws.js} +1 -1
  60. package/dist/client/assets/{index-CGL747cc.js → index-Do5jnJaD.js} +1 -1
  61. package/dist/client/assets/{index-B6HAVOXg.js → index-Doua-39c.js} +1 -1
  62. package/dist/client/assets/{index-B346o2M4.js → index-Dy1k6qgQ.js} +1 -1
  63. package/dist/client/assets/{index-D13zqwu5.js → index-FiUumiJg.js} +1 -1
  64. package/dist/client/assets/{index-Cg4ycKIn.js → index-GI34vWY_.js} +1 -1
  65. package/dist/client/assets/{index-9DST8xeQ.js → index-PkMHY7kQ.js} +1 -1
  66. package/dist/client/assets/{index-De_5ZT9j.js → index-ZW5KMqF_.js} +1 -1
  67. package/dist/client/assets/{index-Phwb5KbD.js → index-bgMpB9N2.js} +1 -1
  68. package/dist/client/assets/{index-CxRcLwsM.js → index-iLcX8j1Q.js} +1 -1
  69. package/dist/client/assets/{index-Di84yQg5.js → index-tYz5N9Zo.js} +1 -1
  70. package/dist/client/assets/{room-files-source-Bg3n7Y23.js → room-files-source-BLYZ2bzp.js} +1 -1
  71. package/dist/client/assets/{soul-file-CoFQFEH4.js → soul-file-CJw1VlLA.js} +1 -1
  72. package/dist/client/assets/{use-personality-commit-KzXn3b-E.js → use-personality-commit-Bwap0Cpr.js} +1 -1
  73. package/dist/client/index.html +1 -1
  74. package/dist/drizzle/20261003185230_extension_agent_sends.sql +28 -0
  75. package/dist/drizzle/meta/20261003185230_snapshot.json +11762 -0
  76. package/dist/drizzle/meta/_journal.json +7 -0
  77. package/dist/server/index.js +14564 -11785
  78. package/dist/server/index.js.map +2 -2
  79. package/package.json +5 -5
  80. package/dist/client/assets/HandlePage-DYkn3y43.js +0 -1
  81. package/dist/client/assets/NamePage-D_P6Hwmu.js +0 -1
  82. package/dist/client/assets/PhotoPage-Dxwoc0x2.js +0 -1
  83. package/dist/client/assets/RunsOnPopover-DGVUWmuw.js +0 -1
package/dist/bin/cli.js CHANGED
@@ -21455,7 +21455,14 @@ var init_config_schema = __esm({
21455
21455
  * whole plugin folder's digest the person said yes to. Any further change
21456
21456
  * asks again, because a path alone no longer says what is there.
21457
21457
  */
21458
- digest: external_exports.string().min(1).optional()
21458
+ digest: external_exports.string().min(1).optional(),
21459
+ /**
21460
+ * The real path of the dev link this approval was given to (DOR-2696);
21461
+ * absent for an installed copy. A dev link sits at its package's normal
21462
+ * folder, so without this an approval of the installed copy would cover the
21463
+ * link's files at the same path, and the other way round.
21464
+ */
21465
+ devLink: external_exports.string().min(1).optional()
21459
21466
  });
21460
21467
  ExtensionDismissedApprovalSchema = external_exports.object({
21461
21468
  /** Absolute path of the extension directory the person declined. */
@@ -25972,7 +25979,7 @@ import path2 from "path";
25972
25979
  import { fileURLToPath } from "url";
25973
25980
  function resolveVersion() {
25974
25981
  if (env2.DORKOS_VERSION_OVERRIDE) return env2.DORKOS_VERSION_OVERRIDE;
25975
- if (true) return "0.96.0";
25982
+ if (true) return "0.97.0";
25976
25983
  const pkgPath = path2.join(path2.dirname(fileURLToPath(import.meta.url)), "../../package.json");
25977
25984
  return JSON.parse(readFileSync(pkgPath, "utf-8")).version;
25978
25985
  }
@@ -32779,8 +32786,9 @@ function describeScheduleArrival(startsEnabled) {
32779
32786
  return startsEnabled ? "waits for your approval before its first run" : "arrives switched off, and would wait for your approval too";
32780
32787
  }
32781
32788
  function describeHookEvent(event, matcher) {
32782
- const when = HOOK_EVENT_SUMMARY[event] ?? `on ${event}`;
32783
- return matcher ? `${when} (${matcher})` : when;
32789
+ const whole = (value) => revealHiddenCharacters(JSON.stringify(value));
32790
+ const when = HOOK_EVENT_SUMMARY[event] ?? `on ${whole(event)}`;
32791
+ return matcher ? `${when} (${whole(matcher)})` : when;
32784
32792
  }
32785
32793
  function describeProgramLine(command, args = []) {
32786
32794
  return [command, ...args].map((part) => revealHiddenCharacters(JSON.stringify(part))).join(" ");
@@ -32801,9 +32809,21 @@ function skillCommandKind(source) {
32801
32809
  function isInstallSiblingName(name) {
32802
32810
  return MARKETPLACE_INSTALL_SIBLING_MARKERS.some((marker) => name.includes(marker));
32803
32811
  }
32804
- var SCHEDULE_PERMISSION_MODE_SUMMARY, HOOK_EVENT_SUMMARY, PLUGIN_PROGRAMS_SCOPE_NOTE, HIDDEN_CHARACTERS, MARKETPLACE_BACKUP_DIR_MARKER, MARKETPLACE_STAGE_DIR_MARKER, MARKETPLACE_UNINSTALL_DIR_MARKER, MARKETPLACE_INSTALL_SIBLING_MARKERS;
32812
+ function parseDevLinksFile(text2) {
32813
+ let raw;
32814
+ try {
32815
+ raw = JSON.parse(text2);
32816
+ } catch {
32817
+ return "unreadable";
32818
+ }
32819
+ const parsed = DevLinksFileSchema.safeParse(raw);
32820
+ return parsed.success ? parsed.data : "unreadable";
32821
+ }
32822
+ var SCHEDULE_PERMISSION_MODE_SUMMARY, HOOK_EVENT_SUMMARY, PLUGIN_PROGRAMS_SCOPE_NOTE, HIDDEN_CHARACTERS, MARKETPLACE_BACKUP_DIR_MARKER, MARKETPLACE_STAGE_DIR_MARKER, MARKETPLACE_UNINSTALL_DIR_MARKER, MARKETPLACE_DEVLINK_PARKED_MARKER, MARKETPLACE_INSTALL_SIBLING_MARKERS, DEV_LINKS_FILE, DevLinkPackageNameSchema, DevLinkPackageTypeSchema, DevLinkViaSchema, DevLinkRecordSchema, DevLinksFileSchema;
32805
32823
  var init_marketplace_schemas = __esm({
32806
32824
  "../shared/src/marketplace-schemas.ts"() {
32825
+ init_zod();
32826
+ init_config_schema();
32807
32827
  SCHEDULE_PERMISSION_MODE_SUMMARY = {
32808
32828
  default: "runs at the most careful setting its agent offers",
32809
32829
  plan: "can only read and plan, and cannot change anything",
@@ -32831,11 +32851,60 @@ var init_marketplace_schemas = __esm({
32831
32851
  MARKETPLACE_BACKUP_DIR_MARKER = ".dorkos-bak-";
32832
32852
  MARKETPLACE_STAGE_DIR_MARKER = ".dorkos-stage-";
32833
32853
  MARKETPLACE_UNINSTALL_DIR_MARKER = ".dorkos-uninstall-";
32854
+ MARKETPLACE_DEVLINK_PARKED_MARKER = ".dorkos-devlink-parked";
32834
32855
  MARKETPLACE_INSTALL_SIBLING_MARKERS = [
32835
32856
  MARKETPLACE_BACKUP_DIR_MARKER,
32836
32857
  MARKETPLACE_STAGE_DIR_MARKER,
32837
- MARKETPLACE_UNINSTALL_DIR_MARKER
32858
+ MARKETPLACE_UNINSTALL_DIR_MARKER,
32859
+ MARKETPLACE_DEVLINK_PARKED_MARKER
32838
32860
  ];
32861
+ DEV_LINKS_FILE = "marketplace/dev-links.json";
32862
+ DevLinkPackageNameSchema = external_exports.string().min(1).max(64).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/).refine((name) => !name.includes("--"), "Must not contain consecutive hyphens");
32863
+ DevLinkPackageTypeSchema = external_exports.enum(["plugin", "skill-pack"]);
32864
+ DevLinkViaSchema = external_exports.enum(["app", "terminal", "agent-card"]);
32865
+ DevLinkRecordSchema = external_exports.object({
32866
+ /** The package name from the folder's manifest at link time. */
32867
+ name: DevLinkPackageNameSchema,
32868
+ /** The package type from the folder's manifest at link time. */
32869
+ type: DevLinkPackageTypeSchema,
32870
+ /** `global` for every session, `project` for one project. */
32871
+ scope: external_exports.enum(["global", "project"]),
32872
+ /** The canonical project folder; present exactly when `scope` is `project`. */
32873
+ projectPath: external_exports.string().min(1).optional(),
32874
+ /** Absolute path of the link itself: the package's normal slot. */
32875
+ slot: external_exports.string().min(1),
32876
+ /** The real path of the working folder the link points at. */
32877
+ target: external_exports.string().min(1),
32878
+ /** Absolute path of the installed copy set aside for the link, when there was one. */
32879
+ parked: external_exports.string().min(1).optional(),
32880
+ /** What unlink puts back for the parked copy, or for another copy of an extension id. */
32881
+ restoreApprovals: external_exports.object({
32882
+ /** Extension approvals the link's own approvals replaced, by extension id. */
32883
+ extensions: external_exports.record(external_exports.string(), ExtensionApprovedSourceSchema).optional(),
32884
+ /** Which of those ids were approved to run then; the rest only had a source. */
32885
+ runIds: external_exports.array(external_exports.string()).optional(),
32886
+ /** Stored global-activation entries (`<name>@global-<digest>`) of the parked copy. */
32887
+ globalActivation: external_exports.array(external_exports.string()).optional()
32888
+ }).optional(),
32889
+ /**
32890
+ * Project hook approvals (`harness.approvedHooks` entries) this link
32891
+ * recorded when it was made, because the card showed those hooks. Unlink
32892
+ * removes exactly these, so an approval that was there before the link
32893
+ * (the installed copy's, the same hooks in the same project) stays.
32894
+ */
32895
+ grantedHooks: external_exports.array(external_exports.string()).optional(),
32896
+ /** When the link was made. ISO 8601. */
32897
+ linkedAt: external_exports.string().min(1),
32898
+ /** Where the person said yes. */
32899
+ linkedVia: DevLinkViaSchema
32900
+ }).refine((record2) => record2.scope === "project" === (record2.projectPath !== void 0), {
32901
+ message: "A project dev link names its project, and a global one does not",
32902
+ path: ["projectPath"]
32903
+ });
32904
+ DevLinksFileSchema = external_exports.object({
32905
+ version: external_exports.literal(1),
32906
+ links: external_exports.array(DevLinkRecordSchema)
32907
+ });
32839
32908
  }
32840
32909
  });
32841
32910
 
@@ -36183,6 +36252,7 @@ function parseSkillFile(filePath, content, schema3, options) {
36183
36252
  }
36184
36253
  var init_parser = __esm({
36185
36254
  "../skills/src/parser.ts"() {
36255
+ "use strict";
36186
36256
  init_constants3();
36187
36257
  init_frontmatter();
36188
36258
  }
@@ -39335,6 +39405,7 @@ var init_capabilities = __esm({
39335
39405
  var PROJECT_NAME_PATTERN, ProjectRefSchema, ProjectInfoSchema, ProjectListResponseSchema, ProjectResolveQuerySchema, ProjectResolveResponseSchema, AccountEligibilityRowSchema, AccountEligibilityQuerySchema, AccountEligibilityResponseSchema, ProjectAccountsRequestSchema, ProjectWithoutCreditsRequestSchema, OnlyProjectsRequestSchema, OnlyProjectsResponseSchema;
39336
39406
  var init_project_schemas = __esm({
39337
39407
  "../shared/src/project-schemas.ts"() {
39408
+ "use strict";
39338
39409
  init_zod();
39339
39410
  init_zod_openapi();
39340
39411
  extendZodWithOpenApiOnce();
@@ -67306,7 +67377,7 @@ var init_factory = __esm({
67306
67377
  }
67307
67378
  return transformedData;
67308
67379
  };
67309
- const transformOutput = async (data, inputModel, select2 = [], join54) => {
67380
+ const transformOutput = async (data, inputModel, select2 = [], join55) => {
67310
67381
  const transformSingleOutput = async (data2, inputModel2, select3 = []) => {
67311
67382
  if (!data2) return null;
67312
67383
  const modelKey2 = getDefaultModelName(inputModel2);
@@ -67343,10 +67414,10 @@ var init_factory = __esm({
67343
67414
  }
67344
67415
  return transformedData2;
67345
67416
  };
67346
- if (!join54 || Object.keys(join54).length === 0) return await transformSingleOutput(data, inputModel, select2);
67417
+ if (!join55 || Object.keys(join55).length === 0) return await transformSingleOutput(data, inputModel, select2);
67347
67418
  const modelKey = getDefaultModelName(inputModel);
67348
67419
  const transformedData = await transformSingleOutput(data, modelKey, select2);
67349
- const requiredModels = Object.entries(join54).map(([model, joinConfig]) => ({
67420
+ const requiredModels = Object.entries(join55).map(([model, joinConfig]) => ({
67350
67421
  modelName: model,
67351
67422
  defaultModelName: joinConfig.modelKey ?? getDefaultModelName(model),
67352
67423
  joinConfig
@@ -67445,8 +67516,8 @@ var init_factory = __esm({
67445
67516
  if (!unsanitizedJoin) return void 0;
67446
67517
  if (Object.keys(unsanitizedJoin).length === 0) return void 0;
67447
67518
  const transformedJoin = {};
67448
- for (const [model, join54] of Object.entries(unsanitizedJoin)) {
67449
- if (!join54) continue;
67519
+ for (const [model, join55] of Object.entries(unsanitizedJoin)) {
67520
+ if (!join55) continue;
67450
67521
  const defaultModelName = getDefaultModelName(model);
67451
67522
  const defaultBaseModelName = getDefaultModelName(baseModel);
67452
67523
  let foreignKeys = Object.entries(schema3[defaultModelName].fields).filter(([field, fieldAttributes]) => fieldAttributes.references && getDefaultModelName(fieldAttributes.references.model) === defaultBaseModelName);
@@ -67487,7 +67558,7 @@ var init_factory = __esm({
67487
67558
  const isUnique = to === "id" ? true : foreignKeyAttributes.unique ?? false;
67488
67559
  let limit = options.advanced?.database?.defaultFindManyLimit ?? 100;
67489
67560
  if (isUnique) limit = 1;
67490
- else if (typeof join54 === "object" && typeof join54.limit === "number") limit = join54.limit;
67561
+ else if (typeof join55 === "object" && typeof join55.limit === "number") limit = join55.limit;
67491
67562
  transformedJoin[getModelName(model)] = {
67492
67563
  modelKey: model,
67493
67564
  on: {
@@ -67720,21 +67791,21 @@ var init_factory = __esm({
67720
67791
  where: unsafeWhere,
67721
67792
  action: "findOne"
67722
67793
  });
67723
- let join54;
67794
+ let join55;
67724
67795
  let passJoinToAdapter = true;
67725
67796
  if (!config3.disableTransformJoin) {
67726
67797
  const result2 = transformJoinClause(modelKey, unsafeJoin, select2);
67727
67798
  if (result2) {
67728
- join54 = result2.join;
67799
+ join55 = result2.join;
67729
67800
  select2 = result2.select;
67730
67801
  }
67731
- if (!options.advanced?.database?.joins && join54 && Object.keys(join54).length > 0) passJoinToAdapter = false;
67732
- } else join54 = unsafeJoin;
67802
+ if (!options.advanced?.database?.joins && join55 && Object.keys(join55).length > 0) passJoinToAdapter = false;
67803
+ } else join55 = unsafeJoin;
67733
67804
  debugLog({ method: "findOne" }, `${formatTransactionId(thisTransactionId)} ${formatStep(1, 3)}`, `${formatMethod("findOne")}:`, {
67734
67805
  model,
67735
67806
  where,
67736
67807
  select: select2,
67737
- join: join54
67808
+ join: join55
67738
67809
  });
67739
67810
  const res = await withSpan3(`db findOne ${model}`, {
67740
67811
  [ATTR_DB_OPERATION_NAME]: "findOne",
@@ -67744,14 +67815,14 @@ var init_factory = __esm({
67744
67815
  modelKey,
67745
67816
  where,
67746
67817
  select: select2,
67747
- join: passJoinToAdapter ? join54 : void 0
67818
+ join: passJoinToAdapter ? join55 : void 0
67748
67819
  }));
67749
67820
  debugLog({ method: "findOne" }, `${formatTransactionId(thisTransactionId)} ${formatStep(2, 3)}`, `${formatMethod("findOne")} ${formatAction("DB Result")}:`, {
67750
67821
  model,
67751
67822
  data: res
67752
67823
  });
67753
67824
  let transformed = res;
67754
- if (!config3.disableTransformOutput) transformed = await transformOutput(res, modelKey, select2, join54);
67825
+ if (!config3.disableTransformOutput) transformed = await transformOutput(res, modelKey, select2, join55);
67755
67826
  debugLog({ method: "findOne" }, `${formatTransactionId(thisTransactionId)} ${formatStep(3, 3)}`, `${formatMethod("findOne")} ${formatAction("Parsed Result")}:`, {
67756
67827
  model,
67757
67828
  data: transformed
@@ -67769,23 +67840,23 @@ var init_factory = __esm({
67769
67840
  where: unsafeWhere,
67770
67841
  action: "findMany"
67771
67842
  });
67772
- let join54;
67843
+ let join55;
67773
67844
  let passJoinToAdapter = true;
67774
67845
  if (!config3.disableTransformJoin) {
67775
67846
  const result2 = transformJoinClause(modelKey, unsafeJoin, select2);
67776
67847
  if (result2) {
67777
- join54 = result2.join;
67848
+ join55 = result2.join;
67778
67849
  select2 = result2.select;
67779
67850
  }
67780
- if (!options.advanced?.database?.joins && join54 && Object.keys(join54).length > 0) passJoinToAdapter = false;
67781
- } else join54 = unsafeJoin;
67851
+ if (!options.advanced?.database?.joins && join55 && Object.keys(join55).length > 0) passJoinToAdapter = false;
67852
+ } else join55 = unsafeJoin;
67782
67853
  debugLog({ method: "findMany" }, `${formatTransactionId(thisTransactionId)} ${formatStep(1, 3)}`, `${formatMethod("findMany")}:`, {
67783
67854
  model,
67784
67855
  where,
67785
67856
  limit,
67786
67857
  sortBy,
67787
67858
  offset,
67788
- join: join54
67859
+ join: join55
67789
67860
  });
67790
67861
  const res = await withSpan3(`db findMany ${model}`, {
67791
67862
  [ATTR_DB_OPERATION_NAME]: "findMany",
@@ -67798,7 +67869,7 @@ var init_factory = __esm({
67798
67869
  select: select2,
67799
67870
  sortBy,
67800
67871
  offset,
67801
- join: passJoinToAdapter ? join54 : void 0
67872
+ join: passJoinToAdapter ? join55 : void 0
67802
67873
  }));
67803
67874
  debugLog({ method: "findMany" }, `${formatTransactionId(thisTransactionId)} ${formatStep(2, 3)}`, `${formatMethod("findMany")} ${formatAction("DB Result")}:`, {
67804
67875
  model,
@@ -67806,7 +67877,7 @@ var init_factory = __esm({
67806
67877
  });
67807
67878
  let transformed = res;
67808
67879
  if (!config3.disableTransformOutput) transformed = await Promise.all(res.map(async (r3) => {
67809
- return await transformOutput(r3, modelKey, void 0, join54);
67880
+ return await transformOutput(r3, modelKey, void 0, join55);
67810
67881
  }));
67811
67882
  debugLog({ method: "findMany" }, `${formatTransactionId(thisTransactionId)} ${formatStep(3, 3)}`, `${formatMethod("findMany")} ${formatAction("Parsed Result")}:`, {
67812
67883
  model,
@@ -68161,7 +68232,7 @@ var init_dist6 = __esm({
68161
68232
  return sortBy.direction === "asc" ? comparison : -comparison;
68162
68233
  });
68163
68234
  };
68164
- function convertWhereClause(where, model, modelKey, join54, select2) {
68235
+ function convertWhereClause(where, model, modelKey, join55, select2) {
68165
68236
  const baseRecords = (() => {
68166
68237
  const table2 = activeDb2[model];
68167
68238
  if (!table2) {
@@ -68221,14 +68292,14 @@ var init_dist6 = __esm({
68221
68292
  })))));
68222
68293
  return records;
68223
68294
  })();
68224
- if (!join54) return baseRecords;
68295
+ if (!join55) return baseRecords;
68225
68296
  const grouped = /* @__PURE__ */ new Map();
68226
68297
  const seenIds = /* @__PURE__ */ new Map();
68227
68298
  for (const baseRecord of baseRecords) {
68228
68299
  const baseId = String(baseRecord.id);
68229
68300
  if (!grouped.has(baseId)) {
68230
68301
  const nested = { ...baseRecord };
68231
- for (const [joinModel, joinAttr] of Object.entries(join54)) {
68302
+ for (const [joinModel, joinAttr] of Object.entries(join55)) {
68232
68303
  const joinModelName = joinModel;
68233
68304
  if (joinAttr.relation === "one-to-one") nested[joinModelName] = null;
68234
68305
  else {
@@ -68239,7 +68310,7 @@ var init_dist6 = __esm({
68239
68310
  grouped.set(baseId, nested);
68240
68311
  }
68241
68312
  const nestedEntry = grouped.get(baseId);
68242
- for (const [joinModel, joinAttr] of Object.entries(join54)) {
68313
+ for (const [joinModel, joinAttr] of Object.entries(join55)) {
68243
68314
  const joinModelName = joinModel;
68244
68315
  const joinTable = activeDb2[joinModelName];
68245
68316
  if (!joinTable) {
@@ -68272,18 +68343,18 @@ var init_dist6 = __esm({
68272
68343
  activeDb2[model].push(data);
68273
68344
  return data;
68274
68345
  },
68275
- findOne: async ({ model, modelKey = model, where, select: select2, join: join54 }) => {
68276
- const res = convertWhereClause(where, model, modelKey, join54, select2);
68277
- if (join54) {
68346
+ findOne: async ({ model, modelKey = model, where, select: select2, join: join55 }) => {
68347
+ const res = convertWhereClause(where, model, modelKey, join55, select2);
68348
+ if (join55) {
68278
68349
  const resArray = res;
68279
68350
  if (!resArray.length) return null;
68280
68351
  return resArray[0];
68281
68352
  }
68282
68353
  return res[0] || null;
68283
68354
  },
68284
- findMany: async ({ model, modelKey = model, where, sortBy, limit, select: select2, offset, join: join54 }) => {
68285
- const res = convertWhereClause(where || [], model, modelKey, join54, select2);
68286
- if (join54) {
68355
+ findMany: async ({ model, modelKey = model, where, sortBy, limit, select: select2, offset, join: join55 }) => {
68356
+ const res = convertWhereClause(where || [], model, modelKey, join55, select2);
68357
+ if (join55) {
68287
68358
  const resArray = res;
68288
68359
  if (!resArray.length) return [];
68289
68360
  applySortToRecords(resArray, sortBy, modelKey);
@@ -70281,10 +70352,10 @@ var init_query_node = __esm({
70281
70352
  where: node2.where ? WhereNode.cloneWithOperation(node2.where, "And", operation) : WhereNode.create(operation)
70282
70353
  });
70283
70354
  },
70284
- cloneWithJoin(node2, join54) {
70355
+ cloneWithJoin(node2, join55) {
70285
70356
  return freeze({
70286
70357
  ...node2,
70287
- joins: node2.joins ? freeze([...node2.joins, join54]) : freeze([join54])
70358
+ joins: node2.joins ? freeze([...node2.joins, join55]) : freeze([join55])
70288
70359
  });
70289
70360
  },
70290
70361
  cloneWithReturning(node2, selections) {
@@ -74795,8 +74866,8 @@ var init_with_schema_transformer = __esm({
74795
74866
  this.#collectSchemableIdsFromTableExpr(node2.table, schemableIds);
74796
74867
  }
74797
74868
  if ("joins" in node2 && node2.joins) {
74798
- for (const join54 of node2.joins) {
74799
- this.#collectSchemableIdsFromTableExpr(join54.table, schemableIds);
74869
+ for (const join55 of node2.joins) {
74870
+ this.#collectSchemableIdsFromTableExpr(join55.table, schemableIds);
74800
74871
  }
74801
74872
  }
74802
74873
  if ("using" in node2 && node2.using) {
@@ -86968,7 +87039,7 @@ var init_mssql_introspector = __esm({
86968
87039
  return await this.#db.selectFrom("sys.schemas").select("name").execute();
86969
87040
  }
86970
87041
  async getTables(options = { withInternalKyselyTables: false }) {
86971
- const rawColumns = await this.#db.selectFrom("sys.tables as tables").leftJoin("sys.schemas as table_schemas", "table_schemas.schema_id", "tables.schema_id").innerJoin("sys.columns as columns", "columns.object_id", "tables.object_id").innerJoin("sys.types as types", "types.user_type_id", "columns.user_type_id").leftJoin("sys.schemas as type_schemas", "type_schemas.schema_id", "types.schema_id").leftJoin("sys.extended_properties as comments", (join54) => join54.onRef("comments.major_id", "=", "tables.object_id").onRef("comments.minor_id", "=", "columns.column_id").on("comments.name", "=", "MS_Description")).$if(!options.withInternalKyselyTables, (qb) => qb.where("tables.name", "!=", DEFAULT_MIGRATION_TABLE).where("tables.name", "!=", DEFAULT_MIGRATION_LOCK_TABLE)).select([
87042
+ const rawColumns = await this.#db.selectFrom("sys.tables as tables").leftJoin("sys.schemas as table_schemas", "table_schemas.schema_id", "tables.schema_id").innerJoin("sys.columns as columns", "columns.object_id", "tables.object_id").innerJoin("sys.types as types", "types.user_type_id", "columns.user_type_id").leftJoin("sys.schemas as type_schemas", "type_schemas.schema_id", "types.schema_id").leftJoin("sys.extended_properties as comments", (join55) => join55.onRef("comments.major_id", "=", "tables.object_id").onRef("comments.minor_id", "=", "columns.column_id").on("comments.name", "=", "MS_Description")).$if(!options.withInternalKyselyTables, (qb) => qb.where("tables.name", "!=", DEFAULT_MIGRATION_TABLE).where("tables.name", "!=", DEFAULT_MIGRATION_LOCK_TABLE)).select([
86972
87043
  "tables.name as table_name",
86973
87044
  (eb) => eb.ref("tables.type").$castTo().as("table_type"),
86974
87045
  "table_schemas.name as table_schema_name",
@@ -86983,7 +87054,7 @@ var init_mssql_introspector = __esm({
86983
87054
  "types.name as type_name",
86984
87055
  "type_schemas.name as type_schema_name",
86985
87056
  "comments.value as column_comment"
86986
- ]).unionAll(this.#db.selectFrom("sys.views as views").leftJoin("sys.schemas as view_schemas", "view_schemas.schema_id", "views.schema_id").innerJoin("sys.columns as columns", "columns.object_id", "views.object_id").innerJoin("sys.types as types", "types.user_type_id", "columns.user_type_id").leftJoin("sys.schemas as type_schemas", "type_schemas.schema_id", "types.schema_id").leftJoin("sys.extended_properties as comments", (join54) => join54.onRef("comments.major_id", "=", "views.object_id").onRef("comments.minor_id", "=", "columns.column_id").on("comments.name", "=", "MS_Description")).select([
87057
+ ]).unionAll(this.#db.selectFrom("sys.views as views").leftJoin("sys.schemas as view_schemas", "view_schemas.schema_id", "views.schema_id").innerJoin("sys.columns as columns", "columns.object_id", "views.object_id").innerJoin("sys.types as types", "types.user_type_id", "columns.user_type_id").leftJoin("sys.schemas as type_schemas", "type_schemas.schema_id", "types.schema_id").leftJoin("sys.extended_properties as comments", (join55) => join55.onRef("comments.major_id", "=", "views.object_id").onRef("comments.minor_id", "=", "columns.column_id").on("comments.name", "=", "MS_Description")).select([
86987
87058
  "views.name as table_name",
86988
87059
  "views.type as table_type",
86989
87060
  "view_schemas.name as table_schema_name",
@@ -88210,10 +88281,10 @@ var init_dist8 = __esm({
88210
88281
  mysqlNoIdWarned = true;
88211
88282
  logger2.warn(`[Kysely Adapter] MySQL does not support INSERT...RETURNING. With generateId set to false, the adapter uses best-effort fallback strategies (unique columns, full-field match) to retrieve inserted rows. For reliable behavior, use Better Auth's default ID generation, a custom generateId function, or generateId: "serial" for auto-increment.`);
88212
88283
  }
88213
- const selectAllJoins = (join54) => {
88284
+ const selectAllJoins = (join55) => {
88214
88285
  const allSelects = [];
88215
88286
  const allSelectsStr = [];
88216
- if (join54) for (const [joinModel, joinConfig] of Object.entries(join54)) {
88287
+ if (join55) for (const [joinModel, joinConfig] of Object.entries(join55)) {
88217
88288
  const fields = schema3[joinConfig.modelKey ?? getDefaultModelName(joinModel)]?.fields;
88218
88289
  const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel];
88219
88290
  if (!fields) continue;
@@ -88438,7 +88509,7 @@ var init_dist8 = __esm({
88438
88509
  async create({ data, model, modelKey = model }) {
88439
88510
  return await withReturning(data, db2.insertInto(model).values(data), model, modelKey, []);
88440
88511
  },
88441
- async findOne({ model, modelKey = model, where, select: select2, join: join54 }) {
88512
+ async findOne({ model, modelKey = model, where, select: select2, join: join55 }) {
88442
88513
  const { and: and2, or: or2 } = convertWhereClause(model, modelKey, where);
88443
88514
  let query = db2.selectFrom((eb) => {
88444
88515
  let b2 = eb.selectFrom(model);
@@ -88451,19 +88522,19 @@ var init_dist8 = __esm({
88451
88522
  else b2 = b2.selectAll();
88452
88523
  return b2.as("primary");
88453
88524
  }).selectAll("primary");
88454
- if (join54) for (const [joinModel, joinAttr] of Object.entries(join54)) {
88525
+ if (join55) for (const [joinModel, joinAttr] of Object.entries(join55)) {
88455
88526
  const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel];
88456
- query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join55) => join55.onRef(`join_${joinModelName}.${joinAttr.on.to}`, "=", `primary.${joinAttr.on.from}`));
88527
+ query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join56) => join56.onRef(`join_${joinModelName}.${joinAttr.on.to}`, "=", `primary.${joinAttr.on.from}`));
88457
88528
  }
88458
- const { allSelectsStr, allSelects } = selectAllJoins(join54);
88529
+ const { allSelectsStr, allSelects } = selectAllJoins(join55);
88459
88530
  query = query.select(allSelects);
88460
88531
  const res = await query.execute();
88461
88532
  if (!res || !Array.isArray(res) || res.length === 0) return null;
88462
88533
  const row2 = res[0];
88463
- if (join54) return processJoinedResults(res, join54, allSelectsStr)[0];
88534
+ if (join55) return processJoinedResults(res, join55, allSelectsStr)[0];
88464
88535
  return row2;
88465
88536
  },
88466
- async findMany({ model, modelKey = model, where, limit, select: select2, offset, sortBy, join: join54 }) {
88537
+ async findMany({ model, modelKey = model, where, limit, select: select2, offset, sortBy, join: join55 }) {
88467
88538
  const { and: and2, or: or2 } = convertWhereClause(model, modelKey, where);
88468
88539
  let query = db2.selectFrom((eb) => {
88469
88540
  let b2 = eb.selectFrom(model);
@@ -88492,11 +88563,11 @@ var init_dist8 = __esm({
88492
88563
  else b2 = b2.selectAll();
88493
88564
  return b2.as("primary");
88494
88565
  }).selectAll("primary");
88495
- if (join54) for (const [joinModel, joinAttr] of Object.entries(join54)) {
88566
+ if (join55) for (const [joinModel, joinAttr] of Object.entries(join55)) {
88496
88567
  const [_joinModelSchema, joinModelName] = joinModel.includes(".") ? joinModel.split(".") : [void 0, joinModel];
88497
- query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join55) => join55.onRef(`join_${joinModelName}.${joinAttr.on.to}`, "=", `primary.${joinAttr.on.from}`));
88568
+ query = query.leftJoin(`${joinModel} as join_${joinModelName}`, (join56) => join56.onRef(`join_${joinModelName}.${joinAttr.on.to}`, "=", `primary.${joinAttr.on.from}`));
88498
88569
  }
88499
- const { allSelectsStr, allSelects } = selectAllJoins(join54);
88570
+ const { allSelectsStr, allSelects } = selectAllJoins(join55);
88500
88571
  query = query.select(allSelects);
88501
88572
  if (sortBy?.field) query = query.orderBy(`${getFieldName({
88502
88573
  model: modelKey,
@@ -88504,7 +88575,7 @@ var init_dist8 = __esm({
88504
88575
  })}`, sortBy.direction);
88505
88576
  const res = await query.execute();
88506
88577
  if (!res) return [];
88507
- if (join54) return processJoinedResults(res, join54, allSelectsStr);
88578
+ if (join55) return processJoinedResults(res, join55, allSelectsStr);
88508
88579
  return res;
88509
88580
  },
88510
88581
  async update({ model, modelKey = model, where, update: values2 }) {
@@ -91437,7 +91508,7 @@ var init_sql2 = __esm({
91437
91508
  return new SQL([new StringChunk(str2)]);
91438
91509
  }
91439
91510
  sql22.raw = raw;
91440
- function join54(chunks, separator) {
91511
+ function join55(chunks, separator) {
91441
91512
  const result2 = [];
91442
91513
  for (const [i2, chunk] of chunks.entries()) {
91443
91514
  if (i2 > 0 && separator !== void 0) {
@@ -91447,7 +91518,7 @@ var init_sql2 = __esm({
91447
91518
  }
91448
91519
  return new SQL(result2);
91449
91520
  }
91450
- sql22.join = join54;
91521
+ sql22.join = join55;
91451
91522
  function identifier(value) {
91452
91523
  return new Name(value);
91453
91524
  }
@@ -92798,10 +92869,10 @@ var init_dist11 = __esm({
92798
92869
  checkMissingFields(table2, modelKey, values2);
92799
92870
  return await withReturning(model, modelKey, db2.insert(table2).values(values2), values2);
92800
92871
  },
92801
- async findOne({ model, modelKey = model, where, select: select2, join: join54 }) {
92872
+ async findOne({ model, modelKey = model, where, select: select2, join: join55 }) {
92802
92873
  const table2 = getSchema2(model);
92803
92874
  const clause = convertWhereClause(where, model, modelKey);
92804
- if (join54) {
92875
+ if (join55) {
92805
92876
  const queryModel = getQueryModel(model);
92806
92877
  if (!db2.query || !queryModel) {
92807
92878
  logger2.error(`[# Drizzle Adapter]: The model "${model}" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth@latest generate".`);
@@ -92811,7 +92882,7 @@ var init_dist11 = __esm({
92811
92882
  const renamedJoinResults = [];
92812
92883
  const relationKeys = getRelationKeysByModel().get(queryModel);
92813
92884
  includes = {};
92814
- const joinEntries = Object.entries(join54);
92885
+ const joinEntries = Object.entries(join55);
92815
92886
  for (const [joinModel, joinAttr] of joinEntries) {
92816
92887
  const limit = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100;
92817
92888
  const isUnique = joinAttr.relation === "one-to-one";
@@ -92853,11 +92924,11 @@ var init_dist11 = __esm({
92853
92924
  if (!res.length) return null;
92854
92925
  return res[0];
92855
92926
  },
92856
- async findMany({ model, modelKey = model, where, sortBy, limit, select: select2, offset, join: join54 }) {
92927
+ async findMany({ model, modelKey = model, where, sortBy, limit, select: select2, offset, join: join55 }) {
92857
92928
  const table2 = getSchema2(model);
92858
92929
  const clause = where ? convertWhereClause(where, model, modelKey) : [];
92859
92930
  const sortFn = sortBy?.direction === "desc" ? desc : asc;
92860
- if (join54) {
92931
+ if (join55) {
92861
92932
  const queryModel = getQueryModel(model);
92862
92933
  if (!db2.query || !queryModel) {
92863
92934
  logger2.error(`[# Drizzle Adapter]: The model "${model}" was not found in the query object. Please update your Drizzle schema to include relations or re-generate using "npx auth@latest generate".`);
@@ -92867,7 +92938,7 @@ var init_dist11 = __esm({
92867
92938
  const renamedJoinResults = [];
92868
92939
  const relationKeys = getRelationKeysByModel().get(queryModel);
92869
92940
  includes = {};
92870
- const joinEntries = Object.entries(join54);
92941
+ const joinEntries = Object.entries(join55);
92871
92942
  for (const [joinModel, joinAttr] of joinEntries) {
92872
92943
  const isUnique = joinAttr.relation === "one-to-one";
92873
92944
  const limit2 = joinAttr.limit ?? options.advanced?.database?.defaultFindManyLimit ?? 100;
@@ -102930,7 +103001,7 @@ var init_select2 = __esm({
102930
103001
  const baseTableName = this.tableName;
102931
103002
  const tableName = getTableLikeName(table2);
102932
103003
  for (const item of extractUsedTable(table2)) this.usedTables.add(item);
102933
- if (typeof tableName === "string" && this.config.joins?.some((join54) => join54.alias === tableName)) {
103004
+ if (typeof tableName === "string" && this.config.joins?.some((join55) => join55.alias === tableName)) {
102934
103005
  throw new Error(`Alias "${tableName}" is already used in this query`);
102935
103006
  }
102936
103007
  if (!this.isPartialSelect) {
@@ -103816,7 +103887,7 @@ var init_update = __esm({
103816
103887
  createJoin(joinType) {
103817
103888
  return (table2, on) => {
103818
103889
  const tableName = getTableLikeName(table2);
103819
- if (typeof tableName === "string" && this.config.joins.some((join54) => join54.alias === tableName)) {
103890
+ if (typeof tableName === "string" && this.config.joins.some((join55) => join55.alias === tableName)) {
103820
103891
  throw new Error(`Alias "${tableName}" is already used in this query`);
103821
103892
  }
103822
103893
  if (typeof on === "function") {
@@ -109103,6 +109174,77 @@ var init_extension_decisions = __esm({
109103
109174
  }
109104
109175
  });
109105
109176
 
109177
+ // ../db/src/schema/extensions/extension-agent-sends.ts
109178
+ var EXTENSION_AGENT_SEND_STATUSES, extensionAgentSends, extensionAgentChats;
109179
+ var init_extension_agent_sends = __esm({
109180
+ "../db/src/schema/extensions/extension-agent-sends.ts"() {
109181
+ "use strict";
109182
+ init_drizzle_orm();
109183
+ init_sqlite_core();
109184
+ EXTENSION_AGENT_SEND_STATUSES = [
109185
+ "held",
109186
+ "queued",
109187
+ "started",
109188
+ "done",
109189
+ "failed"
109190
+ ];
109191
+ extensionAgentSends = sqliteTable(
109192
+ "extension_agent_sends",
109193
+ {
109194
+ /** The message id: on the receipt, the queue row and every delivery event. */
109195
+ id: text("id").primaryKey(),
109196
+ /** The extension that sent it. Part of the key, so one extension's keys never answer another's. */
109197
+ extensionId: text("extension_id").notNull(),
109198
+ /** The extension's own key for this send (1-200 characters). */
109199
+ idempotencyKey: text("idempotency_key").notNull(),
109200
+ /** The Mesh agent it was for, when it was addressed to an agent rather than a chat. */
109201
+ agentId: text("agent_id"),
109202
+ /** The chat it went to (canonical id), or null while an agent's chat is not open yet. */
109203
+ sessionId: text("session_id"),
109204
+ /** The folder the chat runs in, as the dispatch resolved it; what a restart resumes it in. */
109205
+ cwd: text("cwd"),
109206
+ /** See {@link EXTENSION_AGENT_SEND_STATUSES}. */
109207
+ status: text("status", { enum: EXTENSION_AGENT_SEND_STATUSES }).notNull(),
109208
+ /** What the first send was told: running now, or waiting. */
109209
+ receiptStatus: text("receipt_status", { enum: ["started", "queued"] }).notNull(),
109210
+ /** Why the first send was told it is waiting (`busy`, `at_capacity`); null when it started. */
109211
+ receiptReason: text("receipt_reason", { enum: ["busy", "at_capacity"] }),
109212
+ /** Why it will never run, once `failed`; null otherwise. */
109213
+ failureReason: text("failure_reason"),
109214
+ /** The fenced message, kept only while `held`; null once it is dispatched. */
109215
+ content: text("content"),
109216
+ /** When it was sent (ISO 8601). The 24-hour key window is measured from here. */
109217
+ createdAt: text("created_at").notNull(),
109218
+ /** When its status last changed (ISO 8601). */
109219
+ updatedAt: text("updated_at").notNull()
109220
+ },
109221
+ (table2) => [
109222
+ uniqueIndex("extension_agent_sends_key_idx").on(table2.extensionId, table2.idempotencyKey),
109223
+ index("extension_agent_sends_status_idx").on(table2.status),
109224
+ check3(
109225
+ "extension_agent_sends_status",
109226
+ sql2`${table2.status} IN ('held', 'queued', 'started', 'done', 'failed')`
109227
+ ),
109228
+ check3("extension_agent_sends_receipt", sql2`${table2.receiptStatus} IN ('started', 'queued')`)
109229
+ ]
109230
+ );
109231
+ extensionAgentChats = sqliteTable(
109232
+ "extension_agent_chats",
109233
+ {
109234
+ /** The extension. */
109235
+ extensionId: text("extension_id").notNull(),
109236
+ /** The Mesh agent id. */
109237
+ agentId: text("agent_id").notNull(),
109238
+ /** The kept chat (canonical id). */
109239
+ sessionId: text("session_id").notNull(),
109240
+ /** When the chat was opened (ISO 8601). */
109241
+ createdAt: text("created_at").notNull()
109242
+ },
109243
+ (table2) => [primaryKey({ columns: [table2.extensionId, table2.agentId] })]
109244
+ );
109245
+ }
109246
+ });
109247
+
109106
109248
  // ../db/src/schema/canvas/channel.ts
109107
109249
  var canvasDocChannels, canvasDocEvents, canvasDocGrants, canvasDocBatches, canvasDocDeliveries, canvasDocIdentityIntents, canvasDocWriteIntents;
109108
109250
  var init_channel = __esm({
@@ -109348,6 +109490,7 @@ var schema_exports = {};
109348
109490
  __export(schema_exports, {
109349
109491
  DEFAULT_AMBIENT_MAX_ENTRIES: () => DEFAULT_AMBIENT_MAX_ENTRIES,
109350
109492
  EVERY_AGENT_GRANT_SUBJECT_ID: () => EVERY_AGENT_GRANT_SUBJECT_ID,
109493
+ EXTENSION_AGENT_SEND_STATUSES: () => EXTENSION_AGENT_SEND_STATUSES,
109351
109494
  EXTENSION_DECISION_DEADLINE_STATES: () => EXTENSION_DECISION_DEADLINE_STATES,
109352
109495
  EXTENSION_DECISION_RESOLVERS: () => EXTENSION_DECISION_RESOLVERS,
109353
109496
  KNOWN_PROJECT_REPORT_KINDS: () => KNOWN_PROJECT_REPORT_KINDS,
@@ -109410,6 +109553,8 @@ __export(schema_exports, {
109410
109553
  connectorRuntimeBindings: () => connectorRuntimeBindings,
109411
109554
  connectorUsageAttempts: () => connectorUsageAttempts,
109412
109555
  connectorUsageTerminalReceipts: () => connectorUsageTerminalReceipts,
109556
+ extensionAgentChats: () => extensionAgentChats,
109557
+ extensionAgentSends: () => extensionAgentSends,
109413
109558
  extensionDecisions: () => extensionDecisions,
109414
109559
  handleTombstones: () => handleTombstones,
109415
109560
  knownProjectReporters: () => knownProjectReporters,
@@ -109497,6 +109642,7 @@ var init_schema4 = __esm({
109497
109642
  init_notifications();
109498
109643
  init_projects();
109499
109644
  init_extension_decisions();
109645
+ init_extension_agent_sends();
109500
109646
  init_channel();
109501
109647
  }
109502
109648
  });
@@ -112612,7 +112758,12 @@ function permissionSeedForOrigin(origin) {
112612
112758
  // A resume after an account's reset goes to a session that is already
112613
112759
  // bound: its row is its power, and the origin must not add to it.
112614
112760
  //
112761
+ // An extension's message to an agent is app data. No extension turns the
112762
+ // operator's stop into a grant of its own, so the chat it opens is born
112763
+ // with nothing seeded, like a connector event's.
112764
+ //
112615
112765
  // The harness is not a surface anybody ships to.
112766
+ case "extension-message":
112616
112767
  case "schedule":
112617
112768
  case "relay-binding":
112618
112769
  case "agent-dm":
@@ -119898,6 +120049,36 @@ var init_hooks_projection = __esm({
119898
120049
  }
119899
120050
  });
119900
120051
 
120052
+ // ../harness/src/plan/dev-link-labels.ts
120053
+ function devLinkLabel(folder) {
120054
+ return `(dev link: ${folder})`;
120055
+ }
120056
+ function devLinkMarkerLine(folder) {
120057
+ return `<!-- ${DEV_LINK_MARKER} ${folder.split("-->").join("--&gt;")} -->`;
120058
+ }
120059
+ function withDevLinkMarker(generatedLine, devLink) {
120060
+ return devLink === void 0 ? generatedLine : `${generatedLine}
120061
+ ${devLinkMarkerLine(devLink)}`;
120062
+ }
120063
+ function labelDevLinkActions(actions, plugin) {
120064
+ const folder = plugin.devLink?.path;
120065
+ if (folder === void 0) return actions;
120066
+ const label = devLinkLabel(folder);
120067
+ for (const action of actions) {
120068
+ action.devLink = folder;
120069
+ action.reason = action.reason === void 0 ? label : `${action.reason} ${label}`;
120070
+ }
120071
+ return actions;
120072
+ }
120073
+ var DEV_LINK_MARKER, MANAGED_HOOK_DEV_LINK_KEY;
120074
+ var init_dev_link_labels = __esm({
120075
+ "../harness/src/plan/dev-link-labels.ts"() {
120076
+ "use strict";
120077
+ DEV_LINK_MARKER = "dorkos:dev-link";
120078
+ MANAGED_HOOK_DEV_LINK_KEY = "_dorkosDevLink";
120079
+ }
120080
+ });
120081
+
119901
120082
  // ../harness/src/plan/command-formats.ts
119902
120083
  function commandDropReason(harness) {
119903
120084
  const format = HARNESS_COMMAND_FORMATS[harness];
@@ -119958,9 +120139,12 @@ function pluginEnvPrefix(absInstallDir, platform3) {
119958
120139
  const data = shellQuote(pluginDataText(absInstallDir, platform3));
119959
120140
  return `export CLAUDE_PLUGIN_ROOT=${root} CLAUDE_PLUGIN_DATA=${data}; `;
119960
120141
  }
119961
- function buildCommandWrapper(content, absInstallDir, relDir) {
120142
+ function buildCommandWrapper(content, absInstallDir, relDir, devLink) {
119962
120143
  const rewritten = rewritePluginTokens(content, absInstallDir);
119963
- return insertAfterFrontmatter(rewritten, generatedCommandMarkerLine(relDir));
120144
+ return insertAfterFrontmatter(
120145
+ rewritten,
120146
+ withDevLinkMarker(generatedCommandMarkerLine(relDir), devLink)
120147
+ );
119964
120148
  }
119965
120149
  function splitFrontmatter2(content) {
119966
120150
  const lines = content.split("\n");
@@ -119982,11 +120166,11 @@ function frontmatterField(frontmatter, field) {
119982
120166
  function opencodeWrapperFilename(pkg, command) {
119983
120167
  return `${pkg}-${command}.md`;
119984
120168
  }
119985
- function buildOpencodeCommandWrapper(content, absInstallDir, relDir) {
120169
+ function buildOpencodeCommandWrapper(content, absInstallDir, relDir, devLink) {
119986
120170
  const rewritten = rewritePluginTokens(content, absInstallDir);
119987
120171
  const { frontmatter, body } = splitFrontmatter2(rewritten);
119988
120172
  const description = frontmatterField(frontmatter, "description");
119989
- const marker = generatedCommandMarkerLine(relDir);
120173
+ const marker = withDevLinkMarker(generatedCommandMarkerLine(relDir), devLink);
119990
120174
  const reducedFrontmatter = description !== void 0 ? `---
119991
120175
  description: ${description}
119992
120176
  ---
@@ -120051,7 +120235,8 @@ function toManagedHooks(plugin, absInstallDir) {
120051
120235
  out[event] = groups.map((group) => ({
120052
120236
  ...group,
120053
120237
  hooks: group.hooks.map((h2) => ({ ...h2, command: `${prefix}${h2.command}` })),
120054
- [MANAGED_HOOK_SENTINEL_KEY]: plugin.name
120238
+ [MANAGED_HOOK_SENTINEL_KEY]: plugin.name,
120239
+ ...plugin.devLink !== void 0 && { [MANAGED_HOOK_DEV_LINK_KEY]: plugin.devLink.path }
120055
120240
  }));
120056
120241
  }
120057
120242
  return out;
@@ -120141,6 +120326,7 @@ function planInstalledCommands(harness, plugin, repoRoot) {
120141
120326
  }
120142
120327
  function planClaudeInstalledCommands(plugin, relDir, repoRoot) {
120143
120328
  const absInstallDir = join12(repoRoot, relDir);
120329
+ const devLink = plugin.devLink?.path;
120144
120330
  const pkgDir = `${CLAUDE_COMMANDS_DIR}/${plugin.name}`;
120145
120331
  const actions = [];
120146
120332
  for (const cmd of plugin.commands) {
@@ -120153,7 +120339,7 @@ function planClaudeInstalledCommands(plugin, relDir, repoRoot) {
120153
120339
  source: cmd.sourcePath,
120154
120340
  target: `${pkgDir}/${cmd.name}.md`
120155
120341
  };
120156
- setActionContent(action, buildCommandWrapper(cmd.content, absInstallDir, relDir));
120342
+ setActionContent(action, buildCommandWrapper(cmd.content, absInstallDir, relDir, devLink));
120157
120343
  actions.push(action);
120158
120344
  }
120159
120345
  const gitignore = {
@@ -120170,6 +120356,7 @@ function planClaudeInstalledCommands(plugin, relDir, repoRoot) {
120170
120356
  }
120171
120357
  function planOpencodeInstalledCommands(plugin, relDir, repoRoot) {
120172
120358
  const absInstallDir = join12(repoRoot, relDir);
120359
+ const devLink = plugin.devLink?.path;
120173
120360
  const actions = [];
120174
120361
  for (const cmd of plugin.commands) {
120175
120362
  const action = {
@@ -120181,7 +120368,10 @@ function planOpencodeInstalledCommands(plugin, relDir, repoRoot) {
120181
120368
  source: cmd.sourcePath,
120182
120369
  target: `${OPENCODE_COMMANDS_DIR}/${opencodeWrapperFilename(plugin.name, cmd.name)}`
120183
120370
  };
120184
- setActionContent(action, buildOpencodeCommandWrapper(cmd.content, absInstallDir, relDir));
120371
+ setActionContent(
120372
+ action,
120373
+ buildOpencodeCommandWrapper(cmd.content, absInstallDir, relDir, devLink)
120374
+ );
120185
120375
  actions.push(action);
120186
120376
  }
120187
120377
  return actions;
@@ -120309,6 +120499,7 @@ var init_installed_projector = __esm({
120309
120499
  init_schema5();
120310
120500
  init_hooks();
120311
120501
  init_content_map();
120502
+ init_dev_link_labels();
120312
120503
  init_command_formats();
120313
120504
  init_scanner2();
120314
120505
  CLAUDE_COMMANDS_DIR = ".claude/commands";
@@ -120356,7 +120547,10 @@ function bothScopesNoticeReason(pkg, repoRoot) {
120356
120547
  return `is installed twice: once for all your projects, and once in this project. In a session DorkOS runs, Claude Code sees both copies, under different names. On its own, Claude Code sees only this project's copy. So does Codex, until you share it. Uninstall one if you only meant to have one. Run dorkos uninstall ${pkg} --project ${repoRoot} to remove this project's copy. Run dorkos uninstall ${pkg} to remove the all-projects copy. Both need DorkOS running, and both ask you first.`;
120357
120548
  }
120358
120549
  function globalInstallDropReason(plugin, opts) {
120359
- const shared = opts?.sharedWithTools === true;
120550
+ const reason = globalInstallReasonOf(plugin, opts?.sharedWithTools === true);
120551
+ return plugin.devLink === void 0 ? reason : `${reason} ${devLinkLabel(plugin.devLink.path)}`;
120552
+ }
120553
+ function globalInstallReasonOf(plugin, shared) {
120360
120554
  if (plugin.skills.length === 0) {
120361
120555
  return shared ? GLOBAL_INSTALL_NO_SKILLS_SHARED : GLOBAL_INSTALL_NO_SKILLS;
120362
120556
  }
@@ -120365,11 +120559,11 @@ function globalInstallDropReason(plugin, opts) {
120365
120559
  namedSkills(plugin.skills.map((skill) => skill.name)),
120366
120560
  shared
120367
120561
  );
120368
- const join54 = (into) => shared ? into : `${into}${into.endsWith(".") ? "" : "."} ${GLOBAL_INSTALL_SHARE_OFFER}`;
120562
+ const join55 = (into) => shared ? into : `${into}${into.endsWith(".") ? "" : "."} ${GLOBAL_INSTALL_SHARE_OFFER}`;
120369
120563
  const timed = plugin.skills.filter((skill) => skill.hasSchedule);
120370
- if (timed.length === 0) return join54(lead);
120564
+ if (timed.length === 0) return join55(lead);
120371
120565
  const allLinked = timed.every((skill) => skill.linkedInDorkHome === true);
120372
- return join54(`${lead}. ${allLinked ? GLOBAL_INSTALL_TIMERS_WORK : GLOBAL_INSTALL_TIMERS_PENDING}`);
120566
+ return join55(`${lead}. ${allLinked ? GLOBAL_INSTALL_TIMERS_WORK : GLOBAL_INSTALL_TIMERS_PENDING}`);
120373
120567
  }
120374
120568
  function planGlobalInstallDrops(input4) {
120375
120569
  const projectNames = new Set(
@@ -120379,12 +120573,12 @@ function planGlobalInstallDrops(input4) {
120379
120573
  const drops = [];
120380
120574
  for (const plugin of input4.plugins) {
120381
120575
  if (plugin.location.scope !== "global") continue;
120382
- drops.push(
120383
- dropWholePlugin(
120384
- plugin,
120385
- globalInstallDropReason(plugin, { sharedWithTools: input4.sharedWithTools === true })
120386
- )
120576
+ const drop = dropWholePlugin(
120577
+ plugin,
120578
+ globalInstallDropReason(plugin, { sharedWithTools: input4.sharedWithTools === true })
120387
120579
  );
120580
+ if (plugin.devLink !== void 0) drop.devLink = plugin.devLink.path;
120581
+ drops.push(drop);
120388
120582
  if (!projectNames.has(plugin.name) || noticed.has(plugin.name)) continue;
120389
120583
  noticed.add(plugin.name);
120390
120584
  drops.push(dropWholePlugin(plugin, bothScopesNoticeReason(plugin.name, input4.repoRoot)));
@@ -120411,6 +120605,7 @@ var GLOBAL_HOOKS_ATTRIBUTION, GLOBAL_INSTALL_LEAD, GLOBAL_INSTALL_LEAD_SHARED, G
120411
120605
  var init_global_installs = __esm({
120412
120606
  "../harness/src/plan/global-installs.ts"() {
120413
120607
  "use strict";
120608
+ init_dev_link_labels();
120414
120609
  init_installed_projector();
120415
120610
  GLOBAL_HOOKS_ATTRIBUTION = "claude-code";
120416
120611
  GLOBAL_INSTALL_LEAD = "installed for all your projects. Only the Claude Code sessions DorkOS runs can see it.";
@@ -120424,14 +120619,68 @@ var init_global_installs = __esm({
120424
120619
  }
120425
120620
  });
120426
120621
 
120427
- // ../harness/src/sources/installed.ts
120428
- import { existsSync as existsSync6, lstatSync as lstatSync2, readdirSync as readdirSync3 } from "node:fs";
120622
+ // ../harness/src/sources/dev-links.ts
120623
+ import { lstatSync as lstatSync2, realpathSync as realpathSync3 } from "node:fs";
120429
120624
  import { join as join13 } from "node:path";
120625
+ function readDevLinksSync(dorkHome) {
120626
+ if (dorkHome === void 0) return [];
120627
+ let text2;
120628
+ try {
120629
+ text2 = readTextFileWithinSync(
120630
+ join13(dorkHome, DEV_LINKS_FILE),
120631
+ PACKAGE_TEXT_MAX_BYTES,
120632
+ "The dev links file"
120633
+ );
120634
+ } catch {
120635
+ return [];
120636
+ }
120637
+ const parsed = parseDevLinksFile(text2);
120638
+ return parsed === "unreadable" ? [] : parsed.links;
120639
+ }
120640
+ function isLinkAt(target) {
120641
+ try {
120642
+ return lstatSync2(target, { throwIfNoEntry: false })?.isSymbolicLink() === true;
120643
+ } catch {
120644
+ return false;
120645
+ }
120646
+ }
120647
+ function realPathOf(target) {
120648
+ try {
120649
+ return realpathSync3.native(target);
120650
+ } catch {
120651
+ return null;
120652
+ }
120653
+ }
120654
+ function devLinkForSlot(pluginsRoot, entryName, scope, records) {
120655
+ if (records.length === 0) return null;
120656
+ const slot = join13(pluginsRoot, entryName);
120657
+ if (!isLinkAt(slot)) return null;
120658
+ const realRoot = realPathOf(pluginsRoot);
120659
+ if (realRoot === null) return null;
120660
+ const canonicalSlot = join13(realRoot, entryName);
120661
+ const record2 = records.find((r3) => r3.scope === scope && r3.slot === canonicalSlot);
120662
+ if (!record2) return null;
120663
+ return isStillLinked(slot, record2) ? record2 : null;
120664
+ }
120665
+ function isStillLinked(slot, record2) {
120666
+ return realPathOf(slot) === record2.target;
120667
+ }
120668
+ var init_dev_links = __esm({
120669
+ "../harness/src/sources/dev-links.ts"() {
120670
+ "use strict";
120671
+ init_bounded_read();
120672
+ init_marketplace_schemas();
120673
+ }
120674
+ });
120675
+
120676
+ // ../harness/src/sources/installed.ts
120677
+ import { existsSync as existsSync6, lstatSync as lstatSync3, readdirSync as readdirSync3 } from "node:fs";
120678
+ import { join as join14 } from "node:path";
120430
120679
  function isProjectScoped(plugin) {
120431
120680
  return plugin.location.scope === "project";
120432
120681
  }
120433
120682
  function dorkManifestPath(pluginDir) {
120434
- return join13(pluginDir, ".dork", "manifest.json");
120683
+ return join14(pluginDir, ".dork", "manifest.json");
120435
120684
  }
120436
120685
  function readPluginManifest(pluginDir) {
120437
120686
  const manifestPath = dorkManifestPath(pluginDir);
@@ -120447,7 +120696,7 @@ function readPluginManifest(pluginDir) {
120447
120696
  return { name: parsed.data.name, type: parsed.data.type, layers: parsed.data.layers };
120448
120697
  }
120449
120698
  function readCcPluginManifest(pluginDir) {
120450
- const ccManifestPath = join13(pluginDir, ".claude-plugin", "plugin.json");
120699
+ const ccManifestPath = join14(pluginDir, ".claude-plugin", "plugin.json");
120451
120700
  if (!existsSync6(ccManifestPath)) return void 0;
120452
120701
  let raw;
120453
120702
  try {
@@ -120489,7 +120738,7 @@ function readMatcherGroup(group) {
120489
120738
  };
120490
120739
  }
120491
120740
  function readPluginHooks(pluginDir, sourcePrefix) {
120492
- const hooksPath = join13(pluginDir, "hooks", "hooks.json");
120741
+ const hooksPath = join14(pluginDir, "hooks", "hooks.json");
120493
120742
  if (!existsSync6(hooksPath)) return {};
120494
120743
  const relPath2 = `${sourcePrefix}/hooks/hooks.json`;
120495
120744
  let raw;
@@ -120528,7 +120777,7 @@ function toInstalledSkill(entry, absSkillsRoot, dorkHomeLink) {
120528
120777
  let skillMd = "";
120529
120778
  try {
120530
120779
  skillMd = readTextFileWithinSync(
120531
- join13(absSkillsRoot, entry.name, "SKILL.md"),
120780
+ join14(absSkillsRoot, entry.name, "SKILL.md"),
120532
120781
  PACKAGE_TEXT_MAX_BYTES,
120533
120782
  "The SKILL.md"
120534
120783
  );
@@ -120545,8 +120794,8 @@ function toInstalledSkill(entry, absSkillsRoot, dorkHomeLink) {
120545
120794
  };
120546
120795
  }
120547
120796
  function collectPortableSkills(pluginDir, sourcePrefix, dorkHomeLink) {
120548
- const skillsRoot = join13(pluginDir, "skills");
120549
- const tasksRoot = join13(pluginDir, ".dork", "tasks");
120797
+ const skillsRoot = join14(pluginDir, "skills");
120798
+ const tasksRoot = join14(pluginDir, ".dork", "tasks");
120550
120799
  const contained = { followSymlinks: false };
120551
120800
  const skillsRel = `${sourcePrefix}/skills`;
120552
120801
  const tasksRel = `${sourcePrefix}/.dork/tasks`;
@@ -120573,7 +120822,7 @@ function collectPortableSkills(pluginDir, sourcePrefix, dorkHomeLink) {
120573
120822
  };
120574
120823
  }
120575
120824
  function collectCommands(pluginDir, sourcePrefix) {
120576
- const commandsRoot = join13(pluginDir, "commands");
120825
+ const commandsRoot = join14(pluginDir, "commands");
120577
120826
  if (!existsSync6(commandsRoot)) return [];
120578
120827
  const commands = [];
120579
120828
  for (const entry of readdirSync3(commandsRoot, { withFileTypes: true })) {
@@ -120581,7 +120830,7 @@ function collectCommands(pluginDir, sourcePrefix) {
120581
120830
  let content;
120582
120831
  try {
120583
120832
  content = readTextFileWithinSync(
120584
- join13(commandsRoot, entry.name),
120833
+ join14(commandsRoot, entry.name),
120585
120834
  PACKAGE_TEXT_MAX_BYTES,
120586
120835
  "The command"
120587
120836
  );
@@ -120596,13 +120845,15 @@ function collectCommands(pluginDir, sourcePrefix) {
120596
120845
  }
120597
120846
  return commands.sort((a2, b2) => a2.name.localeCompare(b2.name));
120598
120847
  }
120599
- function scanPluginsRoot(pluginsRoot, scope, dorkHome) {
120848
+ function scanPluginsRoot(pluginsRoot, scope, devLinks, dorkHome) {
120600
120849
  if (!existsSync6(pluginsRoot)) return { plugins: [], unreadableManifests: [] };
120601
120850
  const plugins = [];
120602
120851
  const unreadableManifests = [];
120603
120852
  for (const entry of readdirSync3(pluginsRoot, { withFileTypes: true })) {
120604
- if (!entry.isDirectory() || isInstallSiblingName(entry.name)) continue;
120605
- const pluginDir = join13(pluginsRoot, entry.name);
120853
+ if (isInstallSiblingName(entry.name)) continue;
120854
+ const devLink = entry.isSymbolicLink() ? devLinkForSlot(pluginsRoot, entry.name, scope, devLinks) : null;
120855
+ if (!entry.isDirectory() && devLink === null) continue;
120856
+ const pluginDir = join14(pluginsRoot, entry.name);
120606
120857
  const location = scope === "global" ? { scope, absDir: pluginDir } : { scope, relDir: `${PROJECT_PLUGINS_DIR}/${entry.name}` };
120607
120858
  const sourcePrefix = location.scope === "global" ? location.absDir : location.relDir;
120608
120859
  const manifest = readPluginManifest(pluginDir);
@@ -120622,21 +120873,24 @@ function scanPluginsRoot(pluginsRoot, scope, dorkHome) {
120622
120873
  }
120623
120874
  if (!manifest) continue;
120624
120875
  const { hooks, unreadable } = readPluginHooks(pluginDir, sourcePrefix);
120625
- const dorkHomeLink = scope === "global" && dorkHome !== void 0 ? (skillName) => lstatSync2(join13(dorkHome, "skills", `${manifest.name}__${skillName}`), {
120876
+ const dorkHomeLink = scope === "global" && dorkHome !== void 0 ? (skillName) => lstatSync3(join14(dorkHome, "skills", `${manifest.name}__${skillName}`), {
120626
120877
  throwIfNoEntry: false
120627
120878
  }) !== void 0 : void 0;
120628
120879
  const portable = collectPortableSkills(pluginDir, sourcePrefix, dorkHomeLink);
120880
+ const commands = collectCommands(pluginDir, sourcePrefix);
120881
+ if (devLink !== null && !isStillLinked(pluginDir, devLink)) continue;
120629
120882
  plugins.push({
120630
120883
  name: manifest.name,
120631
120884
  type: manifest.type,
120632
120885
  location,
120633
120886
  skills: portable.skills,
120634
- commands: collectCommands(pluginDir, sourcePrefix),
120887
+ commands,
120635
120888
  ...hooks ? { hooks } : {},
120636
120889
  ...unreadable ? { unreadableHooks: unreadable } : {},
120637
120890
  ...portable.unreadableRoots.length > 0 ? { unreadableSkillRoots: portable.unreadableRoots } : {},
120638
120891
  ...portable.unreadableSkills.length > 0 ? { unreadableSkills: portable.unreadableSkills } : {},
120639
- layers: manifest.layers
120892
+ layers: manifest.layers,
120893
+ ...devLink !== null ? { devLink: { path: devLink.target } } : {}
120640
120894
  });
120641
120895
  }
120642
120896
  return {
@@ -120649,8 +120903,9 @@ function scanInstalledPlugins(opts) {
120649
120903
  }
120650
120904
  function scanInstalledSources(opts) {
120651
120905
  const empty = { plugins: [], unreadableManifests: [] };
120652
- const global2 = opts.dorkHome ? scanPluginsRoot(join13(opts.dorkHome, "plugins"), "global", opts.dorkHome) : empty;
120653
- const project2 = opts.projectRoot ? scanPluginsRoot(join13(opts.projectRoot, PROJECT_PLUGINS_DIR), "project") : empty;
120906
+ const devLinks = opts.devLinks ?? readDevLinksSync(opts.dorkHome);
120907
+ const global2 = opts.dorkHome ? scanPluginsRoot(join14(opts.dorkHome, "plugins"), "global", devLinks, opts.dorkHome) : empty;
120908
+ const project2 = opts.projectRoot ? scanPluginsRoot(join14(opts.projectRoot, PROJECT_PLUGINS_DIR), "project", devLinks) : empty;
120654
120909
  return {
120655
120910
  plugins: [...global2.plugins, ...project2.plugins],
120656
120911
  unreadableManifests: [...global2.unreadableManifests, ...project2.unreadableManifests]
@@ -120667,6 +120922,7 @@ var init_installed = __esm({
120667
120922
  init_parser();
120668
120923
  init_scanner2();
120669
120924
  init_hooks();
120925
+ init_dev_links();
120670
120926
  PROJECT_PLUGINS_DIR = ".dork/plugins";
120671
120927
  }
120672
120928
  });
@@ -120752,8 +121008,8 @@ var init_unreadable_skills = __esm({
120752
121008
  });
120753
121009
 
120754
121010
  // ../harness/src/inventory/read.ts
120755
- import { readFileSync as readFileSync7, readdirSync as readdirSync4, lstatSync as lstatSync3, realpathSync as realpathSync3, statSync as statSync4 } from "node:fs";
120756
- import { join as join14, sep as sep3 } from "node:path";
121011
+ import { readFileSync as readFileSync7, readdirSync as readdirSync4, lstatSync as lstatSync4, realpathSync as realpathSync4, statSync as statSync4 } from "node:fs";
121012
+ import { join as join15, sep as sep3 } from "node:path";
120757
121013
  function relPath(...parts) {
120758
121014
  return parts.join("/").split(sep3).join("/");
120759
121015
  }
@@ -120766,7 +121022,7 @@ function parserMessage(err) {
120766
121022
  }
120767
121023
  function nothingIsThere(absPath) {
120768
121024
  try {
120769
- lstatSync3(absPath);
121025
+ lstatSync4(absPath);
120770
121026
  return false;
120771
121027
  } catch (err) {
120772
121028
  return err.code === "ENOENT";
@@ -120829,7 +121085,7 @@ function readJsonFile(absPath, relFile, kind) {
120829
121085
  }
120830
121086
  function realpathOr(absPath) {
120831
121087
  try {
120832
- return realpathSync3(absPath);
121088
+ return realpathSync4(absPath);
120833
121089
  } catch {
120834
121090
  return absPath;
120835
121091
  }
@@ -120845,7 +121101,7 @@ function listMarkdownFiles(absRoot, relRoot, kind, options = {}) {
120845
121101
  const result2 = readDirEntries(absDir, relDir, kind);
120846
121102
  if (result2.unreadable) unreadable.push(result2.unreadable);
120847
121103
  for (const entry of result2.entries) {
120848
- const absEntry = join14(absDir, entry.name);
121104
+ const absEntry = join15(absDir, entry.name);
120849
121105
  const relEntry = relPath(relDir, entry.name);
120850
121106
  if (entry.isDirectory()) {
120851
121107
  if (options.recursive) walk(absEntry, relEntry);
@@ -120894,10 +121150,10 @@ var init_read = __esm({
120894
121150
  });
120895
121151
 
120896
121152
  // ../harness/src/inventory/mcp.ts
120897
- import { join as join15 } from "node:path";
121153
+ import { join as join16 } from "node:path";
120898
121154
  function inventoryMcpServers(repoRoot) {
120899
121155
  const { value, unreadable } = readJsonFile(
120900
- join15(repoRoot, MCP_CONFIG_SOURCE),
121156
+ join16(repoRoot, MCP_CONFIG_SOURCE),
120901
121157
  MCP_CONFIG_SOURCE,
120902
121158
  "mcp"
120903
121159
  );
@@ -121424,15 +121680,15 @@ var init_types4 = __esm({
121424
121680
  });
121425
121681
 
121426
121682
  // ../harness/src/inventory/skills.ts
121427
- import { existsSync as existsSync7, lstatSync as lstatSync4, readdirSync as readdirSync5, realpathSync as realpathSync4, statSync as statSync5 } from "node:fs";
121428
- import { join as join16, resolve as resolve2, sep as sep4 } from "node:path";
121683
+ import { existsSync as existsSync7, lstatSync as lstatSync5, readdirSync as readdirSync5, realpathSync as realpathSync5, statSync as statSync5 } from "node:fs";
121684
+ import { join as join17, resolve as resolve2, sep as sep4 } from "node:path";
121429
121685
  function isInside(absPath, absRoot) {
121430
121686
  return absPath === absRoot || absPath.startsWith(absRoot + sep4);
121431
121687
  }
121432
121688
  function isManagedProjection(repoRoot, absEntry) {
121433
121689
  let real2;
121434
121690
  try {
121435
- real2 = realpathSync4(absEntry);
121691
+ real2 = realpathSync5(absEntry);
121436
121692
  } catch {
121437
121693
  return false;
121438
121694
  }
@@ -121441,14 +121697,14 @@ function isManagedProjection(repoRoot, absEntry) {
121441
121697
  }
121442
121698
  function realpathOr2(absPath) {
121443
121699
  try {
121444
- return realpathSync4(absPath);
121700
+ return realpathSync5(absPath);
121445
121701
  } catch {
121446
121702
  return absPath;
121447
121703
  }
121448
121704
  }
121449
121705
  function declaredName(repoRoot, sourceDir) {
121450
121706
  const rel = relPath(sourceDir, SKILL_FILENAME);
121451
- const { text: text2 } = readTextFile(join16(repoRoot, rel), rel, "skill");
121707
+ const { text: text2 } = readTextFile(join17(repoRoot, rel), rel, "skill");
121452
121708
  if (text2 === void 0) return void 0;
121453
121709
  const declared = readRawFrontmatter(text2)?.data.name;
121454
121710
  if (typeof declared !== "string") return void 0;
@@ -121465,14 +121721,14 @@ function inventorySkills(repoRoot) {
121465
121721
  };
121466
121722
  }
121467
121723
  function collect(repoRoot, root, options) {
121468
- const absRoot = join16(repoRoot, root);
121724
+ const absRoot = join17(repoRoot, root);
121469
121725
  const probe = readDirEntries(absRoot, root, "skill");
121470
121726
  if (probe.unreadable) return { skills: [], unreadable: [probe.unreadable] };
121471
121727
  const scanned = scanSkillDirs(absRoot, root, options);
121472
121728
  const skills = [];
121473
121729
  for (const skill of scanned) {
121474
- const absEntry = join16(repoRoot, skill.sourceDir);
121475
- const isSymlink2 = lstatSync4(absEntry, { throwIfNoEntry: false })?.isSymbolicLink() === true;
121730
+ const absEntry = join17(repoRoot, skill.sourceDir);
121731
+ const isSymlink2 = lstatSync5(absEntry, { throwIfNoEntry: false })?.isSymbolicLink() === true;
121476
121732
  if (root === CLAUDE_SKILLS_DIR && isSymlink2 && isManagedProjection(repoRoot, absEntry))
121477
121733
  continue;
121478
121734
  const declared = declaredName(repoRoot, skill.sourceDir);
@@ -121505,7 +121761,7 @@ function lockedSkillFolders(absRoot, root, entries, found, options) {
121505
121761
  const isLink = entry.isSymbolicLink();
121506
121762
  if (isLink && entry.name.includes(INSTALLED_PROJECTION_MARKER) && !options.includeManagedProjections)
121507
121763
  continue;
121508
- const cause = lockedSkillCause(join16(absRoot, entry.name));
121764
+ const cause = lockedSkillCause(join17(absRoot, entry.name));
121509
121765
  if (cause === void 0) continue;
121510
121766
  records.push({
121511
121767
  kind: "skill",
@@ -121530,7 +121786,7 @@ function lockedSkillCause(absEntry) {
121530
121786
  return "folder";
121531
121787
  }
121532
121788
  if (!listing.includes(SKILL_FILENAME)) return void 0;
121533
- return existsSync7(join16(absEntry, SKILL_FILENAME)) ? void 0 : "file";
121789
+ return existsSync7(join17(absEntry, SKILL_FILENAME)) ? void 0 : "file";
121534
121790
  }
121535
121791
  var MANAGED_LINK_ROOTS, SKILL_ROOTS, ENGINE_WRITTEN_ROOTS, LOCKED_SKILL_REASONS;
121536
121792
  var init_skills = __esm({
@@ -121558,17 +121814,17 @@ var init_skills = __esm({
121558
121814
  });
121559
121815
 
121560
121816
  // ../harness/src/inventory/commands.ts
121561
- import { join as join17 } from "node:path";
121817
+ import { join as join18 } from "node:path";
121562
121818
  function inventoryCommands(repoRoot) {
121563
121819
  const { files, unreadable } = listMarkdownFiles(
121564
- join17(repoRoot, CLAUDE_COMMANDS_DIR),
121820
+ join18(repoRoot, CLAUDE_COMMANDS_DIR),
121565
121821
  CLAUDE_COMMANDS_DIR,
121566
121822
  "command",
121567
121823
  { recursive: true }
121568
121824
  );
121569
121825
  const commands = [];
121570
121826
  for (const file2 of files) {
121571
- const read = readTextFile(join17(repoRoot, file2.source), file2.source, "command");
121827
+ const read = readTextFile(join18(repoRoot, file2.source), file2.source, "command");
121572
121828
  if (read.text === void 0) {
121573
121829
  if (read.unreadable) unreadable.push(read.unreadable);
121574
121830
  continue;
@@ -121592,7 +121848,7 @@ var init_commands = __esm({
121592
121848
  });
121593
121849
 
121594
121850
  // ../harness/src/inventory/hooks.ts
121595
- import { join as join18 } from "node:path";
121851
+ import { join as join19 } from "node:path";
121596
121852
  function isRecord2(value) {
121597
121853
  return typeof value === "object" && value !== null && !Array.isArray(value);
121598
121854
  }
@@ -121603,7 +121859,7 @@ function isWhollyManaged(groups) {
121603
121859
  );
121604
121860
  }
121605
121861
  function inventorySettingsHooks(repoRoot, source, origin) {
121606
- const { value, unreadable } = readJsonFile(join18(repoRoot, source), source, "hook");
121862
+ const { value, unreadable } = readJsonFile(join19(repoRoot, source), source, "hook");
121607
121863
  if (unreadable) return { hooks: [], unreadable: [unreadable] };
121608
121864
  if (value === void 0) return { hooks: [], unreadable: [] };
121609
121865
  const declared = value.hooks;
@@ -121637,7 +121893,7 @@ function inventorySkillFrontmatterHooks(repoRoot, skills) {
121637
121893
  const unreadable = [];
121638
121894
  for (const skill of skills) {
121639
121895
  const source = relPath(skill.source, SKILL_FILENAME);
121640
- const read = readTextFile(join18(repoRoot, source), source, "hook");
121896
+ const read = readTextFile(join19(repoRoot, source), source, "hook");
121641
121897
  if (read.text === void 0) {
121642
121898
  if (read.unreadable) unreadable.push(read.unreadable);
121643
121899
  continue;
@@ -121696,20 +121952,20 @@ var init_hooks2 = __esm({
121696
121952
  });
121697
121953
 
121698
121954
  // ../harness/src/inventory/agents.ts
121699
- import { join as join19 } from "node:path";
121955
+ import { join as join20 } from "node:path";
121700
121956
  function stemOf(source) {
121701
121957
  return (source.split("/").pop() ?? source).slice(0, -".md".length);
121702
121958
  }
121703
121959
  function inventoryAgents(repoRoot) {
121704
121960
  const { files, unreadable } = listMarkdownFiles(
121705
- join19(repoRoot, CLAUDE_AGENTS_DIR),
121961
+ join20(repoRoot, CLAUDE_AGENTS_DIR),
121706
121962
  CLAUDE_AGENTS_DIR,
121707
121963
  "agent",
121708
121964
  { recursive: true }
121709
121965
  );
121710
121966
  const agents2 = [];
121711
121967
  for (const file2 of files) {
121712
- const read = readTextFile(join19(repoRoot, file2.source), file2.source, "agent");
121968
+ const read = readTextFile(join20(repoRoot, file2.source), file2.source, "agent");
121713
121969
  if (read.text === void 0) {
121714
121970
  if (read.unreadable) unreadable.push(read.unreadable);
121715
121971
  continue;
@@ -121745,7 +122001,7 @@ var init_agents = __esm({
121745
122001
  });
121746
122002
 
121747
122003
  // ../harness/src/inventory/rules.ts
121748
- import { join as join20 } from "node:path";
122004
+ import { join as join21 } from "node:path";
121749
122005
  function readPathGlobs(value) {
121750
122006
  const globs = typeof value === "string" ? value.split(",") : Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
121751
122007
  const trimmed = globs.map((glob) => glob.trim()).filter((glob) => glob.length > 0);
@@ -121753,14 +122009,14 @@ function readPathGlobs(value) {
121753
122009
  }
121754
122010
  function inventoryRules(repoRoot) {
121755
122011
  const { files, unreadable } = listMarkdownFiles(
121756
- join20(repoRoot, CLAUDE_RULES_DIR),
122012
+ join21(repoRoot, CLAUDE_RULES_DIR),
121757
122013
  CLAUDE_RULES_DIR,
121758
122014
  "rule",
121759
122015
  { recursive: true }
121760
122016
  );
121761
122017
  const rules = [];
121762
122018
  for (const file2 of files) {
121763
- const read = readTextFile(join20(repoRoot, file2.source), file2.source, "rule");
122019
+ const read = readTextFile(join21(repoRoot, file2.source), file2.source, "rule");
121764
122020
  if (read.text === void 0) {
121765
122021
  if (read.unreadable) unreadable.push(read.unreadable);
121766
122022
  continue;
@@ -122611,7 +122867,7 @@ var init_dist13 = __esm({
122611
122867
  });
122612
122868
 
122613
122869
  // ../harness/src/inventory/foreign-mcp.ts
122614
- import { join as join21 } from "node:path";
122870
+ import { join as join22 } from "node:path";
122615
122871
  function stripBom(text2) {
122616
122872
  return text2.startsWith(BOM) ? text2.slice(BOM.length) : text2;
122617
122873
  }
@@ -122665,7 +122921,7 @@ function inventoryForeignMcpConfigs(repoRoot) {
122665
122921
  const foreignMcpConfigs = [];
122666
122922
  const unreadable = [];
122667
122923
  for (const shape of FOREIGN_MCP_SHAPES) {
122668
- const abs = join21(repoRoot, shape.source);
122924
+ const abs = join22(repoRoot, shape.source);
122669
122925
  if (nothingIsThere(abs)) continue;
122670
122926
  const read = readTextFile(abs, shape.source, "mcp");
122671
122927
  if (read.text === void 0) {
@@ -122765,11 +123021,11 @@ var init_inventory = __esm({
122765
123021
  });
122766
123022
 
122767
123023
  // ../harness/src/apply/link-state.ts
122768
- import { lstatSync as lstatSync5, readdirSync as readdirSync6, statSync as statSync6 } from "node:fs";
123024
+ import { lstatSync as lstatSync6, readdirSync as readdirSync6, statSync as statSync6 } from "node:fs";
122769
123025
  function occupantKind(absPath) {
122770
123026
  let entry;
122771
123027
  try {
122772
- entry = lstatSync5(absPath);
123028
+ entry = lstatSync6(absPath);
122773
123029
  } catch {
122774
123030
  return "absent";
122775
123031
  }
@@ -122818,7 +123074,7 @@ var init_link_state = __esm({
122818
123074
 
122819
123075
  // ../harness/src/apply/write-path-occupants.ts
122820
123076
  import { accessSync, constants as constants2, statSync as statSync7 } from "node:fs";
122821
- import { dirname as dirname5, join as join22 } from "node:path";
123077
+ import { dirname as dirname5, join as join23 } from "node:path";
122822
123078
  function writePathReason(relDir, cause) {
122823
123079
  return `blocked by \`${relDir}\`, which ${WRITE_PATH_REASONS[cause]}`;
122824
123080
  }
@@ -122856,7 +123112,7 @@ function blockedWritePath(repoRoot, target, probed = /* @__PURE__ */ new Map())
122856
123112
  for (const relDir of writePathDirs(target)) {
122857
123113
  let cause = probed.get(relDir);
122858
123114
  if (!probed.has(relDir)) {
122859
- cause = directoryWriteBlock(join22(repoRoot, relDir));
123115
+ cause = directoryWriteBlock(join23(repoRoot, relDir));
122860
123116
  probed.set(relDir, cause);
122861
123117
  }
122862
123118
  if (cause !== void 0) return writePathReason(relDir, cause);
@@ -122867,7 +123123,7 @@ function unwritableWritePath(repoRoot, target) {
122867
123123
  if (!CAN_ASK_ABOUT_WRITING) return void 0;
122868
123124
  const dirs = writePathDirs(target).reverse();
122869
123125
  for (const relDir of dirs) {
122870
- const abs = join22(repoRoot, relDir);
123126
+ const abs = join23(repoRoot, relDir);
122871
123127
  let stats;
122872
123128
  try {
122873
123129
  stats = statSync7(abs);
@@ -122917,8 +123173,8 @@ var init_write_path_occupants = __esm({
122917
123173
  });
122918
123174
 
122919
123175
  // ../harness/src/plan/projector.ts
122920
- import { realpathSync as realpathSync5 } from "node:fs";
122921
- import { join as join23 } from "node:path";
123176
+ import { realpathSync as realpathSync6 } from "node:fs";
123177
+ import { join as join24 } from "node:path";
122922
123178
  function readsAgentsSkillsReason(harness) {
122923
123179
  return `${HARNESS_LABELS[harness]} reads ${AGENTS_SKILLS_DIR} directly (vendor docs, 2026-09-07)`;
122924
123180
  }
@@ -123087,7 +123343,7 @@ function buildPlan(input4) {
123087
123343
  const mergedHooks = mergeHookConfigs([
123088
123344
  claudeHooks,
123089
123345
  ...hookContributors.map(
123090
- (p) => rewritePluginRootInHooks(p.hooks, join23(repoRoot, p.location.relDir))
123346
+ (p) => rewritePluginRootInHooks(p.hooks, join24(repoRoot, p.location.relDir))
123091
123347
  )
123092
123348
  ]);
123093
123349
  warnings.push(...planUnreadableHookWarnings(projectable));
@@ -123121,9 +123377,9 @@ function buildPlan(input4) {
123121
123377
  warnings.push(...inventoried.warnings);
123122
123378
  for (const plugin of projectable) {
123123
123379
  const skillResult = planInstalledSkills(harness, plugin);
123124
- all.push(...skillResult.actions);
123380
+ all.push(...labelDevLinkActions(skillResult.actions, plugin));
123125
123381
  warnings.push(...skillResult.warnings);
123126
- all.push(...planInstalledCommands(harness, plugin, repoRoot));
123382
+ all.push(...labelDevLinkActions(planInstalledCommands(harness, plugin, repoRoot), plugin));
123127
123383
  }
123128
123384
  }
123129
123385
  if (manifest.harnesses.includes("claude-code")) {
@@ -123144,7 +123400,7 @@ function buildPlan(input4) {
123144
123400
  plugins: projectable,
123145
123401
  harnesses: manifest.harnesses
123146
123402
  });
123147
- all.push(...canonicalLinks.actions);
123403
+ all.push(...labelCanonicalLinks(canonicalLinks.actions, projectable));
123148
123404
  warnings.push(...canonicalLinks.warnings);
123149
123405
  const claudeOnly = planClaudeOnlySkills({
123150
123406
  manifest,
@@ -123160,7 +123416,9 @@ function buildPlan(input4) {
123160
123416
  })
123161
123417
  );
123162
123418
  all.push(...planForeignMcpDrops(inventory));
123163
- for (const plugin of projectable) all.push(...dropNonPortableLayers(plugin));
123419
+ for (const plugin of projectable) {
123420
+ all.push(...labelDevLinkActions(dropNonPortableLayers(plugin), plugin));
123421
+ }
123164
123422
  for (const plugin of unsupportedType) {
123165
123423
  all.push(
123166
123424
  dropWholePlugin(plugin, `package type "${plugin.type}" is not a harness-portable plugin`)
@@ -123182,6 +123440,17 @@ function buildPlan(input4) {
123182
123440
  ...unreadableSkillRoots.length > 0 ? { unreadableSkillRoots } : {}
123183
123441
  };
123184
123442
  }
123443
+ function labelCanonicalLinks(actions, plugins) {
123444
+ for (const plugin of plugins) {
123445
+ if (plugin.devLink === void 0) continue;
123446
+ const prefix = `${plugin.location.relDir}/`;
123447
+ labelDevLinkActions(
123448
+ actions.filter((action) => action.source?.startsWith(prefix) === true),
123449
+ plugin
123450
+ );
123451
+ }
123452
+ return actions;
123453
+ }
123185
123454
  function degradeUnreachableNatives(repoRoot, all) {
123186
123455
  const rides = all.some((a2) => a2.kind === "native" && isCanonicalLinkNative(a2));
123187
123456
  if (!rides) return [...all];
@@ -123200,7 +123469,7 @@ function refusedByPermission(repoRoot, link3, source) {
123200
123469
  }
123201
123470
  function linkAlreadyReaches(repoRoot, link3, source) {
123202
123471
  try {
123203
- return realpathSync5(join23(repoRoot, link3)) === realpathSync5(join23(repoRoot, source));
123472
+ return realpathSync6(join24(repoRoot, link3)) === realpathSync6(join24(repoRoot, source));
123204
123473
  } catch {
123205
123474
  return false;
123206
123475
  }
@@ -123238,6 +123507,7 @@ var init_projector = __esm({
123238
123507
  init_global_installs();
123239
123508
  init_installed();
123240
123509
  init_installed_projector();
123510
+ init_dev_link_labels();
123241
123511
  init_unreadable_hooks();
123242
123512
  init_unreadable_manifests();
123243
123513
  init_unreadable_skills();
@@ -123252,7 +123522,7 @@ var init_projector = __esm({
123252
123522
  });
123253
123523
 
123254
123524
  // ../harness/src/plan/global-projector.ts
123255
- import { join as join24 } from "node:path";
123525
+ import { join as join25 } from "node:path";
123256
123526
  function globalClosingNote(roots, boundaryRoot) {
123257
123527
  if (boundaryRoot !== void 0) return globalBoundarySkipLine(boundaryRoot);
123258
123528
  if (roots.agentsSkillsDir !== void 0) return USER_TIER_MEASUREMENT_NOTE;
@@ -123262,10 +123532,10 @@ function globalBoundarySkipLine(root) {
123262
123532
  return `Packages you installed for all your projects stay inside DorkOS on this machine. DorkOS is limited to ${root}, so it will not add links in your home folder.`;
123263
123533
  }
123264
123534
  function globalPluginsDir(dorkHome) {
123265
- return join24(dorkHome, "plugins");
123535
+ return join25(dorkHome, "plugins");
123266
123536
  }
123267
123537
  function globalSkillsDir(dorkHome) {
123268
- return join24(dorkHome, "skills");
123538
+ return join25(dorkHome, "skills");
123269
123539
  }
123270
123540
  function globalPlanTiers(input4) {
123271
123541
  const tiers = [
@@ -123318,10 +123588,10 @@ function buildGlobalPlan(input4) {
123318
123588
  for (const skill of plugin.skills) {
123319
123589
  const namespaced = `${plugin.name}__${skill.name}`;
123320
123590
  for (const tier of tiers) {
123321
- const target = join24(tier.dir, namespaced);
123591
+ const target = join25(tier.dir, namespaced);
123322
123592
  if (planned.has(target)) continue;
123323
123593
  planned.add(target);
123324
- actions.push({
123594
+ const action = {
123325
123595
  kind: "symlink",
123326
123596
  artifact: "skill",
123327
123597
  harness: tier.harness,
@@ -123332,7 +123602,8 @@ function buildGlobalPlan(input4) {
123332
123602
  source: skill.sourceDir,
123333
123603
  target,
123334
123604
  reason: tier.reason(skill.hasSchedule)
123335
- });
123605
+ };
123606
+ actions.push(...labelDevLinkActions([action], plugin));
123336
123607
  }
123337
123608
  const tokenReason = pluginTokenSkillWarningReason(skill);
123338
123609
  if (tokenReason !== void 0) {
@@ -123412,6 +123683,7 @@ var init_global_projector = __esm({
123412
123683
  init_installed();
123413
123684
  init_unreadable_manifests();
123414
123685
  init_unreadable_skills();
123686
+ init_dev_link_labels();
123415
123687
  init_installed_projector();
123416
123688
  init_write_path_occupants();
123417
123689
  GLOBAL_LINK_ATTRIBUTION = "codex";
@@ -123439,7 +123711,7 @@ var init_global_projector = __esm({
123439
123711
 
123440
123712
  // ../harness/src/scaffold/instructions.ts
123441
123713
  import { existsSync as existsSync8, mkdirSync as mkdirSync3 } from "node:fs";
123442
- import { dirname as dirname6, join as join25, relative } from "node:path";
123714
+ import { dirname as dirname6, join as join26, relative } from "node:path";
123443
123715
  function scaffoldInstructions(rootDir, opts) {
123444
123716
  const created = [];
123445
123717
  const skipped = [];
@@ -123456,7 +123728,7 @@ function scaffoldInstructions(rootDir, opts) {
123456
123728
  return { created, skipped, createdDirs };
123457
123729
  }
123458
123730
  function writeIfAbsent(rootDir, relPath2, content, created, skipped, createdDirs) {
123459
- const abs = join25(rootDir, relPath2);
123731
+ const abs = join26(rootDir, relPath2);
123460
123732
  if (existsSync8(abs)) {
123461
123733
  skipped.push(relPath2);
123462
123734
  return;
@@ -123587,10 +123859,10 @@ var init_manifest_edit = __esm({
123587
123859
 
123588
123860
  // ../harness/src/scaffold/enable-harness.ts
123589
123861
  import { readFileSync as readFileSync8 } from "node:fs";
123590
- import { join as join26 } from "node:path";
123862
+ import { join as join27 } from "node:path";
123591
123863
  function enableHarnessInManifest(repoRoot, harness) {
123592
123864
  const path53 = HARNESS_MANIFEST_PATH;
123593
- const abs = join26(repoRoot, path53);
123865
+ const abs = join27(repoRoot, path53);
123594
123866
  const before = readFileSync8(abs, "utf8");
123595
123867
  let parsed;
123596
123868
  try {
@@ -123663,10 +123935,10 @@ var init_enable_harness = __esm({
123663
123935
 
123664
123936
  // ../harness/src/scaffold/declare-claude-only.ts
123665
123937
  import { readFileSync as readFileSync9 } from "node:fs";
123666
- import { join as join27 } from "node:path";
123938
+ import { join as join28 } from "node:path";
123667
123939
  function declareClaudeOnlySkill(repoRoot, entry) {
123668
123940
  const path53 = HARNESS_MANIFEST_PATH;
123669
- const abs = join27(repoRoot, path53);
123941
+ const abs = join28(repoRoot, path53);
123670
123942
  const before = readFileSync9(abs, "utf8");
123671
123943
  let parsed;
123672
123944
  try {
@@ -123741,7 +124013,7 @@ var init_declare_claude_only = __esm({
123741
124013
 
123742
124014
  // ../harness/src/apply/generated-ownership.ts
123743
124015
  import { createHash as createHash3 } from "node:crypto";
123744
- import { lstatSync as lstatSync6, readFileSync as readFileSync10 } from "node:fs";
124016
+ import { lstatSync as lstatSync7, readFileSync as readFileSync10 } from "node:fs";
123745
124017
  function generatedSidecarPath(absTarget) {
123746
124018
  return `${absTarget}${GENERATED_SIDECAR_SUFFIX}`;
123747
124019
  }
@@ -123757,7 +124029,7 @@ function readFileIfPresent(absPath) {
123757
124029
  }
123758
124030
  function hasGeneratedSidecar(absTarget) {
123759
124031
  try {
123760
- lstatSync6(generatedSidecarPath(absTarget));
124032
+ lstatSync7(generatedSidecarPath(absTarget));
123761
124033
  return true;
123762
124034
  } catch {
123763
124035
  return false;
@@ -124404,17 +124676,15 @@ var init_using_the_marketplace = __esm({
124404
124676
  init_tool_name_note();
124405
124677
  usingTheMarketplace = {
124406
124678
  name: "using-the-marketplace",
124407
- description: "Use when finding, inspecting, installing, updating, or removing a DorkOS marketplace package (agent, plugin, skill pack, or adapter), or reading marketplace sources. Covers search, the install confirmation flow, checking for and applying updates and what they keep, packages held back from sessions until a person approves them, the uninstall approval flow, listing what is installed, and why only a person may add or remove a source.",
124679
+ description: "Use when finding, inspecting, installing, updating, or removing a DorkOS marketplace package (agent, plugin, skill pack, or adapter), or reading marketplace sources. Covers search, the install confirmation flow, checking for and applying updates and what they keep, packages held back from sessions until a person approves them, the uninstall approval flow, running a package from a folder (a dev link), listing what is installed, and why only a person may add or remove a source.",
124408
124680
  body: `# Using the marketplace
124409
124681
 
124410
124682
  ${TOOL_NAME_NOTE}
124411
124683
 
124412
- The marketplace distributes installable packages: agents, plugins, skill packs,
124413
- and adapters. Every operation here is a capability, so it is also reachable
124414
- with \`dorkos call marketplace.<verb> --input '<json>'\` from any runtime;
124415
- \`dorkos capabilities\` lists them with their tiers. On the command line,
124416
- \`dorkos marketplace <verb>\` is the home for all of it, and \`dorkos install\`,
124417
- \`dorkos update\` and \`dorkos uninstall\` are shorthand for the same three verbs.
124684
+ The marketplace distributes agents, plugins, skill packs and adapters. Every
124685
+ operation is a capability (\`dorkos call marketplace.<verb> --input '<json>'\`
124686
+ from any runtime; \`dorkos capabilities\` lists the tiers). \`dorkos marketplace
124687
+ <verb>\` does it all, with \`dorkos install|update|uninstall\` as shorthand.
124418
124688
 
124419
124689
  ## Find a package (tier: observe)
124420
124690
 
@@ -124498,29 +124768,32 @@ that they can press **Review** on its row under Marketplace, then Installed.
124498
124768
  ## Remove a package (tier: destructive)
124499
124769
 
124500
124770
  Removing a package is gated on a person's approval and returns the APPROVAL
124501
- payload, not a confirmation token. Two gated paths, pick the one your session has:
124771
+ payload, not a confirmation token. Pick the gated path your session has:
124502
124772
 
124503
124773
  - **In-session tool:** \`marketplace_uninstall\`, retried with an \`approvalToken\`.
124504
124774
  - **Any runtime, from a shell:** \`dorkos call marketplace.uninstall --input
124505
124775
  '{"name":"<pkg>"}'\`, retried with \`--approval <token>\`. This is the path for a
124506
124776
  Codex or OpenCode session, which has no \`marketplace_uninstall\` tool.
124777
+ - **The person's verb,** \`dorkos uninstall <name>\`, is gated for you the same way.
124507
124778
 
124508
124779
  1. Call it with \`name\` (and \`purge: true\` only if the user asked to delete what
124509
124780
  they added). It returns \`status: approval_required\` and an \`approvalToken\`.
124510
124781
  2. Tell the user what would be removed and that a card is waiting in DorkOS.
124511
124782
  3. Call again with the SAME arguments plus the token. Changing any argument,
124512
- \`purge\` included, invalidates the approval.
124513
-
124514
- Read \`reason\` and \`status\` as operating-dorkos describes: \`awaiting_decision\`
124515
- means present the same token later, and \`status: "denied"\` means stop.
124783
+ \`purge\` included, invalidates the approval. \`awaiting_decision\` means present
124784
+ the same token later; \`status: "denied"\` means stop.
124516
124785
 
124517
124786
  Uninstall keeps what the person and their agents added (see above) and a later
124518
124787
  reinstall picks it up; \`purge: true\` removes it too, so say that out loud.
124519
124788
  Uninstalling an agent package also removes that agent from the team: its rooms,
124520
124789
  schedules, sign-ins and access go for good, even after a reinstall; say so first.
124521
124790
 
124522
- \`dorkos uninstall <name>\` is the person's verb, and it is gated for you
124523
- exactly like the paths above, so it is not a way around an approval.
124791
+ ## Run a package from a folder (tier: destructive)
124792
+
124793
+ \`marketplace_link\` with the folder's absolute real \`path\` (\`projectPath\` for one
124794
+ project) always returns \`approval_required\`, whatever the settings: retry with
124795
+ the SAME arguments plus the token. Install, update and uninstall refuse a
124796
+ dev-linked package (\`package_is_dev_linked\`); unlinking is the person's.
124524
124797
 
124525
124798
  ## Sources: you may read them, only a person may change them
124526
124799
 
@@ -124551,10 +124824,9 @@ marketplace is a separate step.
124551
124824
 
124552
124825
  ## Rule
124553
124826
 
124554
- Installing, updating, uninstalling, and scaffolding all change the user's system.
124555
- State plainly what you are about to do, complete whichever gate the tool asks for
124556
- (\`confirmationToken\` for install, update and scaffold, \`approvalToken\` for
124557
- uninstall), then report what landed.`
124827
+ Every change here touches the user's system: say what you are about to do,
124828
+ complete the gate the tool asks for (\`confirmationToken\` for install, update and
124829
+ scaffold, \`approvalToken\` for uninstall and link), then report what landed.`
124558
124830
  };
124559
124831
  }
124560
124832
  });
@@ -125316,8 +125588,8 @@ var init_plan = __esm({
125316
125588
  });
125317
125589
 
125318
125590
  // ../harness/src/apply/gitignore.ts
125319
- import { existsSync as existsSync9, lstatSync as lstatSync7, readFileSync as readFileSync11, realpathSync as realpathSync6 } from "node:fs";
125320
- import { dirname as dirname7, join as join28, relative as relative2, resolve as resolve3, sep as sep5 } from "node:path";
125591
+ import { existsSync as existsSync9, lstatSync as lstatSync8, readFileSync as readFileSync11, realpathSync as realpathSync7 } from "node:fs";
125592
+ import { dirname as dirname7, join as join29, relative as relative2, resolve as resolve3, sep as sep5 } from "node:path";
125321
125593
  function isPathIgnored(patterns, relPath2, leafKind = "file") {
125322
125594
  return ignoringLayer([{ dir: "", file: ROOT_GITIGNORE, patterns }], relPath2, leafKind) !== void 0;
125323
125595
  }
@@ -125390,7 +125662,7 @@ function readGitignore(absPath) {
125390
125662
  function gitCheckoutRoot(projectRoot) {
125391
125663
  let dir = physicalPath(projectRoot);
125392
125664
  for (; ; ) {
125393
- if (existsSync9(join28(dir, ".git"))) return dir;
125665
+ if (existsSync9(join29(dir, ".git"))) return dir;
125394
125666
  const parent = dirname7(dir);
125395
125667
  if (parent === dir) return void 0;
125396
125668
  dir = parent;
@@ -125398,7 +125670,7 @@ function gitCheckoutRoot(projectRoot) {
125398
125670
  }
125399
125671
  function physicalPath(path53) {
125400
125672
  try {
125401
- return realpathSync6.native(path53);
125673
+ return realpathSync7.native(path53);
125402
125674
  } catch {
125403
125675
  return resolve3(path53);
125404
125676
  }
@@ -125417,7 +125689,7 @@ function checkoutContext(projectRoot) {
125417
125689
  }
125418
125690
  function ignoreLayerAt(checkoutRoot, dir) {
125419
125691
  const file2 = dir === "" ? ROOT_GITIGNORE : `${dir}/${ROOT_GITIGNORE}`;
125420
- return { dir, file: file2, patterns: readGitignore(join28(checkoutRoot, ...file2.split("/"))) };
125692
+ return { dir, file: file2, patterns: readGitignore(join29(checkoutRoot, ...file2.split("/"))) };
125421
125693
  }
125422
125694
  function ignoreChain(checkoutRoot, relPath2) {
125423
125695
  const segments = relPath2.split("/").filter((segment) => segment !== "");
@@ -125439,7 +125711,7 @@ function pathIgnoredBy(projectRoot, relPath2, leafKind = "file") {
125439
125711
  return layer === void 0 ? void 0 : displayGitignorePath(checkout.project, checkout.root, layer.file);
125440
125712
  }
125441
125713
  function displayGitignorePath(projectRoot, checkoutRoot, file2) {
125442
- return relative2(projectRoot, join28(checkoutRoot, ...file2.split("/"))).split(sep5).join("/");
125714
+ return relative2(projectRoot, join29(checkoutRoot, ...file2.split("/"))).split(sep5).join("/");
125443
125715
  }
125444
125716
  function ephemeralPaths(plan, repoRoot) {
125445
125717
  const paths2 = /* @__PURE__ */ new Map();
@@ -125454,12 +125726,12 @@ function ephemeralPaths(plan, repoRoot) {
125454
125726
  paths2.set(`${action.target}${GENERATED_SIDECAR_SUFFIX}`, "file");
125455
125727
  }
125456
125728
  }
125457
- if (existsSync9(join28(repoRoot, PROJECT_PLUGINS_DIR))) paths2.set(INSTALL_ROOT_PROBE, "dir");
125729
+ if (existsSync9(join29(repoRoot, PROJECT_PLUGINS_DIR))) paths2.set(INSTALL_ROOT_PROBE, "dir");
125458
125730
  return [...paths2].map(([path53, kind]) => ({ path: path53, kind }));
125459
125731
  }
125460
125732
  function onDiskKind(repoRoot, relPath2, fallback) {
125461
125733
  try {
125462
- const stats = lstatSync7(join28(repoRoot, relPath2), { throwIfNoEntry: false });
125734
+ const stats = lstatSync8(join29(repoRoot, relPath2), { throwIfNoEntry: false });
125463
125735
  if (!stats) return fallback;
125464
125736
  return stats.isDirectory() ? "dir" : "file";
125465
125737
  } catch {
@@ -125501,7 +125773,7 @@ function order(declared, line2) {
125501
125773
  return at === -1 ? declared.length : at;
125502
125774
  }
125503
125775
  function appendGitignoreLines(repoRoot, lines) {
125504
- const abs = join28(repoRoot, ROOT_GITIGNORE);
125776
+ const abs = join29(repoRoot, ROOT_GITIGNORE);
125505
125777
  const existing = existsSync9(abs) ? readFileSync11(abs, "utf8") : "";
125506
125778
  writeFileAtomic(abs, withGitignoreLines(existing, lines));
125507
125779
  return ROOT_GITIGNORE;
@@ -125545,8 +125817,8 @@ var init_gitignore = __esm({
125545
125817
  });
125546
125818
 
125547
125819
  // ../harness/src/adopt/read.ts
125548
- import { lstatSync as lstatSync8, readFileSync as readFileSync12 } from "node:fs";
125549
- import { join as join29 } from "node:path";
125820
+ import { lstatSync as lstatSync9, readFileSync as readFileSync12 } from "node:fs";
125821
+ import { join as join30 } from "node:path";
125550
125822
  function readAdoptCandidates(repoRoot, inventory, manifest) {
125551
125823
  const canonicalNames = new Set(
125552
125824
  inventory.skills.filter((s2) => s2.root === CANONICAL_SKILLS_ROOT).map((s2) => s2.name)
@@ -125623,7 +125895,7 @@ function readCandidate(repoRoot, skill, probed) {
125623
125895
  const pathBlockedReason = blockedWritePath(repoRoot, `${skill.source}/${SKILL_FILENAME}`, probed) ?? blockedWritePath(repoRoot, `${target}/${SKILL_FILENAME}`, probed);
125624
125896
  let text2;
125625
125897
  try {
125626
- text2 = readFileSync12(join29(repoRoot, skill.source, SKILL_FILENAME), "utf8");
125898
+ text2 = readFileSync12(join30(repoRoot, skill.source, SKILL_FILENAME), "utf8");
125627
125899
  } catch {
125628
125900
  text2 = void 0;
125629
125901
  }
@@ -125642,7 +125914,7 @@ function readCandidate(repoRoot, skill, probed) {
125642
125914
  }
125643
125915
  function targetStateOf(repoRoot, target) {
125644
125916
  try {
125645
- lstatSync8(join29(repoRoot, target));
125917
+ lstatSync9(join30(repoRoot, target));
125646
125918
  return "occupied";
125647
125919
  } catch {
125648
125920
  return "absent";
@@ -125698,7 +125970,7 @@ var init_sweep_reasons = __esm({
125698
125970
 
125699
125971
  // ../harness/src/apply/sweep-warnings.ts
125700
125972
  import { accessSync as accessSync2, constants as constants3 } from "node:fs";
125701
- import { dirname as dirname8, join as join30, relative as relative3, sep as sep6 } from "node:path";
125973
+ import { dirname as dirname8, join as join31, relative as relative3, sep as sep6 } from "node:path";
125702
125974
  function sweepBlindWarning(relDir) {
125703
125975
  return `DorkOS could not look inside \`${relDir}\`, so it does not know whether anything a sync would remove is in there. Nothing was taken out of it. If it should be a folder DorkOS can read, fix it and re-run.`;
125704
125976
  }
@@ -125712,7 +125984,7 @@ function sweepScanWarnings(repoRoot, plan) {
125712
125984
  function unlistableSweptDirs(repoRoot) {
125713
125985
  const blind = [];
125714
125986
  for (const rel of SWEPT_DIRS) {
125715
- const abs = join30(repoRoot, rel);
125987
+ const abs = join31(repoRoot, rel);
125716
125988
  if (!pathExists(abs)) continue;
125717
125989
  if (tryListDir(abs) === void 0) {
125718
125990
  blind.push(rel);
@@ -125721,7 +125993,7 @@ function unlistableSweptDirs(repoRoot) {
125721
125993
  if (rel !== CLAUDE_COMMANDS_DIR) continue;
125722
125994
  for (const sub of listDirEntries(abs)) {
125723
125995
  if (!sub.isDirectory()) continue;
125724
- if (tryListDir(join30(abs, sub.name)) === void 0) blind.push(`${rel}/${sub.name}`);
125996
+ if (tryListDir(join31(abs, sub.name)) === void 0) blind.push(`${rel}/${sub.name}`);
125725
125997
  }
125726
125998
  }
125727
125999
  return blind;
@@ -125749,7 +126021,7 @@ function partitionRemovable(repoRoot, paths2) {
125749
126021
  const warnings = [];
125750
126022
  const probed = /* @__PURE__ */ new Map();
125751
126023
  for (const path53 of paths2) {
125752
- const absDir = unwritableParent(join30(repoRoot, path53), probed);
126024
+ const absDir = unwritableParent(join31(repoRoot, path53), probed);
125753
126025
  if (absDir === void 0) removable.push(path53);
125754
126026
  else warnings.push(blockedRemovalWarning(path53, spell(repoRoot, absDir)));
125755
126027
  }
@@ -125784,7 +126056,7 @@ var init_sweep_warnings = __esm({
125784
126056
 
125785
126057
  // ../harness/src/apply/authored-orphans.ts
125786
126058
  import { readlinkSync, rmSync as rmSync3 } from "node:fs";
125787
- import { isAbsolute, join as join31, relative as relative4, resolve as resolve4 } from "node:path";
126059
+ import { isAbsolute, join as join32, relative as relative4, resolve as resolve4 } from "node:path";
125788
126060
  function findOrphanedAuthoredLinks(repoRoot, plan) {
125789
126061
  return removableOf(repoRoot, allOrphanedAuthoredLinks(repoRoot, plan));
125790
126062
  }
@@ -125793,13 +126065,13 @@ function allOrphanedAuthoredLinks(repoRoot, plan) {
125793
126065
  const planned = new Set(
125794
126066
  plan.actions.filter((a2) => a2.kind === "symlink" && a2.target).map((a2) => a2.target)
125795
126067
  );
125796
- const skillsDir = join31(repoRoot, CLAUDE_SKILLS_DIR);
126068
+ const skillsDir = join32(repoRoot, CLAUDE_SKILLS_DIR);
125797
126069
  const orphans = [];
125798
126070
  for (const entry of listDir(skillsDir)) {
125799
126071
  if (entry.includes(INSTALLED_PROJECTION_MARKER)) continue;
125800
126072
  const rel = `${CLAUDE_SKILLS_DIR}/${entry}`;
125801
126073
  if (planned.has(rel)) continue;
125802
- const abs = join31(skillsDir, entry);
126074
+ const abs = join32(skillsDir, entry);
125803
126075
  if (!isSymlink(abs) || !isDanglingSymlink(abs)) continue;
125804
126076
  if (!pointsIntoAuthoredSkills(repoRoot, skillsDir, abs)) continue;
125805
126077
  orphans.push(rel);
@@ -125808,12 +126080,12 @@ function allOrphanedAuthoredLinks(repoRoot, plan) {
125808
126080
  }
125809
126081
  function sweepAuthoredOrphans(repoRoot, plan) {
125810
126082
  const orphans = findOrphanedAuthoredLinks(repoRoot, plan);
125811
- for (const rel of orphans) rmSync3(join31(repoRoot, rel), { force: true });
126083
+ for (const rel of orphans) rmSync3(join32(repoRoot, rel), { force: true });
125812
126084
  return orphans;
125813
126085
  }
125814
126086
  function pointsIntoAuthoredSkills(repoRoot, linkDir, abs) {
125815
126087
  const target = resolve4(linkDir, readlinkSync(abs));
125816
- const inside = relative4(join31(repoRoot, AGENTS_SKILLS_DIR), target);
126088
+ const inside = relative4(join32(repoRoot, AGENTS_SKILLS_DIR), target);
125817
126089
  return inside !== "" && !inside.startsWith("..") && !isAbsolute(inside);
125818
126090
  }
125819
126091
  var init_authored_orphans = __esm({
@@ -125827,7 +126099,7 @@ var init_authored_orphans = __esm({
125827
126099
  });
125828
126100
 
125829
126101
  // ../harness/src/apply/symlink-occupants.ts
125830
- import { readdirSync as readdirSync7, readFileSync as readFileSync13, readlinkSync as readlinkSync2, realpathSync as realpathSync7, statSync as statSync8 } from "node:fs";
126102
+ import { readdirSync as readdirSync7, readFileSync as readFileSync13, readlinkSync as readlinkSync2, realpathSync as realpathSync8, statSync as statSync8 } from "node:fs";
125831
126103
  import { basename as basename4, dirname as dirname9 } from "node:path";
125832
126104
  function withForwardSlashes(path53) {
125833
126105
  return path53.split("\\").join("/");
@@ -125869,7 +126141,7 @@ function linkCheckFor(platform3) {
125869
126141
  function linkMatchesPlan(absTarget, absSource, linkText, how) {
125870
126142
  try {
125871
126143
  if (how === "link-text") return readlinkSync2(absTarget) === linkText;
125872
- return realpathSync7.native(absTarget) === realpathSync7.native(absSource);
126144
+ return realpathSync8.native(absTarget) === realpathSync8.native(absSource);
125873
126145
  } catch {
125874
126146
  return false;
125875
126147
  }
@@ -125888,7 +126160,7 @@ var init_symlink_occupants = __esm({
125888
126160
 
125889
126161
  // ../harness/src/apply/windows-links.ts
125890
126162
  import {
125891
- lstatSync as lstatSync9,
126163
+ lstatSync as lstatSync10,
125892
126164
  mkdirSync as mkdirSync4,
125893
126165
  mkdtempSync,
125894
126166
  readlinkSync as readlinkSync3,
@@ -125897,14 +126169,14 @@ import {
125897
126169
  symlinkSync
125898
126170
  } from "node:fs";
125899
126171
  import { tmpdir } from "node:os";
125900
- import { isAbsolute as isAbsolute2, join as join32 } from "node:path";
126172
+ import { isAbsolute as isAbsolute2, join as join33 } from "node:path";
125901
126173
  function probeDirSymlink() {
125902
126174
  let dir;
125903
126175
  try {
125904
- dir = mkdtempSync(join32(tmpdir(), "dorkos-link-probe-"));
125905
- const source = join32(dir, "source");
126176
+ dir = mkdtempSync(join33(tmpdir(), "dorkos-link-probe-"));
126177
+ const source = join33(dir, "source");
125906
126178
  mkdirSync4(source);
125907
- symlinkSync(source, join32(dir, "link"), "dir");
126179
+ symlinkSync(source, join33(dir, "link"), "dir");
125908
126180
  return true;
125909
126181
  } catch {
125910
126182
  return false;
@@ -125931,7 +126203,7 @@ function symlinkTypeFor(absSource) {
125931
126203
  function isJunctionAt(absTarget) {
125932
126204
  if (process.platform !== "win32") return false;
125933
126205
  try {
125934
- if (!lstatSync9(absTarget).isSymbolicLink()) return false;
126206
+ if (!lstatSync10(absTarget).isSymbolicLink()) return false;
125935
126207
  return isAbsolute2(readlinkSync3(absTarget));
125936
126208
  } catch {
125937
126209
  return false;
@@ -125940,7 +126212,7 @@ function isJunctionAt(absTarget) {
125940
126212
  function junctionCommitWarnings(repoRoot, plan) {
125941
126213
  if (process.platform !== "win32") return [];
125942
126214
  const anyJunction = plan.actions.some(
125943
- (action) => action.kind === "symlink" && action.target !== void 0 && isJunctionAt(join32(repoRoot, action.target))
126215
+ (action) => action.kind === "symlink" && action.target !== void 0 && isJunctionAt(join33(repoRoot, action.target))
125944
126216
  );
125945
126217
  return anyJunction && gitCheckoutRoot(repoRoot) !== void 0 ? [JUNCTION_COMMIT_WARNING] : [];
125946
126218
  }
@@ -125982,7 +126254,7 @@ var init_generate_occupants = __esm({
125982
126254
 
125983
126255
  // ../harness/src/apply/generated-targets.ts
125984
126256
  import { rmSync as rmSync5 } from "node:fs";
125985
- import { join as join33 } from "node:path";
126257
+ import { join as join34 } from "node:path";
125986
126258
  function isGeneratedHookTarget(target) {
125987
126259
  return GENERATED_HOOK_TARGETS.includes(target);
125988
126260
  }
@@ -126023,7 +126295,7 @@ function allGeneratedOrphans(repoRoot, plan) {
126023
126295
  const orphans = [];
126024
126296
  for (const rel of GENERATED_HOOK_TARGETS) {
126025
126297
  if (regenerated.has(rel)) continue;
126026
- const abs = join33(repoRoot, rel);
126298
+ const abs = join34(repoRoot, rel);
126027
126299
  const sidecarRel = `${rel}${GENERATED_SIDECAR_SUFFIX}`;
126028
126300
  const onDisk = readFileIfPresent(abs);
126029
126301
  if (onDisk === void 0) {
@@ -126037,7 +126309,7 @@ function allGeneratedOrphans(repoRoot, plan) {
126037
126309
  }
126038
126310
  function sweepGeneratedOrphans(repoRoot, plan) {
126039
126311
  const orphans = findGeneratedOrphans(repoRoot, plan);
126040
- for (const rel of orphans) rmSync5(join33(repoRoot, rel), { force: true });
126312
+ for (const rel of orphans) rmSync5(join34(repoRoot, rel), { force: true });
126041
126313
  return orphans;
126042
126314
  }
126043
126315
  function findLeftAloneGeneratedHookFiles(repoRoot, plan) {
@@ -126047,7 +126319,7 @@ function findLeftAloneGeneratedHookFiles(repoRoot, plan) {
126047
126319
  const leftAlone = [];
126048
126320
  for (const rel of GENERATED_HOOK_TARGETS) {
126049
126321
  if (planned.has(rel)) continue;
126050
- const abs = join33(repoRoot, rel);
126322
+ const abs = join34(repoRoot, rel);
126051
126323
  const onDisk = readFileIfPresent(abs);
126052
126324
  if (onDisk === void 0) continue;
126053
126325
  if (ownsGeneratedFile(abs, onDisk)) continue;
@@ -126059,7 +126331,7 @@ function findBlockedGenerateTargets(repoRoot, plan) {
126059
126331
  const blocked = [];
126060
126332
  for (const action of plan.actions) {
126061
126333
  if (action.kind !== "generate" || !action.target) continue;
126062
- const absTarget = join33(repoRoot, action.target);
126334
+ const absTarget = join34(repoRoot, action.target);
126063
126335
  const shape = blockingGenerateOccupant(absTarget);
126064
126336
  if (shape !== void 0) {
126065
126337
  blocked.push({ ...action, reason: shape });
@@ -126177,7 +126449,7 @@ var init_settings_hooks = __esm({
126177
126449
 
126178
126450
  // ../harness/src/apply/apply.ts
126179
126451
  import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync15, rmSync as rmSync6, symlinkSync as symlinkSync2 } from "node:fs";
126180
- import { dirname as dirname10, join as join34, relative as relative5 } from "node:path";
126452
+ import { dirname as dirname10, join as join35, relative as relative5 } from "node:path";
126181
126453
  function skillSourcesUnreadable(plan) {
126182
126454
  return (plan.unreadableSkillRoots?.length ?? 0) > 0;
126183
126455
  }
@@ -126188,15 +126460,15 @@ function scaffoldPresent(absTarget) {
126188
126460
  return pathExists(absTarget) && !isDanglingSymlink(absTarget);
126189
126461
  }
126190
126462
  function relativeLink(repoRoot, source, target) {
126191
- return relative5(dirname10(join34(repoRoot, target)), join34(repoRoot, source));
126463
+ return relative5(dirname10(join35(repoRoot, target)), join35(repoRoot, source));
126192
126464
  }
126193
126465
  function applySymlink(repoRoot, action) {
126194
126466
  if (!action.source || !action.target) {
126195
126467
  throw new Error(`symlink action for "${action.name}" is missing source/target`);
126196
126468
  }
126197
- const absTarget = join34(repoRoot, action.target);
126469
+ const absTarget = join35(repoRoot, action.target);
126198
126470
  const linkText = relativeLink(repoRoot, action.source, action.target);
126199
- const absSource = join34(repoRoot, action.source);
126471
+ const absSource = join35(repoRoot, action.source);
126200
126472
  for (let attempt = 0, removalRetries = 0; attempt < SYMLINK_ATTEMPTS; ) {
126201
126473
  if (pathExists(absTarget)) {
126202
126474
  const blocked = blockingSymlinkOccupant(absTarget, linkText);
@@ -126224,13 +126496,13 @@ function applySymlink(repoRoot, action) {
126224
126496
  }
126225
126497
  function applyScaffold(repoRoot, action) {
126226
126498
  if (!action.target) throw new Error(`scaffold action for "${action.name}" is missing target`);
126227
- const absTarget = join34(repoRoot, action.target);
126499
+ const absTarget = join35(repoRoot, action.target);
126228
126500
  if (scaffoldPresent(absTarget)) return;
126229
126501
  writeFileAtomic(absTarget, requireActionContent(action));
126230
126502
  }
126231
126503
  function applyGenerate(repoRoot, action) {
126232
126504
  if (!action.target) throw new Error(`generate action for "${action.name}" is missing target`);
126233
- const absTarget = join34(repoRoot, action.target);
126505
+ const absTarget = join35(repoRoot, action.target);
126234
126506
  const shape = blockingGenerateOccupant(absTarget);
126235
126507
  if (shape !== void 0) return shape;
126236
126508
  const content = requireActionContent(action);
@@ -126244,7 +126516,7 @@ function applyGenerate(repoRoot, action) {
126244
126516
  function applyMerge(repoRoot, action) {
126245
126517
  if (!action.target) throw new Error(`merge action for "${action.name}" is missing target`);
126246
126518
  const managed = JSON.parse(requireActionContent(action));
126247
- return mergeManagedHooks(join34(repoRoot, action.target), managed);
126519
+ return mergeManagedHooks(join35(repoRoot, action.target), managed);
126248
126520
  }
126249
126521
  function findInstalledOrphans(repoRoot, plan) {
126250
126522
  return removableOf(repoRoot, allInstalledOrphans(repoRoot, plan));
@@ -126256,10 +126528,10 @@ function allInstalledOrphans(repoRoot, plan) {
126256
126528
  );
126257
126529
  const orphans = [];
126258
126530
  for (const dir of INSTALLED_SKILL_DIRS) {
126259
- const skillsDir = join34(repoRoot, dir);
126531
+ const skillsDir = join35(repoRoot, dir);
126260
126532
  for (const entry of listDir(skillsDir)) {
126261
126533
  if (!entry.includes(INSTALLED_PROJECTION_MARKER)) continue;
126262
- const abs = join34(skillsDir, entry);
126534
+ const abs = join35(skillsDir, entry);
126263
126535
  if (!isSymlink(abs)) continue;
126264
126536
  const rel = `${dir}/${entry}`;
126265
126537
  if (managed.has(rel)) continue;
@@ -126270,7 +126542,7 @@ function allInstalledOrphans(repoRoot, plan) {
126270
126542
  }
126271
126543
  function sweepInstalledOrphans(repoRoot, plan) {
126272
126544
  const orphans = findInstalledOrphans(repoRoot, plan);
126273
- for (const rel of orphans) rmSync6(join34(repoRoot, rel), { force: true });
126545
+ for (const rel of orphans) rmSync6(join35(repoRoot, rel), { force: true });
126274
126546
  return orphans;
126275
126547
  }
126276
126548
  function findGeneratedCommandOrphans(repoRoot, plan) {
@@ -126280,14 +126552,14 @@ function allGeneratedCommandOrphans(repoRoot, plan) {
126280
126552
  const kept = new Set(
126281
126553
  plan.actions.filter((a2) => a2.kind === "generate" && a2.target?.startsWith(`${CLAUDE_COMMANDS_DIR}/`)).map((a2) => a2.target)
126282
126554
  );
126283
- const commandsDir = join34(repoRoot, CLAUDE_COMMANDS_DIR);
126555
+ const commandsDir = join35(repoRoot, CLAUDE_COMMANDS_DIR);
126284
126556
  const orphans = [];
126285
126557
  for (const sub of listDirEntries(commandsDir)) {
126286
126558
  if (!sub.isDirectory()) continue;
126287
- const subAbs = join34(commandsDir, sub.name);
126559
+ const subAbs = join35(commandsDir, sub.name);
126288
126560
  for (const file2 of listDir(subAbs)) {
126289
126561
  const rel = `${CLAUDE_COMMANDS_DIR}/${sub.name}/${file2}`;
126290
- const abs = join34(subAbs, file2);
126562
+ const abs = join35(subAbs, file2);
126291
126563
  if (isAtomicTempName(file2)) {
126292
126564
  if (isStaleAtomicTemp(abs)) orphans.push(rel);
126293
126565
  continue;
@@ -126301,20 +126573,20 @@ function allGeneratedCommandOrphans(repoRoot, plan) {
126301
126573
  }
126302
126574
  function sweepGeneratedCommandOrphans(repoRoot, plan) {
126303
126575
  const orphans = findGeneratedCommandOrphans(repoRoot, plan);
126304
- for (const rel of orphans) rmSync6(join34(repoRoot, rel), { force: true });
126576
+ for (const rel of orphans) rmSync6(join35(repoRoot, rel), { force: true });
126305
126577
  for (const rel of removableOf(repoRoot, emptiedWrapperDirs(repoRoot, plan))) {
126306
- rmSync6(join34(repoRoot, rel), { recursive: true, force: true });
126578
+ rmSync6(join35(repoRoot, rel), { recursive: true, force: true });
126307
126579
  }
126308
126580
  return orphans;
126309
126581
  }
126310
126582
  function emptiedWrapperDirs(repoRoot, plan) {
126311
- const commandsDir = join34(repoRoot, CLAUDE_COMMANDS_DIR);
126583
+ const commandsDir = join35(repoRoot, CLAUDE_COMMANDS_DIR);
126312
126584
  const taking = new Set(findGeneratedCommandOrphans(repoRoot, plan));
126313
126585
  const dirs = [];
126314
126586
  for (const sub of listDirEntries(commandsDir)) {
126315
126587
  if (!sub.isDirectory()) continue;
126316
126588
  const rel = `${CLAUDE_COMMANDS_DIR}/${sub.name}`;
126317
- const listing = tryListDir(join34(commandsDir, sub.name));
126589
+ const listing = tryListDir(join35(commandsDir, sub.name));
126318
126590
  if (listing === void 0) continue;
126319
126591
  if (listing.every((entry) => taking.has(`${rel}/${entry}`))) dirs.push(rel);
126320
126592
  }
@@ -126327,12 +126599,12 @@ function allOpencodeCommandOrphans(repoRoot, plan) {
126327
126599
  const kept = new Set(
126328
126600
  plan.actions.filter((a2) => a2.kind === "generate" && a2.target?.startsWith(`${OPENCODE_COMMANDS_DIR}/`)).map((a2) => a2.target)
126329
126601
  );
126330
- const commandsDir = join34(repoRoot, OPENCODE_COMMANDS_DIR);
126602
+ const commandsDir = join35(repoRoot, OPENCODE_COMMANDS_DIR);
126331
126603
  const orphans = [];
126332
126604
  for (const entry of listDirEntries(commandsDir)) {
126333
126605
  if (!entry.isFile()) continue;
126334
126606
  const rel = `${OPENCODE_COMMANDS_DIR}/${entry.name}`;
126335
- const abs = join34(commandsDir, entry.name);
126607
+ const abs = join35(commandsDir, entry.name);
126336
126608
  if (isAtomicTempName(entry.name)) {
126337
126609
  if (isStaleAtomicTemp(abs)) orphans.push(rel);
126338
126610
  continue;
@@ -126345,7 +126617,7 @@ function allOpencodeCommandOrphans(repoRoot, plan) {
126345
126617
  }
126346
126618
  function sweepOpencodeCommandOrphans(repoRoot, plan) {
126347
126619
  const orphans = findOpencodeCommandOrphans(repoRoot, plan);
126348
- for (const rel of orphans) rmSync6(join34(repoRoot, rel), { force: true });
126620
+ for (const rel of orphans) rmSync6(join35(repoRoot, rel), { force: true });
126349
126621
  return orphans;
126350
126622
  }
126351
126623
  function isEngineGeneratedCommand(abs) {
@@ -126361,8 +126633,8 @@ function findBlockedWrapperDirs(repoRoot, plan) {
126361
126633
  );
126362
126634
  const blocked = /* @__PURE__ */ new Set();
126363
126635
  for (const relDir of wrapperDirs) {
126364
- const abs = join34(repoRoot, relDir);
126365
- const hasForeignContent = listDir(abs).some((entry) => isForeign(join34(abs, entry), entry));
126636
+ const abs = join35(repoRoot, relDir);
126637
+ const hasForeignContent = listDir(abs).some((entry) => isForeign(join35(abs, entry), entry));
126366
126638
  if (hasForeignContent) blocked.add(relDir);
126367
126639
  }
126368
126640
  return blocked;
@@ -126378,7 +126650,7 @@ function findBlockedOpencodeCommandFiles(repoRoot, plan) {
126378
126650
  if (action.kind !== "generate") continue;
126379
126651
  const target = action.target;
126380
126652
  if (!target?.startsWith(`${OPENCODE_COMMANDS_DIR}/`)) continue;
126381
- const abs = join34(repoRoot, target);
126653
+ const abs = join35(repoRoot, target);
126382
126654
  if (pathExists(abs) && !isEngineGeneratedCommand(abs)) blocked.add(target);
126383
126655
  }
126384
126656
  return blocked;
@@ -126391,11 +126663,11 @@ function allSettingsHooksOrphan(repoRoot, plan) {
126391
126663
  (a2) => a2.kind === "merge" && a2.target === CLAUDE_SETTINGS_LOCAL_TARGET
126392
126664
  );
126393
126665
  if (hasMerge) return [];
126394
- return hasManagedHooks(join34(repoRoot, CLAUDE_SETTINGS_LOCAL_TARGET)) ? [CLAUDE_SETTINGS_LOCAL_TARGET] : [];
126666
+ return hasManagedHooks(join35(repoRoot, CLAUDE_SETTINGS_LOCAL_TARGET)) ? [CLAUDE_SETTINGS_LOCAL_TARGET] : [];
126395
126667
  }
126396
126668
  function sweepSettingsHooksOrphan(repoRoot, plan) {
126397
126669
  const orphans = findSettingsHooksOrphan(repoRoot, plan);
126398
- if (orphans.length > 0) sweepManagedHooks(join34(repoRoot, CLAUDE_SETTINGS_LOCAL_TARGET));
126670
+ if (orphans.length > 0) sweepManagedHooks(join35(repoRoot, CLAUDE_SETTINGS_LOCAL_TARGET));
126399
126671
  return orphans;
126400
126672
  }
126401
126673
  function applyPlan(repoRoot, plan, opts) {
@@ -126483,18 +126755,18 @@ function isDrifted(repoRoot, action) {
126483
126755
  switch (action.kind) {
126484
126756
  case "symlink": {
126485
126757
  if (!action.source || !action.target) return true;
126486
- const absTarget = join34(repoRoot, action.target);
126758
+ const absTarget = join35(repoRoot, action.target);
126487
126759
  const kind = occupantKind(absTarget);
126488
126760
  if (kind === "absent") return true;
126489
126761
  if (kind === "file" || kind === "directory") return false;
126490
126762
  const linkText = relativeLink(repoRoot, action.source, action.target);
126491
- return !linkMatchesPlan(absTarget, join34(repoRoot, action.source), linkText, linkCheck());
126763
+ return !linkMatchesPlan(absTarget, join35(repoRoot, action.source), linkText, linkCheck());
126492
126764
  }
126493
126765
  case "scaffold":
126494
- return !action.target || !scaffoldPresent(join34(repoRoot, action.target));
126766
+ return !action.target || !scaffoldPresent(join35(repoRoot, action.target));
126495
126767
  case "generate": {
126496
126768
  if (!action.target) return true;
126497
- const absTarget = join34(repoRoot, action.target);
126769
+ const absTarget = join35(repoRoot, action.target);
126498
126770
  if (blockingGenerateOccupant(absTarget) !== void 0) return false;
126499
126771
  const onDisk = readFileIfPresent(absTarget);
126500
126772
  if (onDisk === void 0) return true;
@@ -126506,7 +126778,7 @@ function isDrifted(repoRoot, action) {
126506
126778
  case "merge": {
126507
126779
  if (!action.target) return true;
126508
126780
  const managed = JSON.parse(requireActionContent(action));
126509
- return managedHooksDrift(join34(repoRoot, action.target), managed);
126781
+ return managedHooksDrift(join35(repoRoot, action.target), managed);
126510
126782
  }
126511
126783
  case "native":
126512
126784
  case "drop":
@@ -126518,7 +126790,7 @@ function findBlockedSymlinkTargets(repoRoot, plan) {
126518
126790
  for (const action of plan.actions) {
126519
126791
  if (action.kind !== "symlink" || !action.source || !action.target) continue;
126520
126792
  const reason = blockingSymlinkOccupant(
126521
- join34(repoRoot, action.target),
126793
+ join35(repoRoot, action.target),
126522
126794
  relativeLink(repoRoot, action.source, action.target)
126523
126795
  );
126524
126796
  if (reason !== void 0) blocked.push({ ...action, reason });
@@ -126629,8 +126901,8 @@ var init_apply = __esm({
126629
126901
  });
126630
126902
 
126631
126903
  // ../harness/src/adopt/apply.ts
126632
- import { lstatSync as lstatSync10, mkdirSync as mkdirSync6, renameSync as renameSync3, rmdirSync } from "node:fs";
126633
- import { join as join35 } from "node:path";
126904
+ import { lstatSync as lstatSync11, mkdirSync as mkdirSync6, renameSync as renameSync3, rmdirSync } from "node:fs";
126905
+ import { join as join36 } from "node:path";
126634
126906
  function applyAdopt(repoRoot, plan) {
126635
126907
  const moved = [];
126636
126908
  const declared = [];
@@ -126648,9 +126920,9 @@ function applyAdopt(repoRoot, plan) {
126648
126920
  return { moved, declared, refusals };
126649
126921
  }
126650
126922
  function applyMove(repoRoot, move) {
126651
- const absFrom = join35(repoRoot, move.from);
126652
- const absTo = join35(repoRoot, move.to);
126653
- const canonicalLayer = join35(repoRoot, ADOPT_TARGET_ROOT);
126923
+ const absFrom = join36(repoRoot, move.from);
126924
+ const absTo = join36(repoRoot, move.to);
126925
+ const canonicalLayer = join36(repoRoot, ADOPT_TARGET_ROOT);
126654
126926
  const layerExisted = somethingIsAt(canonicalLayer);
126655
126927
  mkdirSync6(canonicalLayer, { recursive: true });
126656
126928
  try {
@@ -126694,7 +126966,7 @@ function restore(input4) {
126694
126966
  if (!somethingIsAt(absFrom)) {
126695
126967
  try {
126696
126968
  renameSync3(absTo, absFrom);
126697
- if (!layerExisted) removeIfEmpty(join35(repoRoot, ADOPT_TARGET_ROOT));
126969
+ if (!layerExisted) removeIfEmpty(join36(repoRoot, ADOPT_TARGET_ROOT));
126698
126970
  return { name: move.name, source: move.from, rule: "link-blocked", reason: blocked };
126699
126971
  } catch {
126700
126972
  }
@@ -126714,7 +126986,7 @@ function removeIfEmpty(abs) {
126714
126986
  }
126715
126987
  function somethingIsAt(abs) {
126716
126988
  try {
126717
- lstatSync10(abs);
126989
+ lstatSync11(abs);
126718
126990
  return true;
126719
126991
  } catch {
126720
126992
  return false;
@@ -126758,13 +127030,13 @@ import {
126758
127030
  accessSync as accessSync3,
126759
127031
  constants as constants4,
126760
127032
  existsSync as existsSync12,
126761
- lstatSync as lstatSync11,
127033
+ lstatSync as lstatSync12,
126762
127034
  mkdirSync as mkdirSync7,
126763
127035
  readlinkSync as readlinkSync4,
126764
127036
  rmSync as rmSync7,
126765
127037
  symlinkSync as symlinkSync3
126766
127038
  } from "node:fs";
126767
- import { basename as basename5, dirname as dirname11, join as join36, relative as relative6, resolve as resolve5, sep as sep7 } from "node:path";
127039
+ import { basename as basename5, dirname as dirname11, join as join37, relative as relative6, resolve as resolve5, sep as sep7 } from "node:path";
126768
127040
  function globalSweepDirs(roots) {
126769
127041
  return [
126770
127042
  ...new Set(
@@ -126781,7 +127053,7 @@ function globalLinkPackage(abs, pluginsRoot) {
126781
127053
  if (!basename5(abs).includes(INSTALLED_PROJECTION_MARKER)) return void 0;
126782
127054
  let stats;
126783
127055
  try {
126784
- stats = lstatSync11(abs);
127056
+ stats = lstatSync12(abs);
126785
127057
  } catch {
126786
127058
  return void 0;
126787
127059
  }
@@ -126815,7 +127087,7 @@ function globalOrphanCandidates(plan, roots) {
126815
127087
  const pkg = globalLinkPackage(abs, pluginsRoot);
126816
127088
  if (pkg === void 0) continue;
126817
127089
  if (planned.has(abs)) continue;
126818
- if (!existsSync12(join36(pluginsRoot, pkg))) {
127090
+ if (!existsSync12(join37(pluginsRoot, pkg))) {
126819
127091
  orphans.set(abs, SWEEP_REASONS["global-package-gone"]);
126820
127092
  continue;
126821
127093
  }
@@ -127139,13 +127411,13 @@ var init_adoptable = __esm({
127139
127411
  // ../harness/src/vendor-facts/coverage.ts
127140
127412
  import {
127141
127413
  existsSync as existsSync13,
127142
- lstatSync as lstatSync12,
127414
+ lstatSync as lstatSync13,
127143
127415
  readdirSync as readdirSync8,
127144
127416
  readFileSync as readFileSync16,
127145
- realpathSync as realpathSync8,
127417
+ realpathSync as realpathSync9,
127146
127418
  statSync as statSync10
127147
127419
  } from "node:fs";
127148
- import { basename as basename6, isAbsolute as isAbsolute4, join as join37, relative as relative7, resolve as resolve6, sep as sep8 } from "node:path";
127420
+ import { basename as basename6, isAbsolute as isAbsolute4, join as join38, relative as relative7, resolve as resolve6, sep as sep8 } from "node:path";
127149
127421
  function statOrUndefined(path53) {
127150
127422
  try {
127151
127423
  return statSync10(path53, { throwIfNoEntry: false });
@@ -127155,7 +127427,7 @@ function statOrUndefined(path53) {
127155
127427
  }
127156
127428
  function lstatOrUndefined(path53) {
127157
127429
  try {
127158
- return lstatSync12(path53, { throwIfNoEntry: false });
127430
+ return lstatSync13(path53, { throwIfNoEntry: false });
127159
127431
  } catch {
127160
127432
  return void 0;
127161
127433
  }
@@ -127182,7 +127454,7 @@ function ascendLevels(root, cwd, stopAtWorktree) {
127182
127454
  const levels2 = [];
127183
127455
  for (; ; ) {
127184
127456
  levels2.push(current2);
127185
- if (stopAtWorktree && existsSync13(join37(current2, ".git"))) break;
127457
+ if (stopAtWorktree && existsSync13(join38(current2, ".git"))) break;
127186
127458
  if (current2 === root) break;
127187
127459
  const parent = resolve6(current2, "..");
127188
127460
  if (parent === current2) break;
@@ -127208,7 +127480,7 @@ function descendScopes(root, facts) {
127208
127480
  if (!entry.isDirectory()) continue;
127209
127481
  if (NEVER_DESCEND.has(entry.name)) continue;
127210
127482
  if (entry.name.startsWith(".") && !listedDotDirs.has(entry.name)) continue;
127211
- visit2(join37(dir, entry.name), depth + 1);
127483
+ visit2(join38(dir, entry.name), depth + 1);
127212
127484
  }
127213
127485
  };
127214
127486
  visit2(root, 0);
@@ -127220,7 +127492,7 @@ function readDirs(facts, root, cwd) {
127220
127492
  const seen = /* @__PURE__ */ new Set();
127221
127493
  for (const scope of scopes) {
127222
127494
  for (const readPath3 of facts.readPaths.project) {
127223
- const abs = join37(scope, readPath3);
127495
+ const abs = join38(scope, readPath3);
127224
127496
  if (seen.has(abs)) continue;
127225
127497
  seen.add(abs);
127226
127498
  dirs.push({ abs, via: viaOf(root, abs) });
@@ -127249,7 +127521,7 @@ function applyDedupe(harness, facts, root, candidates, uncertain) {
127249
127521
  if (facts.dedupe === "none") return candidates;
127250
127522
  const realpathOf = (dir) => {
127251
127523
  try {
127252
- return realpathSync8(dir);
127524
+ return realpathSync9(dir);
127253
127525
  } catch {
127254
127526
  return dir;
127255
127527
  }
@@ -127304,9 +127576,9 @@ function harnessCoverage(harness, root, opts) {
127304
127576
  continue;
127305
127577
  }
127306
127578
  for (const entry of [...entries].sort((a2, b2) => a2.name.localeCompare(b2.name))) {
127307
- const dir = join37(abs, entry.name);
127579
+ const dir = join38(abs, entry.name);
127308
127580
  if (!statOrUndefined(dir)?.isDirectory()) continue;
127309
- const skillMd = join37(dir, "SKILL.md");
127581
+ const skillMd = join38(dir, "SKILL.md");
127310
127582
  if (!statOrUndefined(skillMd)?.isFile()) continue;
127311
127583
  const reachedThroughSymlink = lstatOrUndefined(dir)?.isSymbolicLink() === true;
127312
127584
  const { found, reasons, loads, droppedReason } = evaluate(
@@ -127342,22 +127614,22 @@ var init_coverage = __esm({
127342
127614
  });
127343
127615
 
127344
127616
  // ../harness/src/engine.ts
127345
- import { existsSync as existsSync14, lstatSync as lstatSync13, readFileSync as readFileSync17, readdirSync as readdirSync9 } from "node:fs";
127346
- import { join as join38 } from "node:path";
127617
+ import { existsSync as existsSync14, lstatSync as lstatSync14, readFileSync as readFileSync17, readdirSync as readdirSync9 } from "node:fs";
127618
+ import { join as join39 } from "node:path";
127347
127619
  function loadManifest(repoRoot) {
127348
127620
  const raw = JSON.parse(
127349
- readFileSync17(join38(repoRoot, ".agents", "harness.manifest.json"), "utf8")
127621
+ readFileSync17(join39(repoRoot, ".agents", "harness.manifest.json"), "utf8")
127350
127622
  );
127351
127623
  return parseHarnessManifest(raw);
127352
127624
  }
127353
127625
  function loadClaudeHooks(repoRoot) {
127354
- const settingsPath = join38(repoRoot, ".claude", "settings.json");
127626
+ const settingsPath = join39(repoRoot, ".claude", "settings.json");
127355
127627
  if (!existsSync14(settingsPath)) return void 0;
127356
127628
  const settings = JSON.parse(readFileSync17(settingsPath, "utf8"));
127357
127629
  return settings.hooks;
127358
127630
  }
127359
127631
  function agentsMdExists(repoRoot) {
127360
- return existsSync14(join38(repoRoot, "AGENTS.md"));
127632
+ return existsSync14(join39(repoRoot, "AGENTS.md"));
127361
127633
  }
127362
127634
  function claudeCommandsExist(repoRoot) {
127363
127635
  const walk = (dir) => {
@@ -127369,22 +127641,22 @@ function claudeCommandsExist(repoRoot) {
127369
127641
  }
127370
127642
  for (const entry of entries) {
127371
127643
  if (entry.isFile() && entry.name.endsWith(".md")) return true;
127372
- if (entry.isDirectory() && walk(join38(dir, entry.name))) return true;
127644
+ if (entry.isDirectory() && walk(join39(dir, entry.name))) return true;
127373
127645
  }
127374
127646
  return false;
127375
127647
  };
127376
- return walk(join38(repoRoot, CLAUDE_COMMANDS_DIR));
127648
+ return walk(join39(repoRoot, CLAUDE_COMMANDS_DIR));
127377
127649
  }
127378
127650
  function scanClaudeOnlySkills(repoRoot, manifest) {
127379
127651
  const resolved = /* @__PURE__ */ new Map();
127380
127652
  for (const entry of manifest.claudeOnlySkills) {
127381
127653
  const defaultPath = `${CLAUDE_SKILLS_DIR}/${entry.name}`;
127382
127654
  const path53 = entry.path.trim() === "" ? defaultPath : entry.path;
127383
- const abs = join38(repoRoot, path53);
127655
+ const abs = join39(repoRoot, path53);
127384
127656
  let kind = "missing";
127385
- const stats = lstatSync13(abs, { throwIfNoEntry: false });
127657
+ const stats = lstatSync14(abs, { throwIfNoEntry: false });
127386
127658
  if (stats?.isSymbolicLink()) kind = "symlink";
127387
- else if (stats?.isDirectory() && existsSync14(join38(abs, "SKILL.md"))) kind = "directory";
127659
+ else if (stats?.isDirectory() && existsSync14(join39(abs, "SKILL.md"))) kind = "directory";
127388
127660
  resolved.set(entry.name, { path: path53, kind, atProjectionTarget: path53 === defaultPath });
127389
127661
  }
127390
127662
  return resolved;
@@ -127392,7 +127664,8 @@ function scanClaudeOnlySkills(repoRoot, manifest) {
127392
127664
  function project(repoRoot, opts) {
127393
127665
  const installed = scanInstalledSources({
127394
127666
  dorkHome: opts?.dorkHome,
127395
- projectRoot: repoRoot
127667
+ projectRoot: repoRoot,
127668
+ ...opts?.devLinks ? { devLinks: opts.devLinks } : {}
127396
127669
  });
127397
127670
  const manifest = loadManifest(repoRoot);
127398
127671
  return buildPlan({
@@ -127470,6 +127743,7 @@ __export(src_exports, {
127470
127743
  CURSOR_HOOK_EVENTS: () => CURSOR_HOOK_EVENTS,
127471
127744
  CURSOR_TO_CANONICAL_EVENT_NAMES: () => CURSOR_TO_CANONICAL_EVENT_NAMES,
127472
127745
  DEFAULT_HARNESSES: () => DEFAULT_HARNESSES,
127746
+ DEV_LINK_MARKER: () => DEV_LINK_MARKER,
127473
127747
  DORKOS_OWN_FIELDS: () => DORKOS_OWN_FIELDS,
127474
127748
  EMPTY_INVENTORY: () => EMPTY_INVENTORY,
127475
127749
  EPHEMERAL_GITIGNORE_PATTERNS: () => EPHEMERAL_GITIGNORE_PATTERNS,
@@ -127497,6 +127771,7 @@ __export(src_exports, {
127497
127771
  HarnessManifestSchema: () => HarnessManifestSchema,
127498
127772
  INSTALLED_PROJECTION_MARKER: () => INSTALLED_PROJECTION_MARKER,
127499
127773
  JUNCTION_COMMIT_WARNING: () => JUNCTION_COMMIT_WARNING,
127774
+ MANAGED_HOOK_DEV_LINK_KEY: () => MANAGED_HOOK_DEV_LINK_KEY,
127500
127775
  MANAGED_HOOK_SENTINEL_KEY: () => MANAGED_HOOK_SENTINEL_KEY,
127501
127776
  MCP_CONFIG_SOURCE: () => MCP_CONFIG_SOURCE,
127502
127777
  OPENCODE_COMMANDS_DIR: () => OPENCODE_COMMANDS_DIR,
@@ -127539,6 +127814,9 @@ __export(src_exports, {
127539
127814
  declareClaudeOnlySkill: () => declareClaudeOnlySkill,
127540
127815
  detectHarnessFootprints: () => detectHarnessFootprints,
127541
127816
  detectHarnesses: () => detectHarnesses,
127817
+ devLinkForSlot: () => devLinkForSlot,
127818
+ devLinkLabel: () => devLinkLabel,
127819
+ devLinkMarkerLine: () => devLinkMarkerLine,
127542
127820
  dorkosHarnessScaffoldNotice: () => dorkosHarnessScaffoldNotice,
127543
127821
  dropNonPortableLayers: () => dropNonPortableLayers,
127544
127822
  dropSuppressedPluginHookMerge: () => dropSuppressedPluginHookMerge,
@@ -127583,8 +127861,10 @@ __export(src_exports, {
127583
127861
  isJunctionAt: () => isJunctionAt,
127584
127862
  isPathIgnored: () => isPathIgnored,
127585
127863
  isProjectScoped: () => isProjectScoped,
127864
+ isStillLinked: () => isStillLinked,
127586
127865
  joinNames: () => joinNames2,
127587
127866
  junctionCommitWarnings: () => junctionCommitWarnings,
127867
+ labelDevLinkActions: () => labelDevLinkActions,
127588
127868
  listAuthoredSkills: () => listAuthoredSkills,
127589
127869
  listSkillDirs: () => listSkillDirs,
127590
127870
  loadClaudeHooks: () => loadClaudeHooks,
@@ -127625,6 +127905,7 @@ __export(src_exports, {
127625
127905
  projectGlobal: () => projectGlobal,
127626
127906
  projectedHooks: () => projectedHooks,
127627
127907
  readAdoptCandidates: () => readAdoptCandidates,
127908
+ readDevLinksSync: () => readDevLinksSync,
127628
127909
  removableOf: () => removableOf,
127629
127910
  resolveSourceRoots: () => resolveSourceRoots,
127630
127911
  rewritePluginRootInHooks: () => rewritePluginRootInHooks,
@@ -127647,7 +127928,8 @@ __export(src_exports, {
127647
127928
  sweepSettingsHooksOrphan: () => sweepSettingsHooksOrphan,
127648
127929
  symlinkTypeFor: () => symlinkTypeFor,
127649
127930
  unlistableSweptDirs: () => unlistableSweptDirs,
127650
- unreachableNativeReason: () => unreachableNativeReason
127931
+ unreachableNativeReason: () => unreachableNativeReason,
127932
+ withDevLinkMarker: () => withDevLinkMarker
127651
127933
  });
127652
127934
  var init_src4 = __esm({
127653
127935
  "../harness/src/index.ts"() {
@@ -127661,6 +127943,7 @@ var init_src4 = __esm({
127661
127943
  init_instructions();
127662
127944
  init_command_formats();
127663
127945
  init_installed_projector();
127946
+ init_dev_link_labels();
127664
127947
  init_global_projector();
127665
127948
  init_global_installs();
127666
127949
  init_unreadable_hooks();
@@ -127675,6 +127958,7 @@ var init_src4 = __esm({
127675
127958
  init_declare_claude_only();
127676
127959
  init_resolve_roots();
127677
127960
  init_installed();
127961
+ init_dev_links();
127678
127962
  init_hooks();
127679
127963
  init_adopt();
127680
127964
  init_apply();
@@ -127698,7 +127982,7 @@ __export(adopt_owned_workspace_exports, {
127698
127982
  autoAdoptFromDisk: () => autoAdoptFromDisk
127699
127983
  });
127700
127984
  import { readFileSync as readFileSync18 } from "node:fs";
127701
- import { join as join39 } from "node:path";
127985
+ import { join as join40 } from "node:path";
127702
127986
  function autoAdoptPermitted() {
127703
127987
  return configManager.get("harness").autoAdopt;
127704
127988
  }
@@ -127706,7 +127990,7 @@ function autoAdoptFromDisk(dorkHome) {
127706
127990
  const fallback = UserConfigSchema.shape.harness.parse(void 0).autoAdopt;
127707
127991
  let raw;
127708
127992
  try {
127709
- raw = JSON.parse(readFileSync18(join39(dorkHome, "config.json"), "utf8"));
127993
+ raw = JSON.parse(readFileSync18(join40(dorkHome, "config.json"), "utf8"));
127710
127994
  } catch {
127711
127995
  return fallback;
127712
127996
  }
@@ -127807,18 +128091,18 @@ var init_adopt_owned_workspace = __esm({
127807
128091
  });
127808
128092
 
127809
128093
  // ../../apps/server/src/services/harness/project-agent-workspace.ts
127810
- import { existsSync as existsSync15, realpathSync as realpathSync9 } from "node:fs";
127811
- import { join as join40, relative as relative8, resolve as resolve7, isAbsolute as isAbsolute5 } from "node:path";
128094
+ import { existsSync as existsSync15, realpathSync as realpathSync10 } from "node:fs";
128095
+ import { join as join41, relative as relative8, resolve as resolve7, isAbsolute as isAbsolute5 } from "node:path";
127812
128096
  function canonicalize(p) {
127813
128097
  const absolute = resolve7(p);
127814
128098
  try {
127815
- return realpathSync9(absolute);
128099
+ return realpathSync10(absolute);
127816
128100
  } catch {
127817
128101
  return absolute;
127818
128102
  }
127819
128103
  }
127820
128104
  function isAgentHome(dir, dorkHome) {
127821
- const rel = relative8(canonicalize(join40(dorkHome, "agents")), canonicalize(dir));
128105
+ const rel = relative8(canonicalize(join41(dorkHome, "agents")), canonicalize(dir));
127822
128106
  return rel !== "" && !rel.startsWith("..") && !isAbsolute5(rel);
127823
128107
  }
127824
128108
  var AGENT_SKILLS_DIR;
@@ -127827,9 +128111,10 @@ var init_project_agent_workspace = __esm({
127827
128111
  "use strict";
127828
128112
  init_src4();
127829
128113
  init_src3();
128114
+ init_dork_home();
127830
128115
  init_logger();
127831
128116
  init_adopt_owned_workspace();
127832
- AGENT_SKILLS_DIR = join40(".agents", "skills");
128117
+ AGENT_SKILLS_DIR = join41(".agents", "skills");
127833
128118
  }
127834
128119
  });
127835
128120
 
@@ -127838,14 +128123,14 @@ var directory_ownership_exports = {};
127838
128123
  __export(directory_ownership_exports, {
127839
128124
  resolveDirectoryOwnership: () => resolveDirectoryOwnership
127840
128125
  });
127841
- import { join as join41, relative as relative9, sep as sep9 } from "node:path";
128126
+ import { join as join42, relative as relative9, sep as sep9 } from "node:path";
127842
128127
  function resolveDirectoryOwnership(dir, dorkHome) {
127843
128128
  if (isAgentHome(dir, dorkHome)) return "agent-home";
127844
128129
  if (isRoomWorktree(dir, dorkHome)) return "room-worktree";
127845
128130
  return "plain";
127846
128131
  }
127847
128132
  function isRoomWorktree(dir, dorkHome) {
127848
- const rel = relative9(canonicalize(join41(dorkHome, "rooms")), canonicalize(dir));
128133
+ const rel = relative9(canonicalize(join42(dorkHome, "rooms")), canonicalize(dir));
127849
128134
  if (rel === "" || rel.startsWith("..")) return false;
127850
128135
  const parts = rel.split(sep9);
127851
128136
  return parts.length === 3 && parts[1] === "worktrees";
@@ -127857,9 +128142,9 @@ var init_directory_ownership = __esm({
127857
128142
  });
127858
128143
 
127859
128144
  // src/harness-consent.ts
127860
- import { join as join42 } from "node:path";
128145
+ import { join as join43 } from "node:path";
127861
128146
  function configPathFor(dorkHome) {
127862
- return join42(dorkHome, "config.json");
128147
+ return join43(dorkHome, "config.json");
127863
128148
  }
127864
128149
  async function readStoredDecisions(dorkHome) {
127865
128150
  const { readHookDecisionsFromDisk: readHookDecisionsFromDisk2 } = await Promise.resolve().then(() => (init_hook_consent(), hook_consent_exports));
@@ -128020,11 +128305,11 @@ __export(global_scope_exports, {
128020
128305
  writeGlobalSharing: () => writeGlobalSharing
128021
128306
  });
128022
128307
  import { readFileSync as readFileSync19 } from "node:fs";
128023
- import { join as join43 } from "node:path";
128308
+ import { join as join44 } from "node:path";
128024
128309
  function readGlobalSharingFromDisk(dorkHome) {
128025
128310
  let text2;
128026
128311
  try {
128027
- text2 = readFileSync19(join43(dorkHome, "config.json"), "utf8");
128312
+ text2 = readFileSync19(join44(dorkHome, "config.json"), "utf8");
128028
128313
  } catch (err) {
128029
128314
  if (err.code === "ENOENT") return NOTHING_SHARED;
128030
128315
  return { ...NOTHING_SHARED, unreadable: describeReadFailure2(err) };
@@ -128053,7 +128338,7 @@ function boundaryConfigFromDisk(dorkHome) {
128053
128338
  getDot: (key) => {
128054
128339
  if (key !== "server.boundary") return void 0;
128055
128340
  try {
128056
- const raw = JSON.parse(readFileSync19(join43(dorkHome, "config.json"), "utf8"));
128341
+ const raw = JSON.parse(readFileSync19(join44(dorkHome, "config.json"), "utf8"));
128057
128342
  const server2 = raw?.server;
128058
128343
  return server2?.boundary;
128059
128344
  } catch {
@@ -128084,7 +128369,7 @@ function resolveGlobalScopeInputs(dorkHome, env5, config3) {
128084
128369
  roots: {
128085
128370
  dorkHome,
128086
128371
  ...AGENTS_SKILLS_DIR_READERS.some((harness) => enabled3.has(harness)) ? { agentsSkillsDir: agentsUserSkillsDir() } : {},
128087
- ...enabled3.has("claude-code") ? { claudeSkillsDir: join43(inheritedClaudeRoot(), "skills") } : {}
128372
+ ...enabled3.has("claude-code") ? { claudeSkillsDir: join44(inheritedClaudeRoot(), "skills") } : {}
128088
128373
  }
128089
128374
  };
128090
128375
  }
@@ -128094,7 +128379,7 @@ function globalRootsFor(dorkHome, harnesses, env5, config3) {
128094
128379
  return {
128095
128380
  dorkHome,
128096
128381
  ...AGENTS_SKILLS_DIR_READERS.some((harness) => enabled3.has(harness)) ? { agentsSkillsDir: agentsUserSkillsDir() } : {},
128097
- ...enabled3.has("claude-code") ? { claudeSkillsDir: join43(inheritedClaudeRoot(), "skills") } : {}
128382
+ ...enabled3.has("claude-code") ? { claudeSkillsDir: join44(inheritedClaudeRoot(), "skills") } : {}
128098
128383
  };
128099
128384
  }
128100
128385
  function writeGlobalSharing(harnesses, reason, now2 = /* @__PURE__ */ new Date()) {
@@ -128585,11 +128870,11 @@ __export(project_with_consent_exports, {
128585
128870
  withProjectLock: () => withProjectLock
128586
128871
  });
128587
128872
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
128588
- import { realpathSync as realpathSync10 } from "node:fs";
128873
+ import { realpathSync as realpathSync11 } from "node:fs";
128589
128874
  import { resolve as resolve8 } from "node:path";
128590
128875
  function projectLockKey(projectPath) {
128591
128876
  try {
128592
- return realpathSync10(projectPath);
128877
+ return realpathSync11(projectPath);
128593
128878
  } catch {
128594
128879
  return resolve8(projectPath);
128595
128880
  }
@@ -128704,11 +128989,11 @@ var init_project_with_consent = __esm({
128704
128989
  import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
128705
128990
  import { randomUUID as randomUUID3 } from "node:crypto";
128706
128991
  import { chmod, mkdir as mkdir3, rename, rm, writeFile as writeFile3 } from "node:fs/promises";
128707
- import { basename as basename7, dirname as dirname12, join as join44, resolve as resolve9 } from "node:path";
128992
+ import { basename as basename7, dirname as dirname12, join as join45, resolve as resolve9 } from "node:path";
128708
128993
  async function writeUnlocked(filePath, data, options) {
128709
128994
  const dir = dirname12(filePath);
128710
128995
  await mkdir3(dir, { recursive: true });
128711
- const tempPath = join44(dir, `.${basename7(filePath)}.${process.pid}.${randomUUID3()}.tmp`);
128996
+ const tempPath = join45(dir, `.${basename7(filePath)}.${process.pid}.${randomUUID3()}.tmp`);
128712
128997
  try {
128713
128998
  await writeFile3(tempPath, data, {
128714
128999
  encoding: "utf-8",
@@ -128865,7 +129150,7 @@ var init_git_tree = __esm({
128865
129150
 
128866
129151
  // ../../apps/server/src/services/marketplace/lib/directory-size.ts
128867
129152
  import { lstat as lstat3, readdir as readdir3 } from "node:fs/promises";
128868
- import { join as join45 } from "node:path";
129153
+ import { join as join46 } from "node:path";
128869
129154
  async function directorySize(root) {
128870
129155
  let total = 0;
128871
129156
  const walk = async (dir, depth) => {
@@ -128877,7 +129162,7 @@ async function directorySize(root) {
128877
129162
  return;
128878
129163
  }
128879
129164
  for (const entry of entries) {
128880
- const entryPath = join45(dir, entry.name);
129165
+ const entryPath = join46(dir, entry.name);
128881
129166
  if (entry.isDirectory()) {
128882
129167
  await walk(entryPath, depth + 1);
128883
129168
  } else if (entry.isFile()) {
@@ -128913,7 +129198,7 @@ import {
128913
129198
  stat as stat2,
128914
129199
  utimes
128915
129200
  } from "node:fs/promises";
128916
- import { join as join46 } from "node:path";
129201
+ import { join as join47 } from "node:path";
128917
129202
  function isFetchStatus(value) {
128918
129203
  if (typeof value !== "object" || value === null) return false;
128919
129204
  const v2 = value;
@@ -129005,7 +129290,7 @@ var init_marketplace_cache = __esm({
129005
129290
  entryWrittenListeners = /* @__PURE__ */ new Set();
129006
129291
  /** Compute the cache root path: `${dorkHome}/cache/marketplace`. */
129007
129292
  get cacheRoot() {
129008
- return join46(this.dorkHome, "cache", "marketplace");
129293
+ return join47(this.dorkHome, "cache", "marketplace");
129009
129294
  }
129010
129295
  /**
129011
129296
  * Read a cached marketplace.json document.
@@ -129036,8 +129321,8 @@ var init_marketplace_cache = __esm({
129036
129321
  if (err instanceof PathEscapeError) return null;
129037
129322
  throw err;
129038
129323
  }
129039
- const jsonPath = join46(dir, MARKETPLACE_FILENAME);
129040
- const stampPath = join46(dir, LAST_FETCHED_FILENAME);
129324
+ const jsonPath = join47(dir, MARKETPLACE_FILENAME);
129325
+ const stampPath = join47(dir, LAST_FETCHED_FILENAME);
129041
129326
  let raw;
129042
129327
  let stamp2;
129043
129328
  try {
@@ -129072,9 +129357,9 @@ var init_marketplace_cache = __esm({
129072
129357
  async writeMarketplace(marketplaceName, json3) {
129073
129358
  const dir = this.marketplaceDir(marketplaceName);
129074
129359
  await mkdir4(dir, { recursive: true });
129075
- await writeFile4(join46(dir, MARKETPLACE_FILENAME), `${JSON.stringify(json3, null, 2)}
129360
+ await writeFile4(join47(dir, MARKETPLACE_FILENAME), `${JSON.stringify(json3, null, 2)}
129076
129361
  `);
129077
- await writeFile4(join46(dir, LAST_FETCHED_FILENAME), (/* @__PURE__ */ new Date()).toISOString());
129362
+ await writeFile4(join47(dir, LAST_FETCHED_FILENAME), (/* @__PURE__ */ new Date()).toISOString());
129078
129363
  }
129079
129364
  /**
129080
129365
  * Record how an attempt to fetch a marketplace's listing went.
@@ -129093,7 +129378,7 @@ var init_marketplace_cache = __esm({
129093
129378
  * cache. Callers treat recording as best effort.
129094
129379
  */
129095
129380
  async writeFetchStatus(marketplaceName, status) {
129096
- const file2 = join46(this.marketplaceDir(marketplaceName), LAST_CHECK_FILENAME);
129381
+ const file2 = join47(this.marketplaceDir(marketplaceName), LAST_CHECK_FILENAME);
129097
129382
  await withFileLock(file2, async (write) => {
129098
129383
  const current2 = await this.readFetchStatus(marketplaceName);
129099
129384
  if (current2 && current2.startedAt > status.startedAt) return;
@@ -129113,8 +129398,8 @@ var init_marketplace_cache = __esm({
129113
129398
  try {
129114
129399
  const dir = this.marketplaceDir(marketplaceName);
129115
129400
  const [stamp2] = await Promise.all([
129116
- readFile3(join46(dir, LAST_FETCHED_FILENAME), "utf-8"),
129117
- access(join46(dir, MARKETPLACE_FILENAME))
129401
+ readFile3(join47(dir, LAST_FETCHED_FILENAME), "utf-8"),
129402
+ access(join47(dir, MARKETPLACE_FILENAME))
129118
129403
  ]);
129119
129404
  const at = new Date(stamp2.trim());
129120
129405
  return Number.isNaN(at.getTime()) ? null : at;
@@ -129132,7 +129417,7 @@ var init_marketplace_cache = __esm({
129132
129417
  async readFetchStatus(marketplaceName) {
129133
129418
  try {
129134
129419
  const raw = await readFile3(
129135
- join46(this.marketplaceDir(marketplaceName), LAST_CHECK_FILENAME),
129420
+ join47(this.marketplaceDir(marketplaceName), LAST_CHECK_FILENAME),
129136
129421
  "utf-8"
129137
129422
  );
129138
129423
  const parsed = JSON.parse(raw);
@@ -129244,8 +129529,8 @@ var init_marketplace_cache = __esm({
129244
129529
  * Idempotent. Not safe while a fetch is running in this cache.
129245
129530
  */
129246
129531
  async removeLeftovers() {
129247
- await rm2(join46(this.cacheRoot, LEGACY_PACKAGES_DIRNAME), { recursive: true, force: true });
129248
- const treesRoot = join46(this.cacheRoot, TREES_DIRNAME);
129532
+ await rm2(join47(this.cacheRoot, LEGACY_PACKAGES_DIRNAME), { recursive: true, force: true });
129533
+ const treesRoot = join47(this.cacheRoot, TREES_DIRNAME);
129249
129534
  let entries;
129250
129535
  try {
129251
129536
  entries = await readdir4(treesRoot);
@@ -129255,7 +129540,7 @@ var init_marketplace_cache = __esm({
129255
129540
  await Promise.all(
129256
129541
  entries.filter(
129257
129542
  (entry) => entry.startsWith(TEMP_FETCH_PREFIX) || entry.startsWith(TEMP_PRUNE_PREFIX)
129258
- ).map((entry) => rm2(join46(treesRoot, entry), { recursive: true, force: true }))
129543
+ ).map((entry) => rm2(join47(treesRoot, entry), { recursive: true, force: true }))
129259
129544
  );
129260
129545
  }
129261
129546
  /**
@@ -129266,9 +129551,9 @@ var init_marketplace_cache = __esm({
129266
129551
  * @internal
129267
129552
  */
129268
129553
  async fetchAndPromote(packageName, subpath, fetch2) {
129269
- const treesRoot = join46(this.cacheRoot, TREES_DIRNAME);
129554
+ const treesRoot = join47(this.cacheRoot, TREES_DIRNAME);
129270
129555
  await mkdir4(treesRoot, { recursive: true });
129271
- const tempDir = await mkdtemp(join46(treesRoot, TEMP_FETCH_PREFIX));
129556
+ const tempDir = await mkdtemp(join47(treesRoot, TEMP_FETCH_PREFIX));
129272
129557
  let commitSha;
129273
129558
  let finalPath;
129274
129559
  try {
@@ -129332,7 +129617,7 @@ var init_marketplace_cache = __esm({
129332
129617
  * removed (the others still are).
129333
129618
  */
129334
129619
  async removeUnused(keep) {
129335
- const treesRoot = join46(this.cacheRoot, TREES_DIRNAME);
129620
+ const treesRoot = join47(this.cacheRoot, TREES_DIRNAME);
129336
129621
  const entries = await this.listPackages();
129337
129622
  const kept = keep(entries);
129338
129623
  const result2 = { removed: [], freedBytes: 0, failed: [] };
@@ -129347,7 +129632,7 @@ var init_marketplace_cache = __esm({
129347
129632
  return null;
129348
129633
  }
129349
129634
  if (Date.now() - lastUsedMs < IN_USE_GRACE_MS) return null;
129350
- const target = join46(treesRoot, `${TEMP_PRUNE_PREFIX}${randomUUID4()}`);
129635
+ const target = join47(treesRoot, `${TEMP_PRUNE_PREFIX}${randomUUID4()}`);
129351
129636
  await rename2(entry.path, target);
129352
129637
  return target;
129353
129638
  });
@@ -129396,7 +129681,7 @@ var init_marketplace_cache = __esm({
129396
129681
  * Listing is not use: it stamps nothing.
129397
129682
  */
129398
129683
  async listPackages() {
129399
- const root = join46(this.cacheRoot, TREES_DIRNAME);
129684
+ const root = join47(this.cacheRoot, TREES_DIRNAME);
129400
129685
  let entries;
129401
129686
  try {
129402
129687
  entries = await readdir4(root);
@@ -129410,7 +129695,7 @@ var init_marketplace_cache = __esm({
129410
129695
  if (!parsed) {
129411
129696
  continue;
129412
129697
  }
129413
- const path53 = join46(root, entry);
129698
+ const path53 = join47(root, entry);
129414
129699
  try {
129415
129700
  const info2 = await stat2(path53);
129416
129701
  if (!info2.isDirectory()) {
@@ -129439,8 +129724,8 @@ var init_marketplace_cache = __esm({
129439
129724
  * the cache.
129440
129725
  */
129441
129726
  marketplaceDir(marketplaceName) {
129442
- const root = join46(this.cacheRoot, "marketplaces");
129443
- return assertContainedIn(root, join46(root, marketplaceName));
129727
+ const root = join47(this.cacheRoot, "marketplaces");
129728
+ return assertContainedIn(root, join47(root, marketplaceName));
129444
129729
  }
129445
129730
  /**
129446
129731
  * Compute the directory path for a content-addressable package tree:
@@ -129460,10 +129745,10 @@ var init_marketplace_cache = __esm({
129460
129745
  * the cache.
129461
129746
  */
129462
129747
  packageDir(packageName, commitSha, subpath) {
129463
- const root = join46(this.cacheRoot, TREES_DIRNAME);
129748
+ const root = join47(this.cacheRoot, TREES_DIRNAME);
129464
129749
  const digest2 = subpathDigest(subpath);
129465
129750
  const tree = digest2 === "" ? "" : `${SUBPATH_SEPARATOR}${digest2}`;
129466
- return assertContainedIn(root, join46(root, `${packageName}@${commitSha}${tree}`));
129751
+ return assertContainedIn(root, join47(root, `${packageName}@${commitSha}${tree}`));
129467
129752
  }
129468
129753
  };
129469
129754
  }
@@ -129524,7 +129809,7 @@ var init_source_url_policy = __esm({
129524
129809
 
129525
129810
  // ../../apps/server/src/services/marketplace/sources/marketplace-source-manager.ts
129526
129811
  import { readFile as readFile4 } from "node:fs/promises";
129527
- import { join as join47 } from "node:path";
129812
+ import { join as join48 } from "node:path";
129528
129813
  function buildDefaultSources() {
129529
129814
  const now2 = (/* @__PURE__ */ new Date()).toISOString();
129530
129815
  return [
@@ -129599,7 +129884,7 @@ var init_marketplace_source_manager = __esm({
129599
129884
  */
129600
129885
  constructor(dorkHome) {
129601
129886
  this.dorkHome = dorkHome;
129602
- this.filePath = join47(dorkHome, MARKETPLACES_FILENAME);
129887
+ this.filePath = join48(dorkHome, MARKETPLACES_FILENAME);
129603
129888
  }
129604
129889
  dorkHome;
129605
129890
  filePath;
@@ -130039,7 +130324,7 @@ __export(harness_sync_command_exports, {
130039
130324
  runHarnessSync: () => runHarnessSync
130040
130325
  });
130041
130326
  import { existsSync as existsSync17, readFileSync as readFileSync20 } from "node:fs";
130042
- import { join as join48 } from "node:path";
130327
+ import { join as join49 } from "node:path";
130043
130328
  import { parseArgs as parseArgs3 } from "node:util";
130044
130329
  function parseHarnessSyncArgs(rawArgs) {
130045
130330
  let parsed;
@@ -130166,7 +130451,7 @@ function reportCodexTrust(before, after) {
130166
130451
  }
130167
130452
  function reportClaudeSkillsRestart(existedBefore, repoRoot) {
130168
130453
  if (existedBefore) return;
130169
- if (!existsSync17(join48(repoRoot, CLAUDE_SKILLS_DIR))) return;
130454
+ if (!existsSync17(join49(repoRoot, CLAUDE_SKILLS_DIR))) return;
130170
130455
  const facts = skillsFactsFor("claude-code");
130171
130456
  console.log("");
130172
130457
  console.log(`Created ${CLAUDE_SKILLS_DIR}/, which is where Claude Code reads skills.`);
@@ -130177,7 +130462,7 @@ function reportClaudeSkillsRestart(existedBefore, repoRoot) {
130177
130462
  }
130178
130463
  function readIfPresent(repoRoot, rel) {
130179
130464
  try {
130180
- return readFileSync20(join48(repoRoot, rel), "utf8");
130465
+ return readFileSync20(join49(repoRoot, rel), "utf8");
130181
130466
  } catch {
130182
130467
  return void 0;
130183
130468
  }
@@ -130504,7 +130789,7 @@ async function runHarnessSync(args) {
130504
130789
  }
130505
130790
  const repoRoot = process.cwd();
130506
130791
  const ourHarness = await readDorkosHarness(resolveDorkHome2());
130507
- if (!existsSync17(join48(repoRoot, HARNESS_MANIFEST_PATH))) {
130792
+ if (!existsSync17(join49(repoRoot, HARNESS_MANIFEST_PATH))) {
130508
130793
  if (!args.fix) {
130509
130794
  console.error(`No harness manifest in ${repoRoot}`);
130510
130795
  console.error(` looked for: ${HARNESS_MANIFEST_PATH}`);
@@ -130584,7 +130869,7 @@ async function runHarnessSync(args) {
130584
130869
  return { exitCode: strictExit(exitCode2, withheld, args.strict) };
130585
130870
  }
130586
130871
  const codexHooksBefore = readIfPresent(repoRoot, CODEX_HOOKS_TARGET);
130587
- const claudeSkillsExistedBefore = existsSync17(join48(repoRoot, CLAUDE_SKILLS_DIR));
130872
+ const claudeSkillsExistedBefore = existsSync17(join49(repoRoot, CLAUDE_SKILLS_DIR));
130588
130873
  const result2 = projectWithConsent2(repoRoot, {
130589
130874
  ...consentOpts,
130590
130875
  sweepOrphans: harnessFilter === void 0
@@ -130642,7 +130927,7 @@ __export(harness_adopt_command_exports, {
130642
130927
  runHarnessAdopt: () => runHarnessAdopt
130643
130928
  });
130644
130929
  import { existsSync as existsSync18 } from "node:fs";
130645
- import { join as join49, resolve as resolve10 } from "node:path";
130930
+ import { join as join50, resolve as resolve10 } from "node:path";
130646
130931
  import { parseArgs as parseArgs4 } from "node:util";
130647
130932
  function parseHarnessAdoptArgs(rawArgs) {
130648
130933
  let parsed;
@@ -130683,7 +130968,7 @@ ${USAGE_LINE6}`
130683
130968
  }
130684
130969
  async function runHarnessAdopt(args) {
130685
130970
  const repoRoot = args.project === void 0 ? process.cwd() : resolve10(process.cwd(), args.project);
130686
- if (!existsSync18(join49(repoRoot, HARNESS_MANIFEST_PATH))) {
130971
+ if (!existsSync18(join50(repoRoot, HARNESS_MANIFEST_PATH))) {
130687
130972
  console.error(`No harness manifest in ${repoRoot}`);
130688
130973
  console.error(` looked for: ${HARNESS_MANIFEST_PATH}`);
130689
130974
  console.error("");
@@ -134852,8 +135137,14 @@ var init_release_resolver = __esm({
134852
135137
 
134853
135138
  // src/commands/community-deploy/provider-process.ts
134854
135139
  import { spawn as spawn3 } from "node:child_process";
135140
+ function errorLines(stderr) {
135141
+ return stderr.replace(ANSI_ESCAPE, "").split(/\r?\n/u).map((line2) => line2.trim());
135142
+ }
134855
135143
  function isProviderAccessRefusal(stderr) {
134856
- return stderr.replace(ANSI_ESCAPE, "").split(/\r?\n/u).map((line2) => line2.trim()).some((line2) => FLY_REFUSAL.test(line2) || NEON_REFUSAL.test(line2));
135144
+ return errorLines(stderr).some((line2) => FLY_REFUSAL.test(line2) || NEON_REFUSAL.test(line2));
135145
+ }
135146
+ function isProviderKeyKindLimit(stderr) {
135147
+ return errorLines(stderr).some((line2) => NEON_KEY_KIND_LIMIT.test(line2));
134857
135148
  }
134858
135149
  function runProviderCommand(options) {
134859
135150
  return new Promise((resolve11, reject) => {
@@ -134922,10 +135213,12 @@ function runProviderCommand(options) {
134922
135213
  }
134923
135214
  if (code !== 0) {
134924
135215
  const errorOutput = Buffer.concat(stderrHead);
134925
- const refused = isProviderAccessRefusal(errorOutput.toString("utf8"));
135216
+ const text2 = errorOutput.toString("utf8");
135217
+ const refused = isProviderAccessRefusal(text2);
135218
+ const keyKindLimited = isProviderKeyKindLimit(text2);
134926
135219
  errorOutput.fill(0);
134927
135220
  scrubStdout();
134928
- return reject(new ProviderCommandError("EXIT", refused));
135221
+ return reject(new ProviderCommandError("EXIT", refused, keyKindLimited));
134929
135222
  }
134930
135223
  const output2 = Buffer.concat(stdout3);
134931
135224
  try {
@@ -134941,7 +135234,7 @@ function runProviderCommand(options) {
134941
135234
  child.stdin.end(options.stdin);
134942
135235
  });
134943
135236
  }
134944
- var DEFAULT_MAX_BYTES, REFUSAL_SCAN_BYTES, ANSI_ESCAPE, FLY_REFUSAL, NEON_REFUSAL, COMMUNITY_SERVICE_TIMEOUT_MS, TERMINATION_GRACE_MS, ProviderCommandError;
135237
+ var DEFAULT_MAX_BYTES, REFUSAL_SCAN_BYTES, ANSI_ESCAPE, FLY_REFUSAL, NEON_REFUSAL, NEON_KEY_KIND_LIMIT, COMMUNITY_SERVICE_TIMEOUT_MS, TERMINATION_GRACE_MS, ProviderCommandError;
134945
135238
  var init_provider_process = __esm({
134946
135239
  "src/commands/community-deploy/provider-process.ts"() {
134947
135240
  "use strict";
@@ -134950,6 +135243,7 @@ var init_provider_process = __esm({
134950
135243
  ANSI_ESCAPE = /\u001b\[[0-9;]*m/gu;
134951
135244
  FLY_REFUSAL = /^Error: (?:unauthorized|forbidden)(?: \(Request ID: [^)]*\))?(?: \(Trace ID: [^)]*\))?$/u;
134952
135245
  NEON_REFUSAL = /^ERROR: (?:not allowed to |[a-z-]+ keys are not allowed to |permission denied\b)/u;
135246
+ NEON_KEY_KIND_LIMIT = /^ERROR: not allowed for [a-z][a-z -]* API keys$/u;
134953
135247
  COMMUNITY_SERVICE_TIMEOUT_MS = 3e4;
134954
135248
  TERMINATION_GRACE_MS = 250;
134955
135249
  ProviderCommandError = class extends Error {
@@ -134960,17 +135254,24 @@ var init_provider_process = __esm({
134960
135254
  * ({@link isProviderAccessRefusal}). The output itself is never kept.
134961
135255
  */
134962
135256
  refused;
135257
+ /**
135258
+ * True only for an `EXIT` whose error output said the endpoint does not serve this kind of key
135259
+ * ({@link isProviderKeyKindLimit}). The output itself is never kept.
135260
+ */
135261
+ keyKindLimited;
134963
135262
  /**
134964
135263
  * Create a provider command error without raw stdout or stderr.
134965
135264
  *
134966
135265
  * @param code - Stable failure category.
134967
135266
  * @param refused - Whether the service definitely refused the credential.
135267
+ * @param keyKindLimited - Whether the endpoint does not serve this kind of key.
134968
135268
  */
134969
- constructor(code, refused = false) {
135269
+ constructor(code, refused = false, keyKindLimited = false) {
134970
135270
  super(`Provider command failed (${code})`);
134971
135271
  this.name = "ProviderCommandError";
134972
135272
  this.code = code;
134973
135273
  this.refused = code === "EXIT" && refused;
135274
+ this.keyKindLimited = code === "EXIT" && !refused && keyKindLimited;
134974
135275
  }
134975
135276
  };
134976
135277
  }
@@ -134979,7 +135280,7 @@ var init_provider_process = __esm({
134979
135280
  // src/commands/community-deploy/runtime/github-release-source.ts
134980
135281
  import { mkdtemp as mkdtemp2, rm as rm3, writeFile as writeFile5 } from "node:fs/promises";
134981
135282
  import { tmpdir as tmpdir2 } from "node:os";
134982
- import { join as join50 } from "node:path";
135283
+ import { join as join51 } from "node:path";
134983
135284
  function createGitHubCommunityReleaseSource(options) {
134984
135285
  const verify = async (subject, trusted) => {
134985
135286
  await runProviderCommand({
@@ -135025,8 +135326,8 @@ function createGitHubCommunityReleaseSource(options) {
135025
135326
  return result2.value;
135026
135327
  },
135027
135328
  verifyManifest: async (bytes, trusted) => {
135028
- const directory = await mkdtemp2(join50(tmpdir2(), "dorkos-community-manifest-"));
135029
- const path53 = join50(directory, "manifest.json");
135329
+ const directory = await mkdtemp2(join51(tmpdir2(), "dorkos-community-manifest-"));
135330
+ const path53 = join51(directory, "manifest.json");
135030
135331
  try {
135031
135332
  await writeFile5(path53, bytes, { mode: 384, flag: "wx" });
135032
135333
  return await verify(path53, trusted);
@@ -135134,6 +135435,12 @@ function buildCommunityPreflight(release, selection, inventory, resume = {}) {
135134
135435
  );
135135
135436
  if (!neonOrganization) throw new CommunityPreflightError("NEON_ORGANIZATION_NOT_FOUND");
135136
135437
  const neonRegion = inventory.neonRegions.find(({ id }) => id === selection.neonRegion);
135438
+ if (!neonRegion && inventory.neonRegionsFromSavedList) {
135439
+ throw new CommunityPreflightError(
135440
+ "NEON_REGION_UNAVAILABLE",
135441
+ `This Neon key can't read Neon's live list of regions, so setup checked ${selection.neonRegion} against a saved list, and it isn't there. Check the region name. If it's a new Neon region, use a personal key or sign in with neonctl auth, so setup can read the live list.`
135442
+ );
135443
+ }
135137
135444
  if (!neonRegion) throw new CommunityPreflightError("NEON_REGION_UNAVAILABLE");
135138
135445
  const matchingNeonProjects = inventory.neonProjects.filter(
135139
135446
  ({ name }) => name === selection.neonProjectName
@@ -135181,9 +135488,14 @@ var init_preflight = __esm({
135181
135488
  CommunityPreflightError = class extends Error {
135182
135489
  /** Safe failure classification. */
135183
135490
  code;
135184
- /** Create one secret-free preflight rejection. */
135185
- constructor(code) {
135186
- super(`Space server launch preflight failed (${code})`);
135491
+ /**
135492
+ * Create one secret-free preflight rejection.
135493
+ *
135494
+ * @param code - Safe failure classification.
135495
+ * @param message - Plain guidance for the person, when there is more to say than the code.
135496
+ */
135497
+ constructor(code, message2) {
135498
+ super(message2 ?? `Space server launch preflight failed (${code})`);
135187
135499
  this.name = "CommunityPreflightError";
135188
135500
  this.code = code;
135189
135501
  }
@@ -135494,17 +135806,27 @@ async function runProviderMutation(options) {
135494
135806
  throw new ProviderMutationError("CREATION_OUTCOME_UNCERTAIN");
135495
135807
  }
135496
135808
  }
135497
- var ProviderMutationError, PROVIDER_WRITE_TIMEOUT_MS;
135809
+ var PLAIN_MESSAGES, ProviderMutationError, PROVIDER_WRITE_TIMEOUT_MS;
135498
135810
  var init_provider_mutation = __esm({
135499
135811
  "src/commands/community-deploy/provider-mutation.ts"() {
135500
135812
  "use strict";
135501
135813
  init_provider_process();
135814
+ PLAIN_MESSAGES = {
135815
+ INVALID_INPUT: "Setup was given a value it cannot use, so it stopped before that change.",
135816
+ INVALID_RESPONSE: "Fly, Neon or Tigris answered in a way setup could not check, so setup stopped to stay safe.",
135817
+ PROVIDER_UNAVAILABLE: "Setup could not reach Fly, Neon or the image registry. Check your connection and that fly and neonctl are installed, then try again.",
135818
+ // The error does not know which credential acted, so it names every one it could be, the way
135819
+ // `describeCommunityCredential` does; the create path names the exact one (refused-create.ts).
135820
+ ACCESS_DENIED: "Fly or Neon refused the credential setup used: FLY_API_TOKEN, FLY_ACCESS_TOKEN or NEON_API_KEY if set, otherwise your saved sign-in. Use one that can create these resources.",
135821
+ // Also true for a command that ran to the end and failed, such as a deploy whose check failed.
135822
+ CREATION_OUTCOME_UNCERTAIN: "A Fly, Neon or Tigris step did not finish cleanly, so setup cannot be sure what it changed. Its progress is saved: run the resume command printed above (dorkos community deploy --list-incomplete finds the run)."
135823
+ };
135502
135824
  ProviderMutationError = class extends Error {
135503
135825
  /** Safe classification suitable for the launch journal. */
135504
135826
  code;
135505
135827
  /** Create a mutation error without provider output. */
135506
135828
  constructor(code) {
135507
- super(`Provider mutation failed (${code})`);
135829
+ super(PLAIN_MESSAGES[code]);
135508
135830
  this.name = "ProviderMutationError";
135509
135831
  this.code = code;
135510
135832
  }
@@ -136221,6 +136543,23 @@ async function readNeonRegions(options) {
136221
136543
  longitude: coordinate(region.geo_long)
136222
136544
  }));
136223
136545
  }
136546
+ async function readNeonRegionsForKey(options) {
136547
+ try {
136548
+ return { regions: await readNeonRegions(options), savedList: false };
136549
+ } catch (error63) {
136550
+ if (!(error63 instanceof ProviderCommandError) || !error63.keyKindLimited) throw error63;
136551
+ return {
136552
+ regions: NEON_REGIONS_SNAPSHOT.map((id) => ({
136553
+ id,
136554
+ name: id,
136555
+ isDefault: id === NEON_REGIONS_SNAPSHOT_DEFAULT,
136556
+ latitude: null,
136557
+ longitude: null
136558
+ })),
136559
+ savedList: true
136560
+ };
136561
+ }
136562
+ }
136224
136563
  async function readNeonProjects(options, organizationId) {
136225
136564
  const id = ExternalIdentifierSchema.parse(organizationId);
136226
136565
  const projects = await runNeonJson(
@@ -136379,7 +136718,7 @@ async function readNeonDirectConnection(options, projectId, branchId, databaseNa
136379
136718
  }
136380
136719
  })).value;
136381
136720
  }
136382
- var NeonOrganizationSchema, NeonCreatedAtSchema, NeonProjectSchema, NeonBranchSchema, NeonDatabaseIdSchema, NeonDatabaseSchema, NeonRoleSchema, NeonCoordinateSchema, NeonRegionSchema, NeonRegionsEnvelopeSchema, NeonEndpointSchema, NeonEndpointsEnvelopeSchema, NeonCredentialError, NeonConnectionCredential;
136721
+ var NeonOrganizationSchema, NeonCreatedAtSchema, NeonProjectSchema, NeonBranchSchema, NeonDatabaseIdSchema, NeonDatabaseSchema, NeonRoleSchema, NeonCoordinateSchema, NeonRegionSchema, NeonRegionsEnvelopeSchema, NeonEndpointSchema, NeonEndpointsEnvelopeSchema, NeonCredentialError, NeonConnectionCredential, NEON_REGIONS_SNAPSHOT, NEON_REGIONS_SNAPSHOT_DEFAULT;
136383
136722
  var init_neon_read = __esm({
136384
136723
  "src/commands/community-deploy/neon-read.ts"() {
136385
136724
  "use strict";
@@ -136471,6 +136810,20 @@ var init_neon_read = __esm({
136471
136810
  return "[REDACTED Neon connection credential]";
136472
136811
  }
136473
136812
  };
136813
+ NEON_REGIONS_SNAPSHOT = [
136814
+ "aws-us-east-1",
136815
+ "aws-us-east-2",
136816
+ "aws-us-west-2",
136817
+ "aws-eu-central-1",
136818
+ "aws-eu-west-2",
136819
+ "aws-ap-southeast-1",
136820
+ "aws-ap-southeast-2",
136821
+ "aws-sa-east-1",
136822
+ "azure-eastus2",
136823
+ "azure-westus3",
136824
+ "azure-gwc"
136825
+ ];
136826
+ NEON_REGIONS_SNAPSHOT_DEFAULT = "aws-us-east-1";
136474
136827
  }
136475
136828
  });
136476
136829
 
@@ -137114,16 +137467,44 @@ var init_credential_env = __esm({
137114
137467
  });
137115
137468
 
137116
137469
  // src/commands/community-deploy/runtime/versions.ts
137117
- function classifyCommunityProviderPreflightFailure(provider, error63, access3) {
137118
- if (error63 instanceof CommunityProviderPreflightError) throw error63;
137470
+ function describeCommunityProviderPreflightFailure(provider, error63, access3) {
137471
+ if (error63 instanceof CommunityProviderPreflightError) return error63;
137119
137472
  if (error63 instanceof ProviderCommandError) {
137120
137473
  if (error63.code === "SPAWN")
137121
- throw new CommunityProviderPreflightError(provider, "CLI_NOT_FOUND");
137474
+ return new CommunityProviderPreflightError(provider, "CLI_NOT_FOUND");
137122
137475
  if (error63.refused && access3) {
137123
- throw new CommunityProviderPreflightError(provider, "ACCESS_DENIED", access3);
137476
+ return new CommunityProviderPreflightError(provider, "ACCESS_DENIED", access3);
137477
+ }
137478
+ if (error63.keyKindLimited && access3 && provider === "neon") {
137479
+ return new CommunityProviderPreflightError(provider, "KEY_KIND_UNSUPPORTED", access3);
137124
137480
  }
137125
137481
  }
137126
- throw new CommunityProviderPreflightError(provider, "PROVIDER_UNAVAILABLE");
137482
+ return new CommunityProviderPreflightError(provider, "PROVIDER_UNAVAILABLE");
137483
+ }
137484
+ function classifyCommunityProviderPreflightFailure(provider, error63, access3) {
137485
+ throw describeCommunityProviderPreflightFailure(provider, error63, access3);
137486
+ }
137487
+ function failureRank(reason) {
137488
+ return reason instanceof CommunityProviderPreflightError ? PREFLIGHT_FAILURE_RANK[reason.code] : Object.keys(PREFLIGHT_FAILURE_RANK).length;
137489
+ }
137490
+ async function settleCommunityPreflightReads(reads) {
137491
+ const settled = await Promise.allSettled(reads);
137492
+ let chosen;
137493
+ for (const result2 of settled) {
137494
+ if (result2.status !== "rejected") continue;
137495
+ if (!chosen || failureRank(result2.reason) < failureRank(chosen.reason)) chosen = result2;
137496
+ }
137497
+ if (chosen) throw chosen.reason;
137498
+ return settled.map((result2) => result2.value);
137499
+ }
137500
+ function settleCommunityProviderPreflight(provider, reads, access3) {
137501
+ return settleCommunityPreflightReads(
137502
+ reads.map(
137503
+ (read) => Promise.resolve(read).catch(
137504
+ (error63) => classifyCommunityProviderPreflightFailure(provider, error63, access3)
137505
+ )
137506
+ )
137507
+ );
137127
137508
  }
137128
137509
  function compare(left, right) {
137129
137510
  const tuple2 = (value) => VersionSchema.parse(value).split("-", 1)[0].split(".").map(Number);
@@ -137135,24 +137516,28 @@ function compare(left, right) {
137135
137516
  return 0;
137136
137517
  }
137137
137518
  async function assertCommunityCliVersions(fly, neon, minimums) {
137138
- const [flyVersion, neonVersion] = await Promise.all([
137139
- runProviderCommand({
137140
- ...fly,
137141
- args: ["version", "--json"],
137142
- parse: (stdout3) => FlyVersionSchema.parse(JSON.parse(stdout3)).Version
137143
- }).catch((error63) => classifyCommunityProviderPreflightFailure("fly", error63)),
137144
- runProviderCommand({
137145
- ...neon,
137146
- args: ["--version"],
137147
- parse: (stdout3) => VersionSchema.parse(stdout3.trim())
137148
- }).catch((error63) => classifyCommunityProviderPreflightFailure("neon", error63))
137519
+ const [flyVersion, neonVersion] = await settleCommunityPreflightReads([
137520
+ settleCommunityProviderPreflight("fly", [
137521
+ runProviderCommand({
137522
+ ...fly,
137523
+ args: ["version", "--json"],
137524
+ parse: (stdout3) => FlyVersionSchema.parse(JSON.parse(stdout3)).Version
137525
+ })
137526
+ ]).then(([version4]) => version4),
137527
+ settleCommunityProviderPreflight("neon", [
137528
+ runProviderCommand({
137529
+ ...neon,
137530
+ args: ["--version"],
137531
+ parse: (stdout3) => VersionSchema.parse(stdout3.trim())
137532
+ })
137533
+ ]).then(([version4]) => version4)
137149
137534
  ]);
137150
137535
  if (compare(flyVersion.value, minimums.fly) < 0) throw new CommunityCliVersionError("fly");
137151
137536
  if (compare(neonVersion.value, minimums.neon) < 0) {
137152
137537
  throw new CommunityCliVersionError("neonctl");
137153
137538
  }
137154
137539
  }
137155
- var VersionSchema, FlyVersionSchema, PROVIDER_HELP, CommunityProviderPreflightError, CommunityCliVersionError;
137540
+ var VersionSchema, FlyVersionSchema, PROVIDER_HELP, CommunityProviderPreflightError, PREFLIGHT_FAILURE_RANK, CommunityCliVersionError;
137156
137541
  var init_versions2 = __esm({
137157
137542
  "src/commands/community-deploy/runtime/versions.ts"() {
137158
137543
  "use strict";
@@ -137183,11 +137568,16 @@ var init_versions2 = __esm({
137183
137568
  *
137184
137569
  * @param provider - The service whose read failed.
137185
137570
  * @param code - What kind of failure it was.
137186
- * @param access - For `ACCESS_DENIED`: the credential and organization to name.
137571
+ * @param access - For `ACCESS_DENIED` and `KEY_KIND_UNSUPPORTED`: the credential (and
137572
+ * organization) to name. Without it either is worded, and coded, as unavailable.
137187
137573
  */
137188
137574
  constructor(provider, code, access3) {
137189
137575
  const help = PROVIDER_HELP[provider];
137190
- const message2 = code === "CLI_NOT_FOUND" ? `${provider === "fly" ? "Fly CLI" : "Neon CLI"} is required. Install it from ${help.install}` : code === "AUTH_REQUIRED" ? `${provider === "fly" ? "Fly" : "Neon"} sign-in is required. Run ${help.command}, then retry. ${help.auth}` : code === "ACCESS_DENIED" && access3 ? provider === "fly" ? (
137576
+ const message2 = code === "CLI_NOT_FOUND" ? `${provider === "fly" ? "Fly CLI" : "Neon CLI"} is required. Install it from ${help.install}` : code === "KEY_KIND_UNSUPPORTED" && access3 ? (
137577
+ // Only Neon answers this way (`isProviderKeyKindLimit`). It names the key's kind, not
137578
+ // the organization, so the message names the kinds that work instead.
137579
+ `Neon turned down one of the reads setup needs because of the kind of key ${access3.env.NEON_API_KEY ? "in NEON_API_KEY" : "your Neon sign-in uses"}. Setup works with an organization key, a personal key, or a ${help.command} sign-in. ${help.auth}`
137580
+ ) : code === "ACCESS_DENIED" && access3 ? provider === "fly" ? (
137191
137581
  // Fly answers `unauthorized` both for a token without access and for one that has
137192
137582
  // expired or was revoked, so the message names both.
137193
137583
  `${describeCommunityCredential("fly", access3.env)} can't read organization ${access3.organization}. It may have expired, or it may not have access there. Setup needs a token or sign-in that can create apps in it.`
@@ -137195,9 +137585,15 @@ var init_versions2 = __esm({
137195
137585
  super(message2);
137196
137586
  this.name = "CommunityProviderPreflightError";
137197
137587
  this.provider = provider;
137198
- this.code = code === "ACCESS_DENIED" && !access3 ? "PROVIDER_UNAVAILABLE" : code;
137588
+ this.code = (code === "ACCESS_DENIED" || code === "KEY_KIND_UNSUPPORTED") && !access3 ? "PROVIDER_UNAVAILABLE" : code;
137199
137589
  }
137200
137590
  };
137591
+ PREFLIGHT_FAILURE_RANK = {
137592
+ CLI_NOT_FOUND: 0,
137593
+ ACCESS_DENIED: 1,
137594
+ KEY_KIND_UNSUPPORTED: 2,
137595
+ PROVIDER_UNAVAILABLE: 3
137596
+ };
137201
137597
  CommunityCliVersionError = class extends Error {
137202
137598
  /** CLI whose installed version is below the signed release minimum. */
137203
137599
  cli;
@@ -137216,31 +137612,37 @@ var init_versions2 = __esm({
137216
137612
 
137217
137613
  // src/commands/community-deploy/runtime/default-services.ts
137218
137614
  async function readDefaultCommunityPreflight(options, selection) {
137219
- const [flyInventory, neonInventory] = await Promise.all([
137220
- Promise.all([
137221
- readFlyOrganizations(options.fly),
137222
- readFlyRegions(options.fly),
137223
- readFlyApps(options.fly, selection.flyOrganization)
137224
- ]).catch(
137225
- (error63) => classifyCommunityProviderPreflightFailure("fly", error63, {
137226
- env: options.fly.env,
137227
- organization: selection.flyOrganization
137228
- })
137615
+ const [flyInventory, neonInventory] = await settleCommunityPreflightReads([
137616
+ settleCommunityProviderPreflight(
137617
+ "fly",
137618
+ [
137619
+ readFlyOrganizations(options.fly),
137620
+ readFlyRegions(options.fly),
137621
+ readFlyApps(options.fly, selection.flyOrganization)
137622
+ ],
137623
+ { env: options.fly.env, organization: selection.flyOrganization }
137229
137624
  ),
137230
- Promise.all([
137231
- readNeonOrganizations(options.neon),
137232
- readNeonRegions(options.neon),
137233
- readNeonProjects(options.neon, selection.neonOrganization)
137234
- ]).catch(
137235
- (error63) => classifyCommunityProviderPreflightFailure("neon", error63, {
137236
- env: options.neon.env,
137237
- organization: selection.neonOrganization
137238
- })
137625
+ settleCommunityProviderPreflight(
137626
+ "neon",
137627
+ [
137628
+ readNeonOrganizations(options.neon),
137629
+ readNeonRegionsForKey(options.neon),
137630
+ readNeonProjects(options.neon, selection.neonOrganization)
137631
+ ],
137632
+ { env: options.neon.env, organization: selection.neonOrganization }
137239
137633
  )
137240
137634
  ]);
137241
137635
  const [flyOrganizations, flyRegions, flyApps] = flyInventory;
137242
- const [neonOrganizations, neonRegions, neonProjects] = neonInventory;
137243
- return { flyOrganizations, flyRegions, flyApps, neonOrganizations, neonRegions, neonProjects };
137636
+ const [neonOrganizations, { regions: neonRegions, savedList }, neonProjects] = neonInventory;
137637
+ return {
137638
+ flyOrganizations,
137639
+ flyRegions,
137640
+ flyApps,
137641
+ neonOrganizations,
137642
+ neonRegions,
137643
+ ...savedList ? { neonRegionsFromSavedList: true } : {},
137644
+ neonProjects
137645
+ };
137244
137646
  }
137245
137647
  async function exactFlyApp(options, organizationSlug, appId, appName) {
137246
137648
  const matches = (await readFlyApps(options.fly, organizationSlug)).filter(
@@ -137547,7 +137949,7 @@ var init_default_services = __esm({
137547
137949
  // src/commands/community-deploy/fly-config.ts
137548
137950
  import { mkdtemp as mkdtemp3, rm as rm4, writeFile as writeFile6 } from "node:fs/promises";
137549
137951
  import { tmpdir as tmpdir3 } from "node:os";
137550
- import { join as join51 } from "node:path";
137952
+ import { join as join52 } from "node:path";
137551
137953
  function tomlString(value) {
137552
137954
  return JSON.stringify(value);
137553
137955
  }
@@ -137600,8 +138002,8 @@ kill_timeout = "30s"
137600
138002
  `;
137601
138003
  }
137602
138004
  async function withCommunityFlyConfig(plan, consumer) {
137603
- const directory = await mkdtemp3(join51(tmpdir3(), "dorkos-community-fly-"));
137604
- const path53 = join51(directory, "fly.toml");
138005
+ const directory = await mkdtemp3(join52(tmpdir3(), "dorkos-community-fly-"));
138006
+ const path53 = join52(directory, "fly.toml");
137605
138007
  try {
137606
138008
  await writeFile6(path53, renderCommunityFlyConfig(plan), { mode: 384, flag: "wx" });
137607
138009
  return await consumer(path53);
@@ -137810,6 +138212,135 @@ var init_image_platform = __esm({
137810
138212
  }
137811
138213
  });
137812
138214
 
138215
+ // src/commands/community-deploy/runtime/fly-lease.ts
138216
+ async function readFlyMachineLease(options, appName, machineId) {
138217
+ const app = ExternalIdentifierSchema.parse(appName);
138218
+ const machine = ExternalIdentifierSchema.parse(machineId);
138219
+ return (await runProviderCommand({
138220
+ ...options,
138221
+ args: ["machine", "leases", "view", machine, "--app", app, "--json"],
138222
+ parse: (stdout3) => {
138223
+ const lease = FlyLeaseViewSchema.parse(parseExternalJson(stdout3))[machine];
138224
+ if (!lease) return null;
138225
+ const expiresAt = lease.data?.expires_at;
138226
+ return { expiresAtMs: expiresAt === void 0 ? null : expiresAt * 1e3 };
138227
+ }
138228
+ })).value;
138229
+ }
138230
+ function minutesText(minutes) {
138231
+ return minutes <= 1 ? "1 minute" : `${minutes} minutes`;
138232
+ }
138233
+ function minutesUntil(endMs, nowMs) {
138234
+ return Math.max(1, Math.ceil((endMs - nowMs) / 6e4));
138235
+ }
138236
+ async function waitForFlyMachineLeases(options) {
138237
+ const limitMs = options.limitMs ?? FLY_LEASE_WAIT_LIMIT_MS;
138238
+ const started = options.now();
138239
+ const deadline = started + limitMs;
138240
+ let lastProgress = null;
138241
+ for (; ; ) {
138242
+ const ends = await latestLeaseEnd(options);
138243
+ if (ends === void 0) {
138244
+ if (lastProgress !== null) options.progress("Fly has let go of the Machine. Deploying now\u2026");
138245
+ return;
138246
+ }
138247
+ const now2 = options.now();
138248
+ if (lastProgress === null && ends !== null && ends > deadline) {
138249
+ throw new FlyMachineBusyError(options.appName, minutesUntil(ends, now2));
138250
+ }
138251
+ if (now2 >= deadline) throw new FlyMachineBusyError(options.appName, null);
138252
+ if (lastProgress === null) {
138253
+ options.progress(
138254
+ `Fly is still holding the Machine of ${options.appName} for another deploy. ` + (ends === null ? "Waiting for Fly to let go of it\u2026" : `Waiting up to about ${minutesText(minutesUntil(ends, now2))} for Fly to let go of it\u2026`)
138255
+ );
138256
+ lastProgress = now2;
138257
+ } else if (now2 - lastProgress >= PROGRESS_EVERY_MS) {
138258
+ options.progress("Still waiting for Fly to let go of the Machine\u2026");
138259
+ lastProgress = now2;
138260
+ }
138261
+ const untilEnd = ends === null ? FLY_LEASE_POLL_MS : ends - now2 + 2e3;
138262
+ await options.sleep(
138263
+ Math.min(deadline - now2, Math.max(1e3, Math.min(untilEnd, FLY_LEASE_POLL_MS)))
138264
+ );
138265
+ }
138266
+ }
138267
+ async function latestLeaseEnd(options) {
138268
+ let latest;
138269
+ for (const machineId of options.machineIds) {
138270
+ let lease;
138271
+ try {
138272
+ lease = await options.readLease(machineId);
138273
+ } catch (error63) {
138274
+ if (error63 instanceof ProviderCommandError && error63.code === "CANCELLED") throw error63;
138275
+ continue;
138276
+ }
138277
+ if (!lease) continue;
138278
+ if (lease.expiresAtMs !== null && lease.expiresAtMs <= options.now()) continue;
138279
+ if (lease.expiresAtMs === null || latest === null) latest = null;
138280
+ else latest = latest === void 0 ? lease.expiresAtMs : Math.max(latest, lease.expiresAtMs);
138281
+ }
138282
+ return latest;
138283
+ }
138284
+ async function heldLeaseMinutes(options) {
138285
+ const ends = await latestLeaseEnd({
138286
+ ...options,
138287
+ appName: "",
138288
+ progress: () => void 0,
138289
+ sleep: async () => void 0
138290
+ }).catch(() => void 0);
138291
+ if (ends === void 0) return false;
138292
+ return ends === null ? null : minutesUntil(ends, options.now());
138293
+ }
138294
+ function cancellableSleep(ms, signal) {
138295
+ return new Promise((resolve11, reject) => {
138296
+ if (signal?.aborted) {
138297
+ reject(new ProviderCommandError("CANCELLED"));
138298
+ return;
138299
+ }
138300
+ const onAbort = () => {
138301
+ clearTimeout(timer);
138302
+ reject(new ProviderCommandError("CANCELLED"));
138303
+ };
138304
+ const timer = setTimeout(() => {
138305
+ signal?.removeEventListener("abort", onAbort);
138306
+ resolve11();
138307
+ }, ms);
138308
+ signal?.addEventListener("abort", onAbort, { once: true });
138309
+ });
138310
+ }
138311
+ var FLY_LEASE_WAIT_LIMIT_MS, FLY_LEASE_POLL_MS, PROGRESS_EVERY_MS, FlyLeaseViewSchema, FlyMachineBusyError;
138312
+ var init_fly_lease = __esm({
138313
+ "src/commands/community-deploy/runtime/fly-lease.ts"() {
138314
+ "use strict";
138315
+ init_zod();
138316
+ init_provider_contract();
138317
+ init_provider_process();
138318
+ init_provider_mutation();
138319
+ FLY_LEASE_WAIT_LIMIT_MS = 6 * 6e4;
138320
+ FLY_LEASE_POLL_MS = 15e3;
138321
+ PROGRESS_EVERY_MS = 6e4;
138322
+ FlyLeaseViewSchema = external_exports.record(
138323
+ ExternalIdentifierSchema,
138324
+ external_exports.object({
138325
+ data: external_exports.object({ expires_at: external_exports.number().int().nonnegative().optional() }).passthrough().nullish()
138326
+ }).passthrough().nullable()
138327
+ );
138328
+ FlyMachineBusyError = class extends ProviderMutationError {
138329
+ /**
138330
+ * Create the refusal for one app.
138331
+ *
138332
+ * @param appName - The Fly app setup created.
138333
+ * @param minutes - Roughly how long until Fly lets go, when known.
138334
+ */
138335
+ constructor(appName, minutes) {
138336
+ super("PROVIDER_UNAVAILABLE");
138337
+ this.name = "FlyMachineBusyError";
138338
+ this.message = `Fly is still holding the Machine of ${appName} for another deploy, so setup did not deploy over it. ` + (minutes === null ? "Wait a few minutes, then run the resume command above again." : `Wait about ${minutesText(minutes)}, then run the resume command above again.`);
138339
+ }
138340
+ };
138341
+ }
138342
+ });
138343
+
137813
138344
  // src/commands/community-deploy/runtime/default-deploy.ts
137814
138345
  async function resolveCommunityPlatformDigest(input4) {
137815
138346
  if (input4.release && input4.release.image.digest !== input4.plan.imageDigest) {
@@ -137828,6 +138359,13 @@ async function resolveCommunityPlatformDigest(input4) {
137828
138359
  });
137829
138360
  }
137830
138361
  function createDefaultCommunityDeployDependencies(input4) {
138362
+ const readLease = (machineId) => readFlyMachineLease(input4.options.fly, input4.plan.fly.appName, machineId);
138363
+ const progress = input4.progress ?? ((line2) => void process.stdout.write(`${line2}
138364
+ `));
138365
+ const clock = input4.leaseClock ?? {
138366
+ now: Date.now,
138367
+ sleep: (ms) => cancellableSleep(ms, input4.options.fly.signal)
138368
+ };
137831
138369
  return {
137832
138370
  persist: input4.persist,
137833
138371
  now: input4.now,
@@ -137866,6 +138404,19 @@ function createDefaultCommunityDeployDependencies(input4) {
137866
138404
  configPath
137867
138405
  );
137868
138406
  }),
138407
+ waitForMachineLeases: (machineIds) => waitForFlyMachineLeases({
138408
+ appName: input4.plan.fly.appName,
138409
+ machineIds,
138410
+ readLease,
138411
+ progress,
138412
+ now: clock.now,
138413
+ sleep: clock.sleep
138414
+ }),
138415
+ explainDeployFailure: async (error63, machineIds) => {
138416
+ if (machineIds.length === 0) return error63;
138417
+ const minutes = await heldLeaseMinutes({ machineIds, readLease, now: clock.now });
138418
+ return minutes === false ? error63 : new FlyMachineBusyError(input4.plan.fly.appName, minutes);
138419
+ },
137869
138420
  resolvePlatformDigest: input4.resolvePlatformDigest,
137870
138421
  verifyNewRuntime: (inventory, previous, platformDigest) => verifyFlyDeployment(inventory, previous, COMMUNITY_IMAGE_REPOSITORY, platformDigest),
137871
138422
  verifyExistingRuntime: (inventory, platformDigest) => verifyExistingFlyDeployment(inventory, COMMUNITY_IMAGE_REPOSITORY, platformDigest),
@@ -137888,6 +138439,7 @@ var init_default_deploy = __esm({
137888
138439
  init_health();
137889
138440
  init_provider_mutation();
137890
138441
  init_image_platform();
138442
+ init_fly_lease();
137891
138443
  COMMUNITY_IMAGE_REPOSITORY = "ghcr.io/dork-labs/dorkos-community";
137892
138444
  }
137893
138445
  });
@@ -137895,7 +138447,7 @@ var init_default_deploy = __esm({
137895
138447
  // src/commands/community-deploy/runtime/default-owner.ts
137896
138448
  import { access as access2, constants as constants5, stat as stat3 } from "node:fs/promises";
137897
138449
  import { platform as platform2 } from "node:os";
137898
- import { delimiter, join as join52 } from "node:path";
138450
+ import { delimiter, join as join53 } from "node:path";
137899
138451
  import { createInterface as createInterface4 } from "node:readline/promises";
137900
138452
  import { stdin as stdin2, stdout as stdout2 } from "node:process";
137901
138453
  async function ask(question, signal) {
@@ -137928,7 +138480,7 @@ function handoffCommands(system) {
137928
138480
  async function executableOnPath(executable, path53) {
137929
138481
  for (const directory of path53.split(delimiter).filter(Boolean)) {
137930
138482
  try {
137931
- await access2(join52(directory, executable), constants5.X_OK);
138483
+ await access2(join53(directory, executable), constants5.X_OK);
137932
138484
  return true;
137933
138485
  } catch {
137934
138486
  }
@@ -137962,7 +138514,7 @@ async function assertOwnerHandoffPrerequisites(env5, system = platform2()) {
137962
138514
  "Owner handoff needs an active Wayland clipboard session before setup can create resources. See https://github.com/dork-labs/dorkos/blob/main/apps/community/FLY.md"
137963
138515
  );
137964
138516
  }
137965
- const socketAvailable = await stat3(join52(runtimeDirectory, display)).then(
138517
+ const socketAvailable = await stat3(join53(runtimeDirectory, display)).then(
137966
138518
  (value) => value.isSocket(),
137967
138519
  () => false
137968
138520
  );
@@ -138145,10 +138697,10 @@ import {
138145
138697
  rm as rm5,
138146
138698
  unlink
138147
138699
  } from "node:fs/promises";
138148
- import { basename as basename8, dirname as dirname13, join as join53 } from "node:path";
138700
+ import { basename as basename8, dirname as dirname13, join as join54 } from "node:path";
138149
138701
  function launchJournalPath(dorkHome, runId) {
138150
138702
  const safeRunId = external_exports.uuid().parse(runId);
138151
- return join53(dorkHome, "launches", "community", `${safeRunId}.json`);
138703
+ return join54(dorkHome, "launches", "community", `${safeRunId}.json`);
138152
138704
  }
138153
138705
  async function rejectSymlink(path53) {
138154
138706
  try {
@@ -138185,7 +138737,7 @@ async function exists2(path53) {
138185
138737
  }
138186
138738
  async function writeDurably(filePath, data) {
138187
138739
  const directory = dirname13(filePath);
138188
- const temporary = join53(
138740
+ const temporary = join54(
138189
138741
  directory,
138190
138742
  `.${basename8(filePath)}.${process.pid}.${randomUUID5()}.durable`
138191
138743
  );
@@ -138282,7 +138834,7 @@ async function readLaunchJournal(filePath) {
138282
138834
  }
138283
138835
  }
138284
138836
  async function listIncompleteLaunchJournals(dorkHome) {
138285
- const directory = join53(dorkHome, "launches", "community");
138837
+ const directory = join54(dorkHome, "launches", "community");
138286
138838
  await rejectSymlink(dirname13(directory));
138287
138839
  await rejectSymlink(directory);
138288
138840
  let filenames;
@@ -138903,8 +139455,15 @@ async function executeCommunityDeployPhase(plan, journal, dependencies) {
138903
139455
  const deployedRows = runtimeSecretRows(existingSecrets);
138904
139456
  const settled = platformDigest;
138905
139457
  const deployAndVerify = async () => {
138906
- const previous = (await dependencies.readRuntime()).releases;
138907
- await dependencies.deploy(`${plan.imageDigest}`);
139458
+ const before = await dependencies.readRuntime();
139459
+ const previous = before.releases;
139460
+ const machineIds = before.machines.map((machine2) => machine2.id);
139461
+ await dependencies.waitForMachineLeases(machineIds);
139462
+ try {
139463
+ await dependencies.deploy(`${plan.imageDigest}`);
139464
+ } catch (error63) {
139465
+ throw await dependencies.explainDeployFailure(error63, machineIds);
139466
+ }
138908
139467
  const afterSecrets = exactSecretDigests(await dependencies.readSecrets(), "Deployed");
138909
139468
  if (!sameDigests(afterSecrets, expectedDigests)) {
138910
139469
  throw new ProviderMutationError("INVALID_RESPONSE");
@@ -140172,6 +140731,61 @@ var init_removal_command = __esm({
140172
140731
  }
140173
140732
  });
140174
140733
 
140734
+ // src/commands/community-deploy/runtime/stop-record.ts
140735
+ function stopExitCode(signal) {
140736
+ return signal === "SIGTERM" ? 143 : 130;
140737
+ }
140738
+ function describeStoppedLaunch(journal) {
140739
+ if (journal.lastSafeError?.code === "CANCELLED") {
140740
+ return "Setup was stopped. What it made so far is kept: run the resume command above to carry on.";
140741
+ }
140742
+ const unsure = "Setup was stopped while a change was still in progress, so it cannot tell yet whether that change happened.";
140743
+ return journal.pendingIntent ? `${unsure} Follow the steps above before you resume.` : `${unsure} Check the resources listed above, then run the resume command above.`;
140744
+ }
140745
+ function categoryFor(code) {
140746
+ switch (code) {
140747
+ case "AUTH_REQUIRED":
140748
+ return "authentication";
140749
+ case "ACCESS_DENIED":
140750
+ case "TERMS_NOT_ACCEPTED":
140751
+ return "authorization";
140752
+ case "BILLING_BLOCKED":
140753
+ return "billing";
140754
+ case "QUOTA_EXCEEDED":
140755
+ return "capacity";
140756
+ case "NAME_CONFLICT":
140757
+ return "conflict";
140758
+ case "INVALID_RESPONSE":
140759
+ case "INVALID_INPUT":
140760
+ case "MISSING_TIGRIS_SECRETS":
140761
+ return "invalid-response";
140762
+ case "CREATION_OUTCOME_UNCERTAIN":
140763
+ case "REMOVAL_OUTCOME_UNCERTAIN":
140764
+ return "uncertain";
140765
+ default:
140766
+ return "transient";
140767
+ }
140768
+ }
140769
+ function recordLaunchFailure(journal, error63, now2) {
140770
+ if (journal.pendingRemoval || journal.state === "complete") return null;
140771
+ if (journal.lastSafeError !== null && journal.lastSafeError.code !== "CANCELLED") return null;
140772
+ const raw = error63 && typeof error63 === "object" && "code" in error63 && typeof error63.code === "string" ? error63.code : null;
140773
+ const code = LaunchSafeErrorCodeSchema.safeParse(raw);
140774
+ if (!code.success || code.data === "CANCELLED") return null;
140775
+ return {
140776
+ ...journal,
140777
+ revision: journal.revision + 1,
140778
+ lastSafeError: { category: categoryFor(code.data), code: code.data },
140779
+ updatedAt: now2
140780
+ };
140781
+ }
140782
+ var init_stop_record = __esm({
140783
+ "src/commands/community-deploy/runtime/stop-record.ts"() {
140784
+ "use strict";
140785
+ init_journal();
140786
+ }
140787
+ });
140788
+
140175
140789
  // src/commands/community-deploy/community-dispatcher.ts
140176
140790
  var community_dispatcher_exports = {};
140177
140791
  __export(community_dispatcher_exports, {
@@ -140221,9 +140835,10 @@ function formatCommunityRecovery(journal) {
140221
140835
  journal.resources.neonProjectId ? selection ? ` Neon project ${journal.resources.neonProjectId} \u2014 owner ${selection.neonOrganization}; may incur charges; database data may exist.
140222
140836
  Inspect: neonctl projects get ${journal.resources.neonProjectId} --output json
140223
140837
  Console: https://console.neon.tech` : ` Neon project ${journal.resources.neonProjectId} \u2014 saved owner unavailable; may incur charges; database data may exist.` : null,
140224
- journal.resources.tigrisBucketId ? selection ? ` Tigris bucket ${journal.resources.tigrisBucketId} \u2014 owner ${selection.flyOrganization}; may incur charges; private files may exist.
140838
+ journal.resources.tigrisBucketId ? selection ? ` Tigris bucket ${selection.bucketName} \u2014 owner ${selection.flyOrganization}; may incur charges; private files may exist.
140225
140839
  Inspect: fly storage status ${selection.bucketName} --app ${selection.appName}
140226
- Console: https://fly.io/apps/${selection.appName}` : ` Tigris bucket ${journal.resources.tigrisBucketId} \u2014 saved owner unavailable; may incur charges; private files may exist.` : null
140840
+ Console: https://fly.io/apps/${selection.appName}
140841
+ Access key: usually ${tigrisAccessKeyName(selection.bucketName)} in Tigris. Removing the bucket does not remove this key; it keeps working until you remove it in Tigris.` : ` Tigris bucket ${journal.resources.tigrisBucketId} \u2014 saved owner unavailable; may incur charges; private files may exist.` : null
140227
140842
  ].filter((row2) => row2 !== null);
140228
140843
  const pending = journal.pendingIntent;
140229
140844
  const tigrisKeysMissing = pending?.provider === "tigris" && journal.resources.tigrisBucketId !== void 0 && journal.lastSafeError?.code === "MISSING_TIGRIS_SECRETS";
@@ -140393,9 +141008,15 @@ ${formatCommunityRecovery(latest)}
140393
141008
  const childEnv = context2.processEnv;
140394
141009
  const localEnv = withoutCommunityCredentialEnv(childEnv);
140395
141010
  const cancellation = new AbortController();
140396
- const cancel = () => cancellation.abort();
140397
- process.once("SIGINT", cancel);
140398
- process.once("SIGTERM", cancel);
141011
+ let stopSignal = "SIGINT";
141012
+ const cancelOn = (signal) => () => {
141013
+ if (!cancellation.signal.aborted) stopSignal = signal;
141014
+ cancellation.abort();
141015
+ };
141016
+ const onSigint = cancelOn("SIGINT");
141017
+ const onSigterm = cancelOn("SIGTERM");
141018
+ process.once("SIGINT", onSigint);
141019
+ process.once("SIGTERM", onSigterm);
140399
141020
  const serviceOptions = {
140400
141021
  fly: {
140401
141022
  executable: "fly",
@@ -140568,6 +141189,12 @@ ${formatCommunityRecovery(latest)}
140568
141189
  await writeLaunchJournal(journalPath, cancelled, latest.revision).catch(() => void 0);
140569
141190
  latest = cancelled;
140570
141191
  }
141192
+ const failed = latest && !cancellation.signal.aborted && !(error63 instanceof CommunityCreationRefusedError) ? recordLaunchFailure(latest, error63, (/* @__PURE__ */ new Date()).toISOString()) : null;
141193
+ if (latest && failed) {
141194
+ const previous = latest;
141195
+ await writeLaunchJournal(journalPath, failed, previous.revision).catch(() => void 0);
141196
+ latest = failed;
141197
+ }
140571
141198
  if (error63 instanceof CommunityCreationRefusedError && latest) {
140572
141199
  await stopForRefusedCreate(error63, latest, journalPath, childEnv, formatCommunityRecovery);
140573
141200
  }
@@ -140575,11 +141202,16 @@ ${formatCommunityRecovery(latest)}
140575
141202
  process.stderr.write(`Space setup stopped.
140576
141203
  ${formatCommunityRecovery(latest)}
140577
141204
  `);
141205
+ if (cancellation.signal.aborted && !latest.pendingRemoval) {
141206
+ process.stderr.write(`${describeStoppedLaunch(latest)}
141207
+ `);
141208
+ return stopExitCode(stopSignal);
141209
+ }
140578
141210
  }
140579
141211
  throw error63;
140580
141212
  } finally {
140581
- process.removeListener("SIGINT", cancel);
140582
- process.removeListener("SIGTERM", cancel);
141213
+ process.removeListener("SIGINT", onSigint);
141214
+ process.removeListener("SIGTERM", onSigterm);
140583
141215
  }
140584
141216
  }
140585
141217
  var COMMUNITY_DEPLOY_HELP;
@@ -140602,6 +141234,8 @@ var init_community_dispatcher = __esm({
140602
141234
  init_journal();
140603
141235
  init_resume();
140604
141236
  init_removal_command();
141237
+ init_tigris_access_key();
141238
+ init_stop_record();
140605
141239
  init_provider_process();
140606
141240
  COMMUNITY_DEPLOY_HELP = `
140607
141241
  Usage: dorkos community deploy [options]
@@ -142134,7 +142768,6 @@ var init_connector_authentication_setup = __esm({
142134
142768
  var CONNECTOR_OPERATION_SELECTION_LIMIT, CONNECTOR_AUTHENTICATION_FLOW_TTL_MS, CONNECTOR_EVENT_REVIEW_SCOPE_LIMIT, ConnectorJsonValueSchema, ConnectorJsonObjectSchema, ConnectorProviderInstanceIdSchema, ConnectionIdSchema, ConnectorExternalAccountRefSchema, ConnectorProviderModeSchema, ConnectorProviderHealthSchema, ConnectorGrantReconciliationStatusSchema, ConnectorOperationClassificationSchema, ConnectorAccessLevelSchema, ConnectorRetryPolicySchema, ConnectorOperationRevisionSchema, ConnectorOperationPageSchema, ConnectorCapabilityAvailabilitySchema, ConnectorUnsupportedResultSchema, ConnectorProviderCapabilitySetSchema, ConnectorToolkitVersionResultSchema, ConnectorProviderExecuteResultSchema, ConnectorAuthenticationFlowSchema, ConnectorExecutionTargetSchema, ConnectorProgramExecutionRequestSchema, ConnectorExecutionPublicResultSchema, ConnectorExecutionResponseSchema, ConnectionReadinessStateSchema, ConnectionReadinessReasonSchema, ConnectionFixActionSchema, ConnectionFixSchema, ConnectionReadinessSchema, READINESS_ASK_ON_CONNECTIONS, CONNECTION_GONE_AGENT_COPY, CONNECTION_READINESS_COPY, AccessibleConnectorConnectionSchema, AccessibleConnectorOperationSchema, ConnectorAccessibleConnectionsResponseSchema, ConnectorAccessibleOperationsResponseSchema, ConnectorUsageItemSchema, ConnectorUsagePageSchema, ConnectorReconciliationPreviewRequestSchema, ConnectorReconciliationGrantSelectionSchema, ConnectorReconciliationEveryAgentSelectionSchema, ConnectorReconciliationEveryAgentStateSchema, ConnectorEveryAgentRevokeResponseSchema, ConnectorReconciliationAgentSchema, ConnectorReconciliationCandidateSchema, ConnectorReconciliationPreviewSchema, ConnectorReconciliationApplyRequestSchema, ConnectorReconciliationApplyResponseSchema, ReviewActionBaseSchema, ConnectionTargetSchema, ConnectorRequestAccessSchema, ConnectorReviewActionSchema, ConnectorAgentConnectionRequestInputSchema, ConnectorAgentRequestBaseSchema, ConnectorRequestNotGrantedSchema, ConnectorAgentRequestStatusSchema, ConnectorAgentRequestItemSchema, ConnectorAgentRequestListResponseSchema, ConnectorManagementConnectActionSchema, ConnectorManagementAppliedActionSchema, ConnectorManagementReviewActionSchema, ConnectorManagementReviewCreateRequestSchema, ConnectorManagementReviewOutcomeSchema, ConnectorManagementReviewOperationContextSchema, ConnectorManagementReviewConnectionContextSchema, ConnectorManagementReviewAgentContextSchema, ConnectorManagementReviewContextSchema, ManagementReviewItemBaseShape, ConnectorPendingManagementReviewItemSchema, ConnectorResolvingManagementReviewItemSchema, ConnectorExpiredManagementReviewItemSchema, ConnectorDeniedManagementReviewItemSchema, ConnectorApprovedAppliedManagementReviewItemSchema, ConnectorApprovedConnectManagementReviewItemSchema, ConnectorApprovedUnknownManagementReviewItemSchema, ConnectorManagementReviewItemSchema, ProgramReviewStatusBaseShape, ConnectorProgramReviewStatusSchema, ConnectorManagementReviewDecisionSchema, ConnectorManagementReviewDecisionResultSchema;
142135
142769
  var init_connector_schemas = __esm({
142136
142770
  "../shared/src/connector-schemas.ts"() {
142137
- "use strict";
142138
142771
  init_zod();
142139
142772
  CONNECTOR_OPERATION_SELECTION_LIMIT = 1e5;
142140
142773
  CONNECTOR_AUTHENTICATION_FLOW_TTL_MS = 15 * 60 * 1e3;
@@ -144771,7 +145404,7 @@ var init_connector_managed_discovery_schemas = __esm({
144771
145404
  retryPolicy: ConnectorRetryPolicySchema,
144772
145405
  inputSchema: ConnectorJsonObjectSchema,
144773
145406
  // Presentation hints only, mirroring ConnectorOperationPageSchema's own
144774
- // displayName/important. Optional until every supported app accepts them.
145407
+ // displayName/important; a provider may leave either out.
144775
145408
  displayName: external_exports.string().min(1).max(200).optional(),
144776
145409
  important: external_exports.boolean().optional()
144777
145410
  }).strict();
@@ -149211,7 +149844,7 @@ if (process.argv[2] === "community") {
149211
149844
  );
149212
149845
  Object.assign(childEnv, credentialEnv.pickCommunityCredentialEnv(rawProcessEnv));
149213
149846
  const exitCode = await dispatcher.runCommunityDispatcher(process.argv.slice(3), {
149214
- cliVersion: "0.96.0",
149847
+ cliVersion: "0.97.0",
149215
149848
  dorkHome: DORK_HOME,
149216
149849
  processEnv: childEnv,
149217
149850
  parseRelease: (bytes) => releaseContract.parseCompatibleCommunityReleaseManifest(
@@ -149229,7 +149862,7 @@ if (process.argv[2] === "community") {
149229
149862
  process.exit(1);
149230
149863
  }
149231
149864
  }
149232
- var cliErrorReporter = initCliErrorReporting({ dorkHome: DORK_HOME, version: "0.96.0" });
149865
+ var cliErrorReporter = initCliErrorReporting({ dorkHome: DORK_HOME, version: "0.97.0" });
149233
149866
  var uninstallCliErrorHandlers = cliErrorReporter ? installCliErrorHandlers(cliErrorReporter) : void 0;
149234
149867
  if (process.argv[2] === "doctor") {
149235
149868
  process.env.DORK_HOME = DORK_HOME;
@@ -149239,7 +149872,7 @@ if (process.argv[2] === "doctor") {
149239
149872
  if (process.argv[2] === "feedback") {
149240
149873
  process.env.DORK_HOME = DORK_HOME;
149241
149874
  const { runFeedback: runFeedback2 } = await Promise.resolve().then(() => (init_feedback2(), feedback_exports));
149242
- process.exit(await runFeedback2(DORK_HOME, "0.96.0", process.argv.slice(3)));
149875
+ process.exit(await runFeedback2(DORK_HOME, "0.97.0", process.argv.slice(3)));
149243
149876
  }
149244
149877
  if (process.argv[2] === "auth") {
149245
149878
  process.env.DORK_HOME = DORK_HOME;
@@ -149338,7 +149971,7 @@ if (process.argv[2] === "agent" || process.argv[2] === "task" || process.argv[2]
149338
149971
  }
149339
149972
  }
149340
149973
  const { runVersionDispatcher: runVersionDispatcher2 } = await Promise.resolve().then(() => (init_version5(), version_exports));
149341
- process.exit(await runVersionDispatcher2("0.96.0", DORK_HOME, subArgs));
149974
+ process.exit(await runVersionDispatcher2("0.97.0", DORK_HOME, subArgs));
149342
149975
  }
149343
149976
  function parseCliArgs() {
149344
149977
  try {
@@ -149463,14 +150096,14 @@ Examples:
149463
150096
  process.exit(0);
149464
150097
  }
149465
150098
  if (values.version) {
149466
- console.log("0.96.0");
150099
+ console.log("0.97.0");
149467
150100
  process.exit(0);
149468
150101
  }
149469
150102
  if (values["post-install-check"]) {
149470
150103
  const claudeFound = checkClaude();
149471
150104
  const coreExtensionsFound = checkCoreExtensions();
149472
150105
  const extensionsCompile = await checkExtensionCompilation();
149473
- console.log(`dorkos ${"0.96.0"}`);
150106
+ console.log(`dorkos ${"0.97.0"}`);
149474
150107
  if (!coreExtensionsFound) {
149475
150108
  console.log("Installation incomplete \u2014 bundled core extensions are missing.");
149476
150109
  }
@@ -149624,7 +150257,7 @@ if (fs31.existsSync(envPath)) {
149624
150257
  }
149625
150258
  uninstallCliErrorHandlers?.();
149626
150259
  process.env.DORKOS_CLI_ENTRYPOINT = fileURLToPath6(import.meta.url);
149627
- process.env.DORKOS_CLI_VERSION = "0.96.0";
150260
+ process.env.DORKOS_CLI_VERSION = "0.97.0";
149628
150261
  var server;
149629
150262
  try {
149630
150263
  server = await import("../server/index.js");
@@ -149649,7 +150282,7 @@ var ansiReset = "\x1B[0m";
149649
150282
  console.log("");
149650
150283
  console.log(`${purple}${logo}${ansiReset}`);
149651
150284
  console.log("");
149652
- console.log(` DorkOS v${"0.96.0"}`);
150285
+ console.log(` DorkOS v${"0.97.0"}`);
149653
150286
  console.log(` Local: ${link(localUrl, localUrl)}`);
149654
150287
  var nets = networkInterfaces();
149655
150288
  var networkUrl = null;
@@ -149675,9 +150308,9 @@ if (shouldOpenBrowser && process.stdin.isTTY) {
149675
150308
  const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
149676
150309
  exec(`${openCmd} ${localUrl}`);
149677
150310
  }
149678
- checkForUpdate("0.96.0").then((latestVersion) => {
150311
+ checkForUpdate("0.97.0").then((latestVersion) => {
149679
150312
  if (latestVersion) {
149680
- const msg = `Update available: ${"0.96.0"} \u2192 ${latestVersion}`;
150313
+ const msg = `Update available: ${"0.97.0"} \u2192 ${latestVersion}`;
149681
150314
  const cmd = "Run npm install -g dorkos@latest to update";
149682
150315
  const width = Math.max(msg.length, cmd.length) + 6;
149683
150316
  const pad2 = (s2) => `\u2502 ${s2}${" ".repeat(width - s2.length - 6)} \u2502`;