@codeworksh/cli 0.0.1-dev.20260923023259 → 0.0.1-dev.20260925125202

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/README.md +16 -18
  2. package/{add--i7mPR73.mjs → add-CIQSfxan.mjs} +5 -5
  3. package/{add--i7mPR73.mjs.map → add-CIQSfxan.mjs.map} +1 -1
  4. package/catalog-C5fDCgtx.mjs +17 -0
  5. package/catalog-C5fDCgtx.mjs.map +1 -0
  6. package/{check-Dq2WOgap.mjs → check-B7bP5lRI.mjs} +15 -9
  7. package/check-B7bP5lRI.mjs.map +1 -0
  8. package/entries-CSY5N6jH.mjs +89 -0
  9. package/entries-CSY5N6jH.mjs.map +1 -0
  10. package/{error-BrbT9_4g.mjs → error-D0C5K2Av.mjs} +2307 -2157
  11. package/error-D0C5K2Av.mjs.map +1 -0
  12. package/{harness-Bgvrr0ZB.mjs → harness-DXAwGk0B.mjs} +2 -2
  13. package/{harness-Bgvrr0ZB.mjs.map → harness-DXAwGk0B.mjs.map} +1 -1
  14. package/index.d.mts +1 -5
  15. package/index.mjs +18 -18
  16. package/index.mjs.map +1 -1
  17. package/{install-DoO4D3fk.mjs → install-B02SIXwF.mjs} +4 -4
  18. package/{install-DoO4D3fk.mjs.map → install-B02SIXwF.mjs.map} +1 -1
  19. package/{link-B1zfETsS.mjs → link-CA9XdPwj.mjs} +3 -3
  20. package/{link-B1zfETsS.mjs.map → link-CA9XdPwj.mjs.map} +1 -1
  21. package/{list-3OR68HpY.mjs → list-Bbo4XnG_.mjs} +4 -4
  22. package/{list-3OR68HpY.mjs.map → list-Bbo4XnG_.mjs.map} +1 -1
  23. package/{list-CfPfmfe0.mjs → list-Ce1Ry4JN.mjs} +6 -5
  24. package/list-Ce1Ry4JN.mjs.map +1 -0
  25. package/{login-GFV3Z9f2.mjs → login-CagARGqW.mjs} +4 -4
  26. package/{login-GFV3Z9f2.mjs.map → login-CagARGqW.mjs.map} +1 -1
  27. package/{logout-D17TQUfo.mjs → logout-CYYtjZL3.mjs} +4 -4
  28. package/{logout-D17TQUfo.mjs.map → logout-CYYtjZL3.mjs.map} +1 -1
  29. package/package.json +5 -5
  30. package/{providers-DLXs9aWZ.mjs → providers-CoYj1SYv.mjs} +6 -5
  31. package/providers-CoYj1SYv.mjs.map +1 -0
  32. package/{refresh-BTNuP1zL.mjs → refresh-8_nfeYNZ.mjs} +4 -4
  33. package/{refresh-BTNuP1zL.mjs.map → refresh-8_nfeYNZ.mjs.map} +1 -1
  34. package/refresh-D2a1ikea.mjs +16 -0
  35. package/refresh-D2a1ikea.mjs.map +1 -0
  36. package/{reload-BzwsCBQq.mjs → reload-C5ysPM58.mjs} +3 -3
  37. package/{reload-BzwsCBQq.mjs.map → reload-C5ysPM58.mjs.map} +1 -1
  38. package/{remove-DgB3l5JL.mjs → remove-BkbspSED.mjs} +4 -4
  39. package/{remove-DgB3l5JL.mjs.map → remove-BkbspSED.mjs.map} +1 -1
  40. package/{run-BVo4XsL6.mjs → run-CnxjZIGy.mjs} +4 -4
  41. package/{run-BVo4XsL6.mjs.map → run-CnxjZIGy.mjs.map} +1 -1
  42. package/{runtime-Dl621FOp.mjs → runtime-B3dlWGfs.mjs} +36 -30
  43. package/runtime-B3dlWGfs.mjs.map +1 -0
  44. package/{serve-Dpep18-A.mjs → serve-DaD7Eijz.mjs} +8 -5
  45. package/{serve-Dpep18-A.mjs.map → serve-DaD7Eijz.mjs.map} +1 -1
  46. package/{settings-C52IrA72.mjs → settings-BZXmb54m.mjs} +23 -18
  47. package/settings-BZXmb54m.mjs.map +1 -0
  48. package/{shared-Uwjcofff.mjs → shared-BaTfajJ2.mjs} +3 -3
  49. package/{shared-Uwjcofff.mjs.map → shared-BaTfajJ2.mjs.map} +1 -1
  50. package/{status-DPYq2Sx4.mjs → status-qJImmv6V.mjs} +4 -4
  51. package/{status-DPYq2Sx4.mjs.map → status-qJImmv6V.mjs.map} +1 -1
  52. package/{update-CJrBbHwq.mjs → update-CxcNv_t0.mjs} +15 -9
  53. package/update-CxcNv_t0.mjs.map +1 -0
  54. package/catalog-DJxy_lne.mjs +0 -31
  55. package/catalog-DJxy_lne.mjs.map +0 -1
  56. package/check-Dq2WOgap.mjs.map +0 -1
  57. package/commonjs-BDiLMfFF.mjs +0 -160
  58. package/commonjs-BDiLMfFF.mjs.map +0 -1
  59. package/definitions-Dfwyyv_K.mjs +0 -3348
  60. package/definitions-Dfwyyv_K.mjs.map +0 -1
  61. package/entries-Gfsq7U4P.mjs +0 -48
  62. package/entries-Gfsq7U4P.mjs.map +0 -1
  63. package/error-BrbT9_4g.mjs.map +0 -1
  64. package/generate-DrGYpD3l.mjs +0 -35
  65. package/generate-DrGYpD3l.mjs.map +0 -1
  66. package/lib-BkWR53Bz.mjs +0 -37659
  67. package/lib-BkWR53Bz.mjs.map +0 -1
  68. package/lib-CyynPpjH.mjs +0 -846
  69. package/lib-CyynPpjH.mjs.map +0 -1
  70. package/lib-Dw7R2suc.mjs +0 -16078
  71. package/lib-Dw7R2suc.mjs.map +0 -1
  72. package/lib-JQygPqgO.mjs +0 -10868
  73. package/lib-JQygPqgO.mjs.map +0 -1
  74. package/list-CfPfmfe0.mjs.map +0 -1
  75. package/p-map-C2WSUhyP.mjs +0 -116
  76. package/p-map-C2WSUhyP.mjs.map +0 -1
  77. package/providers-DLXs9aWZ.mjs.map +0 -1
  78. package/runtime-Dl621FOp.mjs.map +0 -1
  79. package/settings-C52IrA72.mjs.map +0 -1
  80. package/type-defs-BZxrtlVD.mjs +0 -538
  81. package/type-defs-BZxrtlVD.mjs.map +0 -1
  82. package/update-CJrBbHwq.mjs.map +0 -1
  83. package/valid-BWgW_TUl.mjs +0 -354
  84. package/valid-BWgW_TUl.mjs.map +0 -1
package/README.md CHANGED
@@ -76,7 +76,7 @@ codework run --server ws://127.0.0.1:7433/rpc --sandbox-id <sandbox-id> "Start a
76
76
 
77
77
  The default address is `127.0.0.1:7433`; `--port 0` picks an available port and prints the actual URL. Set `--home`, `--database`, and `--user-config-dir` on the server. Model credentials, plugins, and working directories are resolved by the server. A remote run does not boot a local harness.
78
78
 
79
- Events are live and not replayed. The client subscribes before admitting its prompt and waits for execution completion after rendering. Lost connections and overflow fail the command; disconnecting leaves server work running. Ctrl-C sends `session.interrupt`, which interrupts the shared session. Remote runs print the sandbox ID for reuse. `session.interrupt` returns `{ interrupted }` as soon as the stop is accepted; `session.wait` is the separate cleanup barrier. A busy period reports itself as `session.execution.started` followed by exactly one of `succeeded`, `failed`, or `interrupted` -- a failure carries a namespaced category (`provider.auth`, `model.not-found`, `sandbox.mount`, ...) that the client renders, and an interruption carries whether it was the user or a server shutdown. Managed sandboxes remain available until explicitly stopped or server shutdown; external sandboxes are not stopped.
79
+ Events are live and not replayed. The client subscribes before admitting its prompt and waits for execution completion after rendering. Lost connections and overflow fail the command; disconnecting leaves server work running. Ctrl-C sends `session.interrupt`, which interrupts the shared session. Remote runs print the sandbox ID for reuse. `session.interrupt` returns `{ interrupted }` as soon as the stop is accepted; `session.wait` is the separate cleanup barrier. A busy period reports itself as `session.execution.started` followed by exactly one of `succeeded`, `failed`, or `interrupted` -- a failure carries a category (`provider-authentication-error`, `model-not-found-error`, `sandbox-mount-error`, ...) that the client renders, and an interruption carries whether it was the user or a server shutdown. Managed sandboxes remain available until explicitly stopped or server shutdown; external sandboxes are not stopped.
80
80
 
81
81
  The v0 endpoint has no authentication; its default binding is loopback. Plugins publish their own event types by declaring them (`Plugin.define({ events: [...] })`, namespaced `plugin.<plugin-id>.*`); the feed carries those and skips types nothing declared. Invalid payloads for declared types fail with a typed encoding error.
82
82
 
@@ -142,19 +142,16 @@ codework models providers
142
142
 
143
143
  ---
144
144
 
145
- ### `codework models generate`
145
+ ### `codework models refresh`
146
146
 
147
- Generate or update the `models.gen.json` catalog from model registries.
147
+ The model catalog lives at `<home>/models.gen.json` (`~/.codework` unless `--home` says otherwise). Every local command checks it before use and downloads a new one once it is older than 15 minutes (`CODEWORK_MODELS_TTL`, e.g. `"1 hour"`); `codework serve` also re-checks every minute and reloads the file whenever it changes. A failed download keeps the previous catalog.
148
148
 
149
149
  ```bash
150
- # Generate to CODEWORK_MODELS_FILE or ./models.gen.json
151
- codework models generate
150
+ # Download the catalog if it is missing or stale; no network call otherwise
151
+ codework models refresh
152
152
 
153
- # Generate into a specific directory (resolves to ./models.gen.json)
154
- codework models generate .
155
-
156
- # Generate to an explicit file path
157
- codework models generate ./path/to/custom-models.json
153
+ # Download it now
154
+ codework models refresh --force
158
155
  ```
159
156
 
160
157
  ---
@@ -212,14 +209,15 @@ file, with `{ "plugin": "<id>", "enabled": false }`.
212
209
 
213
210
  ## Environment Variables
214
211
 
215
- | Variable | Description |
216
- | :----------------------------- | :--------------------------------------------------- |
217
- | `CODEWORK_MODELS_FILE` | Path to the generated `models.gen.json` catalog file |
218
- | `OPENAI_API_KEY` | API key for OpenAI models |
219
- | `ANTHROPIC_API_KEY` | API key for Anthropic models |
220
- | `OPENROUTER_API_KEY` | API key for OpenRouter models |
221
- | `GOOGLE_GENERATIVE_AI_API_KEY` | API key for Google models |
222
- | `XAI_API_KEY` | API key for xAI models |
212
+ | Variable | Description |
213
+ | :----------------------------- | :------------------------------------------------------------------ |
214
+ | `CODEWORK_MODELS_FILE` | Pin the catalog to a file you manage; never refreshed automatically |
215
+ | `CODEWORK_MODELS_TTL` | How old the catalog may get before a refresh (default `15 minutes`) |
216
+ | `OPENAI_API_KEY` | API key for OpenAI models |
217
+ | `ANTHROPIC_API_KEY` | API key for Anthropic models |
218
+ | `OPENROUTER_API_KEY` | API key for OpenRouter models |
219
+ | `GOOGLE_GENERATIVE_AI_API_KEY` | API key for Google models |
220
+ | `XAI_API_KEY` | API key for xAI models |
223
221
 
224
222
  ---
225
223
 
@@ -1,6 +1,6 @@
1
- import { B as inspect, _t as path, a as reportFailure, at as SessionNotLinkedError, bt as resolve, f as writeOut, gt as layer$2, it as SessionNotFoundError, lt as layer$1, ot as layer, rt as Service, xt as ID } from "./error-BrbT9_4g.mjs";
2
- import { i as Cmd, t as handler } from "./runtime-Dl621FOp.mjs";
3
- import { a as resolveTarget, c as writePlugins, i as readPlugins, l as written, n as matches, o as spellings, s as withPluginsLock, t as identify } from "./settings-C52IrA72.mjs";
1
+ import { Ct as path, Dt as ID, Et as resolve, St as layer$2, V as inspect, d as writeOut, dt as SessionNotLinkedError, ft as layer, ht as layer$1, i as reportFailure, lt as Service, ut as SessionNotFoundError } from "./error-D0C5K2Av.mjs";
2
+ import { i as Cmd, t as handler } from "./runtime-B3dlWGfs.mjs";
3
+ import { a as resolveTarget, c as withPluginsLock, i as readPlugins, l as writePlugins, n as matches, o as spellings, t as identify, u as written } from "./settings-BZXmb54m.mjs";
4
4
  import { Effect, Layer, Option, Path } from "effect";
5
5
  //#region src/cli/cmd/handlers/plugin/session.ts
6
6
  /**
@@ -43,7 +43,7 @@ var add_default = handler(Cmd.commands.plugin.commands.add, Effect.fn("CLI.plugi
43
43
  file: target.path
44
44
  });
45
45
  const entry = yield* written(reference, {
46
- cwd: from,
46
+ hostDir: from,
47
47
  file: target.path,
48
48
  root: target.root
49
49
  });
@@ -78,4 +78,4 @@ var add_default = handler(Cmd.commands.plugin.commands.add, Effect.fn("CLI.plugi
78
78
  //#endregion
79
79
  export { add_default as default };
80
80
 
81
- //# sourceMappingURL=add--i7mPR73.mjs.map
81
+ //# sourceMappingURL=add-CIQSfxan.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"add--i7mPR73.mjs","names":["Global.resolve","SessionStore.Service","SessionStore.SessionNotFoundError","SessionStore.SessionNotLinkedError","Event.layer","Database.layer","Database.path","Runtime.handler","Global.resolve","Plugin.inspect"],"sources":["../../src/cli/cmd/handlers/plugin/session.ts","../../src/cli/cmd/handlers/plugin/add.ts"],"sourcesContent":["import { Database, Event, Global, Session, SessionStore } from \"@codeworksh/harness/effect\";\nimport { Effect, Layer, Option } from \"effect\";\n\n/**\n * The host directory a session is linked to.\n *\n * **A session ID can answer this and a project ID cannot**, which is why the flag takes one. A\n * `Project` is env-independent by design -- its identity is a repo marker, a remote hash or a root\n * commit, never a path -- and its spaces hold `location`s *inside* an env, which may be a container\n * on another machine. Deriving a host settings file from one would mean walking the host\n * filesystem from a path that means something somewhere else, which is the exact failure the\n * `hostDir` split exists to prevent: it does not error, it finds a stranger's project.\n *\n * A session, by contrast, carries a `hostDir` that was *declared* on the host. Absent is a normal\n * state rather than corruption, and it is the one this refuses.\n */\nexport const linkedDirectory = Effect.fn(\"CLI.plugin.linkedDirectory\")(function* (\n\tsessionId: string,\n\thome: Option.Option<string>,\n) {\n\tconst paths = yield* Global.resolve(Option.isNone(home) ? {} : { home: home.value });\n\tconst id = Session.SessionSchema.ID.ascending(sessionId);\n\n\treturn yield* Effect.gen(function* () {\n\t\tconst sessions = yield* SessionStore.Service;\n\t\tconst found = yield* sessions.get(id);\n\t\tif (Option.isNone(found)) return yield* new SessionStore.SessionNotFoundError({ sessionId: id });\n\t\tconst hostDir = Option.getOrUndefined(found.value.hostDir);\n\t\tif (hostDir === undefined) return yield* new SessionStore.SessionNotLinkedError({ sessionId: id });\n\t\treturn hostDir;\n\t}).pipe(\n\t\t// Only the session row is read, so this needs the database and the event log the store is\n\t\t// built on -- no sandboxes, no control plane, no plugin machinery.\n\t\tEffect.provide(\n\t\t\tSessionStore.layer.pipe(\n\t\t\t\tLayer.provide(Event.layer),\n\t\t\t\tLayer.provide(Database.layer(yield* Database.path(paths.data))),\n\t\t\t),\n\t\t),\n\t);\n});\n","import { Global, Plugin } from \"@codeworksh/harness/effect\";\nimport { Effect, Option, Path } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Cmd } from \"../../cmd.ts\";\nimport { linkedDirectory } from \"./session.ts\";\nimport {\n\tidentify,\n\tmatches,\n\treadPlugins,\n\tresolveTarget,\n\tspellings,\n\twithPluginsLock,\n\twritePlugins,\n\twritten,\n} from \"./settings.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.plugin.commands.add,\n\tEffect.fn(\"CLI.plugin.add\")(function* ({ package: reference, global: userWide, session }) {\n\t\tconst program = Effect.gen(function* () {\n\t\t\tconst shared = yield* Cmd.spec;\n\t\t\tconst path = yield* Path.Path;\n\t\t\tconst paths = yield* Global.resolve(Option.isNone(shared.home) ? {} : { home: shared.home.value });\n\n\t\t\t// A session names the project to write into when the shell's directory is not it --\n\t\t\t// a server or a UI acting on a session's behalf, rather than a person standing in the\n\t\t\t// repository. It fails when that session has no project, which is a state `session\n\t\t\t// link` exists to fix.\n\t\t\tconst linked = Option.isNone(session) ? undefined : yield* linkedDirectory(session.value, shared.home);\n\t\t\t/*\n\t\t\t * One directory answers every question this command asks about the reference, and it\n\t\t\t * is resolved before any of them.\n\t\t\t *\n\t\t\t * A relative spec anchors here, the `.npmrc` chain governing the install is read from\n\t\t\t * here, and the entry is written anchored here. Splitting them is not a cosmetic\n\t\t\t * inconsistency: under `--session` the shell's directory is a server's, so validating\n\t\t\t * `./plugins/x.ts` against it imports one file and writes a reference to another, and\n\t\t\t * reading the `.npmrc` chain from it installs from the wrong registry -- a private\n\t\t\t * scope's token lives in the project being written to, not wherever the server runs.\n\t\t\t */\n\t\t\tconst from = linked ?? path.resolve(\".\");\n\n\t\t\t// The file the entry will land in decides the install's registry identity: it is named\n\t\t\t// here -- without creating the marker -- so the store keys the artifact under the same\n\t\t\t// `.npmrc` chain every later resolve of this entry re-derives, and a bad reference\n\t\t\t// still leaves nothing behind.\n\t\t\tconst target = yield* resolveTarget(shared, userWide, linked, false);\n\n\t\t\t// Install and import before touching the file: a spec that turns out not to be a plugin\n\t\t\t// should fail here, with its own error, rather than at the next run from a file the user\n\t\t\t// then has to repair by hand.\n\t\t\tconst plugin = yield* Plugin.inspect(reference, { cache: paths.cache, hostDir: from, file: target.path });\n\t\t\t// What goes in the file, which is not always what was typed: a relative path anchors to\n\t\t\t// the settings file being written, not to the directory the command ran in.\n\t\t\tconst entry = yield* written(reference, {\n\t\t\t\tcwd: from,\n\t\t\t\tfile: target.path,\n\t\t\t\troot: target.root,\n\t\t\t});\n\t\t\tconst spelled = yield* spellings(reference, from);\n\t\t\tconst version = plugin.version === undefined ? \"\" : `@${plugin.version}`;\n\t\t\tyield* withPluginsLock(\n\t\t\t\ttarget.path,\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst { source, plugins } = yield* readPlugins(target.path);\n\t\t\t\t\tconst entries = yield* identify(plugins, target.path, paths.cache);\n\t\t\t\t\t// Configured already if any spelling of an existing entry names this plugin -- the same\n\t\t\t\t\t// package under a different version, the path it was added by, or the ID it declares.\n\t\t\t\t\tconst names = (candidate: (typeof entries)[number]) =>\n\t\t\t\t\t\tmatches(candidate, spelled) || candidate.answers.has(plugin.id);\n\t\t\t\t\tconst existing = entries.findIndex((candidate) => candidate.loads && names(candidate));\n\t\t\t\t\tif (existing >= 0) {\n\t\t\t\t\t\tconst current = entries[existing]?.value;\n\t\t\t\t\t\tif (current === entry) {\n\t\t\t\t\t\t\tyield* writeOut(`Plugin \"${reference}\" is already configured in ${target.path}\\n`);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst replaced = [...plugins];\n\t\t\t\t\t\treplaced[existing] = entry;\n\t\t\t\t\t\tyield* writePlugins(target.path, source, replaced);\n\t\t\t\t\t\tyield* writeOut(\n\t\t\t\t\t\t\t`Updated ${plugin.id} (${String(current)} -> ${entry}${version}) in ${target.path}\\n`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Put the loader before existing configuration so its options apply to the module.\n\t\t\t\t\tconst configured = entries.findIndex((candidate) => !candidate.loads && names(candidate));\n\t\t\t\t\tconst updated = [...plugins];\n\t\t\t\t\tupdated.splice(configured < 0 ? updated.length : configured, 0, entry);\n\t\t\t\t\tyield* writePlugins(target.path, source, updated);\n\t\t\t\t\tyield* writeOut(`Added ${plugin.id} (${entry}${version}) to ${target.path}\\n`);\n\t\t\t\t}),\n\t\t\t);\n\t\t\t// Said after the write, because `resolveTarget` only named the marker: the lock's\n\t\t\t// write is what made it, and \"created\" should be true by the time it is printed.\n\t\t\tif (target.created !== undefined) yield* writeOut(`Created ${target.created}/\\n`);\n\t\t});\n\n\t\treturn yield* program.pipe(Effect.catch(reportFailure));\n\t}),\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"add-CIQSfxan.mjs","names":["Global.resolve","SessionStore.Service","SessionStore.SessionNotFoundError","SessionStore.SessionNotLinkedError","Event.layer","Database.layer","Database.path","Runtime.handler","Global.resolve","Plugin.inspect"],"sources":["../../src/cli/cmd/handlers/plugin/session.ts","../../src/cli/cmd/handlers/plugin/add.ts"],"sourcesContent":["import { Database, Event, Global, Session, SessionStore } from \"@codeworksh/harness/effect\";\nimport { Effect, Layer, Option } from \"effect\";\n\n/**\n * The host directory a session is linked to.\n *\n * **A session ID can answer this and a project ID cannot**, which is why the flag takes one. A\n * `Project` is env-independent by design -- its identity is a repo marker, a remote hash or a root\n * commit, never a path -- and its spaces hold `location`s *inside* an env, which may be a container\n * on another machine. Deriving a host settings file from one would mean walking the host\n * filesystem from a path that means something somewhere else, which is the exact failure the\n * `hostDir` split exists to prevent: it does not error, it finds a stranger's project.\n *\n * A session, by contrast, carries a `hostDir` that was *declared* on the host. Absent is a normal\n * state rather than corruption, and it is the one this refuses.\n */\nexport const linkedDirectory = Effect.fn(\"CLI.plugin.linkedDirectory\")(function* (\n\tsessionId: string,\n\thome: Option.Option<string>,\n) {\n\tconst paths = yield* Global.resolve(Option.isNone(home) ? {} : { home: home.value });\n\tconst id = Session.SessionSchema.ID.ascending(sessionId);\n\n\treturn yield* Effect.gen(function* () {\n\t\tconst sessions = yield* SessionStore.Service;\n\t\tconst found = yield* sessions.get(id);\n\t\tif (Option.isNone(found)) return yield* new SessionStore.SessionNotFoundError({ sessionId: id });\n\t\tconst hostDir = Option.getOrUndefined(found.value.hostDir);\n\t\tif (hostDir === undefined) return yield* new SessionStore.SessionNotLinkedError({ sessionId: id });\n\t\treturn hostDir;\n\t}).pipe(\n\t\t// Only the session row is read, so this needs the database and the event log the store is\n\t\t// built on -- no sandboxes, no control plane, no plugin machinery.\n\t\tEffect.provide(\n\t\t\tSessionStore.layer.pipe(\n\t\t\t\tLayer.provide(Event.layer),\n\t\t\t\tLayer.provide(Database.layer(yield* Database.path(paths.data))),\n\t\t\t),\n\t\t),\n\t);\n});\n","import { Global, Plugin } from \"@codeworksh/harness/effect\";\nimport { Effect, Option, Path } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Cmd } from \"../../cmd.ts\";\nimport { linkedDirectory } from \"./session.ts\";\nimport {\n\tidentify,\n\tmatches,\n\treadPlugins,\n\tresolveTarget,\n\tspellings,\n\twithPluginsLock,\n\twritePlugins,\n\twritten,\n} from \"./settings.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.plugin.commands.add,\n\tEffect.fn(\"CLI.plugin.add\")(function* ({ package: reference, global: userWide, session }) {\n\t\tconst program = Effect.gen(function* () {\n\t\t\tconst shared = yield* Cmd.spec;\n\t\t\tconst path = yield* Path.Path;\n\t\t\tconst paths = yield* Global.resolve(Option.isNone(shared.home) ? {} : { home: shared.home.value });\n\n\t\t\t// A session names the project to write into when the shell's directory is not it --\n\t\t\t// a server or a UI acting on a session's behalf, rather than a person standing in the\n\t\t\t// repository. It fails when that session has no project, which is a state `session\n\t\t\t// link` exists to fix.\n\t\t\tconst linked = Option.isNone(session) ? undefined : yield* linkedDirectory(session.value, shared.home);\n\t\t\t/*\n\t\t\t * One directory answers every question this command asks about the reference, and it\n\t\t\t * is resolved before any of them.\n\t\t\t *\n\t\t\t * A relative spec anchors here, the `.npmrc` chain governing the install is read from\n\t\t\t * here, and the entry is written anchored here. Splitting them is not a cosmetic\n\t\t\t * inconsistency: under `--session` the shell's directory is a server's, so validating\n\t\t\t * `./plugins/x.ts` against it imports one file and writes a reference to another, and\n\t\t\t * reading the `.npmrc` chain from it installs from the wrong registry -- a private\n\t\t\t * scope's token lives in the project being written to, not wherever the server runs.\n\t\t\t */\n\t\t\tconst from = linked ?? path.resolve(\".\");\n\n\t\t\t// The file the entry will land in decides the install's registry identity: it is named\n\t\t\t// here -- without creating the marker -- so the store keys the artifact under the same\n\t\t\t// `.npmrc` chain every later resolve of this entry re-derives, and a bad reference\n\t\t\t// still leaves nothing behind.\n\t\t\tconst target = yield* resolveTarget(shared, userWide, linked, false);\n\n\t\t\t// Install and import before touching the file: a spec that turns out not to be a plugin\n\t\t\t// should fail here, with its own error, rather than at the next run from a file the user\n\t\t\t// then has to repair by hand.\n\t\t\tconst plugin = yield* Plugin.inspect(reference, { cache: paths.cache, hostDir: from, file: target.path });\n\t\t\t// What goes in the file, which is not always what was typed: a relative path anchors to\n\t\t\t// the settings file being written, not to the directory the command ran in.\n\t\t\tconst entry = yield* written(reference, {\n\t\t\t\thostDir: from,\n\t\t\t\tfile: target.path,\n\t\t\t\troot: target.root,\n\t\t\t});\n\t\t\tconst spelled = yield* spellings(reference, from);\n\t\t\tconst version = plugin.version === undefined ? \"\" : `@${plugin.version}`;\n\t\t\tyield* withPluginsLock(\n\t\t\t\ttarget.path,\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst { source, plugins } = yield* readPlugins(target.path);\n\t\t\t\t\tconst entries = yield* identify(plugins, target.path, paths.cache);\n\t\t\t\t\t// Configured already if any spelling of an existing entry names this plugin -- the same\n\t\t\t\t\t// package under a different version, the path it was added by, or the ID it declares.\n\t\t\t\t\tconst names = (candidate: (typeof entries)[number]) =>\n\t\t\t\t\t\tmatches(candidate, spelled) || candidate.answers.has(plugin.id);\n\t\t\t\t\tconst existing = entries.findIndex((candidate) => candidate.loads && names(candidate));\n\t\t\t\t\tif (existing >= 0) {\n\t\t\t\t\t\tconst current = entries[existing]?.value;\n\t\t\t\t\t\tif (current === entry) {\n\t\t\t\t\t\t\tyield* writeOut(`Plugin \"${reference}\" is already configured in ${target.path}\\n`);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst replaced = [...plugins];\n\t\t\t\t\t\treplaced[existing] = entry;\n\t\t\t\t\t\tyield* writePlugins(target.path, source, replaced);\n\t\t\t\t\t\tyield* writeOut(\n\t\t\t\t\t\t\t`Updated ${plugin.id} (${String(current)} -> ${entry}${version}) in ${target.path}\\n`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Put the loader before existing configuration so its options apply to the module.\n\t\t\t\t\tconst configured = entries.findIndex((candidate) => !candidate.loads && names(candidate));\n\t\t\t\t\tconst updated = [...plugins];\n\t\t\t\t\tupdated.splice(configured < 0 ? updated.length : configured, 0, entry);\n\t\t\t\t\tyield* writePlugins(target.path, source, updated);\n\t\t\t\t\tyield* writeOut(`Added ${plugin.id} (${entry}${version}) to ${target.path}\\n`);\n\t\t\t\t}),\n\t\t\t);\n\t\t\t// Said after the write, because `resolveTarget` only named the marker: the lock's\n\t\t\t// write is what made it, and \"created\" should be true by the time it is printed.\n\t\t\tif (target.created !== undefined) yield* writeOut(`Created ${target.created}/\\n`);\n\t\t});\n\n\t\treturn yield* program.pipe(Effect.catch(reportFailure));\n\t}),\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;AAgBA,MAAa,kBAAkB,OAAO,GAAG,4BAA4B,CAAC,CAAC,WACtE,WACA,MACC;CACD,MAAM,QAAQ,OAAOA,QAAe,OAAO,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACnF,MAAM,KAAA,GAA8B,UAAU,SAAS;CAEvD,OAAO,OAAO,OAAO,IAAI,aAAa;EAErC,MAAM,QAAQ,QAAO,OADGC,QAAAA,CACM,IAAI,EAAE;EACpC,IAAI,OAAO,OAAO,KAAK,GAAG,OAAO,OAAO,IAAIC,qBAAkC,EAAE,WAAW,GAAG,CAAC;EAC/F,MAAM,UAAU,OAAO,eAAe,MAAM,MAAM,OAAO;EACzD,IAAI,YAAY,KAAA,GAAW,OAAO,OAAO,IAAIC,sBAAmC,EAAE,WAAW,GAAG,CAAC;EACjG,OAAO;CACR,CAAC,CAAC,CAAC,KAGF,OAAO,QAAA,MACa,KAClB,MAAM,QAAQC,OAAW,GACzB,MAAM,QAAQC,QAAe,OAAOC,KAAc,MAAM,IAAI,CAAC,CAAC,CAC/D,CACD,CACD;AACD,CAAC;;;ACtBD,IAAA,cAAeC,QACd,IAAI,SAAS,OAAO,SAAS,KAC7B,OAAO,GAAG,gBAAgB,CAAC,CAAC,WAAW,EAAE,SAAS,WAAW,QAAQ,UAAU,WAAW;CAiFzF,OAAO,OAhFS,OAAO,IAAI,aAAa;EACvC,MAAM,SAAS,OAAO,IAAI;EAC1B,MAAM,OAAO,OAAO,KAAK;EACzB,MAAM,QAAQ,OAAOC,QAAe,OAAO,OAAO,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,OAAO,KAAK,MAAM,CAAC;EAMjG,MAAM,SAAS,OAAO,OAAO,OAAO,IAAI,KAAA,IAAY,OAAO,gBAAgB,QAAQ,OAAO,OAAO,IAAI;EAYrG,MAAM,OAAO,UAAU,KAAK,QAAQ,GAAG;EAMvC,MAAM,SAAS,OAAO,cAAc,QAAQ,UAAU,QAAQ,KAAK;EAKnE,MAAM,SAAS,OAAOC,QAAe,WAAW;GAAE,OAAO,MAAM;GAAO,SAAS;GAAM,MAAM,OAAO;EAAK,CAAC;EAGxG,MAAM,QAAQ,OAAO,QAAQ,WAAW;GACvC,SAAS;GACT,MAAM,OAAO;GACb,MAAM,OAAO;EACd,CAAC;EACD,MAAM,UAAU,OAAO,UAAU,WAAW,IAAI;EAChD,MAAM,UAAU,OAAO,YAAY,KAAA,IAAY,KAAK,IAAI,OAAO;EAC/D,OAAO,gBACN,OAAO,MACP,OAAO,IAAI,aAAa;GACvB,MAAM,EAAE,QAAQ,YAAY,OAAO,YAAY,OAAO,IAAI;GAC1D,MAAM,UAAU,OAAO,SAAS,SAAS,OAAO,MAAM,MAAM,KAAK;GAGjE,MAAM,SAAS,cACd,QAAQ,WAAW,OAAO,KAAK,UAAU,QAAQ,IAAI,OAAO,EAAE;GAC/D,MAAM,WAAW,QAAQ,WAAW,cAAc,UAAU,SAAS,MAAM,SAAS,CAAC;GACrF,IAAI,YAAY,GAAG;IAClB,MAAM,UAAU,QAAQ,SAAS,EAAE;IACnC,IAAI,YAAY,OAAO;KACtB,OAAO,SAAS,WAAW,UAAU,6BAA6B,OAAO,KAAK,GAAG;KACjF;IACD;IACA,MAAM,WAAW,CAAC,GAAG,OAAO;IAC5B,SAAS,YAAY;IACrB,OAAO,aAAa,OAAO,MAAM,QAAQ,QAAQ;IACjD,OAAO,SACN,WAAW,OAAO,GAAG,IAAI,OAAO,OAAO,EAAE,MAAM,QAAQ,QAAQ,OAAO,OAAO,KAAK,GACnF;IACA;GACD;GAGA,MAAM,aAAa,QAAQ,WAAW,cAAc,CAAC,UAAU,SAAS,MAAM,SAAS,CAAC;GACxF,MAAM,UAAU,CAAC,GAAG,OAAO;GAC3B,QAAQ,OAAO,aAAa,IAAI,QAAQ,SAAS,YAAY,GAAG,KAAK;GACrE,OAAO,aAAa,OAAO,MAAM,QAAQ,OAAO;GAChD,OAAO,SAAS,SAAS,OAAO,GAAG,IAAI,QAAQ,QAAQ,OAAO,OAAO,KAAK,GAAG;EAC9E,CAAC,CACF;EAGA,IAAI,OAAO,YAAY,KAAA,GAAW,OAAO,SAAS,WAAW,OAAO,QAAQ,IAAI;CACjF,CAEoB,CAAC,CAAC,KAAK,OAAO,MAAM,aAAa,CAAC;AACvD,CAAC,CACF"}
@@ -0,0 +1,17 @@
1
+ import { Et as resolve, it as sync } from "./error-D0C5K2Av.mjs";
2
+ import { i as Cmd } from "./runtime-B3dlWGfs.mjs";
3
+ import { Effect, Option } from "effect";
4
+ //#region src/cli/cmd/handlers/models/catalog.ts
5
+ /** The home `--home` names, or the default one. */
6
+ const home = Effect.gen(function* () {
7
+ const shared = yield* Cmd.spec;
8
+ return (yield* resolve(Option.isNone(shared.home) ? {} : { home: shared.home.value })).home;
9
+ });
10
+ /** Check the home's catalog, as `run` does at boot, before reading it. */
11
+ const synced = Effect.gen(function* () {
12
+ yield* sync(yield* home);
13
+ });
14
+ //#endregion
15
+ export { synced as n, home as t };
16
+
17
+ //# sourceMappingURL=catalog-C5fDCgtx.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-C5fDCgtx.mjs","names":["Global.resolve","ModelCatalog.sync"],"sources":["../../src/cli/cmd/handlers/models/catalog.ts"],"sourcesContent":["import { Global, ModelCatalog } from \"@codeworksh/harness/effect\";\nimport { Effect, Option } from \"effect\";\nimport { Cmd } from \"../../cmd.ts\";\n\n/** The home `--home` names, or the default one. */\nexport const home = Effect.gen(function* () {\n\tconst shared = yield* Cmd.spec;\n\treturn (yield* Global.resolve(Option.isNone(shared.home) ? {} : { home: shared.home.value })).home;\n});\n\n/** Check the home's catalog, as `run` does at boot, before reading it. */\nexport const synced = Effect.gen(function* () {\n\tyield* ModelCatalog.sync(yield* home);\n});\n"],"mappings":";;;;;AAKA,MAAa,OAAO,OAAO,IAAI,aAAa;CAC3C,MAAM,SAAS,OAAO,IAAI;CAC1B,QAAQ,OAAOA,QAAe,OAAO,OAAO,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,OAAO,KAAK,MAAM,CAAC,EAAA,CAAG;AAC/F,CAAC;;AAGD,MAAa,SAAS,OAAO,IAAI,aAAa;CAC7C,OAAOC,KAAkB,OAAO,IAAI;AACrC,CAAC"}
@@ -1,7 +1,7 @@
1
- import { V as check, a as reportFailure, f as writeOut } from "./error-BrbT9_4g.mjs";
2
- import { i as Cmd, t as handler } from "./runtime-Dl621FOp.mjs";
3
- import { n as probe, r as read, t as fetchable } from "./entries-Gfsq7U4P.mjs";
4
- import { Effect } from "effect";
1
+ import { U as check, d as writeOut, i as reportFailure } from "./error-D0C5K2Av.mjs";
2
+ import { i as Cmd, t as handler } from "./runtime-B3dlWGfs.mjs";
3
+ import { a as targeted, i as read, n as local, r as probe, t as fetchable } from "./entries-CSY5N6jH.mjs";
4
+ import { Effect, Option } from "effect";
5
5
  //#region src/cli/cmd/handlers/plugin/check.ts
6
6
  /**
7
7
  * Which configured plugins have a newer revision available.
@@ -10,15 +10,20 @@ import { Effect } from "effect";
10
10
  * reported per target and the command exits non-zero, rather than being swallowed into "you are up
11
11
  * to date": an outage that reads as currency is the one answer this command must never give.
12
12
  */
13
- var check_default = handler(Cmd.commands.plugin.commands.check, Effect.fn("CLI.plugin.check")(function* ({ refresh }) {
13
+ var check_default = handler(Cmd.commands.plugin.commands.check, Effect.fn("CLI.plugin.check")(function* ({ refresh, spec }) {
14
14
  return yield* Effect.gen(function* () {
15
15
  const shared = yield* Cmd.spec;
16
- const { entries, cache } = yield* read(shared);
16
+ const { entries, cache, hostDir } = yield* read(shared);
17
+ const selected = yield* targeted(entries, spec, hostDir);
18
+ if (selected.length === 0 && Option.isSome(spec)) return;
17
19
  let outdated = 0;
18
20
  let failed = 0;
19
- for (const entry of entries) {
21
+ for (const entry of selected) {
20
22
  const target = fetchable(entry.target);
21
- if (target === void 0) continue;
23
+ if (target === void 0) {
24
+ yield* local(entry, spec);
25
+ continue;
26
+ }
22
27
  const state = yield* check(target, cache, {
23
28
  refresh,
24
29
  probe: probe(cache, entry.from),
@@ -37,6 +42,7 @@ var check_default = handler(Cmd.commands.plugin.commands.check, Effect.fn("CLI.p
37
42
  case "not-installed": yield* writeOut(`${entry.reference} plugin-not-installed\n`);
38
43
  }
39
44
  }
45
+ if (Option.isSome(spec) && selected.every((entry) => fetchable(entry.target) === void 0)) return;
40
46
  yield* writeOut(outdated === 0 && failed === 0 ? "Everything is up to date.\n" : `${outdated} update${outdated === 1 ? "" : "s"} available.\n`);
41
47
  if (failed > 0) process.exitCode = 1;
42
48
  }).pipe(Effect.catch(reportFailure));
@@ -44,4 +50,4 @@ var check_default = handler(Cmd.commands.plugin.commands.check, Effect.fn("CLI.p
44
50
  //#endregion
45
51
  export { check_default as default };
46
52
 
47
- //# sourceMappingURL=check-Dq2WOgap.mjs.map
53
+ //# sourceMappingURL=check-B7bP5lRI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-B7bP5lRI.mjs","names":["Runtime.handler","Plugin.check"],"sources":["../../src/cli/cmd/handlers/plugin/check.ts"],"sourcesContent":["import { Plugin } from \"@codeworksh/harness/effect\";\nimport { Effect, Option } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Cmd } from \"../../cmd.ts\";\nimport { fetchable, local, probe, read, targeted } from \"./entries.ts\";\n\n/**\n * Which configured plugins have a newer revision available.\n *\n * A probe failure -- offline, registry down, a remote that refuses -- is **not** an update. It is\n * reported per target and the command exits non-zero, rather than being swallowed into \"you are up\n * to date\": an outage that reads as currency is the one answer this command must never give.\n */\nexport default Runtime.handler(\n\tCmd.commands.plugin.commands.check,\n\tEffect.fn(\"CLI.plugin.check\")(function* ({ refresh, spec }) {\n\t\tconst program = Effect.gen(function* () {\n\t\t\tconst shared = yield* Cmd.spec;\n\t\t\tconst { entries, cache, hostDir } = yield* read(shared);\n\t\t\tconst selected = yield* targeted(entries, spec, hostDir);\n\t\t\tif (selected.length === 0 && Option.isSome(spec)) return;\n\n\t\t\tlet outdated = 0;\n\t\t\tlet failed = 0;\n\t\t\tfor (const entry of selected) {\n\t\t\t\tconst target = fetchable(entry.target);\n\t\t\t\t// Nothing to compare: a local path has no revision, and `check` skips it rather\n\t\t\t\t// than reporting it as current.\n\t\t\t\tif (target === undefined) {\n\t\t\t\t\tyield* local(entry, spec);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst state = yield* Plugin.check(target, cache, {\n\t\t\t\t\trefresh,\n\t\t\t\t\tprobe: probe(cache, entry.from),\n\t\t\t\t\tfrom: entry.from,\n\t\t\t\t}).pipe(Effect.result);\n\t\t\t\tif (state._tag === \"Failure\") {\n\t\t\t\t\tfailed += 1;\n\t\t\t\t\tyield* writeOut(`${entry.reference} error[${state.failure.reason}]: ${state.failure.message}\\n`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tswitch (state.success._tag) {\n\t\t\t\t\tcase \"outdated\":\n\t\t\t\t\t\toutdated += 1;\n\t\t\t\t\t\tyield* writeOut(`${entry.reference} ${state.success.filed ?? \"?\"} -> ${state.success.available}\\n`);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"not-installed\":\n\t\t\t\t\t\tyield* writeOut(`${entry.reference} plugin-not-installed\\n`);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t// An exact version and a commit SHA cannot move, so neither is worth a line.\n\t\t\t\t\tcase \"immutable\":\n\t\t\t\t\tcase \"current\":\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// A spec that named only local plugins compared nothing, so there is nothing to sum up.\n\t\t\tif (Option.isSome(spec) && selected.every((entry) => fetchable(entry.target) === undefined)) return;\n\t\t\tyield* writeOut(\n\t\t\t\toutdated === 0 && failed === 0\n\t\t\t\t\t? \"Everything is up to date.\\n\"\n\t\t\t\t\t: `${outdated} update${outdated === 1 ? \"\" : \"s\"} available.\\n`,\n\t\t\t);\n\t\t\tif (failed > 0) process.exitCode = 1;\n\t\t});\n\n\t\treturn yield* program.pipe(Effect.catch(reportFailure));\n\t}),\n);\n"],"mappings":";;;;;;;;;;;;AAeA,IAAA,gBAAeA,QACd,IAAI,SAAS,OAAO,SAAS,OAC7B,OAAO,GAAG,kBAAkB,CAAC,CAAC,WAAW,EAAE,SAAS,QAAQ;CAqD3D,OAAO,OApDS,OAAO,IAAI,aAAa;EACvC,MAAM,SAAS,OAAO,IAAI;EAC1B,MAAM,EAAE,SAAS,OAAO,YAAY,OAAO,KAAK,MAAM;EACtD,MAAM,WAAW,OAAO,SAAS,SAAS,MAAM,OAAO;EACvD,IAAI,SAAS,WAAW,KAAK,OAAO,OAAO,IAAI,GAAG;EAElD,IAAI,WAAW;EACf,IAAI,SAAS;EACb,KAAK,MAAM,SAAS,UAAU;GAC7B,MAAM,SAAS,UAAU,MAAM,MAAM;GAGrC,IAAI,WAAW,KAAA,GAAW;IACzB,OAAO,MAAM,OAAO,IAAI;IACxB;GACD;GAEA,MAAM,QAAQ,OAAOC,MAAa,QAAQ,OAAO;IAChD;IACA,OAAO,MAAM,OAAO,MAAM,IAAI;IAC9B,MAAM,MAAM;GACb,CAAC,CAAC,CAAC,KAAK,OAAO,MAAM;GACrB,IAAI,MAAM,SAAS,WAAW;IAC7B,UAAU;IACV,OAAO,SAAS,GAAG,MAAM,UAAU,UAAU,MAAM,QAAQ,OAAO,KAAK,MAAM,QAAQ,QAAQ,GAAG;IAChG;GACD;GACA,QAAQ,MAAM,QAAQ,MAAtB;IACC,KAAK;KACJ,YAAY;KACZ,OAAO,SAAS,GAAG,MAAM,UAAU,IAAI,MAAM,QAAQ,SAAS,IAAI,MAAM,MAAM,QAAQ,UAAU,GAAG;KACnG;IACD,KAAK,iBACJ,OAAO,SAAS,GAAG,MAAM,UAAU,yBAAyB;GAM9D;EACD;EAGA,IAAI,OAAO,OAAO,IAAI,KAAK,SAAS,OAAO,UAAU,UAAU,MAAM,MAAM,MAAM,KAAA,CAAS,GAAG;EAC7F,OAAO,SACN,aAAa,KAAK,WAAW,IAC1B,gCACA,GAAG,SAAS,SAAS,aAAa,IAAI,KAAK,IAAI,cACnD;EACA,IAAI,SAAS,GAAG,QAAQ,WAAW;CACpC,CAEoB,CAAC,CAAC,KAAK,OAAO,MAAM,aAAa,CAAC;AACvD,CAAC,CACF"}
@@ -0,0 +1,89 @@
1
+ import { Et as resolve, H as localName, I as projectRoot, N as load, P as modules, R as anchor, W as digest, X as probe$1, Y as parse, d as writeOut, z as canonical } from "./error-D0C5K2Av.mjs";
2
+ import { s as userLayer } from "./settings-BZXmb54m.mjs";
3
+ import { Effect, Option, Path } from "effect";
4
+ //#region src/cli/cmd/handlers/plugin/entries.ts
5
+ /** Only a string entry loads a module; `{ package }` is configuration for one already selected. */
6
+ const moduleOf = (entry) => typeof entry === "string" ? entry : void 0;
7
+ const read = Effect.fn("CLI.plugin.entries")(function* (shared) {
8
+ const hostCwd = (yield* Path.Path).resolve(".");
9
+ const hostDir = hostCwd;
10
+ const paths = yield* resolve(Option.isNone(shared.home) ? {} : { home: shared.home.value });
11
+ const root = yield* projectRoot(hostDir, paths.home);
12
+ const layers = {
13
+ home: paths.home,
14
+ ...userLayer(shared, hostCwd)
15
+ };
16
+ const boot = yield* load(layers);
17
+ const views = root === void 0 ? [boot] : [boot, yield* load({
18
+ ...layers,
19
+ hostDir: root
20
+ })];
21
+ const entries = /* @__PURE__ */ new Map();
22
+ for (const view of views) for (const [reference, one] of modules(view.declared)) {
23
+ const target = Option.getOrUndefined(yield* parse(reference, hostDir).pipe(Effect.option));
24
+ const from = anchor(one.file, hostDir);
25
+ const key = yield* identity(target, reference, from, paths.cache);
26
+ entries.set(key, {
27
+ written: moduleOf(one.written) ?? reference,
28
+ reference,
29
+ file: one.file,
30
+ from,
31
+ target
32
+ });
33
+ }
34
+ return {
35
+ entries: [...entries.values()],
36
+ cache: paths.cache,
37
+ hostDir
38
+ };
39
+ });
40
+ /**
41
+ * What makes two entries one artifact: the store's own key for a fetched target, the file for a
42
+ * local one. A registry that cannot be read keeps the entry apart, so its install reports why.
43
+ */
44
+ const identity = (target, reference, from, cache) => {
45
+ const fetched = fetchable(target);
46
+ if (fetched === void 0) return Effect.succeed(target?.kind === "local" ? target.path : reference);
47
+ return digest(fetched, cache, from).pipe(Effect.orElseSucceed(() => `${reference}\0${from}`));
48
+ };
49
+ /** What a reference names, whatever version it was written with: a package, a git spec, a file. */
50
+ const source = (reference, hostDir) => canonical(reference, hostDir).pipe(Effect.orElseSucceed(() => reference));
51
+ /**
52
+ * The entries a command acts on: all of them, or every one `spec` names.
53
+ *
54
+ * Matched by source identity, the way the `plugins` array reads -- `@acme/x` selects
55
+ * `@acme/x@^1`, a relative path selects the file it resolves to from `hostDir`, and a local package
56
+ * also answers to the name its `package.json` declares. A plugin ID is not a spelling of anything
57
+ * in that array, so it matches nothing. Every match is kept: a spec both layers declare under
58
+ * different registries is two artifacts, and both answer to it.
59
+ */
60
+ const targeted = Effect.fn("CLI.plugin.targeted")(function* (entries, spec, hostDir) {
61
+ if (Option.isNone(spec)) return entries;
62
+ const wanted = yield* source(spec.value, hostDir);
63
+ const selected = [];
64
+ for (const entry of entries) if ((yield* source(entry.reference, hostDir)) === wanted || entry.target?.kind === "local" && (yield* localName(entry.target.path)) === wanted) selected.push(entry);
65
+ if (selected.length === 0) {
66
+ yield* writeOut(`Plugin "${spec.value}" is not configured. Run \`codework plugin list\` to see what is.\n`);
67
+ process.exitCode = 1;
68
+ }
69
+ return selected;
70
+ });
71
+ /**
72
+ * A local plugin has no revision to compare and is never copied into the store. Skipped quietly
73
+ * when a command walks everything; named, it says why nothing happened.
74
+ */
75
+ const local = (entry, spec) => Option.isSome(spec) ? writeOut(`${entry.reference} local: no remote revision to compare\n`) : Effect.void;
76
+ /**
77
+ * The network half, handed to the store so the store itself never opens a socket.
78
+ *
79
+ * `probe` bypasses pacote's own metadata cache, because a staleness check that reads a cache is
80
+ * not a staleness check. `from` is the host directory: a probe that read a different `.npmrc`
81
+ * chain than the install would answer about a registry nothing is ever fetched from.
82
+ */
83
+ const probe = (cache, from) => (target) => probe$1(target, cache, from);
84
+ /** Only a fetched target has a store entry; a local one is loaded where it lies. */
85
+ const fetchable = (target) => target === void 0 || target.kind === "local" ? void 0 : target;
86
+ //#endregion
87
+ export { targeted as a, read as i, local as n, probe as r, fetchable as t };
88
+
89
+ //# sourceMappingURL=entries-CSY5N6jH.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entries-CSY5N6jH.mjs","names":["Global.resolve","Settings.projectRoot","Settings.load","Settings.modules","Plugin.parse","Plugin.anchor","Plugin.identity","Plugin.canonical","Plugin.localName","Plugin.probe"],"sources":["../../src/cli/cmd/handlers/plugin/entries.ts"],"sourcesContent":["import { Global, Plugin, Settings } from \"@codeworksh/harness/effect\";\nimport { Effect, Option, Path } from \"effect\";\nimport { writeOut } from \"../../../output.ts\";\nimport { userLayer, type Shared } from \"./settings.ts\";\n\n/**\n * Every plugin entry the settings files name, across every layer, in the order they accumulate.\n *\n * This is what `install`, `list`, `check` and `update` all operate on: unlike `add` and `remove`,\n * none of them writes an entry. They read what is already there and act on the store -- each one\n * under the `.npmrc` context of the file that declared it, which is what keys the artifact.\n */\nexport interface Entry {\n\t/** The reference as the settings file spells it: the string a person will search for. */\n\treadonly written: string;\n\t/** The same reference, anchored to the file that declared it. This is what resolves. */\n\treadonly reference: string;\n\t/** Which settings file owns it: the last to declare it in the view that needs it. */\n\treadonly file: string;\n\t/**\n\t * The `.npmrc` anchor for the entry's store identity: the project that declared it, so the\n\t * registry context is the same wherever this command happens to run.\n\t */\n\treadonly from: string;\n\t/** Absent for an unparseable entry and for a local path. */\n\treadonly target: Plugin.Target | undefined;\n}\n\n/** Only a string entry loads a module; `{ package }` is configuration for one already selected. */\nconst moduleOf = (entry: unknown): string | undefined => (typeof entry === \"string\" ? entry : undefined);\n\nexport const read = Effect.fn(\"CLI.plugin.entries\")(function* (shared: Shared) {\n\tconst nodePath = yield* Path.Path;\n\t// The directory the command runs in resolves its app-level flags. No session links it to\n\t// another host directory, so it is the command's anchor too: project settings are discovered\n\t// from here, and a relative spec typed here resolves here.\n\tconst hostCwd = nodePath.resolve(\".\");\n\tconst hostDir = hostCwd;\n\tconst paths = yield* Global.resolve(Option.isNone(shared.home) ? {} : { home: shared.home.value });\n\tconst root = yield* Settings.projectRoot(hostDir, paths.home);\n\tconst layers = { home: paths.home, ...userLayer(shared, hostCwd) };\n\t/*\n\t * The runtime resolves plugins in two views, and each needs its own artifact on disk: boot\n\t * reads the user layers alone, and a session reads every layer. Within a view the last file to\n\t * declare a reference owns it, so a spec both layers name is owned by the user file at boot and\n\t * by the project file in the project's sessions -- two `.npmrc` anchors, and possibly two\n\t * registries. Collapsing it to one owner leaves one of those views without its artifact.\n\t */\n\tconst boot = yield* Settings.load(layers);\n\tconst views = root === undefined ? [boot] : [boot, yield* Settings.load({ ...layers, hostDir: root })];\n\n\t// One entry per store artifact, so two anchors on one registry stay a single line. A later\n\t// view names the file, which is the one a person in this project would edit.\n\tconst entries = new Map<string, Entry>();\n\tfor (const view of views) {\n\t\t// views is [boot] outside a project, or [boot, session] inside one.\n\t\t// Boot comes first, and the order matters (see below).\n\t\tfor (const [reference, one] of Settings.modules(view.declared)) {\n\t\t\t// Already anchored to the file that declared it, so `hostDir` here only affects a\n\t\t\t// reference no settings file produced.\n\t\t\tconst target = Option.getOrUndefined(yield* Plugin.parse(reference, hostDir).pipe(Effect.option));\n\t\t\tconst from = Plugin.anchor(one.file, hostDir);\n\t\t\tconst key = yield* identity(target, reference, from, paths.cache);\n\t\t\tentries.set(key, { written: moduleOf(one.written) ?? reference, reference, file: one.file, from, target });\n\t\t}\n\t}\n\treturn { entries: [...entries.values()] as ReadonlyArray<Entry>, cache: paths.cache, hostDir };\n});\n\n/**\n * What makes two entries one artifact: the store's own key for a fetched target, the file for a\n * local one. A registry that cannot be read keeps the entry apart, so its install reports why.\n */\nconst identity = (target: Plugin.Target | undefined, reference: string, from: string, cache: string) => {\n\tconst fetched = fetchable(target);\n\tif (fetched === undefined) return Effect.succeed(target?.kind === \"local\" ? target.path : reference);\n\treturn Plugin.identity(fetched, cache, from).pipe(Effect.orElseSucceed(() => `${reference}\\0${from}`));\n};\n\n/** What a reference names, whatever version it was written with: a package, a git spec, a file. */\nconst source = (reference: string, hostDir: string) =>\n\tPlugin.canonical(reference, hostDir).pipe(Effect.orElseSucceed(() => reference));\n\n/**\n * The entries a command acts on: all of them, or every one `spec` names.\n *\n * Matched by source identity, the way the `plugins` array reads -- `@acme/x` selects\n * `@acme/x@^1`, a relative path selects the file it resolves to from `hostDir`, and a local package\n * also answers to the name its `package.json` declares. A plugin ID is not a spelling of anything\n * in that array, so it matches nothing. Every match is kept: a spec both layers declare under\n * different registries is two artifacts, and both answer to it.\n */\nexport const targeted = Effect.fn(\"CLI.plugin.targeted\")(function* (\n\tentries: ReadonlyArray<Entry>,\n\tspec: Option.Option<string>,\n\t/** The host directory the command resolves from, which a relative spec is typed against. */\n\thostDir: string,\n) {\n\tif (Option.isNone(spec)) return entries;\n\tconst wanted = yield* source(spec.value, hostDir);\n\tconst selected: Entry[] = [];\n\tfor (const entry of entries) {\n\t\tconst named =\n\t\t\t(yield* source(entry.reference, hostDir)) === wanted ||\n\t\t\t(entry.target?.kind === \"local\" && (yield* Plugin.localName(entry.target.path)) === wanted);\n\t\tif (named) selected.push(entry);\n\t}\n\tif (selected.length === 0) {\n\t\tyield* writeOut(`Plugin \"${spec.value}\" is not configured. Run \\`codework plugin list\\` to see what is.\\n`);\n\t\tprocess.exitCode = 1;\n\t}\n\treturn selected as ReadonlyArray<Entry>;\n});\n\n/**\n * A local plugin has no revision to compare and is never copied into the store. Skipped quietly\n * when a command walks everything; named, it says why nothing happened.\n */\nexport const local = (entry: Entry, spec: Option.Option<string>) =>\n\tOption.isSome(spec) ? writeOut(`${entry.reference} local: no remote revision to compare\\n`) : Effect.void;\n\n/**\n * The network half, handed to the store so the store itself never opens a socket.\n *\n * `probe` bypasses pacote's own metadata cache, because a staleness check that reads a cache is\n * not a staleness check. `from` is the host directory: a probe that read a different `.npmrc`\n * chain than the install would answer about a registry nothing is ever fetched from.\n */\nexport const probe =\n\t(cache: string, from: string): Plugin.Probe =>\n\t(target) =>\n\t\tPlugin.probe(target, cache, from);\n\n/** Only a fetched target has a store entry; a local one is loaded where it lies. */\nexport const fetchable = (target: Plugin.Target | undefined): Plugin.Fetchable | undefined =>\n\ttarget === undefined || target.kind === \"local\" ? undefined : target;\n"],"mappings":";;;;;AA6BA,MAAM,YAAY,UAAwC,OAAO,UAAU,WAAW,QAAQ,KAAA;AAE9F,MAAa,OAAO,OAAO,GAAG,oBAAoB,CAAC,CAAC,WAAW,QAAgB;CAK9E,MAAM,WAAU,OAJQ,KAAK,KAAA,CAIJ,QAAQ,GAAG;CACpC,MAAM,UAAU;CAChB,MAAM,QAAQ,OAAOA,QAAe,OAAO,OAAO,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,OAAO,KAAK,MAAM,CAAC;CACjG,MAAM,OAAO,OAAOC,YAAqB,SAAS,MAAM,IAAI;CAC5D,MAAM,SAAS;EAAE,MAAM,MAAM;EAAM,GAAG,UAAU,QAAQ,OAAO;CAAE;CAQjE,MAAM,OAAO,OAAOC,KAAc,MAAM;CACxC,MAAM,QAAQ,SAAS,KAAA,IAAY,CAAC,IAAI,IAAI,CAAC,MAAM,OAAOA,KAAc;EAAE,GAAG;EAAQ,SAAS;CAAK,CAAC,CAAC;CAIrG,MAAM,0BAAU,IAAI,IAAmB;CACvC,KAAK,MAAM,QAAQ,OAGlB,KAAK,MAAM,CAAC,WAAW,QAAQC,QAAiB,KAAK,QAAQ,GAAG;EAG/D,MAAM,SAAS,OAAO,eAAe,OAAOC,MAAa,WAAW,OAAO,CAAC,CAAC,KAAK,OAAO,MAAM,CAAC;EAChG,MAAM,OAAOC,OAAc,IAAI,MAAM,OAAO;EAC5C,MAAM,MAAM,OAAO,SAAS,QAAQ,WAAW,MAAM,MAAM,KAAK;EAChE,QAAQ,IAAI,KAAK;GAAE,SAAS,SAAS,IAAI,OAAO,KAAK;GAAW;GAAW,MAAM,IAAI;GAAM;GAAM;EAAO,CAAC;CAC1G;CAED,OAAO;EAAE,SAAS,CAAC,GAAG,QAAQ,OAAO,CAAC;EAA2B,OAAO,MAAM;EAAO;CAAQ;AAC9F,CAAC;;;;;AAMD,MAAM,YAAY,QAAmC,WAAmB,MAAc,UAAkB;CACvG,MAAM,UAAU,UAAU,MAAM;CAChC,IAAI,YAAY,KAAA,GAAW,OAAO,OAAO,QAAQ,QAAQ,SAAS,UAAU,OAAO,OAAO,SAAS;CACnG,OAAOC,OAAgB,SAAS,OAAO,IAAI,CAAC,CAAC,KAAK,OAAO,oBAAoB,GAAG,UAAU,IAAI,MAAM,CAAC;AACtG;;AAGA,MAAM,UAAU,WAAmB,YAClCC,UAAiB,WAAW,OAAO,CAAC,CAAC,KAAK,OAAO,oBAAoB,SAAS,CAAC;;;;;;;;;;AAWhF,MAAa,WAAW,OAAO,GAAG,qBAAqB,CAAC,CAAC,WACxD,SACA,MAEA,SACC;CACD,IAAI,OAAO,OAAO,IAAI,GAAG,OAAO;CAChC,MAAM,SAAS,OAAO,OAAO,KAAK,OAAO,OAAO;CAChD,MAAM,WAAoB,CAAC;CAC3B,KAAK,MAAM,SAAS,SAInB,KAFE,OAAO,OAAO,MAAM,WAAW,OAAO,OAAO,UAC7C,MAAM,QAAQ,SAAS,YAAY,OAAOC,UAAiB,MAAM,OAAO,IAAI,OAAO,QAC1E,SAAS,KAAK,KAAK;CAE/B,IAAI,SAAS,WAAW,GAAG;EAC1B,OAAO,SAAS,WAAW,KAAK,MAAM,oEAAoE;EAC1G,QAAQ,WAAW;CACpB;CACA,OAAO;AACR,CAAC;;;;;AAMD,MAAa,SAAS,OAAc,SACnC,OAAO,OAAO,IAAI,IAAI,SAAS,GAAG,MAAM,UAAU,yCAAyC,IAAI,OAAO;;;;;;;;AASvG,MAAa,SACX,OAAe,UACf,WACAC,QAAa,QAAQ,OAAO,IAAI;;AAGlC,MAAa,aAAa,WACzB,WAAW,KAAA,KAAa,OAAO,SAAS,UAAU,KAAA,IAAY"}