@weaveprotocol/cli 0.2.3 → 0.2.4

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 (2) hide show
  1. package/dist/weave.mjs +28 -3
  2. package/package.json +1 -1
package/dist/weave.mjs CHANGED
@@ -12942,7 +12942,8 @@ var app = {
12942
12942
  title: { type: "string", minLength: 1, maxLength: 100 },
12943
12943
  description: { type: "string", maxLength: 1e3 },
12944
12944
  needs: { type: "array", minItems: 1, maxItems: MAX_APP_COLLECTIONS, items: { type: "object" } },
12945
- from: { type: "string", maxLength: 300 }
12945
+ from: { type: "string", maxLength: 300 },
12946
+ updates: { type: "string", minLength: 1, maxLength: 100 }
12946
12947
  },
12947
12948
  required: ["title", "needs"]
12948
12949
  },
@@ -12956,6 +12957,9 @@ function checkApp(value) {
12956
12957
  if (body.description !== void 0 && (typeof body.description !== "string" || body.description.length > 1e3)) {
12957
12958
  return "An app's description is at most 1000 characters";
12958
12959
  }
12960
+ if (body.updates !== void 0 && (typeof body.updates !== "string" || !body.updates || body.updates.length > 100)) {
12961
+ return `An app's "updates" is the key of the app it replaces`;
12962
+ }
12959
12963
  if (!Array.isArray(body.needs) || body.needs.length === 0 || body.needs.length > MAX_APP_COLLECTIONS) {
12960
12964
  return `An app needs 1\u2013${MAX_APP_COLLECTIONS} collections`;
12961
12965
  }
@@ -13031,9 +13035,25 @@ function reviewApp(body, collections) {
13031
13035
  });
13032
13036
  return { needs, added: needs.every((need) => need.status === "same"), problem: null };
13033
13037
  }
13038
+ function supersededApps(records, collections) {
13039
+ const replaces = /* @__PURE__ */ new Map();
13040
+ for (const record of records) {
13041
+ if (record.body?.updates && record.body.updates !== record.key) replaces.set(record.key, record.body.updates);
13042
+ }
13043
+ const superseded = /* @__PURE__ */ new Set();
13044
+ for (const record of records) {
13045
+ if (!record.body || !reviewApp(record.body, collections).added) continue;
13046
+ for (let key3 = replaces.get(record.key); key3 && !superseded.has(key3) && key3 !== record.key; key3 = replaces.get(key3)) superseded.add(key3);
13047
+ }
13048
+ return superseded;
13049
+ }
13034
13050
  async function proposeApp(node, spaceId, body) {
13035
13051
  const problem = checkApp(body);
13036
13052
  if (problem) throw new Error(problem);
13053
+ if (body.updates) {
13054
+ const replaced = await node.records.get(spaceId, body.updates);
13055
+ if (!replaced || replaced.collection !== app.name) throw new Error(`"updates" names no app in this space: ${body.updates}`);
13056
+ }
13037
13057
  return node.records.put(spaceId, app.name, body);
13038
13058
  }
13039
13059
 
@@ -13280,7 +13300,7 @@ var NODE_ACTIONS = Object.freeze([
13280
13300
  },
13281
13301
  {
13282
13302
  name: "apps_list",
13283
- description: 'The apps proposed in a space: each with its title, who proposed it (viaAgent when an agent did), and for every collection it needs whether it is new, already there, or would change one \u2014 with what it allows, worked out from its rules. "added" is true once a person has added it.',
13303
+ description: 'The apps proposed in a space: each with its title, who proposed it (viaAgent when an agent did), and for every collection it needs whether it is new, already there, or would change one \u2014 with what it allows, worked out from its rules. "added" is true once a person has added it. "updates" names the app it is a new version of; "superseded" is true once a newer version of it has been added, so it is only history.',
13284
13304
  input: { type: "object", properties: { space }, required: ["space"] },
13285
13305
  readOnly: true,
13286
13306
  peerContent: true,
@@ -13288,6 +13308,7 @@ var NODE_ACTIONS = Object.freeze([
13288
13308
  const spaceId = str(input, "space");
13289
13309
  const collections = await node.collections.list(spaceId);
13290
13310
  const found = await node.records.list(spaceId, { collection: app.name });
13311
+ const superseded = supersededApps(found, collections);
13291
13312
  return found.map((record) => {
13292
13313
  const review = record.body ? reviewApp(record.body, collections) : null;
13293
13314
  return {
@@ -13297,7 +13318,9 @@ var NODE_ACTIONS = Object.freeze([
13297
13318
  proposedBy: record.createdBy,
13298
13319
  ...record.viaAgent ? { viaAgent: true } : {},
13299
13320
  ...record.body && appScreen(record.body) ? { screen: appScreen(record.body).collection } : {},
13321
+ ...record.body?.updates ? { updates: record.body.updates } : {},
13300
13322
  added: review?.added ?? false,
13323
+ superseded: superseded.has(record.key),
13301
13324
  problem: review?.problem ?? (record.body ? null : "It could not be read"),
13302
13325
  needs: review?.needs.map(({ definition, status, summary, changes }) => ({ name: definition.name, status, summary, changes })) ?? []
13303
13326
  };
@@ -13313,13 +13336,14 @@ var NODE_ACTIONS = Object.freeze([
13313
13336
  },
13314
13337
  {
13315
13338
  name: "apps_propose",
13316
- description: `Propose an app in a space: a new way for its people to work together \u2014 a carpool, a sign-up sheet, a decision log. Give it a title, a line on what it is for, and the collections it needs, each exactly as collections_define takes it (name, title, description, schema, links, permissions, rules \u2014 no version). Nothing is defined yet: everyone in the space sees the proposal, with what it allows worked out from its rules, and a person who may define collections adds it. Read collections_list first and reuse what the space already has (std.poll, std.task\u2026) rather than inventing a twin. For anything plain lists and forms can't show \u2014 a game board, a calendar, a whiteboard \u2014 give the main collection a "screen": its own HTML UI (one document, inline scripts and styles, no network unless the collection names exact origins in "network"). Inside it, use exactly: weave.me ({ did, name }), await weave.list("<collection>", { where: { "link:<rel>": key } }), await weave.put("<collection>", body, { links: [{ rel, to: key }] }), await weave.update(key, body), await weave.remove(key), weave.onChange(redraw). Records are { key, body, links, createdBy, mine }. Read apps_screen_guide for the rest. Returns what each collection will allow; tell the person that, not your own description.`,
13339
+ description: `Propose an app in a space: a new way for its people to work together \u2014 a carpool, a sign-up sheet, a decision log. Give it a title, a line on what it is for, and the collections it needs, each exactly as collections_define takes it (name, title, description, schema, links, permissions, rules \u2014 no version). Nothing is defined yet: everyone in the space sees the proposal, with what it allows worked out from its rules, and a person who may define collections adds it. Read collections_list first and reuse what the space already has (std.poll, std.task\u2026) rather than inventing a twin. To change an app that is already here, read apps_list and pass the key of its newest version, the one not superseded, as "updates": the change then shows as an update to it, and once it is added the old version is not offered again. For anything plain lists and forms can't show \u2014 a game board, a calendar, a whiteboard \u2014 give the main collection a "screen": its own HTML UI (one document, inline scripts and styles, no network unless the collection names exact origins in "network"). Inside it, use exactly: weave.me ({ did, name }), await weave.list("<collection>", { where: { "link:<rel>": key } }), await weave.put("<collection>", body, { links: [{ rel, to: key }] }), await weave.update(key, body), await weave.remove(key), weave.onChange(redraw). Records are { key, body, links, createdBy, mine }. Read apps_screen_guide for the rest. Returns what each collection will allow; tell the person that, not your own description.`,
13317
13340
  input: {
13318
13341
  type: "object",
13319
13342
  properties: {
13320
13343
  space,
13321
13344
  title: { type: "string", description: 'What people will call it, e.g. "Carpool"' },
13322
13345
  description: { type: "string", description: "What it is for, in a sentence" },
13346
+ updates: { type: "string", description: "The key of the app this is a new version of, from apps_list" },
13323
13347
  needs: {
13324
13348
  type: "array",
13325
13349
  description: "Collection definitions, as collections_define takes them \u2014 without version",
@@ -13334,6 +13358,7 @@ var NODE_ACTIONS = Object.freeze([
13334
13358
  const body = {
13335
13359
  title: str(input, "title"),
13336
13360
  ...typeof input.description === "string" ? { description: input.description } : {},
13361
+ ...typeof input.updates === "string" ? { updates: input.updates } : {},
13337
13362
  needs: input.needs
13338
13363
  };
13339
13364
  const problem = checkApp(body);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weaveprotocol/cli",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "The Weave protocol from a terminal: manage spaces, run an always-on node, serve MCP to agents",
5
5
  "type": "module",
6
6
  "bin": {