@elaraai/e3-cloud-codex-plugin 1.0.97 → 1.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.
@@ -1,11 +1,11 @@
1
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/codex-hook.js
1
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/codex-hook.js
2
2
  import { readFile as readFile2 } from "node:fs/promises";
3
3
  import { existsSync, writeFileSync } from "node:fs";
4
4
  import { createHash } from "node:crypto";
5
5
  import { tmpdir } from "node:os";
6
6
  import { join, resolve as resolve3 } from "node:path";
7
7
 
8
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/codex-tools.js
8
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/codex-tools.js
9
9
  import { resolve } from "node:path";
10
10
  function patchFiles(command, cwd) {
11
11
  const files = [];
@@ -43,7 +43,7 @@ function shellReadPaths(command, cwd) {
43
43
  return [...paths];
44
44
  }
45
45
 
46
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/bash-writes.js
46
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/bash-writes.js
47
47
  import { resolve as resolve2 } from "node:path";
48
48
  function isRealPath(token) {
49
49
  if (token === "" || token.startsWith("&"))
@@ -92,7 +92,7 @@ function writtenPaths(command, cwd) {
92
92
  return [...found];
93
93
  }
94
94
 
95
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/transcript.js
95
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/transcript.js
96
96
  import { readFile } from "node:fs/promises";
97
97
  var SEARCH_TOOLS = ["mcp__plugin_east_east__search_east_examples", "mcp__plugin_east_east__get_east_example", "mcp__east__search_east_examples", "mcp__east__get_east_example"];
98
98
  async function searchedInTranscript(transcriptPath, tools = SEARCH_TOOLS) {
@@ -105,7 +105,7 @@ async function searchedInTranscript(transcriptPath, tools = SEARCH_TOOLS) {
105
105
  return tools.some((tool) => raw.includes(`"name":"${tool}"`) || raw.includes(`"name": "${tool}"`));
106
106
  }
107
107
 
108
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/search-guidance.js
108
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/search-guidance.js
109
109
  var EAST_GUIDANCE = {
110
110
  searchTool: "mcp__plugin_east_east__search_east_examples",
111
111
  getTool: "mcp__plugin_east_east__get_east_example",
@@ -147,7 +147,7 @@ var GATE_TEXT = gateText(EAST_GUIDANCE);
147
147
  var READ_TEXT = readText(EAST_GUIDANCE);
148
148
  var isExampleCorpusRead = corpusReadFor(EAST_GUIDANCE.scope);
149
149
 
150
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/codex-hook.js
150
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/codex-hook.js
151
151
  function codexToolCall(event) {
152
152
  const cwd = event.cwd || process.cwd();
153
153
  const input = event.tool_input ?? {};
@@ -199,7 +199,7 @@ async function codexSearchGate(event, options, call = codexToolCall(event)) {
199
199
  return context.length > 0 ? { decision: "context", text: context.join("\n\n") } : null;
200
200
  }
201
201
 
202
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/host.js
202
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/host.js
203
203
  import { existsSync as existsSync2 } from "node:fs";
204
204
  import { fileURLToPath } from "node:url";
205
205
  var isCodex = existsSync2(fileURLToPath(new URL("../../.codex-plugin/plugin.json", import.meta.url)));
@@ -207,7 +207,7 @@ function hostText(text) {
207
207
  return isCodex ? text.replaceAll("mcp__plugin_east_east__", "").replaceAll("/east:", "$east-codex-plugin:").replaceAll("Claude Code", "Codex") : text;
208
208
  }
209
209
 
210
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/hook-io.js
210
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/hook-io.js
211
211
  async function readHookInput() {
212
212
  let input = "";
213
213
  for await (const chunk of process.stdin) {
@@ -235,7 +235,7 @@ function writeHookDecision(hookEventName, decision, reason) {
235
235
  process.stdout.write(JSON.stringify(output));
236
236
  }
237
237
 
238
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/search-hooks.js
238
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/search-hooks.js
239
239
  function writeSearchHookReply(hookEventName, reply) {
240
240
  if (reply.decision === "deny")
241
241
  writeHookDecision(hookEventName, "deny", reply.text);
@@ -15140,7 +15140,7 @@ function object(shape, params) {
15140
15140
  return new ZodMiniObject(def);
15141
15141
  }
15142
15142
 
15143
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
15143
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
15144
15144
  function isZ4Schema(s) {
15145
15145
  const schema = s;
15146
15146
  return !!schema._zod;
@@ -15995,7 +15995,7 @@ function preprocess(fn, schema) {
15995
15995
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/external.js
15996
15996
  config(en_default2());
15997
15997
 
15998
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
15998
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
15999
15999
  var LATEST_PROTOCOL_VERSION = "2025-11-25";
16000
16000
  var SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, "2025-06-18", "2025-03-26", "2024-11-05", "2024-10-07"];
16001
16001
  var RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task";
@@ -17526,7 +17526,7 @@ var UrlElicitationRequiredError = class extends McpError {
17526
17526
  }
17527
17527
  };
17528
17528
 
17529
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
17529
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
17530
17530
  function isTerminal(status) {
17531
17531
  return status === "completed" || status === "failed" || status === "cancelled";
17532
17532
  }
@@ -18815,7 +18815,7 @@ var zodToJsonSchema = (schema, options) => {
18815
18815
  return combined;
18816
18816
  };
18817
18817
 
18818
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
18818
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
18819
18819
  function mapMiniTarget(t) {
18820
18820
  if (!t)
18821
18821
  return "draft-7";
@@ -18857,7 +18857,7 @@ function parseWithCompat(schema, data) {
18857
18857
  return result.data;
18858
18858
  }
18859
18859
 
18860
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
18860
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
18861
18861
  var DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
18862
18862
  var Protocol = class {
18863
18863
  constructor(_options) {
@@ -19834,7 +19834,7 @@ function mergeCapabilities(base, additional) {
19834
19834
  return result;
19835
19835
  }
19836
19836
 
19837
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
19837
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
19838
19838
  var import_ajv = __toESM(require_ajv(), 1);
19839
19839
  var import_ajv_formats = __toESM(require_dist(), 1);
19840
19840
  function createDefaultAjvInstance() {
@@ -19902,7 +19902,7 @@ var AjvJsonSchemaValidator = class {
19902
19902
  }
19903
19903
  };
19904
19904
 
19905
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
19905
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
19906
19906
  var ExperimentalServerTasks = class {
19907
19907
  constructor(_server) {
19908
19908
  this._server = _server;
@@ -20115,7 +20115,7 @@ var ExperimentalServerTasks = class {
20115
20115
  }
20116
20116
  };
20117
20117
 
20118
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
20118
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
20119
20119
  function assertToolsCallTaskCapability(requests, method, entityName) {
20120
20120
  if (!requests) {
20121
20121
  throw new Error(`${entityName} does not support task creation (required for ${method})`);
@@ -20150,7 +20150,7 @@ function assertClientRequestTaskCapability(requests, method, entityName) {
20150
20150
  }
20151
20151
  }
20152
20152
 
20153
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
20153
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
20154
20154
  var Server = class extends Protocol {
20155
20155
  /**
20156
20156
  * Initializes this server with the given name and version information.
@@ -20521,7 +20521,7 @@ var Server = class extends Protocol {
20521
20521
  }
20522
20522
  };
20523
20523
 
20524
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
20524
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
20525
20525
  var COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
20526
20526
  function isCompletable(schema) {
20527
20527
  return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
@@ -20535,7 +20535,7 @@ var McpZodTypeKind;
20535
20535
  McpZodTypeKind2["Completable"] = "McpCompletable";
20536
20536
  })(McpZodTypeKind || (McpZodTypeKind = {}));
20537
20537
 
20538
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
20538
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
20539
20539
  var TOOL_NAME_REGEX = /^[A-Za-z0-9._-]{1,128}$/;
20540
20540
  function validateToolName(name) {
20541
20541
  const warnings = [];
@@ -20593,7 +20593,7 @@ function validateAndWarnToolName(name) {
20593
20593
  return result.isValid;
20594
20594
  }
20595
20595
 
20596
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
20596
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
20597
20597
  var ExperimentalMcpServerTasks = class {
20598
20598
  constructor(_mcpServer) {
20599
20599
  this._mcpServer = _mcpServer;
@@ -20608,7 +20608,7 @@ var ExperimentalMcpServerTasks = class {
20608
20608
  }
20609
20609
  };
20610
20610
 
20611
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
20611
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
20612
20612
  function toolInputElementCount(value, max) {
20613
20613
  let count = 0;
20614
20614
  const stack = [value];
@@ -20657,6 +20657,15 @@ var McpServer = class {
20657
20657
  this._promptHandlersInitialized = false;
20658
20658
  this.server = new Server(serverInfo, options);
20659
20659
  this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
20660
+ if (options?.capabilities?.tools) {
20661
+ this.setToolRequestHandlers();
20662
+ }
20663
+ if (options?.capabilities?.resources) {
20664
+ this.setResourceRequestHandlers();
20665
+ }
20666
+ if (options?.capabilities?.prompts) {
20667
+ this.setPromptRequestHandlers();
20668
+ }
20660
20669
  }
20661
20670
  /**
20662
20671
  * Access experimental features.
@@ -21440,10 +21449,10 @@ var EMPTY_COMPLETION_RESULT = {
21440
21449
  }
21441
21450
  };
21442
21451
 
21443
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
21452
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
21444
21453
  import process from "node:process";
21445
21454
 
21446
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
21455
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
21447
21456
  var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
21448
21457
  var ReadBuffer = class {
21449
21458
  constructor(options) {
@@ -21480,7 +21489,7 @@ function serializeMessage(message) {
21480
21489
  return JSON.stringify(message) + "\n";
21481
21490
  }
21482
21491
 
21483
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
21492
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.2_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
21484
21493
  var StdioServerTransport = class {
21485
21494
  constructor(_stdin = process.stdin, _stdout = process.stdout, options) {
21486
21495
  this._stdin = _stdin;
@@ -21547,7 +21556,7 @@ var StdioServerTransport = class {
21547
21556
  }
21548
21557
  };
21549
21558
 
21550
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/search.js
21559
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/search.js
21551
21560
  import { readFile } from "node:fs/promises";
21552
21561
 
21553
21562
  // ../../node_modules/.pnpm/minisearch@7.2.0/node_modules/minisearch/dist/es/index.js
@@ -23360,7 +23369,7 @@ var objectToNumericMapAsync = async (object3) => {
23360
23369
  var wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
23361
23370
  var SPACE_OR_PUNCTUATION = /[\n\r\p{Z}\p{P}]+/u;
23362
23371
 
23363
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/search-guidance.js
23372
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/search-guidance.js
23364
23373
  var EAST_GUIDANCE = {
23365
23374
  searchTool: "mcp__plugin_east_east__search_east_examples",
23366
23375
  getTool: "mcp__plugin_east_east__get_east_example",
@@ -23402,7 +23411,7 @@ var GATE_TEXT = gateText(EAST_GUIDANCE);
23402
23411
  var READ_TEXT = readText(EAST_GUIDANCE);
23403
23412
  var isExampleCorpusRead = corpusReadFor(EAST_GUIDANCE.scope);
23404
23413
 
23405
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/search.js
23414
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/search.js
23406
23415
  var MIN_SCORE = 5;
23407
23416
  async function loadIndexes(indexPaths) {
23408
23417
  const entries = [];
@@ -23444,6 +23453,7 @@ function normalizePackage(filter, scopes = EAST_SCOPES) {
23444
23453
  const scope = scopes.find((s) => name.startsWith(`${s.toLowerCase()}/`));
23445
23454
  return scope === void 0 ? name : name.slice(scope.length + 1);
23446
23455
  }
23456
+ var OPT_IN_PACKAGES = /* @__PURE__ */ new Set(["east-values"]);
23447
23457
  function searchExamples(index, request) {
23448
23458
  const known = index.packages;
23449
23459
  const filter = request.package;
@@ -23453,7 +23463,7 @@ function searchExamples(index, request) {
23453
23463
  }
23454
23464
  const options = {
23455
23465
  limit: request.limit,
23456
- ...pkg === void 0 ? {} : { filter: (r) => r.package === pkg || r.skill === pkg }
23466
+ filter: (r) => OPT_IN_PACKAGES.has(r.package) ? r.package === pkg : pkg === void 0 || r.package === pkg || r.skill === pkg
23457
23467
  };
23458
23468
  const hits = index.search.search(request.query, options);
23459
23469
  return { entries: hits.filter((r) => r.score >= MIN_SCORE).slice(0, request.limit), known };
@@ -23527,7 +23537,7 @@ function getEntry(index, id) {
23527
23537
  return stored === void 0 ? null : stored;
23528
23538
  }
23529
23539
 
23530
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/mcp/example-tools.js
23540
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/mcp/example-tools.js
23531
23541
  var EAST_PACKAGES = ["east", "east-node-std", "east-node-io", "east-py-datascience", "east-ui", "e3-ui", "e3", "e3-ui-cli", "e3-create"];
23532
23542
  function isLoaded(index) {
23533
23543
  return typeof index.then === "function";
@@ -23548,7 +23558,7 @@ function registerExampleTools(server2, options) {
23548
23558
  language: languageArg,
23549
23559
  format: external_exports.enum(["summary", "full"]).default("summary").describe(`"summary" (default) lists the hits in one line each; "full" includes each hit's code in the requested language`),
23550
23560
  limit: external_exports.number().int().min(1).max(20).default(5).describe("Maximum number of results to return (default 5, max 20)"),
23551
- package: external_exports.string().optional().describe(`Filter results to one package by its bare name \u2014 ${packages.join(", ")} \u2014 ${scopesNamed}; an unknown name is reported with the indexed names`)
23561
+ package: external_exports.string().optional().describe(`Filter results to one package by its bare name \u2014 ${packages.join(", ")} \u2014 ${scopesNamed}; an unknown name is reported with the indexed names${packages.includes("east-values") ? '. "east-values" is east-py code working with East values directly (eager methods on python values, not an East function), and is searched only when named here' : ""}`)
23552
23562
  }, async ({ query, language, format, limit, package: packageFilter }) => {
23553
23563
  const index = await indexPromise;
23554
23564
  const { entries, unknownPackage, known } = searchExamples(index, { query, limit, package: packageFilter, scopes });
@@ -23600,7 +23610,7 @@ function registerExampleTools(server2, options) {
23600
23610
  import { fileURLToPath } from "node:url";
23601
23611
  var E3_CLOUD_INDEX_PATH = fileURLToPath(new URL("../../index.json", import.meta.url));
23602
23612
 
23603
- // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.97_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/transcript.js
23613
+ // ../../node_modules/.pnpm/@elaraai+east-plugin@1.0.100_typescript@5.9.3/node_modules/@elaraai/east-plugin/dist/lib/transcript.js
23604
23614
  var SEARCH_TOOLS = ["mcp__plugin_east_east__search_east_examples", "mcp__plugin_east_east__get_east_example", "mcp__east__search_east_examples", "mcp__east__get_east_example"];
23605
23615
 
23606
23616
  // ../e3-cloud-plugin/dist/lib/names.js
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "e3-cloud-codex-plugin",
3
- "version": "1.0.97",
3
+ "version": "1.1.0",
4
4
  "description": "e3 cloud - apps for hosted e3 workspaces with @elaraai/e3-cloud-ui, files from buckets as inputs with @elaraai/e3-cloud-files, the e3-cloud CLI and @elaraai/e3-cloud-client: skills, example search and the search-first hooks",
5
5
  "author": {
6
6
  "name": "Elara AI",
package/index.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "version": 2,
3
3
  "stats": {
4
- "totalEntries": 40,
4
+ "totalEntries": 44,
5
5
  "totalFiles": 2,
6
6
  "packages": {
7
7
  "e3-cloud-ui": 12,
8
- "e3-cloud-files": 11,
8
+ "e3-cloud-files": 14,
9
9
  "e3-cloud-cli": 13,
10
- "e3-cloud-client": 4
10
+ "e3-cloud-client": 5
11
11
  }
12
12
  },
13
13
  "entries": [
@@ -183,7 +183,7 @@
183
183
  "package": "e3-cloud-ui",
184
184
  "file": "packages/e3-cloud-ui/test/pages.examples.tsx",
185
185
  "suite": "Functions and records",
186
- "test": "Changing a record from a page: Record.bind(orders, [approve]) names the mutations the page may run, and o.mutate.approve(id) commits one",
186
+ "test": "Changing a record from a page: Record.bind(orders, ['approve']) names the mutations the page may run, by the names the record declares them under, and o.mutate.approve(id) commits one",
187
187
  "keywords": [
188
188
  "Record.bind",
189
189
  "mutate",
@@ -203,7 +203,7 @@
203
203
  "languages": [
204
204
  "tsx"
205
205
  ],
206
- "source": "// Changing a record from a page: Record.bind(orders, [approve]) names the mutations the page may run, and o.mutate.approve(id) commits one\n// inputs: []\n/** The runtime the package's functions run on. */\nconst RUNNER: Runner = { runtime: 'east-c', platforms: ['east-c-std'] };\n\nconst Order = StructType({ line: StringType, qty: FloatType, status: StringType });\n\n/** A record of orders, changed only through its mutations. */\nconst orders = e3.record('orders', DictType(StringType, Order), new Map());\n\n/** Approves an order by its id. */\nconst approve = e3.mutation.reduce('approve', orders,\n East.function([DictType(StringType, Order), StringType], DictType(StringType, Order), (_$, all, _id) => all),\n { runner: RUNNER });\n\nEast.function([], UIComponentType, _$ => (\n <Reactive>{$ => {\n const o = $.let(Record.bind(orders, [approve]));\n const approveA17 = $.const(East.function([], NullType, $ => { $(o.mutate.approve('A-17')); }));\n return <Button onClick={approveA17}>Approve A-17</Button>;\n }}</Reactive>\n ))"
206
+ "source": "// Changing a record from a page: Record.bind(orders, ['approve']) names the mutations the page may run, by the names the record declares them under, and o.mutate.approve(id) commits one\n// inputs: []\n/** The runtime the package's functions run on. */\nconst RUNNER: Runner = { runtime: 'east-c', platforms: ['east-c-std'] };\n\nconst Order = StructType({ line: StringType, qty: FloatType, status: StringType });\n\n/** A record of orders, changed only through its mutations, declared whole with its index and its mutation. */\nconst orders = e3.record('orders', DictType(StringType, Order), {\n initial: new Map(),\n indexes: (index) => ({\n /** The orders by line. */\n by_line: index.key(East.function([StringType, Order], StringType, (_$, _id, o) => o.line)),\n }),\n mutations: (mutation) => ({\n /** Approves an order by its id. */\n approve: mutation.reduce(\n East.function([DictType(StringType, Order), StringType], DictType(StringType, Order), (_$, all, _id) => all),\n { runner: RUNNER }),\n }),\n});\n\nEast.function([], UIComponentType, _$ => (\n <Reactive>{$ => {\n const o = $.let(Record.bind(orders, ['approve']));\n const approveA17 = $.const(East.function([], NullType, $ => { $(o.mutate.approve('A-17')); }));\n return <Button onClick={approveA17}>Approve A-17</Button>;\n }}</Reactive>\n ))"
207
207
  },
208
208
  {
209
209
  "id": "e3-cloud-ui:pages.examples.tsx:pageReadsARecordThroughAnIndex",
@@ -211,11 +211,11 @@
211
211
  "package": "e3-cloud-ui",
212
212
  "file": "packages/e3-cloud-ui/test/pages.examples.tsx",
213
213
  "suite": "Functions and records",
214
- "test": "Reading a record through one of its indexes, a page at a time: Data.bindPaged(orders, { index: byLine }) given the index's declaration, its rows the index key and the order's id",
214
+ "test": "Reading a record through one of its indexes, a page at a time: Data.bindPaged(orders, { index: 'by_line' }) given the name the record declares the index under, its rows the index key and the order's id",
215
215
  "keywords": [
216
216
  "Data.bindPaged",
217
217
  "index",
218
- "recordIndex",
218
+ "indexes",
219
219
  "record",
220
220
  "paged",
221
221
  "Table",
@@ -232,7 +232,7 @@
232
232
  "languages": [
233
233
  "tsx"
234
234
  ],
235
- "source": "// Reading a record through one of its indexes, a page at a time: Data.bindPaged(orders, { index: byLine }) given the index's declaration, its rows the index key and the order's id\n// inputs: []\nconst Order = StructType({ line: StringType, qty: FloatType, status: StringType });\n\n/** A record of orders, changed only through its mutations. */\nconst orders = e3.record('orders', DictType(StringType, Order), new Map());\n\n/** The orders by line. */\nconst byLine = e3.recordIndex('by_line', orders,\n { key: East.function([StringType, Order], StringType, (_$, _id, o) => o.line) });\n\nEast.function([], UIComponentType, _$ => (\n <Reactive>{$ => {\n const mine = $.let(Data.bindPaged(orders, { index: byLine }));\n return <Table data={mine} columns={['ik', 'key']} />;\n }}</Reactive>\n ))"
235
+ "source": "// Reading a record through one of its indexes, a page at a time: Data.bindPaged(orders, { index: 'by_line' }) given the name the record declares the index under, its rows the index key and the order's id\n// inputs: []\n/** The runtime the package's functions run on. */\nconst RUNNER: Runner = { runtime: 'east-c', platforms: ['east-c-std'] };\n\nconst Order = StructType({ line: StringType, qty: FloatType, status: StringType });\n\n/** A record of orders, changed only through its mutations, declared whole with its index and its mutation. */\nconst orders = e3.record('orders', DictType(StringType, Order), {\n initial: new Map(),\n indexes: (index) => ({\n /** The orders by line. */\n by_line: index.key(East.function([StringType, Order], StringType, (_$, _id, o) => o.line)),\n }),\n mutations: (mutation) => ({\n /** Approves an order by its id. */\n approve: mutation.reduce(\n East.function([DictType(StringType, Order), StringType], DictType(StringType, Order), (_$, all, _id) => all),\n { runner: RUNNER }),\n }),\n});\n\nEast.function([], UIComponentType, _$ => (\n <Reactive>{$ => {\n const mine = $.let(Data.bindPaged(orders, { index: 'by_line' }));\n return <Table data={mine} columns={['ik', 'key']} />;\n }}</Reactive>\n ))"
236
236
  },
237
237
  {
238
238
  "id": "e3-cloud-files:decode.examples.ts:fileAsJson",
@@ -314,6 +314,34 @@
314
314
  ],
315
315
  "source": "// A text file input's lines, trimmed, blank ones left out\n// inputs: [utf8('first\\n\\n second \\nthird\\n')] returns: ['first', 'second', 'third']\nEast.function([BlobType], ArrayType(StringType), (_$, file) =>\n file.decodeUtf8().split('\\n').map((_$, line) => line.trim()).filter((_$, line) => line.notEquals('')))"
316
316
  },
317
+ {
318
+ "id": "e3-cloud-files:decode.examples.ts:typedFileAsItsValue",
319
+ "skill": "e3-cloud-files",
320
+ "package": "e3-cloud-files",
321
+ "file": "packages/e3-cloud-files/test/decode.examples.ts",
322
+ "suite": "A typed file: no decoding",
323
+ "test": "A typed input needs no decoding: what upload.file('prices', { key: 'prices.beast2', type: ArrayType(Price) }) fills is the beast2 file's value itself, an Array<Price> the task takes as any dataset, here counted",
324
+ "keywords": [
325
+ "Files",
326
+ "typed",
327
+ "type",
328
+ "beast2",
329
+ "file",
330
+ "latest",
331
+ "no decoding",
332
+ "ArrayType",
333
+ "size",
334
+ "task"
335
+ ],
336
+ "imports": [
337
+ "import { East, ArrayType, BlobType, DateTimeType, FloatType, IntegerType, StringType, StructType, example } from '@elaraai/east';",
338
+ "import { FilesFolderType, FilesListingType } from '@elaraai/e3-cloud-files';"
339
+ ],
340
+ "languages": [
341
+ "typescript"
342
+ ],
343
+ "source": "// A typed input needs no decoding: what upload.file('prices', { key: 'prices.beast2', type: ArrayType(Price) }) fills is the beast2 file's value itself, an Array<Price> the task takes as any dataset, here counted\n// inputs: [[{ sku: 'A1', price: 1.5 }, { sku: 'B2', price: 2.25 }, { sku: 'C3', price: 9 }]] returns: 3n\nconst Price = StructType({ sku: StringType, price: FloatType });\n\nEast.function([ArrayType(Price)], IntegerType, (_$, prices) => prices.size())"
344
+ },
317
345
  {
318
346
  "id": "e3-cloud-files:decode.examples.ts:folderAsOneArray",
319
347
  "skill": "e3-cloud-files",
@@ -593,35 +621,104 @@
593
621
  ]
594
622
  },
595
623
  {
596
- "id": "e3-cloud-files:static:typed",
624
+ "id": "e3-cloud-files:static:typed-input",
597
625
  "skill": "e3-cloud-files",
598
626
  "package": "e3-cloud-files",
599
627
  "file": "static",
600
628
  "suite": "Files",
601
- "test": "A beast2 file as an input of its type with no task in between (file or latest with a type), and a record's mutation fed by each new file: the declarations, the package, and what a sync does with them",
629
+ "test": "A beast2 file as an input of its type with no task in between: file or latest with a type, a collection of any size, its header checked before any other byte, a file of another type refused naming both types, the same bytes under a new ETag changing nothing",
602
630
  "keywords": [
603
631
  "Files",
604
632
  "type",
605
633
  "beast2",
606
634
  "typed",
635
+ "typed input",
607
636
  "ArrayType",
608
637
  "upload.file",
609
638
  "upload.latest",
610
- "upload.mutation",
611
- "mutation",
612
- "feed",
613
- "record",
614
- "e3.mutation.reduce",
615
639
  "encodeBeast2For",
640
+ "Beast2ElementWriter",
616
641
  "collection",
642
+ "type_mismatch",
643
+ "not_beast2",
644
+ "e3-cloud-files"
645
+ ],
646
+ "imports": [
647
+ "import { East, ArrayType, FloatType, IntegerType, StringType, StructType } from '@elaraai/east';",
648
+ "import e3, { type Runner } from '@elaraai/e3';",
649
+ "import { Files } from '@elaraai/e3-cloud-files';"
650
+ ],
651
+ "source": "// src/package.ts\nconst Price = StructType({ sku: StringType, price: FloatType });\nexport const upload = Files.source('upload');\n// A beast2 file of Array<Price> (encodeBeast2For(ArrayType(Price)), a Beast2ElementWriter for a collection of any size, east-py, e3 convert):\n// an input of that type, taken in as the value it holds, its header checked before any other byte is read; a file of another type is\n// refused naming both types (type_mismatch), no beast2 at all as not_beast2, and the input keeps its value. The same bytes again under\n// a new ETag give the same value: nothing downstream runs\nexport const prices = upload.file('prices', { key: 'prices.beast2', type: ArrayType(Price) });\nexport const stock = upload.latest('stock', { prefix: 'stock/', include: '*.beast2', type: ArrayType(Price) }); // the greatest key, typed\nconst runner: Runner = { runtime: 'east-c', platforms: ['east-c-std'] };\n// Used as any dataset: no decoding, the value is the file's\nexport const summary = e3.task('price_summary', [prices, stock], East.function([ArrayType(Price), ArrayType(Price)], IntegerType, (_$, rows, latest) => rows.size().add(latest.size())), { runner });\nexport default e3.package('typed', '1.0.0', summary);\n\n// src/files.ts\nexport default Files.manifest([upload]);",
652
+ "languages": [
653
+ "typescript"
654
+ ]
655
+ },
656
+ {
657
+ "id": "e3-cloud-files:static:record-seed",
658
+ "skill": "e3-cloud-files",
659
+ "package": "e3-cloud-files",
660
+ "file": "static",
661
+ "suite": "Files",
662
+ "test": "A record seeded from a file: upload.record(name, type, spec, parts) is e3.record(name, type, parts) with no initial value, declared whole with its indexes, mutations and migrations, pending until its file arrives (its first state, $init), seeded again by a changed file while nothing has mutated it since ($seed) or on --reset, kept once mutated; the tasks over it wait meanwhile, and its history names the file",
663
+ "keywords": [
664
+ "Files",
665
+ "record",
666
+ "seed",
667
+ "seeded",
668
+ "upload.record",
669
+ "pending",
670
+ "$init",
671
+ "$seed",
672
+ "--reset",
673
+ "genesis",
674
+ "no initial value",
675
+ "e3.record",
676
+ "declared whole",
677
+ "mutations",
678
+ "kept",
679
+ "waiting",
617
680
  "e3-cloud-files"
618
681
  ],
619
682
  "imports": [
620
- "import { East, ArrayType, DictType, FloatType, IntegerType, StringType, StructType } from '@elaraai/east';",
683
+ "import { East, DictType, IntegerType, StringType, StructType } from '@elaraai/east';",
621
684
  "import e3, { type Runner } from '@elaraai/e3';",
622
685
  "import { Files } from '@elaraai/e3-cloud-files';"
623
686
  ],
624
- "source": "// src/package.ts\nconst Price = StructType({ sku: StringType, price: FloatType });\nconst PriceBook = DictType(StringType, FloatType);\nexport const upload = Files.source('upload');\n// A beast2 file of Array<Price> (encodeBeast2For(ArrayType(Price)), east-py, e3 convert): an input of that type, taken in as the\n// value it holds, a collection of any size, its header checked first; a file of another type is refused naming both types\nexport const prices = upload.file('prices', { key: 'prices.beast2', type: ArrayType(Price) });\nexport const stock = upload.latest('stock', { prefix: 'stock/', include: '*.beast2', type: ArrayType(Price) }); // the greatest key, typed\n// A record the app's users edit, and a mutation of one argument that loads a delivery into it\nexport const priceBook = e3.record('price_book', PriceBook, new Map());\nexport const loadPrices = e3.mutation.reduce('load_prices', priceBook, East.function([PriceBook, ArrayType(Price)], PriceBook, ($, state, rows) => {\n const next = $.let(state.copy()); // the book as it is (a mutation's state is immutable), each delivered price over its sku's\n $.for(rows, ($, row) => { $(next.insertOrUpdate(row.sku, row.price, (_$, _existing, delivered) => delivered)); });\n return next;\n}));\nconst runner: Runner = { runtime: 'east-c', platforms: ['east-c-std'] };\nexport const summary = e3.task('price_summary', [prices, priceBook], East.function([ArrayType(Price), PriceBook], IntegerType, (_$, rows, book) => rows.size().add(book.size())), { runner });\nexport default e3.package('typed', '1.0.0', summary, loadPrices);\n\n// src/files.ts: each new delta file under deltas/ calls load_prices once with its value, by the file's hash; a refused file is\n// tried again only once it changes; a feed of a record with no state yet waits for it\nupload.mutation(loadPrices, { prefix: 'deltas/', include: '*.beast2' });\nexport default Files.manifest([upload]);",
687
+ "source": "// src/package.ts\nconst Customer = StructType({ name: StringType, tier: IntegerType });\nconst CustomerBook = DictType(StringType, Customer);\nexport const upload = Files.source('upload');\n// e3.record('customers', CustomerBook, parts) with no initial value: pending until customers.beast2 arrives, which is its first state ($init:\n// nothing runs on an empty state first, and the tasks over it wait as on an unset input, the run completing without them); a changed\n// file while nothing has mutated it since is its state again ($seed); once mutated it is kept, until `files sync --reset customers`\n// (or `files push --reset customers`) takes the file as its state over whatever was done. The workspace page shows it Pending, its page\n// what seeds it, `files status` prints pending; its history reads \"Initialised from customers.beast2 (2 rows)\" and \"Seeded again from …\"\n// Declared whole, as any record is: its indexes, mutations and migrations are the fourth argument, as e3.record takes them (an initial\n// value there is refused). Its mutations are any record's: after one, the file no longer seeds it until a reset\nexport const customers = upload.record('customers', CustomerBook, { key: 'customers.beast2' }, {\n mutations: (mutation) => ({\n set_tier: mutation.reduce(East.function([CustomerBook, StringType, IntegerType], CustomerBook, ($, state, key, tier) => {\n const next = $.let(state.copy());\n $(next.insertOrUpdate(key, { name: key, tier }, (_$, existing, _given) => ({ name: existing.name, tier })));\n return next;\n })),\n }),\n});\nconst runner: Runner = { runtime: 'east-c', platforms: ['east-c-std'] };\nexport const customerCount = e3.task('customer_count', [customers], East.function([CustomerBook], IntegerType, (_$, book) => book.size()), { runner });\n// The record carries its mutation: the package takes the task over it\nexport default e3.package('typed', '1.0.0', customerCount);\n\n// src/files.ts\nexport default Files.manifest([upload]);\n\n// A deploy that cannot keep the record (its type changed) under --schema reset unassigns it: pending again, seeded by the next\n// version's file once the new declarations are deployed",
688
+ "languages": [
689
+ "typescript"
690
+ ]
691
+ },
692
+ {
693
+ "id": "e3-cloud-files:static:mutation-feed",
694
+ "skill": "e3-cloud-files",
695
+ "package": "e3-cloud-files",
696
+ "file": "static",
697
+ "suite": "Files",
698
+ "test": "A record's mutation fed by files: upload.mutation(def, spec), def one the record declares (priceBook.mutations.load_prices), applies each new file the spec selects, in key order, once by its bytes' hash, as the mutation's one argument; a refused file is tried again only once it changes, a feed of a pending record waits, and each commit names its file",
699
+ "keywords": [
700
+ "Files",
701
+ "mutation",
702
+ "feed",
703
+ "fed",
704
+ "upload.mutation",
705
+ "mutation.reduce",
706
+ "mutations",
707
+ "one argument",
708
+ "idempotent",
709
+ "once per file",
710
+ "key order",
711
+ "refused",
712
+ "waiting",
713
+ "deltas",
714
+ "e3-cloud-files"
715
+ ],
716
+ "imports": [
717
+ "import { East, ArrayType, DictType, FloatType, StringType, StructType } from '@elaraai/east';",
718
+ "import e3 from '@elaraai/e3';",
719
+ "import { Files } from '@elaraai/e3-cloud-files';"
720
+ ],
721
+ "source": "// src/package.ts\nconst Price = StructType({ sku: StringType, price: FloatType });\nconst PriceBook = DictType(StringType, FloatType);\nexport const upload = Files.source('upload');\n// A record the app's users edit, declared whole with a mutation of one argument that loads a delivery into it: the record's own\n// reduce (or edit; a patch cannot be fed), its rules deciding what a delivery does. A delivery holding a price below zero is refused\n// whole: the mutation fails, the book is kept, and the file is tried again only once it changes, the files after it waiting\nexport const priceBook = e3.record('price_book', PriceBook, {\n initial: new Map(),\n mutations: (mutation) => ({\n load_prices: mutation.reduce(East.function([PriceBook, ArrayType(Price)], PriceBook, ($, state, rows) => {\n const next = $.let(state.copy()); // the book as it is (a mutation's state is immutable), each delivered price over its sku's\n $.for(rows, ($, row) => {\n $.if(row.price.lessThan(0), ($) => $.error(East.str`a price below zero: ${row.sku}`));\n $(next.insertOrUpdate(row.sku, row.price, (_$, _existing, delivered) => delivered));\n });\n return next;\n })),\n }),\n});\n// The record carries its mutation: the package takes the record\nexport default e3.package('typed', '1.0.0', priceBook);\n\n// src/files.ts: each new delta file under deltas/ calls load_prices once with its value, by the file's hash (a sync run again\n// applies nothing twice; the same bytes under another name are applied no more); a feed of a record with no state yet waits for\n// it; a sync seeds records before it feeds mutations. The commit reads in the record's history as any mutation's, through the\n// files channel, naming the file it was fed\nupload.mutation(priceBook.mutations.load_prices, { prefix: 'deltas/', include: '*.beast2' });\nexport default Files.manifest([upload]);",
625
722
  "languages": [
626
723
  "typescript"
627
724
  ]
@@ -909,7 +1006,10 @@
909
1006
  "restore",
910
1007
  "backup-pull",
911
1008
  "commit",
912
- "audit"
1009
+ "audit",
1010
+ "pending",
1011
+ "$seed",
1012
+ "seeded from a file"
913
1013
  ],
914
1014
  "imports": [],
915
1015
  "source": "e3-cloud records list https://e3.example.com/repos/acme production\ne3-cloud records history https://e3.example.com/repos/acme production orders --limit 50\ne3-cloud records show https://e3.example.com/repos/acme production orders <commit> -o orders.beast2\ne3-cloud records backup https://e3.example.com/repos/acme production orders --note \"before the import\"\ne3-cloud records rollback https://e3.example.com/repos/acme production orders <commit> # a new commit holding that state",
@@ -1109,6 +1209,45 @@
1109
1209
  "languages": [
1110
1210
  "typescript"
1111
1211
  ]
1212
+ },
1213
+ {
1214
+ "skill": "e3-cloud-client",
1215
+ "package": "e3-cloud-client",
1216
+ "file": "static",
1217
+ "id": "e3-cloud-client:static:files",
1218
+ "suite": "@elaraai/e3-cloud-client files",
1219
+ "test": "Files from code: deploy a workspace's declarations, bind a source, sync named targets (a seeded record reset) and wait for the sync's report, read what each mapping holds, and plan a push of files from disk",
1220
+ "keywords": [
1221
+ "getFiles",
1222
+ "deployFiles",
1223
+ "bindFilesSource",
1224
+ "startFilesSync",
1225
+ "filesSyncWait",
1226
+ "planFilesPush",
1227
+ "completeFilesPush",
1228
+ "FilesTarget",
1229
+ "targets",
1230
+ "reset",
1231
+ "pending",
1232
+ "seeded",
1233
+ "record",
1234
+ "mutation",
1235
+ "push",
1236
+ "unchanged",
1237
+ "refused",
1238
+ "retaken",
1239
+ "workspace_protected"
1240
+ ],
1241
+ "imports": [
1242
+ "import { none, some, variant } from '@elaraai/east';",
1243
+ "import { bindFilesSource, completeFilesPush, deployFiles, filesSyncWait, getFiles, planFilesPush, startFilesSync } from '@elaraai/e3-cloud-client';",
1244
+ "import { filesPushRefusalText, filesTargetText } from '@elaraai/e3-cloud-types';",
1245
+ "import manifest from './files.js'; // export default Files.manifest([upload])"
1246
+ ],
1247
+ "source": "// The declarations (checked against the package the workspace runs), then where the source's files are\nconst deployed = await deployFiles(url, 'acme', 'staging', manifest, options);\nif (deployed.type === 'refused') throw new Error(deployed.value.problems.map((p) => p.type).join(', '));\nawait bindFilesSource(url, 'acme', 'staging', { source: 'upload', url: 's3://partner-drop/acme/', region: none, profile: none, latest: none }, options);\n\n// A sync of two targets: the seeded record's file taken as its state again (reset), and the fed mutation's new files\nconst start = await startFilesSync(url, 'acme', 'staging', {\n targets: [variant('record', 'customers'), variant('mutation', { record: 'price_book', mutation: 'load_prices' })],\n reset: ['customers'],\n}, options);\nconst id = start.value; // started, or running: the sync under way, waited on the same way\nconst job = await filesSyncWait(url, 'acme', 'staging', id, options, { deadlineMs: 10 * 60_000 });\nfor (const m of job.report.type === 'some' ? job.report.value.mappings : []) {\n console.log(filesTargetText(m.target), m.updated ? `written (commit ${m.commit.type === 'some' ? m.commit.value.slice(0, 12) : 'none'})` : 'as it was', m.refused.length === 0 ? '' : `refused ${m.refused[0]!.key}`);\n}\n\n// What each mapping holds now; a record not yet seeded is pending\nconst files = await getFiles(url, 'acme', 'staging', options);\nconsole.log(files.status.mappings.map((m) => `${filesTargetText(m.target)}: ${m.pending ? 'pending' : m.holds.type === 'some' ? m.holds.value.key : 'nothing yet'}`).join(' · '));\n\n// A push from disk: the plan says per file where it goes and how to upload it (a single PUT here); then sync what was put\nconst plan = await planFilesPush(url, 'acme', 'staging', { files: [{ name: 'customers.beast2', directory: none, size: 4096n, sha256, type: some(customerBookType) }], as: none }, options);\nfor (const f of plan.files) {\n if (f.outcome.type === 'refused') console.warn(f.name, filesPushRefusalText(f.outcome.value));\n else if (f.outcome.type === 'put' && f.outcome.value.upload.type === 'single') {\n await fetch(f.outcome.value.upload.value.url, { method: 'PUT', body: bytes, headers: Object.fromEntries(f.outcome.value.upload.value.headers) });\n } else if (f.outcome.type === 'put' && f.outcome.value.upload.type === 'multipart') {\n const parts = []; // each part PUT to its url, its ETag kept\n await completeFilesPush(url, 'acme', 'staging', { key: f.outcome.value.key, uploadId: f.outcome.value.upload.value.uploadId, parts }, options);\n }\n}",
1248
+ "languages": [
1249
+ "typescript"
1250
+ ]
1112
1251
  }
1113
1252
  ]
1114
1253
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elaraai/e3-cloud-codex-plugin",
3
- "version": "1.0.97",
3
+ "version": "1.1.0",
4
4
  "description": "e3 cloud - apps for hosted e3 workspaces with @elaraai/e3-cloud-ui, files from buckets as inputs with @elaraai/e3-cloud-files, the e3-cloud CLI and @elaraai/e3-cloud-client: skills, example search and the search-first hooks",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "type": "module",
@@ -163,9 +163,9 @@ e3 dataflow run URL staging
163
163
 
164
164
  ### 5. Migrate a record
165
165
 
166
- A record's new type comes with a migration in the package: e3's
167
- `e3.migration.value`, `rows` or `rekey`, each step naming the one before it
168
- with `after` (the e3 skill). Then, in staging:
166
+ A record's new type comes with a migration in its own declaration: a step
167
+ added at the end of its `migrations` (`migration.value`, `rows` or `rekey`,
168
+ each named, the list's order the chain; the e3 skill). Then, in staging:
169
169
 
170
170
  ```bash
171
171
  e3-cloud records backup URL staging orders --note "before orders v2"
@@ -193,6 +193,8 @@ e3-cloud release URL staging production --plan
193
193
  e3-cloud files deploy URL staging src/files.ts
194
194
  e3-cloud files bind URL staging upload s3://bucket/acme/staging/
195
195
  e3-cloud files sync URL staging
196
+ e3-cloud files push URL staging ./data/prices.beast2 ./data/customers.beast2 # from disk: matched by name (or --as), put, synced
197
+ e3-cloud files sync URL staging --target record:customers --reset customers # named targets; a seeded record's file as its state again
196
198
  e3 dataflow run URL staging
197
199
  ```
198
200
 
@@ -317,8 +319,9 @@ e3-cloud app deploy URL staging --from-source src/apps/ops.tsx --for-platform 1.
317
319
  e3-cloud release URL staging production
318
320
  ```
319
321
 
320
- - Build with the next release's packages and stage the bundle beside the
321
- live app: it goes live when the platform moves to that e3. A release
322
+ - Build with the e3 cloud release built with the next e3 (its packages pin
323
+ it) and stage the bundle beside the live app: it goes live when the
324
+ platform moves to that e3. A release
322
325
  carries staging's staged bundles, so production gets them through its
323
326
  staging.
324
327
 
@@ -413,7 +416,7 @@ a repository URL:
413
416
  changes them, and a source may be bound before a release brings the
414
417
  declarations that read it.
415
418
  - `files sync <repo> <ws>` reads only files whose ETag or size changed and
416
- writes only inputs whose files changed; `--input`, `--dry-run`. It doesn't
419
+ writes only inputs whose files changed; `--target`, `--reset`, `--dry-run`. It doesn't
417
420
  run the dataflow: `e3 dataflow run` does, and the sync prints the command.
418
421
  - `files status <repo> <ws>`: the declarations, the bindings, the last sync.
419
422
 
@@ -431,5 +434,6 @@ a repository URL:
431
434
  hasn't bound: bind it in the target first.
432
435
  - `secrets set` reads the value from stdin unless `--value` is given; the
433
436
  next run reads the new value.
434
- - The version is the @elaraai lockstep: use the CLI of the release your
435
- deployment runs.
437
+ - The version is e3 cloud's own, not e3's: use the CLI of the e3 cloud
438
+ release your deployment runs, beside e3's CLI of the e3 that release is
439
+ built with (its dependencies pin it).
@@ -67,10 +67,44 @@ try {
67
67
  and its `undoes` lists forced changes it undoes. `rollbackWorkspace` takes
68
68
  an entry of `workspaceHistory`.
69
69
 
70
+ ## Files
71
+
72
+ - `getFiles(url, repo, ws, options)` answers a workspace's Files: its
73
+ declarations (`manifest`), where each source is bound (`bindings`), the
74
+ last sync, a sync under way, and `status` — per mapping, what it holds and
75
+ whether its record is `pending` (seeded from a file, its file not yet
76
+ arrived).
77
+ - `deployFiles(url, repo, ws, manifest, options `{ dryRun?, force? }`)` deploys declarations
78
+ (`Files.manifest(...)` from `@elaraai/e3-cloud-files`): `deployed` with
79
+ the targets the next sync takes again whole (`retaken`), `checked` for a
80
+ dry run, or `refused` with every problem. A workspace with a staging
81
+ refuses it (`workspace_protected`) unless an admin forces it.
82
+ - `bindFilesSource(url, repo, ws, binding, options)` says where a source's
83
+ files are (`s3://bucket/prefix/`): `bound` with what the next sync takes
84
+ again, or `refused` (a bucket the deployment does not let the repository
85
+ bind). Bindings are each workspace's own; a release never changes them.
86
+ - `startFilesSync(url, repo, ws, { dryRun?, targets?, reset? }, options)`
87
+ answers `started` with the sync's id, or `running` with the one under way;
88
+ `filesSyncWait(url, repo, ws, id, options, { deadlineMs?, refresh?, signal? })`
89
+ polls it to its end and answers the job, its `report` per target (what was
90
+ taken, the commit a seed or feed made, what was refused and why, what
91
+ waits). `targets` are `variant('input', name)`, `variant('record', name)`
92
+ or `variant('mutation', { record, mutation })`; `reset` names seeded
93
+ records whose file is taken as their state again.
94
+ - `planFilesPush(url, repo, ws, { files, as }, options)` plans a push of
95
+ files from disk (each offered with its name, size, SHA-256 and beast2
96
+ header type): per file `put` with its key and how to upload it — `single`
97
+ (one PUT with the plan's headers), `multipart` (a URL per part, then
98
+ `completeFilesPush(url, repo, ws, { key, uploadId, parts }, options)`) or
99
+ `external` (your own credentials) — `unchanged`, or `refused` with why
100
+ (`filesPushRefusalText`). Then sync the targets put. The CLI's
101
+ `files push` does all of this.
102
+
70
103
  ## Traps
71
104
 
72
105
  - The URL is the deployment's origin, not `…/api`: the client adds the path.
73
106
  - A refusal of a release or an app deploy is an answer (`refused`), not a
74
107
  throw; a request the server cannot take at all throws `ApiError`.
75
- - The version is the @elaraai lockstep: use the client of the release the
76
- deployment runs.
108
+ - The version is e3 cloud's own, shared by every e3 cloud package and
109
+ independent of e3's: use the client of the e3 cloud release the deployment
110
+ runs, beside the east and e3 it pins.
@@ -5,7 +5,7 @@ description: "Files for e3 cloud — a solution's inputs that come from files in
5
5
 
6
6
  ## Detailed skill scope
7
7
 
8
- Files for e3 cloud — a solution's inputs that come from files in a bucket (s3://bucket/prefix/), declared in its code and synced when asked, the same on a local repository and a deployed workspace. Use when: (1) Declaring which inputs a bucket's files fill with Files.source(name) and its file, latest, folder and listing, then Files.manifest([...]) as a module's default export, (2) Decoding what arrives in a task: a Blob (file, latest), a Dict of path to Blob (folder) or a listing of sizes, times and ETags, as East's JSON, CSV or text, (3) Deploying the declarations to a workspace and binding each source to s3://bucket/prefix/ with e3-cloud files deploy and bind, (4) Syncing what changed with e3-cloud files sync, locally with your own cloud profile (--profile, --latest), then running the dataflow with e3 dataflow run, (5) Reading a refusal: declarations that don't fit the package (FilesDeclarationError, a deploy's problems), an unbound source, a file over its limit, a protected workspace (workspace_protected), (6) Moving declarations to production through staging: a release carries them with the package and apps, a rollback restores them, a copy brings bindings and what each input took, and production's bindings stay its own, (7) Reading Files' East types (FilesManifestType, FilesBindingType, FilesSyncReportType — @elaraai/e3-cloud-types), (8) Taking a beast2 file in as an input of its type with no task in between: file or latest with a type, a collection of any size, (9) Feeding a record's mutation from files with source.mutation(def, spec), each new file applied once, (10) Pushing files from disk into a source and taking them in with e3-cloud files push, matched by name or --as, dry-run, unchanged, (11) Syncing or resetting particular targets with --target and --reset.
8
+ Files for e3 cloud — a solution's inputs that come from files in a bucket (s3://bucket/prefix/), declared in its code and synced when asked, the same on a local repository and a deployed workspace. Use when: (1) Declaring which inputs a bucket's files fill with Files.source(name) and its file, latest, folder and listing, then Files.manifest([...]) as a module's default export, (2) Decoding what arrives in a task: a Blob (file, latest), a Dict of path to Blob (folder) or a listing of sizes, times and ETags, as East's JSON, CSV or text, (3) Deploying the declarations to a workspace and binding each source to s3://bucket/prefix/ with e3-cloud files deploy and bind, (4) Syncing what changed with e3-cloud files sync, locally with your own cloud profile (--profile, --latest), then running the dataflow with e3 dataflow run, (5) Reading a refusal: declarations that don't fit the package (FilesDeclarationError, a deploy's problems), an unbound source, a file over its limit, a protected workspace (workspace_protected), (6) Moving declarations to production through staging: a release carries them with the package and apps, a rollback restores them, a copy brings bindings and what each input took, and production's bindings stay its own, (7) Reading Files' East types (FilesManifestType, FilesBindingType, FilesSyncReportType — @elaraai/e3-cloud-types), (8) Taking a beast2 file in as an input of its type with no task in between: file or latest with a type, a collection of any size, (9) Feeding a record's mutation from files with source.mutation(def, spec), def one its record declares (priceBook.mutations.load_prices), each new file applied once, (10) Pushing files from disk into a source and taking them in with e3-cloud files push, matched by name or --as, dry-run, unchanged, (11) Seeding a record from a file with source.record(name, type, spec, parts): e3.record with no initial value, declared whole with its indexes, mutations and migrations, pending until its file, its tasks waiting meanwhile, (12) Syncing or resetting particular targets with --target and --reset.
9
9
 
10
10
  # e3-cloud-files — files as e3 inputs
11
11
 
@@ -74,7 +74,8 @@ What do you need?
74
74
  │ ├─ A beast2 file as its value → source.file(input, { key, type: ArrayType(Row) }) input: Array<Row>, no task between
75
75
  │ ├─ The newest of a folder → source.latest(input, { prefix, include? }) input: Blob, the greatest key
76
76
  │ ├─ The newest, typed → source.latest(input, { prefix, include?, type })
77
- │ ├─ Feed a record's mutation → source.mutation(def, { key } | { prefix, include? }) each new file calls it once
77
+ │ ├─ A record's first state → source.record(name, type, { key } | { prefix, include? }, parts?) e3.record(name, type, parts): pending until its file
78
+ │ ├─ Feed a record's mutation → source.mutation(record.mutations.<name>, { key } | { prefix, include? }) every new file, in key order, once
78
79
  │ ├─ Every file of a folder → source.folder(input, { prefix, include? }) input: Dict<String, Blob> by path
79
80
  │ ├─ A folder's files, not bytes → source.listing(input, { prefix, include? }) input: Dict<String, {size, modified, etag}>
80
81
  │ ├─ Subfolders' files too → include: '**/*.csv' ('*.csv' is the top level only)
@@ -122,6 +123,9 @@ export const rates = upload.file('rates', { key: 'rates.json' });
122
123
  export const stock = upload.latest('stock', { prefix: 'stock/', include: '*.json' }); // input: Blob, the greatest key
123
124
  export const orders = upload.folder('orders', { prefix: 'orders/', include: '*.json' }); // input: Dict<String, Blob>
124
125
  export const orderFiles = upload.listing('order_files', { prefix: 'orders/' }); // input: each file's size, modified, etag
126
+ export const prices = upload.file('prices', { key: 'prices.beast2', type: ArrayType(Price) }); // input: Array<Price>: the beast2 file's value, any size
127
+ export const customers = upload.record('customers', CustomerBook, { key: 'customers.beast2' }); // a record, e3.record('customers', CustomerBook): pending until its file
128
+ upload.mutation(priceBook.mutations.load_prices, { prefix: 'deltas/', include: '*.beast2' }); // each new delta file fed to the record's mutation, in key order
125
129
 
126
130
  export default Files.manifest([upload]); // what e3-cloud files deploy deploys
127
131
  ```
@@ -131,9 +135,22 @@ export default Files.manifest([upload]); // what e3-cloud files deploy dep
131
135
  `file` or `latest` with a `type` is an input of that type: the file must be
132
136
  beast2 of it (`encodeBeast2For(T)`, east-py, `e3 convert`), a collection of
133
137
  any size, checked by its header before any other byte is read.
134
- - `source.mutation(def, spec)` feeds a record's mutation: `def` is the
135
- package's `e3.mutation.reduce` or `edit` taking exactly one argument, and
136
- each new file is applied once, by its hash.
138
+ - `source.record(name, type, spec, parts?)` is `e3.record(name, type, parts)`
139
+ with no initial value. It is declared whole: its indexes, mutations and
140
+ migrations are `parts`, as `e3.record` takes them
141
+ (`{ mutations: (mutation) => ({ set_tier: mutation.reduce(fn) }) }`), and an
142
+ initial value is refused. It is pending until its file arrives, which is
143
+ its first state (`$init`; nothing runs on an empty state first, and the
144
+ tasks over it wait as on an unset input, the run completing without them).
145
+ A changed file while nothing has mutated it since is its state again
146
+ (`$seed`); mutated since, it is kept until `files sync --reset <record>`.
147
+ - `source.mutation(def, spec)` feeds a record's mutation: `def` is one the
148
+ record declares, `record.mutations.<name>`, a `reduce` or an `edit` taking
149
+ exactly one argument. Every new file the spec selects (one key, or each
150
+ under the prefix its glob matches) is applied in key order, once by its
151
+ bytes' hash, so the same bytes under another name are applied no more; a
152
+ file the mutation refuses holds the ones after it until it changes; a busy
153
+ record leaves the file to the next sync.
137
154
  - Keys and prefixes are relative to where a workspace binds the source; a
138
155
  prefix is `''` or ends with `/`.
139
156
  - `include` is a glob over the path under the prefix: `*` within one folder,
@@ -172,7 +189,14 @@ name, a `latest` under its prefix, a directory to the `folder`; `--as` names
172
189
  one), checks its type and size, puts it where the source is bound (the
173
190
  platform signs the upload into the deployment's own bucket, bound to the
174
191
  file's SHA-256; your own credentials elsewhere), then syncs what was put. A
175
- file the source holds already is `unchanged`.
192
+ file the source holds already is `unchanged`; refused: `no_mapping`,
193
+ `ambiguous` (name the target with `--as`), `not_included` (the mapping's
194
+ glob leaves it out), `not_latest` (a greater key would shadow it), a typed
195
+ mapping's file of another type or no beast2, one over the limit.
196
+
197
+ `--target` names an input, `record:<name>` or `mutation:<record>.<name>`
198
+ (split at its last dot); `--reset <record>` takes a seeded record's file as
199
+ its state again, whatever mutated it since.
176
200
 
177
201
  `<repo>` is a local repository's path or a repository URL. Deploy the package
178
202
  first (`e3 workspace deploy`), then the declarations, which are checked
@@ -193,9 +217,20 @@ keeps only each folder's n greatest keys.
193
217
  (`type_mismatch` with both types, `not_beast2`): the input keeps its value.
194
218
  A typed value that is no collection is at most 1 GiB; a collection's
195
219
  segments at most 64 MiB (`segment_too_large`: write it again).
196
- - A seeded record (`upload.record`) waits for the e3 release that lets a
197
- record be declared with no initial value; the rest of typed files, feeds
198
- and push is here now.
220
+ - A seeded record (`upload.record(name, type, { key })`) is pending until
221
+ its file, which is its first state (`$init`); a changed file seeds it
222
+ again while unmutated (`$seed`), `--reset` does whatever was done since;
223
+ the tasks over it wait meanwhile. The workspace page shows it Pending, its
224
+ page says what seeds it, `files status` prints `pending`; its seeds read
225
+ "Initialised from customers.beast2 (12,004 rows)" / "Seeded again from …"
226
+ in its history (the record page, `e3-cloud records history`), a feed names
227
+ its file. A deploy that cannot keep it (its type changed) under
228
+ `--schema reset` unassigns it: pending again, seeded by the next version's
229
+ file.
230
+ - A record is declared whole: a fed mutation is one its record declares
231
+ (`priceBook.mutations.load_prices`), and a seeded record's indexes,
232
+ mutations and migrations are `upload.record`'s `parts`; an initial value
233
+ there is refused, its file being its first state.
199
234
  - A file over 1 GiB less 64 KiB (`file`, `latest`), or over 64 MiB less
200
235
  64 KiB in a folder, is refused and named in the report, never truncated.
201
236
  So is a file the sync can't read (archived, under a key it may not use,
@@ -213,7 +248,9 @@ keeps only each folder's n greatest keys.
213
248
  - Bindings never travel with a release; a copy carries them. A staging
214
249
  started as a copy of production reads production's files until you bind it
215
250
  elsewhere.
216
- - The version is the @elaraai lockstep: use the same version as east and e3.
251
+ - The version is e3 cloud's own, not e3's: install the release built with the
252
+ e3 the deployment runs, its peers (east, e3) at exactly the versions it
253
+ names, and the `e3-cloud` CLI of the same release.
217
254
 
218
255
  ## Related skills
219
256
 
@@ -64,7 +64,10 @@ const overview = Page('overview', { title: 'Overview', icon: 'gauge-high' },
64
64
  - The function's **one argument is the page's params** (or none). Never write
65
65
  the type separately: TypeScript takes it from the function.
66
66
  - Bind data exactly as a `ui()` body does: `Data.bind`, `Data.bindPaged`,
67
- `Func.bind`, `Record.bind`. Pass the defs, never names.
67
+ `Func.bind`, `Record.bind`. Pass the defs, never a dataset's or a
68
+ function's name; a record's mutations and indexes are named as the record
69
+ declares them: `Record.bind(orders, ['approve'])`,
70
+ `Data.bindPaged(orders, { index: 'by_line' })`.
68
71
  - `meta.parent` makes the crumbs and lights the menu item.
69
72
  - Bind event handlers once: `const go = $.const(East.function([], NullType, $ => { $(Nav.go(line, key)); }))`.
70
73
 
@@ -103,6 +106,12 @@ on the workspace fits.
103
106
  - A body written without the thunk can only link to pages defined above it.
104
107
  - A page that writes a task's output or a record through `Data.bind` is
105
108
  refused: write inputs; change records through their mutations.
109
+ - A record is declared whole: its indexes, mutations and migrations in its
110
+ own `e3.record(name, type, { initial, indexes, mutations, migrations })`.
111
+ `e3.package` takes the record, never one of its parts.
106
112
  - `Page.task` needs a task in the `ui` role (`ui()`), and its output shows only
107
113
  after the workspace's next dataflow run.
108
- - The version is the @elaraai lockstep: use the same version as east and e3.
114
+ - The version is e3 cloud's own, not e3's: install the release built with the
115
+ e3 the deployment runs, its peers (east, east-ui, e3, e3-ui) at exactly the
116
+ versions it names. An app built with another e3 than the platform's is
117
+ refused, naming both.