@p4code/cli 0.0.52 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/bin.mjs +311 -58
  2. package/dist/client/assets/{DiffPanel-wkFFgH2M.js → DiffPanel-CIQUc1AN.js} +2 -2
  3. package/dist/client/assets/{FilePreviewPanel-D0sXtk7J.js → FilePreviewPanel-C13QLIQQ.js} +2 -2
  4. package/dist/client/assets/{PreviewPanel-BKcBSqy8.js → PreviewPanel-BiABC8t9.js} +2 -2
  5. package/dist/client/assets/{angular-html-SfFqn_n1.js → angular-html-D1bodirL.js} +2 -2
  6. package/dist/client/assets/{angular-ts-TqTMcSgN.js → angular-ts-DFwSl5dY.js} +2 -2
  7. package/dist/client/assets/{apl-DvTVLZcC.js → apl-BSgDHbhR.js} +2 -2
  8. package/dist/client/assets/arrow-right-Cv0-U4r_.js +2 -0
  9. package/dist/client/assets/{astro-DEpzE1sb.js → astro-B5xAVlWW.js} +2 -2
  10. package/dist/client/assets/{blade-Brgi-xhV.js → blade-DWwZA3Xz.js} +2 -2
  11. package/dist/client/assets/{c-7H0fCJJT.js → c-BEpb31ei.js} +2 -2
  12. package/dist/client/assets/{cobol-Cq_E3Ld9.js → cobol-C6zTWyM4.js} +2 -2
  13. package/dist/client/assets/{coffee-DpUX5Xcz.js → coffee-DdF9Yam1.js} +2 -2
  14. package/dist/client/assets/{cpp-BEjZmHLc.js → cpp-DKWi6_r-.js} +2 -2
  15. package/dist/client/assets/{crystal-CycEJw4X.js → crystal-DgkDMi80.js} +2 -2
  16. package/dist/client/assets/{css-y3Oj4fDi.js → css-Bwoot0jv.js} +2 -2
  17. package/dist/client/assets/{edge-DIFYHFsA.js → edge-DpISuE7V.js} +2 -2
  18. package/dist/client/assets/{elixir-raLzjUMQ.js → elixir-C01RZc83.js} +2 -2
  19. package/dist/client/assets/{elm-CZsXcOy1.js → elm-Bf8f9rUd.js} +2 -2
  20. package/dist/client/assets/{erb-DhXjIste.js → erb-CIf6pEnP.js} +2 -2
  21. package/dist/client/assets/{fileCommentAnnotations-CzUv-k6P.js → fileCommentAnnotations-Ce1J3H2T.js} +2 -2
  22. package/dist/client/assets/{git-rebase-CZvi6-AX.js → git-rebase-BvUdIX_d.js} +2 -2
  23. package/dist/client/assets/{glimmer-js-N_UF0Pmi.js → glimmer-js-D81v3RPP.js} +2 -2
  24. package/dist/client/assets/{glimmer-ts-Cxd1tQNi.js → glimmer-ts-fNKMT61k.js} +2 -2
  25. package/dist/client/assets/{glsl-B8RUupmi.js → glsl-vja7cLas.js} +2 -2
  26. package/dist/client/assets/{graphql-Cz2mi8GF.js → graphql-BAZB24Xe.js} +2 -2
  27. package/dist/client/assets/{hack-DD3q-ECT.js → hack-CMtrp-V5.js} +2 -2
  28. package/dist/client/assets/{haml-C75rIu1p.js → haml-DBWpAY-o.js} +2 -2
  29. package/dist/client/assets/{handlebars-C1zz9h1i.js → handlebars-XK5zfRVr.js} +2 -2
  30. package/dist/client/assets/{html-derivative-HEAA-Z2a.js → html-derivative-Cw9C5kli.js} +2 -2
  31. package/dist/client/assets/{html-mXOatteF.js → html-vebb6dVP.js} +2 -2
  32. package/dist/client/assets/{http-DO0ZHyk0.js → http-BYvuKZHX.js} +2 -2
  33. package/dist/client/assets/{hurl-DyDQ6Iuv.js → hurl-CpsMR6xa.js} +2 -2
  34. package/dist/client/assets/{index-4lXVitrP.js → index-DdbMSXRB.js} +197 -196
  35. package/dist/client/assets/{java-DicQ_x8H.js → java-RQhZQoJi.js} +2 -2
  36. package/dist/client/assets/{javascript-CTx-kiCR.js → javascript-zuHlOJ3o.js} +2 -2
  37. package/dist/client/assets/{jinja-ERQPZ9pQ.js → jinja-D85yp_cm.js} +2 -2
  38. package/dist/client/assets/{jison-BEedW5zW.js → jison-BrwNTiOp.js} +2 -2
  39. package/dist/client/assets/{json-MMdgCPnh.js → json-D6zKnh4D.js} +2 -2
  40. package/dist/client/assets/{jsx-CJ--w_e-.js → jsx-pJNfQcG9.js} +2 -2
  41. package/dist/client/assets/{julia-BvGAE4O0.js → julia-DciUhiLe.js} +2 -2
  42. package/dist/client/assets/{just-BvBn61hL.js → just-BEjxPLNv.js} +2 -2
  43. package/dist/client/assets/{latex-P2_b6CEl.js → latex-DsAADVlo.js} +2 -2
  44. package/dist/client/assets/{liquid-Dm2xzeBN.js → liquid-iJJrReic.js} +2 -2
  45. package/dist/client/assets/{lua-DYQLFKMA.js → lua-BI7-JqfY.js} +2 -2
  46. package/dist/client/assets/{marko-DCc0fplW.js → marko-EIBrVtPm.js} +2 -2
  47. package/dist/client/assets/{mdc-BI6uqWRL.js → mdc-Ck49TBkx.js} +2 -2
  48. package/dist/client/assets/{nginx-ijGdX1bh.js → nginx-DopLa0xS.js} +2 -2
  49. package/dist/client/assets/{nim-CUp-JGxu.js → nim-COE1mnjh.js} +2 -2
  50. package/dist/client/assets/{perl-BKpwnNRr.js → perl-D7l0Da76.js} +2 -2
  51. package/dist/client/assets/{php-DDStFT9W.js → php-BCE4oDfX.js} +2 -2
  52. package/dist/client/assets/{pug-HXcSxf00.js → pug-B_c7OAy1.js} +2 -2
  53. package/dist/client/assets/{qml-CbzgrBYo.js → qml-k34ZhWfO.js} +2 -2
  54. package/dist/client/assets/{r-CgMrZP2h.js → r-wgJNeMVi.js} +2 -2
  55. package/dist/client/assets/{razor-0ZAHbKMz.js → razor-JbycVmC6.js} +2 -2
  56. package/dist/client/assets/{regexp-Bzi1hKAb.js → regexp-7QFekdWt.js} +2 -2
  57. package/dist/client/assets/{rst-qWyAhT77.js → rst-C8gOEuzM.js} +2 -2
  58. package/dist/client/assets/{ruby-LCEp4zKA.js → ruby-DfZNo4kq.js} +2 -2
  59. package/dist/client/assets/{sas-BFhxcd3b.js → sas-BJhOgW_o.js} +2 -2
  60. package/dist/client/assets/{scss-BK0-84uz.js → scss-D926pszU.js} +2 -2
  61. package/dist/client/assets/{shellscript-CyZVCH9y.js → shellscript-CoqnDwms.js} +2 -2
  62. package/dist/client/assets/{shellsession-BMyVGgke.js → shellsession-CGMS8gZk.js} +2 -2
  63. package/dist/client/assets/{soy-C5EqpU05.js → soy-CIKF2D6I.js} +2 -2
  64. package/dist/client/assets/{sql-D51Kht_s.js → sql-CkVOyoyS.js} +2 -2
  65. package/dist/client/assets/{stata-ClgcFk9O.js → stata-CECQ179z.js} +2 -2
  66. package/dist/client/assets/{surrealql-DcFIgIgS.js → surrealql-Bf1Az_cR.js} +2 -2
  67. package/dist/client/assets/{svelte-5uir_iV_.js → svelte-BpIBHbiM.js} +2 -2
  68. package/dist/client/assets/{templ-IHhNUhu5.js → templ-DtxTEUC-.js} +2 -2
  69. package/dist/client/assets/{tex-DbjEQBr6.js → tex-CNvbX85C.js} +2 -2
  70. package/dist/client/assets/textarea-Da1Z5UPN.js +46 -0
  71. package/dist/client/assets/{ts-tags-xML8Swir.js → ts-tags-B2_hHKj2.js} +2 -2
  72. package/dist/client/assets/{tsx-BwMUW3gO.js → tsx-DNp5WCP5.js} +2 -2
  73. package/dist/client/assets/{twig-BRlCEyLn.js → twig-CBMvmisW.js} +2 -2
  74. package/dist/client/assets/{typescript-DC1qlCSF.js → typescript-CD8iaNuH.js} +2 -2
  75. package/dist/client/assets/{vue-Cta_ijHF.js → vue-BOpxstHd.js} +2 -2
  76. package/dist/client/assets/{vue-html-C6cjjUjR.js → vue-html-C7Ua1z7r.js} +2 -2
  77. package/dist/client/assets/{vue-vine-DMiSqDlT.js → vue-vine-BW2B7VA6.js} +2 -2
  78. package/dist/client/assets/{xml-DJpzo_Kg.js → xml-J7P8pGRv.js} +2 -2
  79. package/dist/client/assets/{xsl-DAqFroi4.js → xsl-B-mxb3Nx.js} +2 -2
  80. package/dist/client/assets/{yaml-Brab7tCG.js → yaml-IDU07r3p.js} +2 -2
  81. package/dist/client/index.html +2 -2
  82. package/package.json +1 -1
  83. package/dist/client/assets/arrow-right-BHEVGFLQ.js +0 -2
  84. package/dist/client/assets/textarea-C6kz4NLj.js +0 -46
package/dist/bin.mjs CHANGED
@@ -233,7 +233,7 @@ const make$72 = () => {
233
233
  const layer$68 = Layer.sync(NetService, make$72);
234
234
  //#endregion
235
235
  //#region package.json
236
- var version = "0.0.52";
236
+ var version = "0.1.0";
237
237
  //#endregion
238
238
  //#region src/config.ts
239
239
  /**
@@ -7734,6 +7734,47 @@ const AgentAssetDeleteInput = Schema$1.Struct({
7734
7734
  expectedVersion: Schema$1.optional(PositiveInt)
7735
7735
  });
7736
7736
  /**
7737
+ * Create an asset on this machine's disk, and only there.
7738
+ *
7739
+ * The hub is not involved: a new skill starts as an unmanaged local file, the
7740
+ * same as one written by hand, and becomes shared only through an explicit
7741
+ * publish. That keeps "nothing uploads by accident" true for assets p4code
7742
+ * itself creates, and it means creation works on a machine with no hub
7743
+ * configured at all.
7744
+ */
7745
+ const AgentAssetCreateLocalInput = Schema$1.Struct({
7746
+ kind: AgentAssetKind,
7747
+ name: AgentAssetName,
7748
+ files: AgentAssetFiles
7749
+ });
7750
+ /**
7751
+ * What a local create or remove did, or why it did nothing.
7752
+ *
7753
+ * An enum rather than an error, because every branch is an ordinary answer a
7754
+ * panel has to render: `exists` and `missing` are races with the filesystem,
7755
+ * `managed` is the guard that keeps a hub-synced asset from being deleted
7756
+ * locally only to be re-materialized by the next sync pass, `refused` is a
7757
+ * policy answer (a skill without `SKILL.md`, a memory name outside the
7758
+ * allowlist, an MCP registration that belongs to `mcp.save`), `no-root` is an
7759
+ * unconfigured provider, and `failed` is a disk that would not take the write.
7760
+ */
7761
+ const AgentAssetLocalMutationOutcome = Schema$1.Literals([
7762
+ "created",
7763
+ "removed",
7764
+ "exists",
7765
+ "missing",
7766
+ "managed",
7767
+ "refused",
7768
+ "no-root",
7769
+ "failed"
7770
+ ]);
7771
+ const AgentAssetLocalMutation = Schema$1.Struct({
7772
+ outcome: AgentAssetLocalMutationOutcome,
7773
+ /** Absolute path of the created asset, so a panel can hand it to an agent. */
7774
+ path: Schema$1.NullOr(Schema$1.String),
7775
+ detail: Schema$1.NullOr(Schema$1.String)
7776
+ });
7777
+ /**
7737
7778
  * Changing the hub link failed.
7738
7779
  *
7739
7780
  * Only the link operations can fail. Syncing cannot: an unreachable hub, a
@@ -8153,6 +8194,8 @@ const WS_METHODS = {
8153
8194
  assetsRead: "assets.read",
8154
8195
  assetsSave: "assets.save",
8155
8196
  assetsDelete: "assets.delete",
8197
+ assetsCreateLocal: "assets.createLocal",
8198
+ assetsRemoveLocal: "assets.removeLocal",
8156
8199
  mcpList: "mcp.list",
8157
8200
  mcpSave: "mcp.save",
8158
8201
  mcpRemove: "mcp.remove",
@@ -8351,6 +8394,31 @@ const WsAssetsDeleteRpc = Rpc.make(WS_METHODS.assetsDelete, {
8351
8394
  error: Schema$1.Union([EnvironmentAuthorizationError])
8352
8395
  });
8353
8396
  /**
8397
+ * Creating and removing assets on this machine only.
8398
+ *
8399
+ * These are the hub-free half of asset management: they write and delete the
8400
+ * local files directly, work on a server with no hub configured, and leave
8401
+ * sharing to the explicit publish. Removal refuses managed assets — deleting
8402
+ * only the local copy of a synced asset would just re-materialize on the next
8403
+ * pass, so the honest operations there are unpublish or `assets.delete`.
8404
+ */
8405
+ const WsAssetsCreateLocalRpc = Rpc.make(WS_METHODS.assetsCreateLocal, {
8406
+ payload: AgentAssetCreateLocalInput,
8407
+ success: Schema$1.Struct({
8408
+ result: AgentAssetLocalMutation,
8409
+ status: AgentSyncStatus
8410
+ }),
8411
+ error: Schema$1.Union([EnvironmentAuthorizationError])
8412
+ });
8413
+ const WsAssetsRemoveLocalRpc = Rpc.make(WS_METHODS.assetsRemoveLocal, {
8414
+ payload: AgentAssetRefInput,
8415
+ success: Schema$1.Struct({
8416
+ result: AgentAssetLocalMutation,
8417
+ status: AgentSyncStatus
8418
+ }),
8419
+ error: Schema$1.Union([EnvironmentAuthorizationError])
8420
+ });
8421
+ /**
8354
8422
  * Registering the user's own MCP servers.
8355
8423
  *
8356
8424
  * Every one of these answers with the whole list, for the same reason the sync
@@ -8750,7 +8818,7 @@ const WsSubscribeAuthAccessRpc = Rpc.make(WS_METHODS.subscribeAuthAccess, {
8750
8818
  error: Schema$1.Union([AuthAccessStreamError, EnvironmentAuthorizationError]),
8751
8819
  stream: true
8752
8820
  });
8753
- const WsRpcGroup = RpcGroup.make(WsServerProbeRpc, WsServerGetConfigRpc, WsServerRefreshProvidersRpc, WsServerUpdateProviderRpc, WsServerUpdateServerRpc, WsServerUpsertKeybindingRpc, WsServerRemoveKeybindingRpc, WsServerGetSettingsRpc, WsServerUpdateSettingsRpc, WsServerDiscoverSourceControlRpc, WsServerGetTraceDiagnosticsRpc, WsServerGetProcessDiagnosticsRpc, WsServerGetProcessResourceHistoryRpc, WsServerSignalProcessRpc, WsSourceControlLookupRepositoryRpc, WsSourceControlCloneRepositoryRpc, WsSourceControlPublishRepositoryRpc, WsProjectsListEntriesRpc, WsProjectsReadFileRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsShellOpenInEditorRpc, WsFilesystemBrowseRpc, WsAssetsCreateUrlRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsVcsListRefsRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsReviewGetDiffPreviewRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsPreviewOpenRpc, WsPreviewNavigateRpc, WsPreviewResizeRpc, WsPreviewRefreshRpc, WsPreviewCloseRpc, WsPreviewListRpc, WsPreviewReportStatusRpc, WsPreviewAutomationConnectRpc, WsPreviewAutomationRespondRpc, WsPreviewAutomationFocusHostRpc, WsSubscribePreviewEventsRpc, WsSubscribeDiscoveredLocalServersRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsTasksListRpc, WsTasksGetRpc, WsTasksCreateRpc, WsTasksUpdateRpc, WsTasksDeleteRpc, WsTasksStartThreadRpc, WsSubscribeTasksRpc, WsHubGetSyncStatusRpc, WsHubConnectRpc, WsHubDisconnectRpc, WsHubSetSyncModeRpc, WsHubSetShareModeRpc, WsHubMintTokenRpc, WsSkillsSyncRpc, WsSkillsPublishRpc, WsSkillsPublishAllRpc, WsSkillsUnpublishRpc, WsAssetsReadRpc, WsAssetsSaveRpc, WsAssetsDeleteRpc, WsMcpListRpc, WsMcpSaveRpc, WsMcpRemoveRpc, WsMcpSetSecretRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc);
8821
+ const WsRpcGroup = RpcGroup.make(WsServerProbeRpc, WsServerGetConfigRpc, WsServerRefreshProvidersRpc, WsServerUpdateProviderRpc, WsServerUpdateServerRpc, WsServerUpsertKeybindingRpc, WsServerRemoveKeybindingRpc, WsServerGetSettingsRpc, WsServerUpdateSettingsRpc, WsServerDiscoverSourceControlRpc, WsServerGetTraceDiagnosticsRpc, WsServerGetProcessDiagnosticsRpc, WsServerGetProcessResourceHistoryRpc, WsServerSignalProcessRpc, WsSourceControlLookupRepositoryRpc, WsSourceControlCloneRepositoryRpc, WsSourceControlPublishRepositoryRpc, WsProjectsListEntriesRpc, WsProjectsReadFileRpc, WsProjectsSearchEntriesRpc, WsProjectsWriteFileRpc, WsShellOpenInEditorRpc, WsFilesystemBrowseRpc, WsAssetsCreateUrlRpc, WsSubscribeVcsStatusRpc, WsVcsPullRpc, WsVcsRefreshStatusRpc, WsGitRunStackedActionRpc, WsGitResolvePullRequestRpc, WsGitPreparePullRequestThreadRpc, WsVcsListRefsRpc, WsVcsCreateWorktreeRpc, WsVcsRemoveWorktreeRpc, WsVcsCreateRefRpc, WsVcsSwitchRefRpc, WsVcsInitRpc, WsReviewGetDiffPreviewRpc, WsTerminalOpenRpc, WsTerminalAttachRpc, WsTerminalWriteRpc, WsTerminalResizeRpc, WsTerminalClearRpc, WsTerminalRestartRpc, WsTerminalCloseRpc, WsSubscribeTerminalEventsRpc, WsSubscribeTerminalMetadataRpc, WsPreviewOpenRpc, WsPreviewNavigateRpc, WsPreviewResizeRpc, WsPreviewRefreshRpc, WsPreviewCloseRpc, WsPreviewListRpc, WsPreviewReportStatusRpc, WsPreviewAutomationConnectRpc, WsPreviewAutomationRespondRpc, WsPreviewAutomationFocusHostRpc, WsSubscribePreviewEventsRpc, WsSubscribeDiscoveredLocalServersRpc, WsSubscribeServerConfigRpc, WsSubscribeServerLifecycleRpc, WsSubscribeAuthAccessRpc, WsTasksListRpc, WsTasksGetRpc, WsTasksCreateRpc, WsTasksUpdateRpc, WsTasksDeleteRpc, WsTasksStartThreadRpc, WsSubscribeTasksRpc, WsHubGetSyncStatusRpc, WsHubConnectRpc, WsHubDisconnectRpc, WsHubSetSyncModeRpc, WsHubSetShareModeRpc, WsHubMintTokenRpc, WsSkillsSyncRpc, WsSkillsPublishRpc, WsSkillsPublishAllRpc, WsSkillsUnpublishRpc, WsAssetsReadRpc, WsAssetsSaveRpc, WsAssetsDeleteRpc, WsAssetsCreateLocalRpc, WsAssetsRemoveLocalRpc, WsMcpListRpc, WsMcpSaveRpc, WsMcpRemoveRpc, WsMcpSetSecretRpc, WsOrchestrationDispatchCommandRpc, WsOrchestrationGetTurnDiffRpc, WsOrchestrationGetFullThreadDiffRpc, WsOrchestrationGetArchivedShellSnapshotRpc, WsOrchestrationSubscribeShellRpc, WsOrchestrationSubscribeThreadRpc);
8754
8822
  //#endregion
8755
8823
  //#region ../../packages/shared/src/oauthScope.ts
8756
8824
  const OAUTH_SCOPE_TOKEN = /^[\u0021\u0023-\u005b\u005d-\u007e]+$/u;
@@ -15593,6 +15661,48 @@ const writeSkillManifest = Effect.fn("skillManifest.write")(function* (manifestP
15593
15661
  });
15594
15662
  });
15595
15663
  //#endregion
15664
+ //#region src/sync/localAssetOps.ts
15665
+ const refuse = (outcome, detail) => ({
15666
+ _tag: "refuse",
15667
+ outcome,
15668
+ detail
15669
+ });
15670
+ const PROCEED = { _tag: "proceed" };
15671
+ /**
15672
+ * May this asset be created here?
15673
+ *
15674
+ * - MCP registrations have their own write path (`mcp.save`), which is where
15675
+ * the definition/secret split is enforced. Creating one as a bare file would
15676
+ * bypass the decode-before-write rule, so it is refused rather than routed.
15677
+ * - A skill without `SKILL.md` would be invisible to discovery: the picker
15678
+ * skips directories without one, so the create would look like it silently
15679
+ * failed. Refused with the reason instead.
15680
+ * - An existing local name is never overwritten. Create means create; editing
15681
+ * is a different operation with a different surface.
15682
+ */
15683
+ function decideCreateLocal(input) {
15684
+ if (input.asset.kind === "mcp") return refuse("refused", "MCP registrations are created through mcp.save, not as files.");
15685
+ if (input.asset.kind === "skill" && !input.asset.files.some((file) => file.path === "SKILL.md")) return refuse("refused", "A skill needs a SKILL.md at its root; without one, discovery skips the directory.");
15686
+ if (input.localNames.has(input.asset.name)) return refuse("exists", `An asset named '${input.asset.name}' already exists locally.`);
15687
+ return PROCEED;
15688
+ }
15689
+ /**
15690
+ * May this asset be removed from this machine?
15691
+ *
15692
+ * The managed refusal is the load-bearing one. A managed asset is a hub-synced
15693
+ * asset, and the sync plan's answer to "managed and missing locally" is to
15694
+ * re-materialize it - so a local-only delete would quietly undo itself on the
15695
+ * next pass. The honest operations for a managed asset are unpublish (keep it
15696
+ * here, stop sharing) or a hub delete (remove it everywhere), and the refusal
15697
+ * detail names both.
15698
+ */
15699
+ function decideRemoveLocal(input) {
15700
+ if (input.ref.kind === "mcp") return refuse("refused", "MCP registrations are removed through mcp.remove, not as files.");
15701
+ if (input.managedNames.has(input.ref.name)) return refuse("managed", `'${input.ref.name}' is synced with the hub; deleting it here would be undone by the next sync. Unpublish it to keep sharing off this machine, or delete it from the hub to remove it everywhere.`);
15702
+ if (!input.localNames.has(input.ref.name)) return refuse("missing", `No local asset named '${input.ref.name}' exists.`);
15703
+ return PROCEED;
15704
+ }
15705
+ //#endregion
15596
15706
  //#region src/sync/skillSyncPlan.ts
15597
15707
  /**
15598
15708
  * Deciding what a skill sync should do, given three views of the world.
@@ -16362,6 +16472,85 @@ const make$58 = Effect.gen(function* () {
16362
16472
  };
16363
16473
  return yield* run;
16364
16474
  }).pipe(Effect.provide(services), Effect.catchCause((cause) => Effect.logWarning("asset delete failed", { cause }).pipe(Effect.as(EMPTY_REPORT))));
16475
+ const FAILED_MUTATION = {
16476
+ outcome: "failed",
16477
+ path: null,
16478
+ detail: "The write failed; see the server log."
16479
+ };
16480
+ const createLocal = (input) => Effect.gen(function* () {
16481
+ const driver = driverFor(input.kind);
16482
+ if (driver === void 0) return {
16483
+ outcome: "refused",
16484
+ path: null,
16485
+ detail: `Unknown asset kind '${input.kind}'.`
16486
+ };
16487
+ const root = yield* driver.resolveRoot;
16488
+ if (root === null) return {
16489
+ outcome: "no-root",
16490
+ path: null,
16491
+ detail: "This asset kind has no home here - the provider is not configured."
16492
+ };
16493
+ const local = yield* driver.read(root);
16494
+ const decision = decideCreateLocal({
16495
+ asset: input,
16496
+ localNames: new Set(local.skills.map((skill) => skill.name))
16497
+ });
16498
+ if (decision._tag === "refuse") return {
16499
+ outcome: decision.outcome,
16500
+ path: null,
16501
+ detail: decision.detail
16502
+ };
16503
+ const written = yield* driver.write({
16504
+ root,
16505
+ name: input.name,
16506
+ files: input.files
16507
+ });
16508
+ if (written !== "written") return {
16509
+ outcome: written,
16510
+ path: null,
16511
+ detail: written === "refused" ? "This kind does not accept that name here." : "The disk would not take the write."
16512
+ };
16513
+ return {
16514
+ outcome: "created",
16515
+ path: path.join(root, input.name),
16516
+ detail: null
16517
+ };
16518
+ }).pipe(Effect.provide(services), Effect.catchCause((cause) => Effect.logWarning("asset create-local failed", { cause }).pipe(Effect.as(FAILED_MUTATION))));
16519
+ const removeLocal = (ref) => Effect.gen(function* () {
16520
+ const driver = driverFor(ref.kind);
16521
+ if (driver === void 0) return {
16522
+ outcome: "refused",
16523
+ path: null,
16524
+ detail: `Unknown asset kind '${ref.kind}'.`
16525
+ };
16526
+ const root = yield* driver.resolveRoot;
16527
+ if (root === null) return {
16528
+ outcome: "no-root",
16529
+ path: null,
16530
+ detail: "This asset kind has no home here - the provider is not configured."
16531
+ };
16532
+ const local = yield* driver.read(root);
16533
+ const manifest = yield* readSkillManifest(manifestPath);
16534
+ const decision = decideRemoveLocal({
16535
+ ref,
16536
+ localNames: new Set(local.skills.map((skill) => skill.name)),
16537
+ managedNames: new Set(entriesFor(manifest, root).map((entry) => entry.name))
16538
+ });
16539
+ if (decision._tag === "refuse") return {
16540
+ outcome: decision.outcome,
16541
+ path: null,
16542
+ detail: decision.detail
16543
+ };
16544
+ yield* driver.remove({
16545
+ root,
16546
+ name: ref.name
16547
+ });
16548
+ return {
16549
+ outcome: "removed",
16550
+ path: null,
16551
+ detail: null
16552
+ };
16553
+ }).pipe(Effect.provide(services), Effect.catchCause((cause) => Effect.logWarning("asset remove-local failed", { cause }).pipe(Effect.as(FAILED_MUTATION))));
16365
16554
  return {
16366
16555
  run,
16367
16556
  status: assetStatus,
@@ -16370,7 +16559,9 @@ const make$58 = Effect.gen(function* () {
16370
16559
  unpublish,
16371
16560
  read,
16372
16561
  save,
16373
- deleteFromHub
16562
+ deleteFromHub,
16563
+ createLocal,
16564
+ removeLocal
16374
16565
  };
16375
16566
  });
16376
16567
  const layer$53 = Layer.effect(AssetSync, make$58);
@@ -41128,6 +41319,8 @@ const RPC_REQUIRED_SCOPE = /* @__PURE__ */ new Map([
41128
41319
  [WS_METHODS.assetsRead, AuthOrchestrationReadScope],
41129
41320
  [WS_METHODS.assetsSave, AuthOrchestrationOperateScope],
41130
41321
  [WS_METHODS.assetsDelete, AuthOrchestrationOperateScope],
41322
+ [WS_METHODS.assetsCreateLocal, AuthOrchestrationOperateScope],
41323
+ [WS_METHODS.assetsRemoveLocal, AuthOrchestrationOperateScope],
41131
41324
  [WS_METHODS.mcpList, AuthOrchestrationReadScope],
41132
41325
  [WS_METHODS.mcpSave, AuthOrchestrationOperateScope],
41133
41326
  [WS_METHODS.mcpRemove, AuthOrchestrationOperateScope],
@@ -41812,6 +42005,18 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
41812
42005
  status: yield* assetSync.status
41813
42006
  };
41814
42007
  }), { "rpc.aggregate": "skills" }),
42008
+ [WS_METHODS.assetsCreateLocal]: (input) => observeRpcEffect$1(WS_METHODS.assetsCreateLocal, Effect.gen(function* () {
42009
+ return {
42010
+ result: yield* assetSync.createLocal(input),
42011
+ status: yield* assetSync.status
42012
+ };
42013
+ }), { "rpc.aggregate": "skills" }),
42014
+ [WS_METHODS.assetsRemoveLocal]: (input) => observeRpcEffect$1(WS_METHODS.assetsRemoveLocal, Effect.gen(function* () {
42015
+ return {
42016
+ result: yield* assetSync.removeLocal(input),
42017
+ status: yield* assetSync.status
42018
+ };
42019
+ }), { "rpc.aggregate": "skills" }),
41815
42020
  [WS_METHODS.mcpList]: (_input) => observeRpcEffect$1(WS_METHODS.mcpList, mcpRegistry.list.pipe(Effect.map((servers) => ({ servers }))), { "rpc.aggregate": "mcp" }),
41816
42021
  [WS_METHODS.mcpSave]: ({ registration }) => observeRpcEffect$1(WS_METHODS.mcpSave, mcpRegistry.save(registration).pipe(Effect.andThen(mcpRegistry.list.pipe(Effect.map((servers) => ({ servers }))))), { "rpc.aggregate": "mcp" }),
41817
42022
  [WS_METHODS.mcpRemove]: ({ name }) => observeRpcEffect$1(WS_METHODS.mcpRemove, mcpRegistry.remove(name).pipe(Effect.andThen(mcpRegistry.list.pipe(Effect.map((servers) => ({ servers }))))), { "rpc.aggregate": "mcp" }),
@@ -46643,6 +46848,80 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
46643
46848
  };
46644
46849
  yield* updateResumeCursor(context);
46645
46850
  });
46851
+ const applyTurnSessionOptions = Effect.fn("applyTurnSessionOptions")(function* (context, modelSelection, interactionMode) {
46852
+ if (modelSelection?.model) {
46853
+ const apiModelId = resolveClaudeApiModelId(modelSelection);
46854
+ if (context.currentApiModelId !== apiModelId) {
46855
+ yield* Effect.tryPromise({
46856
+ try: () => context.query.setModel(apiModelId),
46857
+ catch: (cause) => toRequestError$1(context.session.threadId, "turn/setModel", cause)
46858
+ });
46859
+ context.currentApiModelId = apiModelId;
46860
+ }
46861
+ context.session = {
46862
+ ...context.session,
46863
+ model: modelSelection.model
46864
+ };
46865
+ }
46866
+ if (interactionMode === "plan") yield* Effect.tryPromise({
46867
+ try: () => context.query.setPermissionMode("plan"),
46868
+ catch: (cause) => toRequestError$1(context.session.threadId, "turn/setPermissionMode", cause)
46869
+ });
46870
+ else if (interactionMode === "default") yield* Effect.tryPromise({
46871
+ try: () => context.query.setPermissionMode(context.basePermissionMode ?? "default"),
46872
+ catch: (cause) => toRequestError$1(context.session.threadId, "turn/setPermissionMode", cause)
46873
+ });
46874
+ });
46875
+ const beginTurn = Effect.fn("beginTurn")(function* (context, turnId, model) {
46876
+ const turnState = {
46877
+ turnId,
46878
+ startedAt: yield* nowIso,
46879
+ items: [],
46880
+ assistantTextBlocks: /* @__PURE__ */ new Map(),
46881
+ assistantTextBlockOrder: [],
46882
+ capturedProposedPlanKeys: /* @__PURE__ */ new Set(),
46883
+ nextSyntheticAssistantBlockIndex: -1
46884
+ };
46885
+ const updatedAt = yield* nowIso;
46886
+ context.turnState = turnState;
46887
+ context.session = {
46888
+ ...context.session,
46889
+ status: "running",
46890
+ activeTurnId: turnId,
46891
+ updatedAt
46892
+ };
46893
+ const turnStartedStamp = yield* makeEventStamp();
46894
+ yield* offerRuntimeEvent({
46895
+ type: "turn.started",
46896
+ eventId: turnStartedStamp.eventId,
46897
+ provider: PROVIDER$5,
46898
+ createdAt: turnStartedStamp.createdAt,
46899
+ threadId: context.session.threadId,
46900
+ turnId,
46901
+ payload: model ? { model } : {},
46902
+ providerRefs: {}
46903
+ });
46904
+ });
46905
+ /**
46906
+ * Start the next queued sendTurn, if the session has gone idle.
46907
+ *
46908
+ * Runs after every turn completion. A message sent during a running turn
46909
+ * waits here for the agent loop to end; pressing Stop ends the loop early,
46910
+ * and the same drain is what makes Stop mean "and run my message now".
46911
+ * One request per drain, so each queued message gets its own turn boundary -
46912
+ * the next one starts when this turn's result arrives.
46913
+ */
46914
+ const drainPendingTurns = Effect.fn("drainPendingTurns")(function* (context) {
46915
+ if (context.stopped || context.turnState !== void 0) return;
46916
+ const pending = context.pendingTurnRequests.shift();
46917
+ if (pending === void 0) return;
46918
+ yield* applyTurnSessionOptions(context, pending.modelSelection, pending.interactionMode).pipe(Effect.catchCause((cause) => Effect.logWarning("claude pending turn session options failed", { cause })));
46919
+ yield* beginTurn(context, pending.turnId, pending.modelSelection?.model);
46920
+ yield* Queue.offer(context.promptQueue, {
46921
+ type: "message",
46922
+ message: pending.message
46923
+ }).pipe(Effect.ignore);
46924
+ });
46646
46925
  const handleStreamEvent = Effect.fn("handleStreamEvent")(function* (context, message) {
46647
46926
  if (message.type !== "stream_event") return;
46648
46927
  const { event } = message;
@@ -46978,6 +47257,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
46978
47257
  const errorMessage = message.subtype === "success" ? void 0 : message.errors[0];
46979
47258
  if (status === "failed") yield* emitRuntimeError(context, errorMessage ?? "Claude turn failed.");
46980
47259
  yield* completeTurn(context, status, errorMessage, message);
47260
+ yield* drainPendingTurns(context);
46981
47261
  });
46982
47262
  const handleSystemMessage = Effect.fn("handleSystemMessage")(function* (context, message) {
46983
47263
  if (message.type !== "system") return;
@@ -47718,6 +47998,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
47718
47998
  inFlightTools,
47719
47999
  claudeTasks,
47720
48000
  turnState: void 0,
48001
+ pendingTurnRequests: [],
47721
48002
  lastKnownContextWindow: initialContextWindow,
47722
48003
  lastKnownTokenUsage: void 0,
47723
48004
  lastKnownTotalProcessedTokens: void 0,
@@ -47778,66 +48059,29 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
47778
48059
  const sendTurn = Effect.fn("sendTurn")(function* (input) {
47779
48060
  const context = yield* requireSession(input.threadId);
47780
48061
  const modelSelection = input.modelSelection !== void 0 && input.modelSelection.instanceId === boundInstanceId ? input.modelSelection : void 0;
47781
- const steeringTurnState = context.turnState && context.turnState.synthetic !== true ? context.turnState : null;
47782
- if (context.turnState && steeringTurnState === null) yield* completeTurn(context, "completed");
47783
- if (modelSelection?.model) {
47784
- const apiModelId = resolveClaudeApiModelId(modelSelection);
47785
- if (context.currentApiModelId !== apiModelId) {
47786
- yield* Effect.tryPromise({
47787
- try: () => context.query.setModel(apiModelId),
47788
- catch: (cause) => toRequestError$1(input.threadId, "turn/setModel", cause)
47789
- });
47790
- context.currentApiModelId = apiModelId;
47791
- }
47792
- context.session = {
47793
- ...context.session,
47794
- model: modelSelection.model
47795
- };
47796
- }
47797
- if (input.interactionMode === "plan") yield* Effect.tryPromise({
47798
- try: () => context.query.setPermissionMode("plan"),
47799
- catch: (cause) => toRequestError$1(input.threadId, "turn/setPermissionMode", cause)
47800
- });
47801
- else if (input.interactionMode === "default") yield* Effect.tryPromise({
47802
- try: () => context.query.setPermissionMode(context.basePermissionMode ?? "default"),
47803
- catch: (cause) => toRequestError$1(input.threadId, "turn/setPermissionMode", cause)
47804
- });
47805
- const turnId = steeringTurnState?.turnId ?? TurnId.make(yield* randomUUIDv4);
47806
- if (steeringTurnState === null) {
47807
- const turnState = {
47808
- turnId,
47809
- startedAt: yield* nowIso,
47810
- items: [],
47811
- assistantTextBlocks: /* @__PURE__ */ new Map(),
47812
- assistantTextBlockOrder: [],
47813
- capturedProposedPlanKeys: /* @__PURE__ */ new Set(),
47814
- nextSyntheticAssistantBlockIndex: -1
47815
- };
47816
- const updatedAt = yield* nowIso;
47817
- context.turnState = turnState;
47818
- context.session = {
47819
- ...context.session,
47820
- status: "running",
47821
- activeTurnId: turnId,
47822
- updatedAt
47823
- };
47824
- const turnStartedStamp = yield* makeEventStamp();
47825
- yield* offerRuntimeEvent({
47826
- type: "turn.started",
47827
- eventId: turnStartedStamp.eventId,
47828
- provider: PROVIDER$5,
47829
- createdAt: turnStartedStamp.createdAt,
47830
- threadId: context.session.threadId,
47831
- turnId,
47832
- payload: modelSelection?.model ? { model: modelSelection.model } : {},
47833
- providerRefs: {}
47834
- });
47835
- }
48062
+ if (context.turnState?.synthetic === true) yield* completeTurn(context, "completed");
47836
48063
  const message = yield* buildUserMessageEffect(input, {
47837
48064
  fileSystem,
47838
48065
  attachmentsDir: serverConfig.attachmentsDir,
47839
48066
  boundInstanceId
47840
48067
  });
48068
+ if (context.turnState) {
48069
+ const turnId = TurnId.make(yield* randomUUIDv4);
48070
+ context.pendingTurnRequests.push({
48071
+ turnId,
48072
+ message,
48073
+ modelSelection,
48074
+ interactionMode: input.interactionMode
48075
+ });
48076
+ return {
48077
+ threadId: context.session.threadId,
48078
+ turnId,
48079
+ ...context.session.resumeCursor !== void 0 ? { resumeCursor: context.session.resumeCursor } : {}
48080
+ };
48081
+ }
48082
+ yield* applyTurnSessionOptions(context, modelSelection, input.interactionMode);
48083
+ const turnId = TurnId.make(yield* randomUUIDv4);
48084
+ yield* beginTurn(context, turnId, modelSelection?.model);
47841
48085
  yield* Queue.offer(context.promptQueue, {
47842
48086
  type: "message",
47843
48087
  message
@@ -82405,6 +82649,15 @@ const make$1 = Effect.gen(function* () {
82405
82649
  }).pipe(Effect.catch(() => Effect.void));
82406
82650
  return;
82407
82651
  }
82652
+ if ((yield* providerService.listSessions()).find((session) => session.threadId !== event.payload.threadId && session.cwd === sessionRuntime.value.cwd)) {
82653
+ yield* appendRevertFailureActivity({
82654
+ threadId: event.payload.threadId,
82655
+ turnCount: event.payload.turnCount,
82656
+ detail: "Another active thread is working in the same directory; reverting would overwrite or delete its uncommitted work. Settle or stop that thread first.",
82657
+ createdAt: now
82658
+ }).pipe(Effect.catch(() => Effect.void));
82659
+ return;
82660
+ }
82408
82661
  const currentTurnCount = thread.checkpoints.reduce((maxTurnCount, checkpoint) => Math.max(maxTurnCount, checkpoint.checkpointTurnCount), 0);
82409
82662
  if (event.payload.turnCount > currentTurnCount) {
82410
82663
  yield* appendRevertFailureActivity({