cherry-works 0.3.0 → 0.5.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.
package/dist/main.js CHANGED
@@ -6,7 +6,7 @@ import { pathToFileURL as pathToFileURL2 } from "url";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "cherry-works",
9
- version: "0.3.0",
9
+ version: "0.5.0",
10
10
  description: "The charter engine: resolves a charter and compiles it into what a coding agent reads.",
11
11
  keywords: [
12
12
  "claude-code",
@@ -48,8 +48,6 @@ var package_default = {
48
48
  test: 'pnpm run lint:deps && pnpm run build && node --import tsx --test "test/**/*.test.ts"',
49
49
  cw: "node --import tsx main.ts",
50
50
  "lint:deps": "depcruise src main.ts",
51
- "specs:link": "node --import tsx scripts/link-specs.ts",
52
- "specs:check": "node --import tsx scripts/link-specs.ts --check",
53
51
  release: "node --import tsx scripts/release.ts",
54
52
  prepublishOnly: `node -e "console.error('Publish with \\"pnpm release <version>\\", which checks the package first.'); process.exit(1)"`
55
53
  },
@@ -474,21 +472,21 @@ var DoctorCommand = class {
474
472
 
475
473
  // src/driver/cli/commands/EditCommand.ts
476
474
  var OPTIONS2 = {
477
- identity: {
475
+ id: {
478
476
  type: "string",
479
- describe: 'What the primitive is named by across the whole charter: "guide:no-any"'
477
+ describe: 'What the primitive is named by across the whole charter, its id: "no-any"'
480
478
  }
481
479
  };
482
480
  var EditCommand = class {
483
- name = "edit <identity>";
481
+ name = "edit <id>";
484
482
  summary = "Open the file of one primitive in your editor";
485
483
  options = OPTIONS2;
486
- async run({ cwd, charterAuthoringApp: charterAuthoringApp2 }, { identity }) {
487
- const primitive = (await charterAuthoringApp2.open(identity ?? "")).data;
484
+ async run({ cwd, charterAuthoringApp: charterAuthoringApp2 }, { id }) {
485
+ const primitive = (await charterAuthoringApp2.open(id ?? "")).data;
488
486
  if (primitive.layerName === BUILTIN_LAYER)
489
487
  throw new DomainFault(
490
- `${primitive.identity} is built into cw, and there is no file of it in this repository to edit.`,
491
- `To differ from it, run "cw add" for a primitive of your own under an identity of its own.`
488
+ `${primitive.id} is built into cw, and there is no file of it in this repository to edit.`,
489
+ `To differ from it, run "cw add" for a primitive of your own under an id of its own.`
492
490
  );
493
491
  const problem = await editInEditor(cwd, primitive.file);
494
492
  if (problem !== void 0) return { code: EXIT_FAILURE, problem };
@@ -501,17 +499,17 @@ var EditCommand = class {
501
499
 
502
500
  // src/driver/cli/commands/ExplainCommand.ts
503
501
  var OPTIONS3 = {
504
- identity: {
502
+ id: {
505
503
  type: "string",
506
- describe: 'What the primitive is named by across the whole charter: "guide:no-any"'
504
+ describe: 'What the primitive is named by across the whole charter, its id: "no-any"'
507
505
  }
508
506
  };
509
507
  var ExplainCommand = class {
510
- name = "explain <identity>";
511
- summary = "Say which file declares an identity, and which layer it came from";
508
+ name = "explain <id>";
509
+ summary = "Say which file declares an id, and which layer it came from";
512
510
  options = OPTIONS3;
513
- async run({ charterAuthoringApp: charterAuthoringApp2 }, { identity }) {
514
- const explanationOutcomeDTO2 = await charterAuthoringApp2.explain(identity ?? "");
511
+ async run({ charterAuthoringApp: charterAuthoringApp2 }, { id }) {
512
+ const explanationOutcomeDTO2 = await charterAuthoringApp2.explain(id ?? "");
515
513
  if (explanationOutcomeDTO2.type === "FaultsByFile") {
516
514
  const noOfFiles = Object.keys(explanationOutcomeDTO2.data.files).length;
517
515
  return {
@@ -527,16 +525,16 @@ Run "cw doctor" to see what is wrong with them.
527
525
  return {
528
526
  code: EXIT_OK,
529
527
  result: [
530
- `${primitive.data.identity} ${primitive.data.description}`,
528
+ `${primitive.data.id} ${primitive.data.description}`,
531
529
  ` ${primitive.data.file}`,
532
530
  ` ${layer(primitive.data.layerName)}`,
533
531
  ` comes up when ${activatesWhen}`,
534
532
  ...declaredHeaders.map(([name, value]) => ` declares ${name}: ${typeof value === "string" ? value : value.join(", ")}`),
535
- ...useMixins.map(({ data }) => ` uses mixin ${data.identity}`),
536
- ...rationale !== void 0 ? [` rationale ${rationale.data.identity}`] : citedRationale !== void 0 ? [` rationale ${String(citedRationale)} (does not resolve)`] : [],
537
- ...hosts.map(({ data }) => ` mixin of ${data.identity}`),
538
- ...citers.map(({ data }) => ` rationale of ${data.identity}`),
539
- ...mentioners.map(({ data }) => ` mentioned in ${data.identity}`),
533
+ ...useMixins.map(({ data }) => ` uses mixin ${data.id}`),
534
+ ...rationale !== void 0 ? [` rationale ${rationale.data.id}`] : citedRationale !== void 0 ? [` rationale ${String(citedRationale)} (does not resolve)`] : [],
535
+ ...hosts.map(({ data }) => ` mixin of ${data.id}`),
536
+ ...citers.map(({ data }) => ` rationale of ${data.id}`),
537
+ ...mentioners.map(({ data }) => ` mentioned in ${data.id}`),
540
538
  ...Object.entries(testCasesByFile.data).flatMap(
541
539
  ([file, situations]) => situations.map((situation) => ` pinned down by ${file}: ${situation}`)
542
540
  ),
@@ -677,7 +675,7 @@ var LISTING = {
677
675
  kind: { type: "string", describe: "Only the primitives of this kind" },
678
676
  min: {
679
677
  type: "boolean",
680
- describe: "What an agent surveys by: identity and description, nothing else",
678
+ describe: "What an agent surveys by: id and description, nothing else",
681
679
  default: false
682
680
  }
683
681
  };
@@ -711,8 +709,8 @@ Run "cw doctor" to see what is wrong with them.
711
709
  };
712
710
  }
713
711
  };
714
- function surveyed({ data: { identity, description } }) {
715
- return `${identity} ${description}`;
712
+ function surveyed({ data: { id, description } }) {
713
+ return `${id} ${description}`;
716
714
  }
717
715
  function inFull(entry) {
718
716
  const { file, globs } = entry.data;
@@ -722,9 +720,9 @@ function inFull(entry) {
722
720
  // src/driver/cli/commands/McpAuthCommand.ts
723
721
  import prompts3 from "prompts";
724
722
  var OPTIONS6 = {
725
- identity: {
723
+ id: {
726
724
  type: "string",
727
- describe: 'One mcp whose address to sign in to again, whatever you were signed in as: "mcp:github/billing"'
725
+ describe: 'One mcp whose address to sign in to again, whatever you were signed in as: "github/billing"'
728
726
  },
729
727
  status: {
730
728
  type: "boolean",
@@ -733,28 +731,28 @@ var OPTIONS6 = {
733
731
  }
734
732
  };
735
733
  var McpAuthCommand = class {
736
- name = "mcp auth [identity]";
734
+ name = "mcp auth [id]";
737
735
  summary = "Sign in, as yourself, to every place the charter reaches";
738
736
  options = OPTIONS6;
739
- async run({ mcpConnectingApp: mcpConnectingApp2 }, { identity, status }) {
737
+ async run({ mcpConnectingApp: mcpConnectingApp2 }, { id, status }) {
740
738
  const signInStatuses = (await mcpConnectingApp2.signInStatus()).map((one) => one.data);
741
739
  if (status)
742
740
  return {
743
741
  code: EXIT_OK,
744
742
  result: signInStatuses.length === 0 ? "No place the last build listed takes a sign-in.\n" : signInStatuses.map(
745
- ({ address, identities, signedIn, method }) => [address, ` ${identities.join(", ")}`, ` ${signedIn ? `signed in by ${method}` : "not signed in"}`, ""].join("\n")
743
+ ({ address, ids, signedIn, method }) => [address, ` ${ids.join(", ")}`, ` ${signedIn ? `signed in by ${method}` : "not signed in"}`, ""].join("\n")
746
744
  ).join("")
747
745
  };
748
746
  let unsignedStatuses;
749
- if (identity === void 0) unsignedStatuses = signInStatuses.filter((one) => !one.signedIn);
747
+ if (id === void 0) unsignedStatuses = signInStatuses.filter((one) => !one.signedIn);
750
748
  else {
751
- const identityStatus = signInStatuses.find((one) => one.identities.includes(identity));
752
- if (identityStatus === void 0)
749
+ const signInStatus = signInStatuses.find((one) => one.ids.includes(id));
750
+ if (signInStatus === void 0)
753
751
  throw new DomainFault(
754
- `No place the last build listed is declared by ${identity}.`,
752
+ `No place the last build listed is declared by ${id}.`,
755
753
  'Run "cw mcp auth --status" to see every mcp, or "cw build" if the charter changed.'
756
754
  );
757
- unsignedStatuses = [identityStatus];
755
+ unsignedStatuses = [signInStatus];
758
756
  }
759
757
  if (unsignedStatuses.length === 0)
760
758
  return {
@@ -772,9 +770,9 @@ var McpAuthCommand = class {
772
770
  ""
773
771
  ].join("\n")
774
772
  };
775
- for (const { address, identities, auth: auth2 } of unsignedStatuses) {
773
+ for (const { address, ids, auth: auth2 } of unsignedStatuses) {
776
774
  process.stderr.write(`${address}
777
- ${identities.join(", ")}
775
+ ${ids.join(", ")}
778
776
  `);
779
777
  const { method } = auth2.length > 1 ? await prompts3({
780
778
  type: "select",
@@ -858,7 +856,7 @@ import { serveStatic } from "@hono/node-server/serve-static";
858
856
  // src/driver/portal/routes.ts
859
857
  import { createRoute, OpenAPIHono } from "@hono/zod-openapi";
860
858
  import { HTTPException } from "hono/http-exception";
861
- import { z as z12 } from "zod";
859
+ import { z as z8 } from "zod";
862
860
 
863
861
  // src/hexagon/port/driver/dtos/dto.ts
864
862
  import { z } from "zod";
@@ -894,7 +892,7 @@ var PrimitiveKindsSchema = dto("PrimitiveKinds", z2.record(z2.string(), z2.strin
894
892
  var CatalogueEntrySchema = dto(
895
893
  "CatalogueEntry",
896
894
  z2.object({
897
- identity: z2.string(),
895
+ id: z2.string(),
898
896
  kind: z2.string(),
899
897
  description: z2.string(),
900
898
  file: z2.string(),
@@ -910,7 +908,7 @@ var CatalogueSchema = dto(
910
908
  var PrimitiveSchema = dto(
911
909
  "Primitive",
912
910
  z2.object({
913
- identity: z2.string(),
911
+ id: z2.string(),
914
912
  kind: z2.string(),
915
913
  description: z2.string(),
916
914
  file: z2.string(),
@@ -972,7 +970,7 @@ var TestCaseSchema = dto(
972
970
  z2.object({
973
971
  situation: z2.string(),
974
972
  expectation: z2.string(),
975
- identity: z2.string().optional()
973
+ id: z2.string().optional()
976
974
  })
977
975
  );
978
976
  var TestSuiteSchema = dto(
@@ -995,7 +993,7 @@ var SignInStatusSchema = dto(
995
993
  "SignInStatus",
996
994
  z2.object({
997
995
  address: z2.string(),
998
- identities: StringsSchema,
996
+ ids: StringsSchema,
999
997
  auth: z2.array(z2.enum(["oauth", "token"])).readonly(),
1000
998
  signedIn: z2.boolean(),
1001
999
  method: z2.enum(["oauth", "token"]).optional()
@@ -1078,10 +1076,10 @@ var ExplanationOutcomeSchema = dto(
1078
1076
  var OutcomeDTOs = byType(DoctorOutcomeSchema, ExplanationOutcomeSchema);
1079
1077
 
1080
1078
  // src/hexagon/domain/models/test/TestSuite.ts
1081
- import { z as z11 } from "zod";
1079
+ import { z as z7 } from "zod";
1082
1080
 
1083
1081
  // src/hexagon/domain/models/test/TestCase.ts
1084
- import { z as z10 } from "zod";
1082
+ import { z as z6 } from "zod";
1085
1083
 
1086
1084
  // src/hexagon/domain/models/charter/primitive/SensorPrimitive.ts
1087
1085
  import { z as z5 } from "zod";
@@ -1100,7 +1098,7 @@ function shortenStringsOf(strings) {
1100
1098
  const shortStrings = {};
1101
1099
  const takenShortStrings = /* @__PURE__ */ new Set();
1102
1100
  for (const string of [...new Set(strings)].sort()) {
1103
- const firstSegment = string.slice(string.indexOf(":") + 1).split("/")[0];
1101
+ const firstSegment = string.split("/")[0];
1104
1102
  let hash = 2166136261;
1105
1103
  for (const char of string) hash = Math.imul(hash ^ char.charCodeAt(0), 16777619);
1106
1104
  const hashedString = `${firstSegment}_${(hash >>> 0).toString(16).padStart(8, "0").slice(0, 4)}`;
@@ -1118,11 +1116,14 @@ function contentHashOf(content) {
1118
1116
  }
1119
1117
 
1120
1118
  // src/hexagon/domain/models/charter/primitive/BasePrimitive.ts
1119
+ var ID_SOURCE = /[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\/[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*/.source;
1120
+ var REFERENCE = new RegExp(`\\[\\[(${ID_SOURCE})\\]\\]`, "g");
1121
+ var TOOL_REFERENCE = new RegExp(`^\\[\\[(${ID_SOURCE})\\]\\](?::([^:\\s]+))?$`);
1121
1122
  var DELIMITER = "---";
1122
1123
  var GoodLineSchema = z4.string().regex(/\S/);
1123
1124
  var GoodArraySchema = z4.array(GoodLineSchema).min(1).readonly();
1124
1125
  var CommonHeadersSchema = z4.object({
1125
- /** Slugs joined by `/`, so identities can be grouped by team or domain
1126
+ /** Slugs joined by `/`, so ids can be grouped by team or domain
1126
1127
  * (FR-141). The `/` is written `-` in the file's name and nothing else:
1127
1128
  * nothing is read from what a file is called. At most 40 characters, so every name a host
1128
1129
  * is given for it — an mcp's tools among them, `mcp__cw__mcp-<id>__<tool>` —
@@ -1135,7 +1136,8 @@ var CommonHeadersSchema = z4.object({
1135
1136
  * are what decide when its body is loaded; a mixin may name them to say how
1136
1137
  * far what it lends reaches (FR-006). */
1137
1138
  globs: z4.array(GoodLineSchema).readonly().optional(),
1138
- /** `corpus:<id>`, the reasoning this primitive cites (FR-005). */
1139
+ /** The id of the corpus this primitive cites as its reasoning (FR-005,
1140
+ * FR-172). */
1139
1141
  rationale: GoodLineSchema.optional(),
1140
1142
  mixins: z4.array(GoodLineSchema).readonly().optional()
1141
1143
  });
@@ -1177,7 +1179,7 @@ var BasePrimitive = class _BasePrimitive {
1177
1179
  return `${this.charterFolder}/${this.primitiveFolder}/${this.index}`;
1178
1180
  }
1179
1181
  /** Whether a word someone searched for is anywhere a reader would look for
1180
- * it: the identity, the kind, what it is for, when its kind comes up, its
1182
+ * it: the id, the kind, what it is for, when its kind comes up, its
1181
1183
  * file, or any header it declared — ignoring case, since whoever typed it
1182
1184
  * did not know how it was written (FR-114). */
1183
1185
  search(word) {
@@ -1185,7 +1187,7 @@ var BasePrimitive = class _BasePrimitive {
1185
1187
  (value) => value === void 0 ? [] : Array.isArray(value) ? value : [String(value)]
1186
1188
  );
1187
1189
  const loweredWord = word.toLowerCase();
1188
- return [this.identity, this.kind, this.activatesWhen, this.file, ...headerValues].some((one) => one.toLowerCase().includes(loweredWord));
1190
+ return [this.headers.id, this.kind, this.activatesWhen, this.file, ...headerValues].some((one) => one.toLowerCase().includes(loweredWord));
1189
1191
  }
1190
1192
  /** Its folder, from its charter folder: its kind, then each segment of its
1191
1193
  * id (FR-141). */
@@ -1208,16 +1210,12 @@ var BasePrimitive = class _BasePrimitive {
1208
1210
  get hash() {
1209
1211
  return contentHashOf(this.toMarkdown());
1210
1212
  }
1211
- /** What the whole charter names it by: `guide:no-any` (FR-014). */
1212
- get identity() {
1213
- return `${this.kind}:${this.headers.id}`;
1214
- }
1215
- /** Its identity as every name given to a host writes it, `:` and `/` as
1216
- * `-`: `guide-mfbs-no-any` for `guide:mfbs/no-any` (FR-141). Made here,
1217
- * once, so nothing that names a host's file or a place's tools spells it
1218
- * again. */
1219
- get normIdentity() {
1220
- return this.identity.replace(/[:/]/g, "-");
1213
+ /** Its id as every name given to a host writes it, `/` as `-`:
1214
+ * `mfbs-no-any` for `mfbs/no-any`, so a skill is invoked as `/mfbs-no-any`
1215
+ * (FR-141, FR-171). Made here, once, so nothing that names a host's file
1216
+ * spells it again. */
1217
+ get normId() {
1218
+ return this.headers.id.replace(/\//g, "-");
1221
1219
  }
1222
1220
  /**
1223
1221
  * This primitive as the file it is authored in: its headers between the
@@ -1328,664 +1326,139 @@ var SensorPrimitive = class _SensorPrimitive extends BasePrimitive {
1328
1326
  }
1329
1327
  };
1330
1328
 
1331
- // src/hexagon/domain/models/charter/primitive/Primitive.ts
1332
- import { z as z9 } from "zod";
1333
-
1334
- // src/hexagon/domain/models/charter/primitive/AgentPrimitive.ts
1335
- var AgentHeadersSchema = CommonHeadersSchema.extend({
1336
- tools: GoodArraySchema
1337
- });
1338
- var AgentPrimitive = class _AgentPrimitive extends BasePrimitive {
1339
- static kind = "agent";
1340
- kind = _AgentPrimitive.kind;
1341
- /** What this kind requires beyond the common headers, declared where its
1342
- * contract is: it is read both where a file is checked and where one is
1343
- * scaffolded (FR-004, FR-039). */
1344
- static requires = { tools: "list" };
1345
- /** The schema its headers are read by: what `headersOf` refuses a file
1346
- * against, and what says the shape of every header this kind takes, required
1347
- * or not (FR-004). */
1348
- static schema = AgentHeadersSchema;
1349
- /** When a reader of this charter is to open this kind at all, said
1350
- * where the kind's contract is: the neutral surface lists one
1351
- * line per kind and none of them is written down twice (FR-002). */
1352
- static activatesWhen = "it is spawned by identity, holding the `tools` it lists and nothing else \u2014 a place as `mcp:<id>`, or one of its tools as `mcp:<id>:<tool>`";
1353
- /** An agent as an author writes one: what a refused header is fixed with.
1354
- * It holds one tool of a place the way an author writes it (FR-156). */
1355
- static sample = {
1356
- id: "reviewer",
1357
- description: "Review a diff and name what is wrong with it.",
1358
- tools: ["Read", "Grep", "mcp:mfbs/billing:search_code"]
1359
- };
1360
- /** One agent, or every fault its headers have (FR-004). */
1361
- static of(record, body, assetFiles = [], primitiveLayer) {
1362
- return new _AgentPrimitive(headersOf(_AgentPrimitive, AgentHeadersSchema, record), body, assetFiles, primitiveLayer);
1329
+ // src/hexagon/domain/models/test/TestCase.ts
1330
+ var ExpectedIdSchema = CommonHeadersSchema.shape.id;
1331
+ var TestCaseSchema2 = z6.union([
1332
+ z6.strictObject({
1333
+ do: z6.strictObject({ touchFile: z6.string().min(1) }),
1334
+ expect: z6.union([
1335
+ z6.strictObject({ activate: ExpectedIdSchema }),
1336
+ z6.strictObject({ allow: z6.boolean() })
1337
+ ])
1338
+ }),
1339
+ z6.strictObject({
1340
+ when: z6.enum(SIGNALS),
1341
+ expect: z6.strictObject({ run: ExpectedIdSchema })
1342
+ })
1343
+ ]);
1344
+ var TestCase = class {
1345
+ constructor(written) {
1346
+ this.written = written;
1347
+ }
1348
+ written;
1349
+ /** The situation it puts, said as a line, and what it expects of it: what a
1350
+ * run reports it under, and what an explanation names it by (FR-048,
1351
+ * FR-014). */
1352
+ describe() {
1353
+ return `${this.situation} ${this.expectation}`;
1354
+ }
1355
+ /** The situation it puts: the file it touches, or the event it raises. */
1356
+ get situation() {
1357
+ return "when" in this.written ? `firing event ${this.written.when}` : `touching ${this.written.do.touchFile}`;
1358
+ }
1359
+ /** What it expects the charter to make of its situation. */
1360
+ get expectation() {
1361
+ const written = this.written;
1362
+ if ("when" in written) return `runs ${written.expect.run}`;
1363
+ if ("activate" in written.expect) return `activates ${written.expect.activate}`;
1364
+ return `is ${written.expect.allow ? "allowed" : "denied"}`;
1365
+ }
1366
+ /**
1367
+ * Which primitive this case expects to be activated: the sensor a raised event
1368
+ * is expected to run, or the guide a touched file is expected to bring up
1369
+ * (FR-014).
1370
+ *
1371
+ * Nothing for the third shape. That one expects a touched file to be allowed
1372
+ * or denied, which every posture in the charter answers between them, so it
1373
+ * activates no one primitive by name.
1374
+ */
1375
+ get activatedId() {
1376
+ if ("when" in this.written) return this.written.expect.run;
1377
+ if ("activate" in this.written.expect) return this.written.expect.activate;
1378
+ return void 0;
1363
1379
  }
1364
1380
  };
1365
1381
 
1366
- // src/hexagon/domain/models/charter/primitive/CorpusPrimitive.ts
1367
- var CorpusHeadersSchema = CommonHeadersSchema.extend({});
1368
- var CorpusPrimitive = class _CorpusPrimitive extends BasePrimitive {
1369
- static kind = "corpus";
1370
- kind = _CorpusPrimitive.kind;
1371
- /** What this kind requires beyond the common headers: nothing. Declared all
1372
- * the same, since what a file is scaffolded with is read off this (FR-039). */
1373
- static requires = {};
1374
- /** The schema its headers are read by: what `headersOf` refuses a file
1375
- * against, and what says the shape of every header this kind takes, required
1376
- * or not (FR-004). */
1377
- static schema = CorpusHeadersSchema;
1378
- /** When a reader of this charter is to open this kind at all, said
1379
- * where the kind's contract is: the neutral surface lists one
1380
- * line per kind and none of them is written down twice (FR-002). */
1381
- static activatesWhen = "a primitive's `rationale` cites it \u2014 the reasoning, read when someone asks why";
1382
- /** A corpus as an author writes one: what a refused header is fixed with. */
1383
- static sample = {
1384
- id: "type-safety",
1385
- description: "Why the charter insists on types."
1386
- };
1387
- /** One corpus, or every fault its headers have (FR-004). */
1388
- static of(record, body, assetFiles = [], primitiveLayer) {
1389
- return new _CorpusPrimitive(headersOf(_CorpusPrimitive, CorpusHeadersSchema, record), body, assetFiles, primitiveLayer);
1382
+ // src/hexagon/domain/models/test/TestSuite.ts
1383
+ var TestSuiteSchema2 = z7.strictObject({
1384
+ description: z7.string().min(1).optional(),
1385
+ cases: z7.array(TestCaseSchema2.transform((written) => new TestCase(written))).min(1)
1386
+ });
1387
+ var TestSuite = class {
1388
+ constructor(description, cases, body) {
1389
+ this.description = description;
1390
+ this.cases = cases;
1391
+ this.body = body;
1390
1392
  }
1393
+ description;
1394
+ cases;
1395
+ body;
1391
1396
  };
1397
+ var SAMPLE_CASES = [
1398
+ { do: { touchFile: "src/one.ts" }, expect: { activate: "no-any" } },
1399
+ { do: { touchFile: ".env" }, expect: { allow: false } },
1400
+ { when: "PreToolUse", expect: { run: "no-secrets" } }
1401
+ ];
1402
+ var SAMPLE = JSON.stringify({ cases: SAMPLE_CASES }, void 0, 1).replace(/\n\s*/g, " ");
1403
+ var DEFAULT_TEST_SUITE_BODY = `${JSON.stringify({ description: "What these cases pin down.", cases: [SAMPLE_CASES[0]] }, null, 2)}
1404
+ `;
1405
+ function testSuiteOf(text) {
1406
+ let written;
1407
+ try {
1408
+ written = JSON.parse(text);
1409
+ } catch {
1410
+ throw new TestSuiteFault(
1411
+ `This file is not JSON, so nothing can read the cases it was meant to hold.`,
1412
+ `Write it as ${SAMPLE}`
1413
+ );
1414
+ }
1415
+ const read = TestSuiteSchema2.safeParse(written);
1416
+ if (!read.success) throw new TestSuiteFault(`This file is not written as a suite of cases.`, `Write it as ${SAMPLE}`);
1417
+ return new TestSuite(read.data.description, read.data.cases, text);
1418
+ }
1392
1419
 
1393
- // src/hexagon/domain/models/charter/primitive/GuidePrimitive.ts
1394
- var GuideHeadersSchema = CommonHeadersSchema.extend({});
1395
- var GuidePrimitive = class _GuidePrimitive extends BasePrimitive {
1396
- static kind = "guide";
1397
- kind = _GuidePrimitive.kind;
1398
- /** What this kind requires beyond the common headers: nothing. Declared all
1399
- * the same, since what a file is scaffolded with is read off this (FR-039). */
1400
- static requires = {};
1401
- /** The schema its headers are read by: what `headersOf` refuses a file
1402
- * against, and what says the shape of every header this kind takes, required
1403
- * or not (FR-004). */
1404
- static schema = GuideHeadersSchema;
1405
- /** When a reader of this charter is to open this kind at all, said
1406
- * where the kind's contract is: the neutral surface lists one
1407
- * line per kind and none of them is written down twice (FR-002). */
1408
- static activatesWhen = "a touched file matches one of its `globs`, or every turn where globs are not specified";
1409
- /** A guide as an author writes one: what a refused header is fixed with. */
1410
- static sample = {
1411
- id: "no-any",
1412
- description: "Reject the any type in application code.",
1413
- globs: ["src/**/*.ts"],
1414
- tags: ["typescript"],
1415
- rationale: "corpus:type-safety"
1416
- };
1417
- /** One guide, or every fault its headers have (FR-004). */
1418
- static of(record, body, assetFiles = [], primitiveLayer) {
1419
- return new _GuidePrimitive(headersOf(_GuidePrimitive, GuideHeadersSchema, record), body, assetFiles, primitiveLayer);
1420
+ // src/hexagon/domain/models/test/TestRoot.ts
1421
+ function testSuiteNameOf(path) {
1422
+ return path.slice(`${TEST_DIRECTORY}/`.length);
1423
+ }
1424
+ var TestRoot = class {
1425
+ constructor(suitesByFile, faultsByFiles) {
1426
+ this.suitesByFile = suitesByFile;
1427
+ this.faultsByFiles = faultsByFiles;
1428
+ }
1429
+ suitesByFile;
1430
+ faultsByFiles;
1431
+ /** Whether a test file is under this name, whether it reads or not. A name
1432
+ * reaching outside `.cw/test/` is no name of one. */
1433
+ hasTestSuiteNamed(name) {
1434
+ const path = `${TEST_DIRECTORY}/${name}`;
1435
+ return path in this.suitesByFile || path in this.faultsByFiles.files;
1436
+ }
1437
+ /** What a new test file is named: `untitled-<n>.json` for the first `n` no
1438
+ * test file has (FR-091). */
1439
+ get untitledName() {
1440
+ let untitledNumber = 1;
1441
+ while (this.hasTestSuiteNamed(`untitled-${untitledNumber}.json`)) untitledNumber++;
1442
+ return `untitled-${untitledNumber}.json`;
1420
1443
  }
1421
1444
  };
1445
+ function testRootOf(testSuiteFiles) {
1446
+ const suitesByFile = {};
1447
+ const faultsByFiles = {};
1448
+ for (const { path, contents } of [...testSuiteFiles].sort((one, another) => one.path.localeCompare(another.path))) {
1449
+ try {
1450
+ suitesByFile[path] = testSuiteOf(contents);
1451
+ } catch (raised) {
1452
+ if (!(raised instanceof DomainFault)) throw raised;
1453
+ faultsByFiles[path] = [raised];
1454
+ }
1455
+ }
1456
+ return new TestRoot(suitesByFile, new FaultsByFile(faultsByFiles));
1457
+ }
1422
1458
 
1423
- // src/hexagon/domain/models/charter/primitive/McpPrimitive.ts
1424
- import { z as z6 } from "zod";
1425
-
1426
- // src/hexagon/domain/models/McpAuthMethod.ts
1427
- var MCP_AUTH_METHODS = ["oauth", "token"];
1428
-
1429
- // src/hexagon/domain/models/charter/primitive/McpPrimitive.ts
1430
- function isSecureEndpoint(endpoint) {
1431
- if (!URL.canParse(endpoint)) return false;
1432
- const endpointURL = new URL(endpoint);
1433
- return endpointURL.protocol === "https:" || endpointURL.protocol === "http:" && ["127.0.0.1", "localhost"].includes(endpointURL.hostname);
1434
- }
1435
- var MCP_MENTION = /\bmcp:([a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\/[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*)/g;
1436
- var MCP_TOOL_REFERENCE = /^(mcp:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\/[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*)(?::([^:\s]+))?$/;
1437
- var McpHeadersSchema = CommonHeadersSchema.extend({
1438
- /** Reached over HTTP. Plain `http` only to this machine, for a server under
1439
- * test: anything else would send a developer's credential in the clear. */
1440
- endpoint: GoodLineSchema.refine(isSecureEndpoint, {
1441
- message: `"endpoint" is an https:// URL, or http:// to 127.0.0.1 or localhost for a server under test.`
1442
- }).optional(),
1443
- /** Started as a local process, spoken to over its standard input and output. */
1444
- command: GoodLineSchema.optional(),
1445
- args: z6.array(GoodLineSchema).readonly().optional(),
1446
- auth: z6.array(z6.enum(MCP_AUTH_METHODS)).min(1).readonly().optional(),
1447
- /** The environment variable a command reads its token from. */
1448
- tokenEnv: z6.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/).optional(),
1449
- /** The place inside that server: a repository, a database, a channel. */
1450
- path: GoodLineSchema.optional(),
1451
- /** The server's tools the agent may use there, by the server's own names. */
1452
- tools: GoodArraySchema
1453
- }).superRefine((headers, context) => {
1454
- const addFault = (message) => context.addIssue({ code: "custom", message });
1455
- const { endpoint, command, args, auth: auth2, tokenEnv } = headers;
1456
- if (endpoint !== void 0 && command !== void 0)
1457
- return addFault(`This declares both "endpoint" and "command"; an mcp is one server, reached one way.`);
1458
- if (endpoint === void 0 && command === void 0)
1459
- return addFault(`This declares neither "endpoint" nor "command", so there is no server to reach.`);
1460
- if (endpoint !== void 0) {
1461
- if (auth2 === void 0) addFault(`An endpoint says how a developer signs in to it: "auth" of oauth, token or both.`);
1462
- if (args !== void 0) addFault(`"args" are a command's; an endpoint takes none.`);
1463
- if (tokenEnv !== void 0) addFault(`"tokenEnv" is where a command reads its token; an endpoint takes none.`);
1464
- return;
1465
- }
1466
- const takesToken = auth2 !== void 0;
1467
- if (takesToken && (auth2.length !== 1 || auth2[0] !== "token"))
1468
- addFault(`A command signs in by token alone: "auth: [token]", or no "auth" for one that takes none.`);
1469
- if (takesToken && tokenEnv === void 0) addFault(`A command taking a token names where it reads it: "tokenEnv".`);
1470
- if (!takesToken && tokenEnv !== void 0) addFault(`"tokenEnv" is read only by a command taking a token: add "auth: [token]", or drop it.`);
1471
- });
1472
- var McpPrimitive = class _McpPrimitive extends BasePrimitive {
1473
- static kind = "mcp";
1474
- kind = _McpPrimitive.kind;
1475
- /** What this kind requires beyond the common headers. `endpoint` or
1476
- * `command` is required too, but which depends on the shape, so the schema's
1477
- * refinement says it rather than this (FR-004, FR-039). */
1478
- static requires = { tools: "list" };
1479
- /** The schema its headers are read by: what `headersOf` refuses a file
1480
- * against, and what says the shape of every header this kind takes, required
1481
- * or not (FR-004). */
1482
- static schema = McpHeadersSchema;
1483
- /** When a reader of this charter is to open this kind at all, said
1484
- * where the kind's contract is: the neutral surface lists one
1485
- * line per kind and none of them is written down twice (FR-002). */
1486
- static activatesWhen = "a primitive's body names it as `mcp:<id>` \u2014 a place outside the repository, reached through `cw mcp serve`";
1487
- /** An mcp reached at an endpoint, as an author writes one: what a refused
1488
- * header is fixed with. */
1489
- static sample = {
1490
- id: "mfbs/billing",
1491
- description: "Billing service code and pull requests.",
1492
- endpoint: "https://api.githubcopilot.com/mcp/",
1493
- path: "moneyforward/billing-service",
1494
- auth: ["oauth", "token"],
1495
- tools: ["get_file_contents", "search_code", "list_pull_requests"]
1496
- };
1497
- /** The same place started as a local process: what a refused file declaring
1498
- * `command` is held up against, since that is the shape it was nearer. */
1499
- static commandSample = {
1500
- id: "mfbs/billing",
1501
- description: "Billing service code and pull requests.",
1502
- command: "npx",
1503
- args: ["-y", "@modelcontextprotocol/server-github"],
1504
- tokenEnv: "GITHUB_PERSONAL_ACCESS_TOKEN",
1505
- auth: ["token"],
1506
- path: "moneyforward/billing-service",
1507
- tools: ["get_file_contents", "search_code", "list_pull_requests"]
1508
- };
1509
- /** What a developer signs in to, and what places are told apart by beside
1510
- * their `path`: the endpoint, or the command followed by each of its
1511
- * arguments. The refinement has already held that one of the two is here
1512
- * (FR-142). */
1513
- get address() {
1514
- const { endpoint, command, args = [] } = this.headers;
1515
- return endpoint ?? [command, ...args].join(" ");
1516
- }
1517
- /** One mcp, or every fault its headers have, shown the sample of the shape
1518
- * it declared (FR-004, FR-142). */
1519
- static of(record, body, assetFiles = [], primitiveLayer) {
1520
- const nearerSample = record.command === void 0 ? _McpPrimitive.sample : _McpPrimitive.commandSample;
1521
- return new _McpPrimitive(headersOf({ kind: _McpPrimitive.kind, sample: nearerSample }, McpHeadersSchema, record), body, assetFiles, primitiveLayer);
1522
- }
1523
- };
1524
-
1525
- // src/hexagon/domain/models/charter/primitive/MixinPrimitive.ts
1526
- import { z as z7 } from "zod";
1527
- var MixinHeadersSchema = CommonHeadersSchema.extend({
1528
- /** Never: reading refuses a mixin that declares one. */
1529
- mixins: z7.undefined().optional()
1530
- });
1531
- var MixinPrimitive = class _MixinPrimitive extends BasePrimitive {
1532
- static kind = "mixin";
1533
- kind = _MixinPrimitive.kind;
1534
- /** What this kind requires beyond the common headers: nothing. Declared all
1535
- * the same, since what a file is scaffolded with is read off this (FR-039). */
1536
- static requires = {};
1537
- /** The schema its headers are read by: what `headersOf` refuses a file
1538
- * against, and what says the shape of every header this kind takes, required
1539
- * or not (FR-004). */
1540
- static schema = MixinHeadersSchema;
1541
- /** When a reader of this charter is to open this kind at all, said
1542
- * where the kind's contract is: the neutral surface lists one
1543
- * line per kind and none of them is written down twice (FR-002). */
1544
- static activatesWhen = "never on its own: its body is lent to the primitives that pull it in";
1545
- /** A mixin as an author writes one: what a refused header is fixed with. */
1546
- static sample = {
1547
- id: "typescript-scope",
1548
- description: "What counts as TypeScript application code.",
1549
- globs: ["src/**/*.ts"]
1550
- };
1551
- /** One mixin, or every fault its headers have (FR-004, FR-006). */
1552
- static of(record, body, assetFiles = [], primitiveLayer) {
1553
- return new _MixinPrimitive(headersOf(_MixinPrimitive, MixinHeadersSchema, record), body, assetFiles, primitiveLayer);
1554
- }
1555
- };
1556
-
1557
- // src/hexagon/domain/models/charter/primitive/PlaybookPrimitive.ts
1558
- var PlaybookHeadersSchema = CommonHeadersSchema.extend({
1559
- triggers: GoodArraySchema
1560
- });
1561
- var PlaybookPrimitive = class _PlaybookPrimitive extends BasePrimitive {
1562
- static kind = "playbook";
1563
- kind = _PlaybookPrimitive.kind;
1564
- /** What this kind requires beyond the common headers, declared where its
1565
- * contract is: it is read both where a file is checked and where one is
1566
- * scaffolded (FR-004, FR-039). */
1567
- static requires = { triggers: "list" };
1568
- /** The schema its headers are read by: what `headersOf` refuses a file
1569
- * against, and what says the shape of every header this kind takes, required
1570
- * or not (FR-004). */
1571
- static schema = PlaybookHeadersSchema;
1572
- /** When a reader of this charter is to open this kind at all, said
1573
- * where the kind's contract is: the neutral surface lists one
1574
- * line per kind and none of them is written down twice (FR-002). */
1575
- static activatesWhen = "one of its `triggers` matches; the body is a sequence of skills";
1576
- /** A playbook as an author writes one: what a refused header is fixed with. */
1577
- static sample = {
1578
- id: "ship-a-feature",
1579
- description: "Take a finished branch from review to release.",
1580
- triggers: ["ship this", "release this feature"]
1581
- };
1582
- /** What this is found by: what it is for, and the requests its author said
1583
- * bring it up. */
1584
- description() {
1585
- return `${this.headers.description} Use when: ${this.headers.triggers.join("; ")}.`;
1586
- }
1587
- /** One playbook, or every fault its headers have (FR-004). */
1588
- static of(record, body, assetFiles = [], primitiveLayer) {
1589
- return new _PlaybookPrimitive(headersOf(_PlaybookPrimitive, PlaybookHeadersSchema, record), body, assetFiles, primitiveLayer);
1590
- }
1591
- };
1592
-
1593
- // src/hexagon/domain/models/charter/primitive/PosturePrimitive.ts
1594
- var PostureHeadersSchema = CommonHeadersSchema.extend({
1595
- allow: GoodArraySchema,
1596
- deny: GoodArraySchema
1597
- });
1598
- var PosturePrimitive = class _PosturePrimitive extends BasePrimitive {
1599
- static kind = "posture";
1600
- kind = _PosturePrimitive.kind;
1601
- /** What this kind requires beyond the common headers, declared where its
1602
- * contract is: it is read both where a file is checked and where one is
1603
- * scaffolded (FR-004, FR-039). */
1604
- static requires = { allow: "list", deny: "list" };
1605
- /** The schema its headers are read by: what `headersOf` refuses a file
1606
- * against, and what says the shape of every header this kind takes, required
1607
- * or not (FR-004). */
1608
- static schema = PostureHeadersSchema;
1609
- /** When a reader of this charter is to open this kind at all, said
1610
- * where the kind's contract is: the neutral surface lists one
1611
- * line per kind and none of them is written down twice (FR-002). */
1612
- static activatesWhen = "always, wherever the host can be told what to `allow` and what to `deny`";
1613
- /** A posture as an author writes one: what a refused header is fixed with. */
1614
- static sample = {
1615
- id: "no-force-push",
1616
- description: "Never rewrite history someone else may have pulled.",
1617
- allow: ["Bash(git push:*)"],
1618
- deny: ["Bash(git push --force:*)"]
1619
- };
1620
- /** One posture, or every fault its headers have (FR-004). */
1621
- static of(record, body, assetFiles = [], primitiveLayer) {
1622
- return new _PosturePrimitive(headersOf(_PosturePrimitive, PostureHeadersSchema, record), body, assetFiles, primitiveLayer);
1623
- }
1624
- };
1625
-
1626
- // src/hexagon/domain/models/charter/primitive/SkillPrimitive.ts
1627
- var SkillHeadersSchema = CommonHeadersSchema.extend({
1628
- triggers: GoodArraySchema
1629
- });
1630
- var SkillPrimitive = class _SkillPrimitive extends BasePrimitive {
1631
- static kind = "skill";
1632
- kind = _SkillPrimitive.kind;
1633
- /** What this kind requires beyond the common headers, declared where its
1634
- * contract is: it is read both where a file is checked and where one is
1635
- * scaffolded (FR-004, FR-039). */
1636
- static requires = { triggers: "list" };
1637
- /** The schema its headers are read by: what `headersOf` refuses a file
1638
- * against, and what says the shape of every header this kind takes, required
1639
- * or not (FR-004). */
1640
- static schema = SkillHeadersSchema;
1641
- /** When a reader of this charter is to open this kind at all, said
1642
- * where the kind's contract is: the neutral surface lists one
1643
- * line per kind and none of them is written down twice (FR-002). */
1644
- static activatesWhen = "one of its `triggers` matches what is being asked";
1645
- /** A skill as an author writes one: what a refused header is fixed with. */
1646
- static sample = {
1647
- id: "refactoring",
1648
- description: "Change how code is structured without changing what it does.",
1649
- triggers: ["refactor this", "clean this up"]
1650
- };
1651
- /** What this is found by: what it is for, and the requests its author said
1652
- * bring it up. */
1653
- description() {
1654
- return `${this.headers.description} Use when: ${this.headers.triggers.join("; ")}.`;
1655
- }
1656
- /** One skill, or every fault its headers have (FR-004). */
1657
- static of(record, body, assetFiles = [], primitiveLayer) {
1658
- return new _SkillPrimitive(headersOf(_SkillPrimitive, SkillHeadersSchema, record), body, assetFiles, primitiveLayer);
1659
- }
1660
- };
1661
-
1662
- // src/hexagon/domain/models/charter/primitive/ScriptPrimitive.ts
1663
- import { z as z8 } from "zod";
1664
- var SCRIPT_MENTION = /\bscript:([a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\/[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*)/g;
1665
- var ScriptHeadersSchema = CommonHeadersSchema.extend({
1666
- /** The one asset that runs, from the script's `index.md`: `./` and a path
1667
- * inside its folder, no segment of which climbs out again. Letters, digits,
1668
- * `.`, `_` and `-` only: it is written into commands a shell reads
1669
- * (FR-169). */
1670
- executionPath: z8.string().regex(/^\.\/[A-Za-z0-9._-]+(\/[A-Za-z0-9._-]+)*$/).refine((executionPath) => !executionPath.split("/").slice(1).some((segment) => segment === "." || segment === ".."), {
1671
- message: `"executionPath" stays inside the script's own folder: no segment of it is "." or "..".`
1672
- })
1673
- });
1674
- var ScriptPrimitive = class _ScriptPrimitive extends BasePrimitive {
1675
- static kind = "script";
1676
- kind = _ScriptPrimitive.kind;
1677
- /** What this kind requires beyond the common headers, declared where its
1678
- * contract is (FR-004, FR-039). */
1679
- static requires = { executionPath: "line" };
1680
- /** The schema its headers are read by (FR-004). */
1681
- static schema = ScriptHeadersSchema;
1682
- /** When a reader of this charter is to open this kind at all (FR-002). */
1683
- static activatesWhen = "a primitive names it as `script:<id>`, or a sensor runs it \u2014 its assets, copied to `.cw/out/script/<id>/`, of which its `executionPath` names the one to run";
1684
- /** A script as an author writes one: what a refused header is fixed with. */
1685
- static sample = {
1686
- id: "check-changelog",
1687
- description: "Fail when CHANGELOG.md holds no entry for the version being released.",
1688
- executionPath: "./run.sh"
1689
- };
1690
- /** One script, or every fault its headers have (FR-004). */
1691
- static of(record, body, assetFiles = [], primitiveLayer) {
1692
- return new _ScriptPrimitive(headersOf(_ScriptPrimitive, ScriptHeadersSchema, record), body, assetFiles, primitiveLayer);
1693
- }
1694
- /** The asset that runs, as a path inside its folder: `run.sh` of
1695
- * `./run.sh`. */
1696
- get executionPathInFolder() {
1697
- return this.headers.executionPath.slice("./".length);
1698
- }
1699
- /** Whether an asset of it is the one its `executionPath` names: the one
1700
- * run by its path, and no other (FR-160). */
1701
- isExecutionFile(file) {
1702
- return file === this.executionPathInFolder;
1703
- }
1704
- };
1705
-
1706
- // src/hexagon/domain/models/charter/primitive/TemplatePrimitive.ts
1707
- var TEMPLATE_MENTION = /\btemplate:([a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\/[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*)/g;
1708
- var TemplateHeadersSchema = CommonHeadersSchema.extend({});
1709
- var TemplatePrimitive = class _TemplatePrimitive extends BasePrimitive {
1710
- static kind = "template";
1711
- kind = _TemplatePrimitive.kind;
1712
- /** What this kind requires beyond the common headers: nothing. Declared all
1713
- * the same, since what a file is scaffolded with is read off this (FR-039). */
1714
- static requires = {};
1715
- /** The schema its headers are read by (FR-004). */
1716
- static schema = TemplateHeadersSchema;
1717
- /** When a reader of this charter is to open this kind at all (FR-002). */
1718
- static activatesWhen = "a primitive names it as `template:<id>` \u2014 a file the agent fills or copies, written as its body";
1719
- /** A template as an author writes one: what a refused header is fixed with. */
1720
- static sample = {
1721
- id: "release-note",
1722
- description: "The shape every release note follows."
1723
- };
1724
- /** One template, or every fault its headers have (FR-004). */
1725
- static of(record, body, assetFiles = [], primitiveLayer) {
1726
- return new _TemplatePrimitive(headersOf(_TemplatePrimitive, TemplateHeadersSchema, record), body, assetFiles, primitiveLayer);
1727
- }
1728
- };
1729
-
1730
- // src/hexagon/domain/models/charter/primitive/Primitive.ts
1731
- var PRIMITIVE_CLASSES = [
1732
- GuidePrimitive,
1733
- SensorPrimitive,
1734
- SkillPrimitive,
1735
- PlaybookPrimitive,
1736
- AgentPrimitive,
1737
- PosturePrimitive,
1738
- CorpusPrimitive,
1739
- MixinPrimitive,
1740
- McpPrimitive,
1741
- ScriptPrimitive,
1742
- TemplatePrimitive
1743
- ];
1744
- var KINDS = Object.freeze(PRIMITIVE_CLASSES.map((one) => one.kind));
1745
- var PrimitiveIdentitySchema = z9.string().regex(/^[a-z0-9-]+:[a-z0-9-]+(\/[a-z0-9-]+)*$/).transform((identity) => identity);
1746
- function identityOf(kindAndId) {
1747
- if (typeof kindAndId !== "string") return `${kindAndId.kind}:${kindAndId.id}`;
1748
- const parsed = PrimitiveIdentitySchema.safeParse(kindAndId);
1749
- if (!parsed.success)
1750
- throw new CharterPrimitiveFault(
1751
- `"${kindAndId}" is not an identity: one is a kind and an id with a colon between them.`,
1752
- 'Write it as <kind>:<id>, as in "guide:no-any".'
1753
- );
1754
- return parsed.data;
1755
- }
1756
- function isKind(value) {
1757
- return typeof value === "string" && KINDS.includes(value);
1758
- }
1759
- var CLASS_OF = new Map(
1760
- PRIMITIVE_CLASSES.map((one) => [one.kind, one])
1761
- );
1762
- var PrimitiveHeader = class {
1763
- constructor(field, shape, required, allowedValues) {
1764
- this.field = field;
1765
- this.shape = shape;
1766
- this.required = required;
1767
- this.allowedValues = allowedValues;
1768
- }
1769
- field;
1770
- shape;
1771
- required;
1772
- allowedValues;
1773
- };
1774
- var PrimitiveRequirements = class {
1775
- constructor(headers, sample) {
1776
- this.headers = headers;
1777
- this.sample = sample;
1778
- }
1779
- headers;
1780
- sample;
1781
- };
1782
- function primitiveHeadersOf(kind) {
1783
- const kindClass = CLASS_OF.get(kind);
1784
- const required = { ...BasePrimitive.requires, ...kindClass.requires };
1785
- return Object.entries(kindClass.schema.shape).filter(([field]) => field !== "id").map(([field, type]) => {
1786
- let heldType = type;
1787
- while (!(heldType instanceof z9.ZodArray) && typeof heldType?.unwrap === "function")
1788
- heldType = heldType.unwrap();
1789
- return new PrimitiveHeader(
1790
- field,
1791
- heldType instanceof z9.ZodArray ? "list" : "line",
1792
- field in required,
1793
- heldType instanceof z9.ZodEnum ? heldType.options : void 0
1794
- );
1795
- });
1796
- }
1797
- function primitiveSampleOf(kind) {
1798
- return Object.entries({ kind, ...CLASS_OF.get(kind).sample }).map(([field, value]) => `${field}: ${formatFrontmatterValue(value)}`).join("\n");
1799
- }
1800
- function primitiveOf(input, parser, assetFiles = [], primitiveLayer) {
1801
- let headers;
1802
- let body;
1803
- if (typeof input === "string") {
1804
- const lines3 = input.replace(/^/, "").split(/\r?\n/);
1805
- if (lines3[0]?.trim() !== DELIMITER)
1806
- throwAggregateError([
1807
- new CharterPrimitiveFault(
1808
- `This file opens with no "${DELIMITER}" frontmatter block.`,
1809
- `Add one at the top declaring at least "id" and "description".`
1810
- )
1811
- ]);
1812
- const end = lines3.findIndex((line, index) => index > 0 && line.trim() === DELIMITER);
1813
- if (end === -1)
1814
- throwAggregateError([
1815
- new CharterPrimitiveFault(
1816
- `The frontmatter block is never closed.`,
1817
- `Add a "${DELIMITER}" line after the headers.`
1818
- )
1819
- ]);
1820
- headers = parser.parse(lines3.slice(1, end).join("\n"));
1821
- body = lines3.slice(end + 1).join("\n").replace(/^(\s*\n)+/, "").trimEnd();
1822
- } else {
1823
- headers = input.headers;
1824
- body = input.body;
1825
- }
1826
- if (!isKind(headers.kind))
1827
- throwAggregateError([
1828
- headers.kind === void 0 ? new CharterPrimitiveFault(
1829
- `This file declares no "kind", so nothing knows what to read it as.`,
1830
- `Add "kind: <one the charter knows>" to the frontmatter.`
1831
- ) : new CharterPrimitiveFault(
1832
- `"${String(headers.kind)}" is not a kind the charter knows.`,
1833
- `Declare a kind the charter knows: ${KINDS.join(", ")}.`
1834
- )
1835
- ]);
1836
- const kind = headers.kind;
1837
- if (typeof input === "string") return CLASS_OF.get(kind).of(headers, body, assetFiles, primitiveLayer);
1838
- const headerFields = primitiveHeadersOf(kind).map((header) => header.field);
1839
- const unknownHeaderFaults = Object.keys(headers).filter((field) => field !== "kind" && field !== "id" && !headerFields.includes(field)).map(
1840
- (field) => new CharterPrimitiveFault(
1841
- `A ${kind} holds no "${field}".`,
1842
- `Answer one of what a ${kind} holds: ${headerFields.join(", ")}.`
1843
- )
1844
- );
1845
- let primitive;
1846
- let schemaFaults = [];
1847
- try {
1848
- primitive = CLASS_OF.get(kind).of(headers, body);
1849
- } catch (raised) {
1850
- if (!(raised instanceof AggregateError)) throw raised;
1851
- schemaFaults = raised.errors;
1852
- }
1853
- if (primitive === void 0 || unknownHeaderFaults.length > 0) throwAggregateError([...unknownHeaderFaults, ...schemaFaults]);
1854
- return primitive;
1855
- }
1856
-
1857
- // src/hexagon/domain/models/test/TestCase.ts
1858
- var TestCaseSchema2 = z10.union([
1859
- z10.strictObject({
1860
- do: z10.strictObject({ touchFile: z10.string().min(1) }),
1861
- expect: z10.union([
1862
- z10.strictObject({ activate: PrimitiveIdentitySchema }),
1863
- z10.strictObject({ allow: z10.boolean() })
1864
- ])
1865
- }),
1866
- z10.strictObject({
1867
- when: z10.enum(SIGNALS),
1868
- expect: z10.strictObject({ run: PrimitiveIdentitySchema })
1869
- })
1870
- ]);
1871
- var TestCase = class {
1872
- constructor(written) {
1873
- this.written = written;
1874
- }
1875
- written;
1876
- /** The situation it puts, said as a line, and what it expects of it: what a
1877
- * run reports it under, and what an explanation names it by (FR-048,
1878
- * FR-014). */
1879
- describe() {
1880
- return `${this.situation} ${this.expectation}`;
1881
- }
1882
- /** The situation it puts: the file it touches, or the event it raises. */
1883
- get situation() {
1884
- return "when" in this.written ? `firing event ${this.written.when}` : `touching ${this.written.do.touchFile}`;
1885
- }
1886
- /** What it expects the charter to make of its situation. */
1887
- get expectation() {
1888
- const written = this.written;
1889
- if ("when" in written) return `runs ${written.expect.run}`;
1890
- if ("activate" in written.expect) return `activates ${written.expect.activate}`;
1891
- return `is ${written.expect.allow ? "allowed" : "denied"}`;
1892
- }
1893
- /**
1894
- * Which primitive this case expects to be activated: the sensor a raised event
1895
- * is expected to run, or the guide a touched file is expected to bring up
1896
- * (FR-014).
1897
- *
1898
- * Nothing for the third shape. That one expects a touched file to be allowed
1899
- * or denied, which every posture in the charter answers between them, so it
1900
- * activates no one primitive by name.
1901
- */
1902
- get activatedIdentity() {
1903
- if ("when" in this.written) return this.written.expect.run;
1904
- if ("activate" in this.written.expect) return this.written.expect.activate;
1905
- return void 0;
1906
- }
1907
- };
1908
-
1909
- // src/hexagon/domain/models/test/TestSuite.ts
1910
- var TestSuiteSchema2 = z11.strictObject({
1911
- description: z11.string().min(1).optional(),
1912
- cases: z11.array(TestCaseSchema2.transform((written) => new TestCase(written))).min(1)
1913
- });
1914
- var TestSuite = class {
1915
- constructor(description, cases, body) {
1916
- this.description = description;
1917
- this.cases = cases;
1918
- this.body = body;
1919
- }
1920
- description;
1921
- cases;
1922
- body;
1923
- };
1924
- var SAMPLE_CASES = [
1925
- { do: { touchFile: "src/one.ts" }, expect: { activate: "guide:no-any" } },
1926
- { do: { touchFile: ".env" }, expect: { allow: false } },
1927
- { when: "PreToolUse", expect: { run: "sensor:no-secrets" } }
1928
- ];
1929
- var SAMPLE = JSON.stringify({ cases: SAMPLE_CASES }, void 0, 1).replace(/\n\s*/g, " ");
1930
- var DEFAULT_TEST_SUITE_BODY = `${JSON.stringify({ description: "What these cases pin down.", cases: [SAMPLE_CASES[0]] }, null, 2)}
1931
- `;
1932
- function testSuiteOf(text) {
1933
- let written;
1934
- try {
1935
- written = JSON.parse(text);
1936
- } catch {
1937
- throw new TestSuiteFault(
1938
- `This file is not JSON, so nothing can read the cases it was meant to hold.`,
1939
- `Write it as ${SAMPLE}`
1940
- );
1941
- }
1942
- const read = TestSuiteSchema2.safeParse(written);
1943
- if (!read.success) throw new TestSuiteFault(`This file is not written as a suite of cases.`, `Write it as ${SAMPLE}`);
1944
- return new TestSuite(read.data.description, read.data.cases, text);
1945
- }
1946
-
1947
- // src/hexagon/domain/models/test/TestRoot.ts
1948
- function testSuiteNameOf(path) {
1949
- return path.slice(`${TEST_DIRECTORY}/`.length);
1950
- }
1951
- var TestRoot = class {
1952
- constructor(suitesByFile, faultsByFiles) {
1953
- this.suitesByFile = suitesByFile;
1954
- this.faultsByFiles = faultsByFiles;
1955
- }
1956
- suitesByFile;
1957
- faultsByFiles;
1958
- /** Whether a test file is under this name, whether it reads or not. A name
1959
- * reaching outside `.cw/test/` is no name of one. */
1960
- hasTestSuiteNamed(name) {
1961
- const path = `${TEST_DIRECTORY}/${name}`;
1962
- return path in this.suitesByFile || path in this.faultsByFiles.files;
1963
- }
1964
- /** What a new test file is named: `untitled-<n>.json` for the first `n` no
1965
- * test file has (FR-091). */
1966
- get untitledName() {
1967
- let untitledNumber = 1;
1968
- while (this.hasTestSuiteNamed(`untitled-${untitledNumber}.json`)) untitledNumber++;
1969
- return `untitled-${untitledNumber}.json`;
1970
- }
1971
- };
1972
- function testRootOf(testSuiteFiles) {
1973
- const suitesByFile = {};
1974
- const faultsByFiles = {};
1975
- for (const { path, contents } of [...testSuiteFiles].sort((one, another) => one.path.localeCompare(another.path))) {
1976
- try {
1977
- suitesByFile[path] = testSuiteOf(contents);
1978
- } catch (raised) {
1979
- if (!(raised instanceof DomainFault)) throw raised;
1980
- faultsByFiles[path] = [raised];
1981
- }
1982
- }
1983
- return new TestRoot(suitesByFile, new FaultsByFile(faultsByFiles));
1984
- }
1985
-
1986
- // src/hexagon/application/dtos.ts
1987
- function catalogueDTO(catalogue) {
1988
- return { type: "Catalogue", data: { entries: catalogue.entries.map((one) => ({ type: "CatalogueEntry", data: one })) } };
1459
+ // src/hexagon/application/dtos.ts
1460
+ function catalogueDTO(catalogue) {
1461
+ return { type: "Catalogue", data: { entries: catalogue.entries.map((one) => ({ type: "CatalogueEntry", data: one })) } };
1989
1462
  }
1990
1463
  function doctorOutcomeDTO({ agents }, faultsByFile, planSummary, driftedVendors2, repo) {
1991
1464
  const faults = Object.values(faultsByFile.files).flat();
@@ -2052,11 +1525,11 @@ function primitiveKindsDTO(kinds) {
2052
1525
  return { type: "PrimitiveKinds", data: Object.fromEntries(kinds.map((one) => [one.kind, one.activatesWhen])) };
2053
1526
  }
2054
1527
  function primitiveDTO(primitive) {
2055
- const { identity, layerName, file, body, hash } = primitive;
1528
+ const { layerName, file, body, hash } = primitive;
2056
1529
  return {
2057
1530
  type: "Primitive",
2058
1531
  data: {
2059
- identity,
1532
+ id: primitive.headers.id,
2060
1533
  kind: primitive.kind,
2061
1534
  description: primitive.headers.description,
2062
1535
  file,
@@ -2077,7 +1550,7 @@ function primitivesDTO(primitives) {
2077
1550
  return {
2078
1551
  type: "Primitives",
2079
1552
  data: {
2080
- primitives: [...primitives].sort((one, another) => one.identity < another.identity ? -1 : one.identity > another.identity ? 1 : 0).map(primitiveDTO)
1553
+ primitives: [...primitives].sort((one, another) => one.headers.id < another.headers.id ? -1 : one.headers.id > another.headers.id ? 1 : 0).map(primitiveDTO)
2081
1554
  }
2082
1555
  };
2083
1556
  }
@@ -2104,9 +1577,9 @@ function testSuitesDTO({ suitesByFile, faultsByFiles }) {
2104
1577
  name: testSuiteNameOf(path),
2105
1578
  ...suite === void 0 ? {} : { text: suite.body },
2106
1579
  ...suite?.description === void 0 ? {} : { description: suite.description },
2107
- cases: (suite?.cases ?? []).map(({ situation, expectation, activatedIdentity }) => ({
1580
+ cases: (suite?.cases ?? []).map(({ situation, expectation, activatedId }) => ({
2108
1581
  type: "TestCase",
2109
- data: { situation, expectation, ...activatedIdentity === void 0 ? {} : { identity: activatedIdentity } }
1582
+ data: { situation, expectation, ...activatedId === void 0 ? {} : { id: activatedId } }
2110
1583
  })),
2111
1584
  ...fault === void 0 ? {} : { fault: faultDTO(fault) }
2112
1585
  }
@@ -2143,10 +1616,10 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2143
1616
  createRoute({
2144
1617
  method: "get",
2145
1618
  path: "/charter/root/primitives",
2146
- request: { query: z12.object({ matching: z12.string().optional() }) },
1619
+ request: { query: z8.object({ matching: z8.string().optional() }) },
2147
1620
  responses: {
2148
1621
  200: json(DataDTOs.Primitives, "Every primitive of every layer, or those mentioning the word"),
2149
- 422: json(z12.union([DataDTOs.FaultsByFile, DataDTOs.Fault]), "The charter does not hold")
1622
+ 422: json(z8.union([DataDTOs.FaultsByFile, DataDTOs.Fault]), "The charter does not hold")
2150
1623
  }
2151
1624
  }),
2152
1625
  async (c) => {
@@ -2156,16 +1629,16 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2156
1629
  ).openapi(
2157
1630
  createRoute({
2158
1631
  method: "get",
2159
- path: "/charter/root/primitives/{identity}/explanation",
2160
- request: { params: z12.object({ identity: z12.string() }) },
1632
+ path: "/charter/root/primitives/{id}/explanation",
1633
+ request: { params: z8.object({ id: z8.string() }) },
2161
1634
  responses: {
2162
1635
  200: json(OutcomeDTOs.ExplanationOutcome, "What the engine says of one primitive"),
2163
- 422: json(z12.union([DataDTOs.FaultsByFile, DataDTOs.Fault]), "The charter does not hold, or holds nothing of it")
1636
+ 422: json(z8.union([DataDTOs.FaultsByFile, DataDTOs.Fault]), "The charter does not hold, or holds nothing of it")
2164
1637
  }
2165
1638
  }),
2166
1639
  async (c) => {
2167
- const { identity } = c.req.valid("param");
2168
- const explanationOutcomeDTO2 = await charterAuthoringApp2.explain(identity);
1640
+ const { id } = c.req.valid("param");
1641
+ const explanationOutcomeDTO2 = await charterAuthoringApp2.explain(id);
2169
1642
  return explanationOutcomeDTO2.type === "FaultsByFile" ? c.json(explanationOutcomeDTO2, 422) : c.json(explanationOutcomeDTO2, 200);
2170
1643
  }
2171
1644
  ).openapi(
@@ -2174,11 +1647,11 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2174
1647
  path: "/charter/root/primitives",
2175
1648
  request: {
2176
1649
  body: json(
2177
- z12.object({
2178
- kind: z12.string(),
2179
- id: z12.string(),
2180
- headers: z12.record(z12.string(), z12.union([z12.string(), z12.array(z12.string())])),
2181
- body: z12.string()
1650
+ z8.object({
1651
+ kind: z8.string(),
1652
+ id: z8.string(),
1653
+ headers: z8.record(z8.string(), z8.union([z8.string(), z8.array(z8.string())])),
1654
+ body: z8.string()
2182
1655
  }),
2183
1656
  "A new primitive: its kind and id, a line or a list under each header, and its body"
2184
1657
  )
@@ -2186,46 +1659,46 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2186
1659
  responses: {
2187
1660
  201: {
2188
1661
  ...json(DataDTOs.Primitive, "The primitive written"),
2189
- headers: z12.object({ Location: z12.string() })
1662
+ headers: z8.object({ Location: z8.string() })
2190
1663
  },
2191
- 422: json(z12.union([DataDTOs.Faults, DataDTOs.Fault]), "The answers the kind refused, or an identity already claimed")
1664
+ 422: json(z8.union([DataDTOs.Faults, DataDTOs.Fault]), "The answers the kind refused, or an id already claimed")
2192
1665
  }
2193
1666
  }),
2194
1667
  async (c) => {
2195
1668
  const { kind, id, headers, body } = c.req.valid("json");
2196
1669
  const primitiveDTO2 = await charterAuthoringApp2.add(kind, id, headers, body);
2197
1670
  if (primitiveDTO2.type === "Faults") return c.json(primitiveDTO2, 422);
2198
- return c.json(primitiveDTO2, 201, { Location: `/api/charter/root/primitives/${encodeURIComponent(primitiveDTO2.data.identity)}` });
1671
+ return c.json(primitiveDTO2, 201, { Location: `/api/charter/root/primitives/${encodeURIComponent(primitiveDTO2.data.id)}` });
2199
1672
  }
2200
1673
  ).openapi(
2201
1674
  createRoute({
2202
1675
  method: "get",
2203
- path: "/charter/root/primitives/{identity}",
2204
- request: { params: z12.object({ identity: z12.string() }) },
1676
+ path: "/charter/root/primitives/{id}",
1677
+ request: { params: z8.object({ id: z8.string() }) },
2205
1678
  responses: {
2206
1679
  200: {
2207
1680
  ...json(DataDTOs.Primitive, "One primitive as the charter read it"),
2208
- headers: z12.object({ ETag: z12.string() })
1681
+ headers: z8.object({ ETag: z8.string() })
2209
1682
  },
2210
1683
  422: json(DataDTOs.Fault, "The charter holds nothing of it")
2211
1684
  }
2212
1685
  }),
2213
1686
  async (c) => {
2214
- const { identity } = c.req.valid("param");
2215
- const primitiveDTO2 = await charterAuthoringApp2.open(identity);
1687
+ const { id } = c.req.valid("param");
1688
+ const primitiveDTO2 = await charterAuthoringApp2.open(id);
2216
1689
  return c.json(primitiveDTO2, 200, { ETag: `"${primitiveDTO2.data.hash}"` });
2217
1690
  }
2218
1691
  ).openapi(
2219
1692
  createRoute({
2220
1693
  method: "put",
2221
- path: "/charter/root/primitives/{identity}",
1694
+ path: "/charter/root/primitives/{id}",
2222
1695
  request: {
2223
- params: z12.object({ identity: z12.string() }),
2224
- headers: z12.object({ "if-match": z12.string().optional() }),
1696
+ params: z8.object({ id: z8.string() }),
1697
+ headers: z8.object({ "if-match": z8.string().optional() }),
2225
1698
  body: json(
2226
- z12.object({
2227
- headers: z12.record(z12.string(), z12.union([z12.string(), z12.array(z12.string())])),
2228
- body: z12.string()
1699
+ z8.object({
1700
+ headers: z8.record(z8.string(), z8.union([z8.string(), z8.array(z8.string())])),
1701
+ body: z8.string()
2229
1702
  }),
2230
1703
  "A line or a list under each header, and the body, written over the primitive's own"
2231
1704
  )
@@ -2233,12 +1706,12 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2233
1706
  responses: {
2234
1707
  200: json(DataDTOs.Primitive, "The primitive written"),
2235
1708
  412: json(DataDTOs.Fault, "The file changed on disk after it was opened"),
2236
- 422: json(z12.union([DataDTOs.Faults, DataDTOs.Fault]), "The answers the kind refused, or a primitive this repository did not author")
1709
+ 422: json(z8.union([DataDTOs.Faults, DataDTOs.Fault]), "The answers the kind refused, or a primitive this repository did not author")
2237
1710
  }
2238
1711
  }),
2239
1712
  async (c) => {
2240
- const { identity } = c.req.valid("param");
2241
- const primitive = (await charterAuthoringApp2.open(identity)).data;
1713
+ const { id } = c.req.valid("param");
1714
+ const primitive = (await charterAuthoringApp2.open(id)).data;
2242
1715
  if (c.req.valid("header")["if-match"] !== `"${primitive.hash}"`)
2243
1716
  return c.json(
2244
1717
  faultDTO(
@@ -2250,22 +1723,22 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2250
1723
  412
2251
1724
  );
2252
1725
  const { headers, body } = c.req.valid("json");
2253
- const primitiveDTO2 = await charterAuthoringApp2.rewrite(identity, headers, body, primitive.hash);
1726
+ const primitiveDTO2 = await charterAuthoringApp2.rewrite(id, headers, body, primitive.hash);
2254
1727
  return primitiveDTO2.type === "Faults" ? c.json(primitiveDTO2, 422) : c.json(primitiveDTO2, 200);
2255
1728
  }
2256
1729
  ).openapi(
2257
1730
  createRoute({
2258
1731
  method: "delete",
2259
- path: "/charter/root/primitives/{identity}",
2260
- request: { params: z12.object({ identity: z12.string() }) },
1732
+ path: "/charter/root/primitives/{id}",
1733
+ request: { params: z8.object({ id: z8.string() }) },
2261
1734
  responses: {
2262
1735
  204: { description: "The file is gone" },
2263
1736
  422: json(DataDTOs.Fault, "A primitive this repository did not author, or none at all")
2264
1737
  }
2265
1738
  }),
2266
1739
  async (c) => {
2267
- const { identity } = c.req.valid("param");
2268
- await charterAuthoringApp2.remove(identity);
1740
+ const { id } = c.req.valid("param");
1741
+ await charterAuthoringApp2.remove(id);
2269
1742
  return c.body(null, 204);
2270
1743
  }
2271
1744
  ).openapi(
@@ -2279,7 +1752,7 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2279
1752
  createRoute({
2280
1753
  method: "get",
2281
1754
  path: "/definitions/kinds/{kind}/requirements",
2282
- request: { params: z12.object({ kind: z12.string() }) },
1755
+ request: { params: z8.object({ kind: z8.string() }) },
2283
1756
  responses: {
2284
1757
  200: json(DataDTOs.PrimitiveRequirements, "Every header the kind takes, and its sample"),
2285
1758
  422: json(DataDTOs.Fault, "A word that is no kind")
@@ -2332,8 +1805,8 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2332
1805
  path: "/test-suites",
2333
1806
  responses: {
2334
1807
  201: {
2335
- ...json(z12.string(), "The name of the test file written"),
2336
- headers: z12.object({ Location: z12.string() })
1808
+ ...json(z8.string(), "The name of the test file written"),
1809
+ headers: z8.object({ Location: z8.string() })
2337
1810
  }
2338
1811
  }
2339
1812
  }),
@@ -2346,11 +1819,11 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2346
1819
  method: "put",
2347
1820
  path: "/test-suites/{name}",
2348
1821
  request: {
2349
- params: z12.object({ name: z12.string() }),
2350
- body: json(z12.object({ text: z12.string() }), "The whole text the test file is written over with")
1822
+ params: z8.object({ name: z8.string() }),
1823
+ body: json(z8.object({ text: z8.string() }), "The whole text the test file is written over with")
2351
1824
  },
2352
1825
  responses: {
2353
- 200: json(z12.string(), "The name of the test file written"),
1826
+ 200: json(z8.string(), "The name of the test file written"),
2354
1827
  422: json(DataDTOs.Fault, "Text that is not a suite, with its sample, or a name that is no test file")
2355
1828
  }
2356
1829
  }),
@@ -2359,7 +1832,7 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2359
1832
  createRoute({
2360
1833
  method: "delete",
2361
1834
  path: "/test-suites/{name}",
2362
- request: { params: z12.object({ name: z12.string() }) },
1835
+ request: { params: z8.object({ name: z8.string() }) },
2363
1836
  responses: {
2364
1837
  204: { description: "The test file is gone" },
2365
1838
  422: json(DataDTOs.Fault, "A name that is no test file")
@@ -2386,7 +1859,7 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2386
1859
  createRoute({
2387
1860
  method: "get",
2388
1861
  path: "/vendors",
2389
- responses: { 200: json(z12.array(z12.string()).readonly(), "Every folder a vendor source was installed as") }
1862
+ responses: { 200: json(z8.array(z8.string()).readonly(), "Every folder a vendor source was installed as") }
2390
1863
  }),
2391
1864
  async (c) => c.json(await charterVendoringApp2.installed(), 200)
2392
1865
  ).openapi(
@@ -2395,7 +1868,7 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2395
1868
  path: "/vendors",
2396
1869
  request: {
2397
1870
  body: json(
2398
- z12.object({ source: z12.string(), version: z12.string().optional() }),
1871
+ z8.object({ source: z8.string(), version: z8.string().optional() }),
2399
1872
  "A source as git fetches it, and the version to pin it to where one is named"
2400
1873
  )
2401
1874
  },
@@ -2413,7 +1886,7 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2413
1886
  createRoute({
2414
1887
  method: "delete",
2415
1888
  path: "/vendors/{name}",
2416
- request: { params: z12.object({ name: z12.string() }) },
1889
+ request: { params: z8.object({ name: z8.string() }) },
2417
1890
  responses: {
2418
1891
  204: { description: "The folder is gone, and that it is gone is committed" },
2419
1892
  422: json(DataDTOs.Fault, "No repository, work in hand, or what git refused")
@@ -2426,385 +1899,904 @@ function api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2) {
2426
1899
  );
2427
1900
  }
2428
1901
 
2429
- // src/driver/portal/server.ts
2430
- var DEFAULT_PORT = 9927;
2431
- async function startPortal(page, charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2, port = DEFAULT_PORT) {
2432
- await access(new URL("index.html", page)).catch(() => {
2433
- throw new DomainFault("The portal's page is not built.", 'Run "pnpm build", then start the portal again.');
2434
- });
2435
- const token = randomBytes(32).toString("base64url");
2436
- for (let next = port; ; next++) {
2437
- try {
2438
- const address = new URL(`http://127.0.0.1:${next}/?t=${token}`);
2439
- return { address, server: await listen(portal(page, charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2, token, next), next) };
2440
- } catch (raised) {
2441
- if (raised.code !== "EADDRINUSE" || next === 65535) throw raised;
1902
+ // src/driver/portal/server.ts
1903
+ var DEFAULT_PORT = 9927;
1904
+ async function startPortal(page, charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2, port = DEFAULT_PORT) {
1905
+ await access(new URL("index.html", page)).catch(() => {
1906
+ throw new DomainFault("The portal's page is not built.", 'Run "pnpm build", then start the portal again.');
1907
+ });
1908
+ const token = randomBytes(32).toString("base64url");
1909
+ for (let next = port; ; next++) {
1910
+ try {
1911
+ const address = new URL(`http://127.0.0.1:${next}/?t=${token}`);
1912
+ return { address, server: await listen(portal(page, charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2, token, next), next) };
1913
+ } catch (raised) {
1914
+ if (raised.code !== "EADDRINUSE" || next === 65535) throw raised;
1915
+ }
1916
+ }
1917
+ }
1918
+ function portal(page, charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2, token, port) {
1919
+ const hosts = [`127.0.0.1:${port}`, `localhost:${port}`];
1920
+ return new Hono().use(async (c, next) => {
1921
+ if (!hosts.includes(c.req.header("host") ?? "")) {
1922
+ return c.text(`The portal answers only at ${hosts.join(" and ")}.`, 403);
1923
+ }
1924
+ if (c.req.method !== "GET" && c.req.header("content-type")?.split(";")[0]?.trim() !== "application/json") {
1925
+ return c.text("Every request but a GET is sent with Content-Type: application/json.", 415);
1926
+ }
1927
+ await next();
1928
+ }).use("/", async (c, next) => {
1929
+ if (c.req.query("t") !== token) return c.text('Open the address "cw portal" printed: this one has no token.', 401);
1930
+ await next();
1931
+ }).use("/api/*", bearerAuth({ token })).route("/api", api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2)).use("/*", serveStatic({ root: fileURLToPath(page) }));
1932
+ }
1933
+ function listen(app, port) {
1934
+ return new Promise((resolve, reject) => {
1935
+ const server = serve({ fetch: app.fetch, hostname: "127.0.0.1", port }, () => resolve(server));
1936
+ server.once("error", reject);
1937
+ });
1938
+ }
1939
+
1940
+ // src/driver/cli/commands/PortalCommand.ts
1941
+ var OPTIONS7 = {
1942
+ port: {
1943
+ type: "number",
1944
+ describe: "Which port to serve on, the next free one when it is taken",
1945
+ default: DEFAULT_PORT
1946
+ }
1947
+ };
1948
+ var PortalCommand = class {
1949
+ name = "portal";
1950
+ summary = "Serve this repository's charter to a browser on this machine";
1951
+ options = OPTIONS7;
1952
+ async run({ charterAuthoringApp: charterAuthoringApp2, charterVendoringApp: charterVendoringApp2, testAuthoringApp: testAuthoringApp2 }, { port }) {
1953
+ await charterAuthoringApp2.ensureRepoReady();
1954
+ const { address } = await startPortal(
1955
+ new URL("./", import.meta.resolve("#portal/index.html")),
1956
+ charterAuthoringApp2,
1957
+ charterVendoringApp2,
1958
+ testAuthoringApp2,
1959
+ port
1960
+ );
1961
+ return { code: EXIT_OK, result: `The portal is at ${address}
1962
+ Press Ctrl+C to stop it.
1963
+ ` };
1964
+ }
1965
+ };
1966
+
1967
+ // src/driver/cli/commands/RemoveCommand.ts
1968
+ import prompts4 from "prompts";
1969
+ var OPTIONS8 = {
1970
+ id: {
1971
+ type: "string",
1972
+ describe: 'What the primitive is named by across the whole charter, its id: "no-any"'
1973
+ },
1974
+ yes: {
1975
+ type: "boolean",
1976
+ alias: "y",
1977
+ default: false,
1978
+ describe: "Remove it without asking first, as a run with nobody at the terminal must"
1979
+ }
1980
+ };
1981
+ var RemoveCommand = class {
1982
+ name = "remove <id>";
1983
+ summary = "Delete the file of one primitive this repository authored";
1984
+ options = OPTIONS8;
1985
+ async run({ charterAuthoringApp: charterAuthoringApp2 }, { id, yes }) {
1986
+ const primitive = (await charterAuthoringApp2.open(id ?? "")).data;
1987
+ if (!yes && primitive.layerName === REPO_LAYER) {
1988
+ if (!process.stdin.isTTY)
1989
+ throw new DomainFault(
1990
+ `Removing ${primitive.file} is asked first, and nobody is at the terminal to answer.`,
1991
+ `Run "cw remove ${primitive.id} --yes" to remove it without asking.`
1992
+ );
1993
+ const { confirmed } = await prompts4({
1994
+ type: "confirm",
1995
+ name: "confirmed",
1996
+ message: `Remove ${primitive.file}?`,
1997
+ initial: false
1998
+ });
1999
+ if (confirmed !== true) return { code: EXIT_OK, result: "Nothing was removed.\n" };
2000
+ }
2001
+ const primitiveDTO2 = await charterAuthoringApp2.remove(primitive.id);
2002
+ return {
2003
+ code: EXIT_OK,
2004
+ result: [
2005
+ `Removed ${primitiveDTO2.data.file}.`,
2006
+ 'Run "cw doctor" to see what still names it, then "cw build".',
2007
+ ""
2008
+ ].join("\n")
2009
+ };
2010
+ }
2011
+ };
2012
+
2013
+ // src/driver/cli/commands/SuiteAddCommand.ts
2014
+ var SuiteAddCommand = class {
2015
+ name = "suite add";
2016
+ summary = `Write a new test file under ${TEST_DIRECTORY}/, holding one sample case`;
2017
+ async run({ testAuthoringApp: testAuthoringApp2 }) {
2018
+ const name = await testAuthoringApp2.addSuite();
2019
+ return {
2020
+ code: EXIT_OK,
2021
+ result: [`Wrote ${TEST_DIRECTORY}/${name}.`, `Run "cw suite edit ${name}" to write its cases, then "cw test".`, ""].join("\n")
2022
+ };
2023
+ }
2024
+ };
2025
+
2026
+ // src/driver/cli/commands/SuiteEditCommand.ts
2027
+ var OPTIONS9 = {
2028
+ name: {
2029
+ type: "string",
2030
+ describe: `The test file's name under ${TEST_DIRECTORY}/: "untitled-1.json"`
2031
+ }
2032
+ };
2033
+ var SuiteEditCommand = class {
2034
+ name = "suite edit <name>";
2035
+ summary = "Open one test file in your editor";
2036
+ options = OPTIONS9;
2037
+ async run({ cwd, testAuthoringApp: testAuthoringApp2 }, { name }) {
2038
+ const { testSuites } = (await testAuthoringApp2.suites()).data;
2039
+ if (!testSuites.some((one) => one.data.name === name))
2040
+ throw new DomainFault(`${TEST_DIRECTORY}/ holds no test file called "${name ?? ""}".`, 'Run "cw suite add" to write a new one.');
2041
+ const file = `${TEST_DIRECTORY}/${name}`;
2042
+ const problem = await editInEditor(cwd, file);
2043
+ if (problem !== void 0) return { code: EXIT_FAILURE, problem };
2044
+ return { code: EXIT_OK, result: [`Closed ${file}.`, 'Run "cw test" to see how its cases come out.', ""].join("\n") };
2045
+ }
2046
+ };
2047
+
2048
+ // src/driver/cli/commands/SuiteRemoveCommand.ts
2049
+ var OPTIONS10 = {
2050
+ name: {
2051
+ type: "string",
2052
+ describe: `The test file's name under ${TEST_DIRECTORY}/: "untitled-1.json"`
2053
+ }
2054
+ };
2055
+ var SuiteRemoveCommand = class {
2056
+ name = "suite remove <name>";
2057
+ summary = "Delete one test file";
2058
+ options = OPTIONS10;
2059
+ async run({ testAuthoringApp: testAuthoringApp2 }, { name }) {
2060
+ const removedName = await testAuthoringApp2.removeSuite(name ?? "");
2061
+ return { code: EXIT_OK, result: `Removed ${TEST_DIRECTORY}/${removedName}.
2062
+ ` };
2063
+ }
2064
+ };
2065
+
2066
+ // src/driver/cli/commands/TestCommand.ts
2067
+ var TestCommand = class {
2068
+ name = "test";
2069
+ summary = `Resolve every situation in ${TEST_DIRECTORY}/ against the charter`;
2070
+ async run({ charterAuthoringApp: charterAuthoringApp2 }, _options) {
2071
+ const testRunReportDTO2 = await charterAuthoringApp2.test();
2072
+ if (testRunReportDTO2.type === "FaultsByFile")
2073
+ return { code: EXIT_FAILURE, problem: `Nothing was resolved.
2074
+
2075
+ ${toText(testRunReportDTO2)}` };
2076
+ const cases = testRunReportDTO2.data.testCaseReports;
2077
+ if (cases.length === 0) {
2078
+ return {
2079
+ code: EXIT_OK,
2080
+ result: `No tests: ${TEST_DIRECTORY}/ holds no case.
2081
+ Write one as ${TEST_DIRECTORY}/<name>.json to pin a situation down.
2082
+ `
2083
+ };
2442
2084
  }
2085
+ const failed = cases.filter((one) => !one.data.passed);
2086
+ return {
2087
+ code: failed.length === 0 ? EXIT_OK : EXIT_FAILURE,
2088
+ result: [
2089
+ ...cases.flatMap(lines2),
2090
+ "",
2091
+ failed.length === 0 ? `${cases.length} case${cases.length === 1 ? "" : "s"} passed.` : `${failed.length} of ${cases.length} case${cases.length === 1 ? "" : "s"} failed.`,
2092
+ ""
2093
+ ].join("\n")
2094
+ };
2443
2095
  }
2444
- }
2445
- function portal(page, charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2, token, port) {
2446
- const hosts = [`127.0.0.1:${port}`, `localhost:${port}`];
2447
- return new Hono().use(async (c, next) => {
2448
- if (!hosts.includes(c.req.header("host") ?? "")) {
2449
- return c.text(`The portal answers only at ${hosts.join(" and ")}.`, 403);
2450
- }
2451
- if (c.req.method !== "GET" && c.req.header("content-type")?.split(";")[0]?.trim() !== "application/json") {
2452
- return c.text("Every request but a GET is sent with Content-Type: application/json.", 415);
2453
- }
2454
- await next();
2455
- }).use("/", async (c, next) => {
2456
- if (c.req.query("t") !== token) return c.text('Open the address "cw portal" printed: this one has no token.', 401);
2457
- await next();
2458
- }).use("/api/*", bearerAuth({ token })).route("/api", api(charterAuthoringApp2, charterVendoringApp2, testAuthoringApp2)).use("/*", serveStatic({ root: fileURLToPath(page) }));
2459
- }
2460
- function listen(app, port) {
2461
- return new Promise((resolve, reject) => {
2462
- const server = serve({ fetch: app.fetch, hostname: "127.0.0.1", port }, () => resolve(server));
2463
- server.once("error", reject);
2464
- });
2096
+ };
2097
+ function lines2(one) {
2098
+ return [
2099
+ ` ${one.data.passed ? "pass" : "FAIL"} ${one.data.situation}`,
2100
+ ...one.data.unmet === void 0 ? [] : [` ${one.data.unmet.data.message}`, ` ${one.data.unmet.data.fix}`]
2101
+ ];
2465
2102
  }
2466
2103
 
2467
- // src/driver/cli/commands/PortalCommand.ts
2468
- var OPTIONS7 = {
2469
- port: {
2470
- type: "number",
2471
- describe: "Which port to serve on, the next free one when it is taken",
2472
- default: DEFAULT_PORT
2104
+ // src/driver/cli/commands/VendorAddCommand.ts
2105
+ var OPTIONS11 = {
2106
+ source: {
2107
+ type: "string",
2108
+ describe: "What git clones the charter from: an address over any transport, or a path on disk"
2109
+ },
2110
+ ref: {
2111
+ type: "string",
2112
+ describe: "The tag, branch or commit to pin to; the source's own default where none is named"
2473
2113
  }
2474
2114
  };
2475
- var PortalCommand = class {
2476
- name = "portal";
2477
- summary = "Serve this repository's charter to a browser on this machine";
2478
- options = OPTIONS7;
2479
- async run({ charterAuthoringApp: charterAuthoringApp2, charterVendoringApp: charterVendoringApp2, testAuthoringApp: testAuthoringApp2 }, { port }) {
2480
- await charterAuthoringApp2.ensureRepoReady();
2481
- const { address } = await startPortal(
2482
- new URL("./", import.meta.resolve("#portal/index.html")),
2483
- charterAuthoringApp2,
2484
- charterVendoringApp2,
2485
- testAuthoringApp2,
2486
- port
2487
- );
2488
- return { code: EXIT_OK, result: `The portal is at ${address}
2489
- Press Ctrl+C to stop it.
2115
+ var VendorAddCommand = class {
2116
+ name = "vendor add <source>";
2117
+ summary = "Install a charter from a git source, or bring an installed one up to date";
2118
+ options = OPTIONS11;
2119
+ async run({ charterVendoringApp: charterVendoringApp2 }, { source, ref }) {
2120
+ const folder = await charterVendoringApp2.add(source ?? "", ref);
2121
+ return {
2122
+ code: EXIT_OK,
2123
+ result: [
2124
+ `Installed ${source} under ${folder}${ref === void 0 ? "" : `, pinned to ${ref}`}.`,
2125
+ 'Run "cw build" to compile what it adds to this charter.',
2126
+ ""
2127
+ ].join("\n")
2128
+ };
2129
+ }
2130
+ };
2131
+
2132
+ // src/driver/cli/commands/VendorListCommand.ts
2133
+ var VendorListCommand = class {
2134
+ name = "vendor list";
2135
+ summary = "List the folders this repository installed charters as";
2136
+ async run({ charterVendoringApp: charterVendoringApp2 }) {
2137
+ const folders = await charterVendoringApp2.installed();
2138
+ if (folders.length === 0)
2139
+ return { code: EXIT_OK, result: 'No vendor source is installed. Run "cw vendor add <source>" to install one.\n' };
2140
+ return { code: EXIT_OK, result: `${folders.join("\n")}
2490
2141
  ` };
2491
2142
  }
2492
2143
  };
2493
2144
 
2494
- // src/driver/cli/commands/RemoveCommand.ts
2495
- import prompts4 from "prompts";
2496
- var OPTIONS8 = {
2497
- identity: {
2498
- type: "string",
2499
- describe: 'What the primitive is named by across the whole charter: "guide:no-any"'
2500
- },
2501
- yes: {
2502
- type: "boolean",
2503
- alias: "y",
2504
- default: false,
2505
- describe: "Remove it without asking first, as a run with nobody at the terminal must"
2145
+ // src/driver/cli/commands/VendorRemoveCommand.ts
2146
+ var OPTIONS12 = {
2147
+ name: {
2148
+ type: "string",
2149
+ describe: "The folder this charter was installed as, as it reads under .cw/vendor/"
2150
+ }
2151
+ };
2152
+ var VendorRemoveCommand = class {
2153
+ name = "vendor remove <name>";
2154
+ summary = "Take an installed charter away";
2155
+ options = OPTIONS12;
2156
+ async run({ charterVendoringApp: charterVendoringApp2 }, { name }) {
2157
+ const folder = await charterVendoringApp2.remove(name ?? "");
2158
+ return {
2159
+ code: EXIT_OK,
2160
+ result: [
2161
+ `Removed ${folder}.`,
2162
+ 'Run "cw build" to compile this charter without it.',
2163
+ ""
2164
+ ].join("\n")
2165
+ };
2166
+ }
2167
+ };
2168
+
2169
+ // src/driver/cli/commands/index.ts
2170
+ var COMMANDS = [
2171
+ new InitCommand(),
2172
+ new BuildCommand(),
2173
+ new ListCommand(),
2174
+ new KindsCommand(),
2175
+ new AddCommand(),
2176
+ new EditCommand(),
2177
+ new RemoveCommand(),
2178
+ new ExplainCommand(),
2179
+ new DoctorCommand(),
2180
+ new TestCommand(),
2181
+ new SuiteAddCommand(),
2182
+ new SuiteEditCommand(),
2183
+ new SuiteRemoveCommand(),
2184
+ new VendorAddCommand(),
2185
+ new VendorRemoveCommand(),
2186
+ new VendorListCommand(),
2187
+ new PortalCommand(),
2188
+ new McpAuthCommand(),
2189
+ new McpServeCommand()
2190
+ ];
2191
+
2192
+ // src/driver/cli/Commander.ts
2193
+ var Commander = class {
2194
+ #context;
2195
+ #commands;
2196
+ constructor(context, commands = COMMANDS) {
2197
+ this.#context = context;
2198
+ this.#commands = commands;
2199
+ }
2200
+ async run(argv) {
2201
+ let code = EXIT_OK;
2202
+ let failed = false;
2203
+ await this.#parser((outcome) => {
2204
+ code = outcome.code;
2205
+ if (outcome.result) process.stdout.write(outcome.result);
2206
+ if (outcome.problem) process.stderr.write(outcome.problem);
2207
+ }).parseAsync([...argv], {}, (error, _parsed, output) => {
2208
+ failed = error !== null && error !== void 0;
2209
+ if (output) (failed ? process.stderr : process.stdout).write(`${output}
2210
+ `);
2211
+ });
2212
+ return failed ? EXIT_USAGE : code;
2213
+ }
2214
+ #parser(collect) {
2215
+ let cli2 = yargs().scriptName("cw").usage("Usage: $0 <command> [options]").demandCommand(1, "").strict().recommendCommands().help("help").alias("h", "help").version(this.#context.version).wrap(80).exitProcess(false);
2216
+ const groups = /* @__PURE__ */ new Map();
2217
+ for (const command of this.#commands) {
2218
+ const head = wordsOf(command.name)[0];
2219
+ groups.set(head, [...groups.get(head) ?? [], command]);
2220
+ }
2221
+ for (const [head, commands] of groups) {
2222
+ const [only] = commands;
2223
+ cli2 = commands.length === 1 && only !== void 0 && wordsOf(only.name).length === 1 ? this.#declaringCommand(cli2, only, only.name, collect) : cli2.command({
2224
+ command: head,
2225
+ // What the group is for is what its commands are: saying it any
2226
+ // other way would be a second description to keep in step.
2227
+ describe: commands.map((one) => wordsOf(one.name)[1]).join(", "),
2228
+ builder: (child) => commands.reduce((parser, command) => this.#declaringCommand(parser, command, command.name.slice(head.length + 1), collect), child).demandCommand(1, ""),
2229
+ handler: () => void 0
2230
+ });
2231
+ }
2232
+ return cli2;
2233
+ }
2234
+ /** One command, said to yargs under the name it is typed by — the whole of it
2235
+ * for a command that stands alone, what follows the group for one inside
2236
+ * it. */
2237
+ #declaringCommand(cli2, command, name, collect) {
2238
+ return cli2.command({
2239
+ command: name,
2240
+ describe: command.summary,
2241
+ builder: (child) => declaringArguments(child, command.options ?? {}, name),
2242
+ handler: async (options) => {
2243
+ try {
2244
+ collect(await command.run(this.#context, options));
2245
+ } catch (raised) {
2246
+ if (!(raised instanceof DomainFault)) throw raised;
2247
+ collect({ code: EXIT_FAILURE, problem: `${raised.message}
2248
+ ${raised.fix}
2249
+ ` });
2250
+ }
2251
+ }
2252
+ });
2253
+ }
2254
+ };
2255
+ function wordsOf(name) {
2256
+ return name.split(" ").filter((word) => !word.startsWith("<") && !word.startsWith("["));
2257
+ }
2258
+ function declaringArguments(cli2, options, name) {
2259
+ return Object.entries(options).reduce((parser, [argument, option]) => {
2260
+ const declared = {
2261
+ type: option.type,
2262
+ describe: option.describe,
2263
+ ...option.alias === void 0 ? {} : { alias: option.alias },
2264
+ ...option.default === void 0 ? {} : { default: option.default },
2265
+ // Typed once per value: yargs collects them, and a run that typed none
2266
+ // reads an empty list rather than nothing, so the command asks how many
2267
+ // were typed instead of whether any were.
2268
+ ...option.isArray === void 0 ? {} : { array: true, default: [] }
2269
+ };
2270
+ return name.includes(`<${argument}>`) || name.includes(`[${argument}]`) ? parser.positional(argument, declared) : parser.option(argument, declared);
2271
+ }, cli2);
2272
+ }
2273
+
2274
+ // src/hexagon/utils/globs.ts
2275
+ import picomatch from "picomatch";
2276
+ function covers(outer, inner) {
2277
+ return outer === inner || matches(outer, inner);
2278
+ }
2279
+ function matches(glob, path) {
2280
+ return picomatch(glob, { dot: true })(path);
2281
+ }
2282
+
2283
+ // src/hexagon/domain/models/charter/primitive/Primitive.ts
2284
+ import { z as z12 } from "zod";
2285
+
2286
+ // src/hexagon/domain/models/charter/primitive/AgentPrimitive.ts
2287
+ var AgentHeadersSchema = CommonHeadersSchema.extend({
2288
+ tools: GoodArraySchema
2289
+ });
2290
+ var AgentPrimitive = class _AgentPrimitive extends BasePrimitive {
2291
+ static kind = "agent";
2292
+ kind = _AgentPrimitive.kind;
2293
+ /** What this kind requires beyond the common headers, declared where its
2294
+ * contract is: it is read both where a file is checked and where one is
2295
+ * scaffolded (FR-004, FR-039). */
2296
+ static requires = { tools: "list" };
2297
+ /** The schema its headers are read by: what `headersOf` refuses a file
2298
+ * against, and what says the shape of every header this kind takes, required
2299
+ * or not (FR-004). */
2300
+ static schema = AgentHeadersSchema;
2301
+ /** When a reader of this charter is to open this kind at all, said
2302
+ * where the kind's contract is: the neutral surface lists one
2303
+ * line per kind and none of them is written down twice (FR-002). */
2304
+ static activatesWhen = "it is spawned by id, holding the `tools` it lists and nothing else \u2014 a place as `[[<id>]]`, or one of its tools as `[[<id>]]:<tool>`";
2305
+ /** An agent as an author writes one: what a refused header is fixed with.
2306
+ * It holds one tool of a place the way an author writes it (FR-156). */
2307
+ static sample = {
2308
+ id: "reviewer",
2309
+ description: "Review a diff and name what is wrong with it.",
2310
+ tools: ["Read", "Grep", "[[mfbs/billing]]:search_code"]
2311
+ };
2312
+ /** One agent, or every fault its headers have (FR-004). */
2313
+ static of(record, body, assetFiles = [], primitiveLayer) {
2314
+ return new _AgentPrimitive(headersOf(_AgentPrimitive, AgentHeadersSchema, record), body, assetFiles, primitiveLayer);
2506
2315
  }
2507
2316
  };
2508
- var RemoveCommand = class {
2509
- name = "remove <identity>";
2510
- summary = "Delete the file of one primitive this repository authored";
2511
- options = OPTIONS8;
2512
- async run({ charterAuthoringApp: charterAuthoringApp2 }, { identity, yes }) {
2513
- const primitive = (await charterAuthoringApp2.open(identity ?? "")).data;
2514
- if (!yes && primitive.layerName === REPO_LAYER) {
2515
- if (!process.stdin.isTTY)
2516
- throw new DomainFault(
2517
- `Removing ${primitive.file} is asked first, and nobody is at the terminal to answer.`,
2518
- `Run "cw remove ${primitive.identity} --yes" to remove it without asking.`
2519
- );
2520
- const { confirmed } = await prompts4({
2521
- type: "confirm",
2522
- name: "confirmed",
2523
- message: `Remove ${primitive.file}?`,
2524
- initial: false
2525
- });
2526
- if (confirmed !== true) return { code: EXIT_OK, result: "Nothing was removed.\n" };
2527
- }
2528
- const primitiveDTO2 = await charterAuthoringApp2.remove(primitive.identity);
2529
- return {
2530
- code: EXIT_OK,
2531
- result: [
2532
- `Removed ${primitiveDTO2.data.file}.`,
2533
- 'Run "cw doctor" to see what still names it, then "cw build".',
2534
- ""
2535
- ].join("\n")
2536
- };
2317
+
2318
+ // src/hexagon/domain/models/charter/primitive/CorpusPrimitive.ts
2319
+ var CorpusHeadersSchema = CommonHeadersSchema.extend({});
2320
+ var CorpusPrimitive = class _CorpusPrimitive extends BasePrimitive {
2321
+ static kind = "corpus";
2322
+ kind = _CorpusPrimitive.kind;
2323
+ /** What this kind requires beyond the common headers: nothing. Declared all
2324
+ * the same, since what a file is scaffolded with is read off this (FR-039). */
2325
+ static requires = {};
2326
+ /** The schema its headers are read by: what `headersOf` refuses a file
2327
+ * against, and what says the shape of every header this kind takes, required
2328
+ * or not (FR-004). */
2329
+ static schema = CorpusHeadersSchema;
2330
+ /** When a reader of this charter is to open this kind at all, said
2331
+ * where the kind's contract is: the neutral surface lists one
2332
+ * line per kind and none of them is written down twice (FR-002). */
2333
+ static activatesWhen = "a primitive's `rationale` cites it \u2014 the reasoning, read when someone asks why";
2334
+ /** A corpus as an author writes one: what a refused header is fixed with. */
2335
+ static sample = {
2336
+ id: "type-safety",
2337
+ description: "Why the charter insists on types."
2338
+ };
2339
+ /** One corpus, or every fault its headers have (FR-004). */
2340
+ static of(record, body, assetFiles = [], primitiveLayer) {
2341
+ return new _CorpusPrimitive(headersOf(_CorpusPrimitive, CorpusHeadersSchema, record), body, assetFiles, primitiveLayer);
2537
2342
  }
2538
2343
  };
2539
2344
 
2540
- // src/driver/cli/commands/SuiteAddCommand.ts
2541
- var SuiteAddCommand = class {
2542
- name = "suite add";
2543
- summary = `Write a new test file under ${TEST_DIRECTORY}/, holding one sample case`;
2544
- async run({ testAuthoringApp: testAuthoringApp2 }) {
2545
- const name = await testAuthoringApp2.addSuite();
2546
- return {
2547
- code: EXIT_OK,
2548
- result: [`Wrote ${TEST_DIRECTORY}/${name}.`, `Run "cw suite edit ${name}" to write its cases, then "cw test".`, ""].join("\n")
2549
- };
2345
+ // src/hexagon/domain/models/charter/primitive/GuidePrimitive.ts
2346
+ var GuideHeadersSchema = CommonHeadersSchema.extend({});
2347
+ var GuidePrimitive = class _GuidePrimitive extends BasePrimitive {
2348
+ static kind = "guide";
2349
+ kind = _GuidePrimitive.kind;
2350
+ /** What this kind requires beyond the common headers: nothing. Declared all
2351
+ * the same, since what a file is scaffolded with is read off this (FR-039). */
2352
+ static requires = {};
2353
+ /** The schema its headers are read by: what `headersOf` refuses a file
2354
+ * against, and what says the shape of every header this kind takes, required
2355
+ * or not (FR-004). */
2356
+ static schema = GuideHeadersSchema;
2357
+ /** When a reader of this charter is to open this kind at all, said
2358
+ * where the kind's contract is: the neutral surface lists one
2359
+ * line per kind and none of them is written down twice (FR-002). */
2360
+ static activatesWhen = "a touched file matches one of its `globs`, or every turn where globs are not specified";
2361
+ /** A guide as an author writes one: what a refused header is fixed with. */
2362
+ static sample = {
2363
+ id: "no-any",
2364
+ description: "Reject the any type in application code.",
2365
+ globs: ["src/**/*.ts"],
2366
+ tags: ["typescript"],
2367
+ rationale: "type-safety"
2368
+ };
2369
+ /** One guide, or every fault its headers have (FR-004). */
2370
+ static of(record, body, assetFiles = [], primitiveLayer) {
2371
+ return new _GuidePrimitive(headersOf(_GuidePrimitive, GuideHeadersSchema, record), body, assetFiles, primitiveLayer);
2550
2372
  }
2551
2373
  };
2552
2374
 
2553
- // src/driver/cli/commands/SuiteEditCommand.ts
2554
- var OPTIONS9 = {
2555
- name: {
2556
- type: "string",
2557
- describe: `The test file's name under ${TEST_DIRECTORY}/: "untitled-1.json"`
2375
+ // src/hexagon/domain/models/charter/primitive/McpPrimitive.ts
2376
+ import { z as z9 } from "zod";
2377
+
2378
+ // src/hexagon/domain/models/McpAuthMethod.ts
2379
+ var MCP_AUTH_METHODS = ["oauth", "token"];
2380
+
2381
+ // src/hexagon/domain/models/charter/primitive/McpPrimitive.ts
2382
+ function isSecureEndpoint(endpoint) {
2383
+ if (!URL.canParse(endpoint)) return false;
2384
+ const endpointURL = new URL(endpoint);
2385
+ return endpointURL.protocol === "https:" || endpointURL.protocol === "http:" && ["127.0.0.1", "localhost"].includes(endpointURL.hostname);
2386
+ }
2387
+ var McpHeadersSchema = CommonHeadersSchema.extend({
2388
+ /** Reached over HTTP. Plain `http` only to this machine, for a server under
2389
+ * test: anything else would send a developer's credential in the clear. */
2390
+ endpoint: GoodLineSchema.refine(isSecureEndpoint, {
2391
+ message: `"endpoint" is an https:// URL, or http:// to 127.0.0.1 or localhost for a server under test.`
2392
+ }).optional(),
2393
+ /** Started as a local process, spoken to over its standard input and output. */
2394
+ command: GoodLineSchema.optional(),
2395
+ args: z9.array(GoodLineSchema).readonly().optional(),
2396
+ auth: z9.array(z9.enum(MCP_AUTH_METHODS)).min(1).readonly().optional(),
2397
+ /** The environment variable a command reads its token from. */
2398
+ tokenEnv: z9.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/).optional(),
2399
+ /** The place inside that server: a repository, a database, a channel. */
2400
+ path: GoodLineSchema.optional(),
2401
+ /** The server's tools the agent may use there, by the server's own names. */
2402
+ tools: GoodArraySchema
2403
+ }).superRefine((headers, context) => {
2404
+ const addFault = (message) => context.addIssue({ code: "custom", message });
2405
+ const { endpoint, command, args, auth: auth2, tokenEnv } = headers;
2406
+ if (endpoint !== void 0 && command !== void 0)
2407
+ return addFault(`This declares both "endpoint" and "command"; an mcp is one server, reached one way.`);
2408
+ if (endpoint === void 0 && command === void 0)
2409
+ return addFault(`This declares neither "endpoint" nor "command", so there is no server to reach.`);
2410
+ if (endpoint !== void 0) {
2411
+ if (auth2 === void 0) addFault(`An endpoint says how a developer signs in to it: "auth" of oauth, token or both.`);
2412
+ if (args !== void 0) addFault(`"args" are a command's; an endpoint takes none.`);
2413
+ if (tokenEnv !== void 0) addFault(`"tokenEnv" is where a command reads its token; an endpoint takes none.`);
2414
+ return;
2415
+ }
2416
+ const takesToken = auth2 !== void 0;
2417
+ if (takesToken && (auth2.length !== 1 || auth2[0] !== "token"))
2418
+ addFault(`A command signs in by token alone: "auth: [token]", or no "auth" for one that takes none.`);
2419
+ if (takesToken && tokenEnv === void 0) addFault(`A command taking a token names where it reads it: "tokenEnv".`);
2420
+ if (!takesToken && tokenEnv !== void 0) addFault(`"tokenEnv" is read only by a command taking a token: add "auth: [token]", or drop it.`);
2421
+ });
2422
+ var McpPrimitive = class _McpPrimitive extends BasePrimitive {
2423
+ static kind = "mcp";
2424
+ kind = _McpPrimitive.kind;
2425
+ /** What this kind requires beyond the common headers. `endpoint` or
2426
+ * `command` is required too, but which depends on the shape, so the schema's
2427
+ * refinement says it rather than this (FR-004, FR-039). */
2428
+ static requires = { tools: "list" };
2429
+ /** The schema its headers are read by: what `headersOf` refuses a file
2430
+ * against, and what says the shape of every header this kind takes, required
2431
+ * or not (FR-004). */
2432
+ static schema = McpHeadersSchema;
2433
+ /** When a reader of this charter is to open this kind at all, said
2434
+ * where the kind's contract is: the neutral surface lists one
2435
+ * line per kind and none of them is written down twice (FR-002). */
2436
+ static activatesWhen = "a primitive's body names it as `[[<id>]]` \u2014 a place outside the repository, reached through `cw mcp serve`";
2437
+ /** An mcp reached at an endpoint, as an author writes one: what a refused
2438
+ * header is fixed with. */
2439
+ static sample = {
2440
+ id: "mfbs/billing",
2441
+ description: "Billing service code and pull requests.",
2442
+ endpoint: "https://api.githubcopilot.com/mcp/",
2443
+ path: "moneyforward/billing-service",
2444
+ auth: ["oauth", "token"],
2445
+ tools: ["get_file_contents", "search_code", "list_pull_requests"]
2446
+ };
2447
+ /** The same place started as a local process: what a refused file declaring
2448
+ * `command` is held up against, since that is the shape it was nearer. */
2449
+ static commandSample = {
2450
+ id: "mfbs/billing",
2451
+ description: "Billing service code and pull requests.",
2452
+ command: "npx",
2453
+ args: ["-y", "@modelcontextprotocol/server-github"],
2454
+ tokenEnv: "GITHUB_PERSONAL_ACCESS_TOKEN",
2455
+ auth: ["token"],
2456
+ path: "moneyforward/billing-service",
2457
+ tools: ["get_file_contents", "search_code", "list_pull_requests"]
2458
+ };
2459
+ /** What a developer signs in to, and what places are told apart by beside
2460
+ * their `path`: the endpoint, or the command followed by each of its
2461
+ * arguments. The refinement has already held that one of the two is here
2462
+ * (FR-142). */
2463
+ get address() {
2464
+ const { endpoint, command, args = [] } = this.headers;
2465
+ return endpoint ?? [command, ...args].join(" ");
2466
+ }
2467
+ /** One mcp, or every fault its headers have, shown the sample of the shape
2468
+ * it declared (FR-004, FR-142). */
2469
+ static of(record, body, assetFiles = [], primitiveLayer) {
2470
+ const nearerSample = record.command === void 0 ? _McpPrimitive.sample : _McpPrimitive.commandSample;
2471
+ return new _McpPrimitive(headersOf({ kind: _McpPrimitive.kind, sample: nearerSample }, McpHeadersSchema, record), body, assetFiles, primitiveLayer);
2558
2472
  }
2559
2473
  };
2560
- var SuiteEditCommand = class {
2561
- name = "suite edit <name>";
2562
- summary = "Open one test file in your editor";
2563
- options = OPTIONS9;
2564
- async run({ cwd, testAuthoringApp: testAuthoringApp2 }, { name }) {
2565
- const { testSuites } = (await testAuthoringApp2.suites()).data;
2566
- if (!testSuites.some((one) => one.data.name === name))
2567
- throw new DomainFault(`${TEST_DIRECTORY}/ holds no test file called "${name ?? ""}".`, 'Run "cw suite add" to write a new one.');
2568
- const file = `${TEST_DIRECTORY}/${name}`;
2569
- const problem = await editInEditor(cwd, file);
2570
- if (problem !== void 0) return { code: EXIT_FAILURE, problem };
2571
- return { code: EXIT_OK, result: [`Closed ${file}.`, 'Run "cw test" to see how its cases come out.', ""].join("\n") };
2474
+
2475
+ // src/hexagon/domain/models/charter/primitive/MixinPrimitive.ts
2476
+ import { z as z10 } from "zod";
2477
+ var MixinHeadersSchema = CommonHeadersSchema.extend({
2478
+ /** Never: reading refuses a mixin that declares one. */
2479
+ mixins: z10.undefined().optional()
2480
+ });
2481
+ var MixinPrimitive = class _MixinPrimitive extends BasePrimitive {
2482
+ static kind = "mixin";
2483
+ kind = _MixinPrimitive.kind;
2484
+ /** What this kind requires beyond the common headers: nothing. Declared all
2485
+ * the same, since what a file is scaffolded with is read off this (FR-039). */
2486
+ static requires = {};
2487
+ /** The schema its headers are read by: what `headersOf` refuses a file
2488
+ * against, and what says the shape of every header this kind takes, required
2489
+ * or not (FR-004). */
2490
+ static schema = MixinHeadersSchema;
2491
+ /** When a reader of this charter is to open this kind at all, said
2492
+ * where the kind's contract is: the neutral surface lists one
2493
+ * line per kind and none of them is written down twice (FR-002). */
2494
+ static activatesWhen = "never on its own: its body is lent to the primitives that pull it in";
2495
+ /** A mixin as an author writes one: what a refused header is fixed with. */
2496
+ static sample = {
2497
+ id: "typescript-scope",
2498
+ description: "What counts as TypeScript application code.",
2499
+ globs: ["src/**/*.ts"]
2500
+ };
2501
+ /** One mixin, or every fault its headers have (FR-004, FR-006). */
2502
+ static of(record, body, assetFiles = [], primitiveLayer) {
2503
+ return new _MixinPrimitive(headersOf(_MixinPrimitive, MixinHeadersSchema, record), body, assetFiles, primitiveLayer);
2572
2504
  }
2573
2505
  };
2574
2506
 
2575
- // src/driver/cli/commands/SuiteRemoveCommand.ts
2576
- var OPTIONS10 = {
2577
- name: {
2578
- type: "string",
2579
- describe: `The test file's name under ${TEST_DIRECTORY}/: "untitled-1.json"`
2507
+ // src/hexagon/domain/models/charter/primitive/PlaybookPrimitive.ts
2508
+ var PlaybookHeadersSchema = CommonHeadersSchema.extend({
2509
+ triggers: GoodArraySchema
2510
+ });
2511
+ var PlaybookPrimitive = class _PlaybookPrimitive extends BasePrimitive {
2512
+ static kind = "playbook";
2513
+ kind = _PlaybookPrimitive.kind;
2514
+ /** What this kind requires beyond the common headers, declared where its
2515
+ * contract is: it is read both where a file is checked and where one is
2516
+ * scaffolded (FR-004, FR-039). */
2517
+ static requires = { triggers: "list" };
2518
+ /** The schema its headers are read by: what `headersOf` refuses a file
2519
+ * against, and what says the shape of every header this kind takes, required
2520
+ * or not (FR-004). */
2521
+ static schema = PlaybookHeadersSchema;
2522
+ /** When a reader of this charter is to open this kind at all, said
2523
+ * where the kind's contract is: the neutral surface lists one
2524
+ * line per kind and none of them is written down twice (FR-002). */
2525
+ static activatesWhen = "one of its `triggers` matches; the body is a sequence of skills";
2526
+ /** A playbook as an author writes one: what a refused header is fixed with. */
2527
+ static sample = {
2528
+ id: "ship-a-feature",
2529
+ description: "Take a finished branch from review to release.",
2530
+ triggers: ["ship this", "release this feature"]
2531
+ };
2532
+ /** What this is found by: what it is for, and the requests its author said
2533
+ * bring it up. */
2534
+ description() {
2535
+ return `${this.headers.description} Use when: ${this.headers.triggers.join("; ")}.`;
2580
2536
  }
2581
- };
2582
- var SuiteRemoveCommand = class {
2583
- name = "suite remove <name>";
2584
- summary = "Delete one test file";
2585
- options = OPTIONS10;
2586
- async run({ testAuthoringApp: testAuthoringApp2 }, { name }) {
2587
- const removedName = await testAuthoringApp2.removeSuite(name ?? "");
2588
- return { code: EXIT_OK, result: `Removed ${TEST_DIRECTORY}/${removedName}.
2589
- ` };
2537
+ /** One playbook, or every fault its headers have (FR-004). */
2538
+ static of(record, body, assetFiles = [], primitiveLayer) {
2539
+ return new _PlaybookPrimitive(headersOf(_PlaybookPrimitive, PlaybookHeadersSchema, record), body, assetFiles, primitiveLayer);
2590
2540
  }
2591
2541
  };
2592
2542
 
2593
- // src/driver/cli/commands/TestCommand.ts
2594
- var TestCommand = class {
2595
- name = "test";
2596
- summary = `Resolve every situation in ${TEST_DIRECTORY}/ against the charter`;
2597
- async run({ charterAuthoringApp: charterAuthoringApp2 }, _options) {
2598
- const testRunReportDTO2 = await charterAuthoringApp2.test();
2599
- if (testRunReportDTO2.type === "FaultsByFile")
2600
- return { code: EXIT_FAILURE, problem: `Nothing was resolved.
2601
-
2602
- ${toText(testRunReportDTO2)}` };
2603
- const cases = testRunReportDTO2.data.testCaseReports;
2604
- if (cases.length === 0) {
2605
- return {
2606
- code: EXIT_OK,
2607
- result: `No tests: ${TEST_DIRECTORY}/ holds no case.
2608
- Write one as ${TEST_DIRECTORY}/<name>.json to pin a situation down.
2609
- `
2610
- };
2611
- }
2612
- const failed = cases.filter((one) => !one.data.passed);
2613
- return {
2614
- code: failed.length === 0 ? EXIT_OK : EXIT_FAILURE,
2615
- result: [
2616
- ...cases.flatMap(lines2),
2617
- "",
2618
- failed.length === 0 ? `${cases.length} case${cases.length === 1 ? "" : "s"} passed.` : `${failed.length} of ${cases.length} case${cases.length === 1 ? "" : "s"} failed.`,
2619
- ""
2620
- ].join("\n")
2621
- };
2543
+ // src/hexagon/domain/models/charter/primitive/PosturePrimitive.ts
2544
+ var PostureHeadersSchema = CommonHeadersSchema.extend({
2545
+ allow: GoodArraySchema,
2546
+ deny: GoodArraySchema
2547
+ });
2548
+ var PosturePrimitive = class _PosturePrimitive extends BasePrimitive {
2549
+ static kind = "posture";
2550
+ kind = _PosturePrimitive.kind;
2551
+ /** What this kind requires beyond the common headers, declared where its
2552
+ * contract is: it is read both where a file is checked and where one is
2553
+ * scaffolded (FR-004, FR-039). */
2554
+ static requires = { allow: "list", deny: "list" };
2555
+ /** The schema its headers are read by: what `headersOf` refuses a file
2556
+ * against, and what says the shape of every header this kind takes, required
2557
+ * or not (FR-004). */
2558
+ static schema = PostureHeadersSchema;
2559
+ /** When a reader of this charter is to open this kind at all, said
2560
+ * where the kind's contract is: the neutral surface lists one
2561
+ * line per kind and none of them is written down twice (FR-002). */
2562
+ static activatesWhen = "always, wherever the host can be told what to `allow` and what to `deny`";
2563
+ /** A posture as an author writes one: what a refused header is fixed with. */
2564
+ static sample = {
2565
+ id: "no-force-push",
2566
+ description: "Never rewrite history someone else may have pulled.",
2567
+ allow: ["Bash(git push:*)"],
2568
+ deny: ["Bash(git push --force:*)"]
2569
+ };
2570
+ /** One posture, or every fault its headers have (FR-004). */
2571
+ static of(record, body, assetFiles = [], primitiveLayer) {
2572
+ return new _PosturePrimitive(headersOf(_PosturePrimitive, PostureHeadersSchema, record), body, assetFiles, primitiveLayer);
2622
2573
  }
2623
2574
  };
2624
- function lines2(one) {
2625
- return [
2626
- ` ${one.data.passed ? "pass" : "FAIL"} ${one.data.situation}`,
2627
- ...one.data.unmet === void 0 ? [] : [` ${one.data.unmet.data.message}`, ` ${one.data.unmet.data.fix}`]
2628
- ];
2629
- }
2630
2575
 
2631
- // src/driver/cli/commands/VendorAddCommand.ts
2632
- var OPTIONS11 = {
2633
- source: {
2634
- type: "string",
2635
- describe: "What git clones the charter from: an address over any transport, or a path on disk"
2636
- },
2637
- ref: {
2638
- type: "string",
2639
- describe: "The tag, branch or commit to pin to; the source's own default where none is named"
2576
+ // src/hexagon/domain/models/charter/primitive/SkillPrimitive.ts
2577
+ var SkillHeadersSchema = CommonHeadersSchema.extend({
2578
+ triggers: GoodArraySchema
2579
+ });
2580
+ var SkillPrimitive = class _SkillPrimitive extends BasePrimitive {
2581
+ static kind = "skill";
2582
+ kind = _SkillPrimitive.kind;
2583
+ /** What this kind requires beyond the common headers, declared where its
2584
+ * contract is: it is read both where a file is checked and where one is
2585
+ * scaffolded (FR-004, FR-039). */
2586
+ static requires = { triggers: "list" };
2587
+ /** The schema its headers are read by: what `headersOf` refuses a file
2588
+ * against, and what says the shape of every header this kind takes, required
2589
+ * or not (FR-004). */
2590
+ static schema = SkillHeadersSchema;
2591
+ /** When a reader of this charter is to open this kind at all, said
2592
+ * where the kind's contract is: the neutral surface lists one
2593
+ * line per kind and none of them is written down twice (FR-002). */
2594
+ static activatesWhen = "one of its `triggers` matches what is being asked";
2595
+ /** A skill as an author writes one: what a refused header is fixed with. */
2596
+ static sample = {
2597
+ id: "refactoring",
2598
+ description: "Change how code is structured without changing what it does.",
2599
+ triggers: ["refactor this", "clean this up"]
2600
+ };
2601
+ /** What this is found by: what it is for, and the requests its author said
2602
+ * bring it up. */
2603
+ description() {
2604
+ return `${this.headers.description} Use when: ${this.headers.triggers.join("; ")}.`;
2640
2605
  }
2641
- };
2642
- var VendorAddCommand = class {
2643
- name = "vendor add <source>";
2644
- summary = "Install a charter from a git source, or bring an installed one up to date";
2645
- options = OPTIONS11;
2646
- async run({ charterVendoringApp: charterVendoringApp2 }, { source, ref }) {
2647
- const folder = await charterVendoringApp2.add(source ?? "", ref);
2648
- return {
2649
- code: EXIT_OK,
2650
- result: [
2651
- `Installed ${source} under ${folder}${ref === void 0 ? "" : `, pinned to ${ref}`}.`,
2652
- 'Run "cw build" to compile what it adds to this charter.',
2653
- ""
2654
- ].join("\n")
2655
- };
2606
+ /** One skill, or every fault its headers have (FR-004). */
2607
+ static of(record, body, assetFiles = [], primitiveLayer) {
2608
+ return new _SkillPrimitive(headersOf(_SkillPrimitive, SkillHeadersSchema, record), body, assetFiles, primitiveLayer);
2656
2609
  }
2657
2610
  };
2658
2611
 
2659
- // src/driver/cli/commands/VendorListCommand.ts
2660
- var VendorListCommand = class {
2661
- name = "vendor list";
2662
- summary = "List the folders this repository installed charters as";
2663
- async run({ charterVendoringApp: charterVendoringApp2 }) {
2664
- const folders = await charterVendoringApp2.installed();
2665
- if (folders.length === 0)
2666
- return { code: EXIT_OK, result: 'No vendor source is installed. Run "cw vendor add <source>" to install one.\n' };
2667
- return { code: EXIT_OK, result: `${folders.join("\n")}
2668
- ` };
2612
+ // src/hexagon/domain/models/charter/primitive/ScriptPrimitive.ts
2613
+ import { z as z11 } from "zod";
2614
+ var ScriptHeadersSchema = CommonHeadersSchema.extend({
2615
+ /** The one asset that runs, from the script's `index.md`: `./` and a path
2616
+ * inside its folder, no segment of which climbs out again. Letters, digits,
2617
+ * `.`, `_` and `-` only: it is written into commands a shell reads
2618
+ * (FR-169). */
2619
+ executionPath: z11.string().regex(/^\.\/[A-Za-z0-9._-]+(\/[A-Za-z0-9._-]+)*$/).refine((executionPath) => !executionPath.split("/").slice(1).some((segment) => segment === "." || segment === ".."), {
2620
+ message: `"executionPath" stays inside the script's own folder: no segment of it is "." or "..".`
2621
+ })
2622
+ });
2623
+ var ScriptPrimitive = class _ScriptPrimitive extends BasePrimitive {
2624
+ static kind = "script";
2625
+ kind = _ScriptPrimitive.kind;
2626
+ /** What this kind requires beyond the common headers, declared where its
2627
+ * contract is (FR-004, FR-039). */
2628
+ static requires = { executionPath: "line" };
2629
+ /** The schema its headers are read by (FR-004). */
2630
+ static schema = ScriptHeadersSchema;
2631
+ /** When a reader of this charter is to open this kind at all (FR-002). */
2632
+ static activatesWhen = "a primitive names it as `[[<id>]]`, or a sensor runs it \u2014 its assets, copied to `.cw/out/script/<id>/`, of which its `executionPath` names the one to run";
2633
+ /** A script as an author writes one: what a refused header is fixed with. */
2634
+ static sample = {
2635
+ id: "check-changelog",
2636
+ description: "Fail when CHANGELOG.md holds no entry for the version being released.",
2637
+ executionPath: "./run.sh"
2638
+ };
2639
+ /** One script, or every fault its headers have (FR-004). */
2640
+ static of(record, body, assetFiles = [], primitiveLayer) {
2641
+ return new _ScriptPrimitive(headersOf(_ScriptPrimitive, ScriptHeadersSchema, record), body, assetFiles, primitiveLayer);
2669
2642
  }
2670
- };
2671
-
2672
- // src/driver/cli/commands/VendorRemoveCommand.ts
2673
- var OPTIONS12 = {
2674
- name: {
2675
- type: "string",
2676
- describe: "The folder this charter was installed as, as it reads under .cw/vendor/"
2643
+ /** The asset that runs, as a path inside its folder: `run.sh` of
2644
+ * `./run.sh`. */
2645
+ get executionPathInFolder() {
2646
+ return this.headers.executionPath.slice("./".length);
2647
+ }
2648
+ /** Whether an asset of it is the one its `executionPath` names: the one
2649
+ * run by its path, and no other (FR-160). */
2650
+ isExecutionFile(file) {
2651
+ return file === this.executionPathInFolder;
2677
2652
  }
2678
2653
  };
2679
- var VendorRemoveCommand = class {
2680
- name = "vendor remove <name>";
2681
- summary = "Take an installed charter away";
2682
- options = OPTIONS12;
2683
- async run({ charterVendoringApp: charterVendoringApp2 }, { name }) {
2684
- const folder = await charterVendoringApp2.remove(name ?? "");
2685
- return {
2686
- code: EXIT_OK,
2687
- result: [
2688
- `Removed ${folder}.`,
2689
- 'Run "cw build" to compile this charter without it.',
2690
- ""
2691
- ].join("\n")
2692
- };
2654
+
2655
+ // src/hexagon/domain/models/charter/primitive/TemplatePrimitive.ts
2656
+ var TemplateHeadersSchema = CommonHeadersSchema.extend({});
2657
+ var TemplatePrimitive = class _TemplatePrimitive extends BasePrimitive {
2658
+ static kind = "template";
2659
+ kind = _TemplatePrimitive.kind;
2660
+ /** What this kind requires beyond the common headers: nothing. Declared all
2661
+ * the same, since what a file is scaffolded with is read off this (FR-039). */
2662
+ static requires = {};
2663
+ /** The schema its headers are read by (FR-004). */
2664
+ static schema = TemplateHeadersSchema;
2665
+ /** When a reader of this charter is to open this kind at all (FR-002). */
2666
+ static activatesWhen = "a primitive names it as `[[<id>]]` \u2014 a file the agent fills or copies, written as its body";
2667
+ /** A template as an author writes one: what a refused header is fixed with. */
2668
+ static sample = {
2669
+ id: "release-note",
2670
+ description: "The shape every release note follows."
2671
+ };
2672
+ /** One template, or every fault its headers have (FR-004). */
2673
+ static of(record, body, assetFiles = [], primitiveLayer) {
2674
+ return new _TemplatePrimitive(headersOf(_TemplatePrimitive, TemplateHeadersSchema, record), body, assetFiles, primitiveLayer);
2693
2675
  }
2694
2676
  };
2695
2677
 
2696
- // src/driver/cli/commands/index.ts
2697
- var COMMANDS = [
2698
- new InitCommand(),
2699
- new BuildCommand(),
2700
- new ListCommand(),
2701
- new KindsCommand(),
2702
- new AddCommand(),
2703
- new EditCommand(),
2704
- new RemoveCommand(),
2705
- new ExplainCommand(),
2706
- new DoctorCommand(),
2707
- new TestCommand(),
2708
- new SuiteAddCommand(),
2709
- new SuiteEditCommand(),
2710
- new SuiteRemoveCommand(),
2711
- new VendorAddCommand(),
2712
- new VendorRemoveCommand(),
2713
- new VendorListCommand(),
2714
- new PortalCommand(),
2715
- new McpAuthCommand(),
2716
- new McpServeCommand()
2678
+ // src/hexagon/domain/models/charter/primitive/Primitive.ts
2679
+ var PRIMITIVE_CLASSES = [
2680
+ GuidePrimitive,
2681
+ SensorPrimitive,
2682
+ SkillPrimitive,
2683
+ PlaybookPrimitive,
2684
+ AgentPrimitive,
2685
+ PosturePrimitive,
2686
+ CorpusPrimitive,
2687
+ MixinPrimitive,
2688
+ McpPrimitive,
2689
+ ScriptPrimitive,
2690
+ TemplatePrimitive
2717
2691
  ];
2718
-
2719
- // src/driver/cli/Commander.ts
2720
- var Commander = class {
2721
- #context;
2722
- #commands;
2723
- constructor(context, commands = COMMANDS) {
2724
- this.#context = context;
2725
- this.#commands = commands;
2726
- }
2727
- async run(argv) {
2728
- let code = EXIT_OK;
2729
- let failed = false;
2730
- await this.#parser((outcome) => {
2731
- code = outcome.code;
2732
- if (outcome.result) process.stdout.write(outcome.result);
2733
- if (outcome.problem) process.stderr.write(outcome.problem);
2734
- }).parseAsync([...argv], {}, (error, _parsed, output) => {
2735
- failed = error !== null && error !== void 0;
2736
- if (output) (failed ? process.stderr : process.stdout).write(`${output}
2737
- `);
2738
- });
2739
- return failed ? EXIT_USAGE : code;
2740
- }
2741
- #parser(collect) {
2742
- let cli2 = yargs().scriptName("cw").usage("Usage: $0 <command> [options]").demandCommand(1, "").strict().recommendCommands().help("help").alias("h", "help").version(this.#context.version).wrap(80).exitProcess(false);
2743
- const groups = /* @__PURE__ */ new Map();
2744
- for (const command of this.#commands) {
2745
- const head = wordsOf(command.name)[0];
2746
- groups.set(head, [...groups.get(head) ?? [], command]);
2747
- }
2748
- for (const [head, commands] of groups) {
2749
- const [only] = commands;
2750
- cli2 = commands.length === 1 && only !== void 0 && wordsOf(only.name).length === 1 ? this.#declaringCommand(cli2, only, only.name, collect) : cli2.command({
2751
- command: head,
2752
- // What the group is for is what its commands are: saying it any
2753
- // other way would be a second description to keep in step.
2754
- describe: commands.map((one) => wordsOf(one.name)[1]).join(", "),
2755
- builder: (child) => commands.reduce((parser, command) => this.#declaringCommand(parser, command, command.name.slice(head.length + 1), collect), child).demandCommand(1, ""),
2756
- handler: () => void 0
2757
- });
2758
- }
2759
- return cli2;
2692
+ var KINDS = Object.freeze(PRIMITIVE_CLASSES.map((one) => one.kind));
2693
+ function primitiveIdOf(typed) {
2694
+ if (!CommonHeadersSchema.shape.id.safeParse(typed).success)
2695
+ throw new CharterPrimitiveFault(
2696
+ `"${typed}" is not an id: one is lowercase letters, digits and inner hyphens, in segments joined by "/".`,
2697
+ 'Type it as the primitive declares it, as in "no-any".'
2698
+ );
2699
+ return typed;
2700
+ }
2701
+ function isKind(value) {
2702
+ return typeof value === "string" && KINDS.includes(value);
2703
+ }
2704
+ var CLASS_OF = new Map(
2705
+ PRIMITIVE_CLASSES.map((one) => [one.kind, one])
2706
+ );
2707
+ var PrimitiveHeader = class {
2708
+ constructor(field, shape, required, allowedValues) {
2709
+ this.field = field;
2710
+ this.shape = shape;
2711
+ this.required = required;
2712
+ this.allowedValues = allowedValues;
2760
2713
  }
2761
- /** One command, said to yargs under the name it is typed by — the whole of it
2762
- * for a command that stands alone, what follows the group for one inside
2763
- * it. */
2764
- #declaringCommand(cli2, command, name, collect) {
2765
- return cli2.command({
2766
- command: name,
2767
- describe: command.summary,
2768
- builder: (child) => declaringArguments(child, command.options ?? {}, name),
2769
- handler: async (options) => {
2770
- try {
2771
- collect(await command.run(this.#context, options));
2772
- } catch (raised) {
2773
- if (!(raised instanceof DomainFault)) throw raised;
2774
- collect({ code: EXIT_FAILURE, problem: `${raised.message}
2775
- ${raised.fix}
2776
- ` });
2777
- }
2778
- }
2779
- });
2714
+ field;
2715
+ shape;
2716
+ required;
2717
+ allowedValues;
2718
+ };
2719
+ var PrimitiveRequirements = class {
2720
+ constructor(headers, sample) {
2721
+ this.headers = headers;
2722
+ this.sample = sample;
2780
2723
  }
2724
+ headers;
2725
+ sample;
2781
2726
  };
2782
- function wordsOf(name) {
2783
- return name.split(" ").filter((word) => !word.startsWith("<") && !word.startsWith("["));
2784
- }
2785
- function declaringArguments(cli2, options, name) {
2786
- return Object.entries(options).reduce((parser, [argument, option]) => {
2787
- const declared = {
2788
- type: option.type,
2789
- describe: option.describe,
2790
- ...option.alias === void 0 ? {} : { alias: option.alias },
2791
- ...option.default === void 0 ? {} : { default: option.default },
2792
- // Typed once per value: yargs collects them, and a run that typed none
2793
- // reads an empty list rather than nothing, so the command asks how many
2794
- // were typed instead of whether any were.
2795
- ...option.isArray === void 0 ? {} : { array: true, default: [] }
2796
- };
2797
- return name.includes(`<${argument}>`) || name.includes(`[${argument}]`) ? parser.positional(argument, declared) : parser.option(argument, declared);
2798
- }, cli2);
2727
+ function primitiveHeadersOf(kind) {
2728
+ const kindClass = CLASS_OF.get(kind);
2729
+ const required = { ...BasePrimitive.requires, ...kindClass.requires };
2730
+ return Object.entries(kindClass.schema.shape).filter(([field]) => field !== "id").map(([field, type]) => {
2731
+ let heldType = type;
2732
+ while (!(heldType instanceof z12.ZodArray) && typeof heldType?.unwrap === "function")
2733
+ heldType = heldType.unwrap();
2734
+ return new PrimitiveHeader(
2735
+ field,
2736
+ heldType instanceof z12.ZodArray ? "list" : "line",
2737
+ field in required,
2738
+ heldType instanceof z12.ZodEnum ? heldType.options : void 0
2739
+ );
2740
+ });
2799
2741
  }
2800
-
2801
- // src/hexagon/utils/globs.ts
2802
- import picomatch from "picomatch";
2803
- function covers(outer, inner) {
2804
- return outer === inner || matches(outer, inner);
2742
+ function primitiveSampleOf(kind) {
2743
+ return Object.entries({ kind, ...CLASS_OF.get(kind).sample }).map(([field, value]) => `${field}: ${formatFrontmatterValue(value)}`).join("\n");
2805
2744
  }
2806
- function matches(glob, path) {
2807
- return picomatch(glob, { dot: true })(path);
2745
+ function primitiveOf(input, parser, assetFiles = [], primitiveLayer) {
2746
+ let headers;
2747
+ let body;
2748
+ if (typeof input === "string") {
2749
+ const lines3 = input.replace(/^/, "").split(/\r?\n/);
2750
+ if (lines3[0]?.trim() !== DELIMITER)
2751
+ throwAggregateError([
2752
+ new CharterPrimitiveFault(
2753
+ `This file opens with no "${DELIMITER}" frontmatter block.`,
2754
+ `Add one at the top declaring at least "id" and "description".`
2755
+ )
2756
+ ]);
2757
+ const end = lines3.findIndex((line, index) => index > 0 && line.trim() === DELIMITER);
2758
+ if (end === -1)
2759
+ throwAggregateError([
2760
+ new CharterPrimitiveFault(
2761
+ `The frontmatter block is never closed.`,
2762
+ `Add a "${DELIMITER}" line after the headers.`
2763
+ )
2764
+ ]);
2765
+ headers = parser.parse(lines3.slice(1, end).join("\n"));
2766
+ body = lines3.slice(end + 1).join("\n").replace(/^(\s*\n)+/, "").trimEnd();
2767
+ } else {
2768
+ headers = input.headers;
2769
+ body = input.body;
2770
+ }
2771
+ if (!isKind(headers.kind))
2772
+ throwAggregateError([
2773
+ headers.kind === void 0 ? new CharterPrimitiveFault(
2774
+ `This file declares no "kind", so nothing knows what to read it as.`,
2775
+ `Add "kind: <one the charter knows>" to the frontmatter.`
2776
+ ) : new CharterPrimitiveFault(
2777
+ `"${String(headers.kind)}" is not a kind the charter knows.`,
2778
+ `Declare a kind the charter knows: ${KINDS.join(", ")}.`
2779
+ )
2780
+ ]);
2781
+ const kind = headers.kind;
2782
+ if (typeof input === "string") return CLASS_OF.get(kind).of(headers, body, assetFiles, primitiveLayer);
2783
+ const headerFields = primitiveHeadersOf(kind).map((header) => header.field);
2784
+ const unknownHeaderFaults = Object.keys(headers).filter((field) => field !== "kind" && field !== "id" && !headerFields.includes(field)).map(
2785
+ (field) => new CharterPrimitiveFault(
2786
+ `A ${kind} holds no "${field}".`,
2787
+ `Answer one of what a ${kind} holds: ${headerFields.join(", ")}.`
2788
+ )
2789
+ );
2790
+ let primitive;
2791
+ let schemaFaults = [];
2792
+ try {
2793
+ primitive = CLASS_OF.get(kind).of(headers, body);
2794
+ } catch (raised) {
2795
+ if (!(raised instanceof AggregateError)) throw raised;
2796
+ schemaFaults = raised.errors;
2797
+ }
2798
+ if (primitive === void 0 || unknownHeaderFaults.length > 0) throwAggregateError([...unknownHeaderFaults, ...schemaFaults]);
2799
+ return primitive;
2808
2800
  }
2809
2801
 
2810
2802
  // src/hexagon/domain/models/charter/CharterRoot.ts
@@ -2823,48 +2815,38 @@ var CharterRoot = class {
2823
2815
  get allFaultsByFiles() {
2824
2816
  return this.faultsByFiles.with(this.compositeFaultsByFiles);
2825
2817
  }
2826
- /** Every mixin, under the id a host names it by, wherever it was authored. */
2827
- get mixins() {
2828
- return new Map(
2829
- this.primitives.filter((primitive) => primitive.kind === "mixin").map((one) => [one.headers.id, one])
2830
- );
2831
- }
2832
2818
  /**
2833
- * Every primitive under the identity the whole charter names it by (FR-017).
2819
+ * Every primitive under the id the whole charter names it by (FR-015,
2820
+ * FR-017).
2834
2821
  *
2835
- * Held here for the reason `mixins` is: one identity space covers every
2836
- * layer, so which file declares a name is a question about the whole charter
2837
- * and not about either layer on its own (FR-014).
2838
- *
2839
- * The first claim on an identity is the one in here where two files claim it.
2840
- * A collision is what `compositeFaultsByFiles` is for, and it names both files
2822
+ * One id space covers every layer and every kind, so which file declares a
2823
+ * name is a question about the whole charter and not about any one layer.
2824
+ * The first claim on an id is the one in here where two files claim it: a
2825
+ * collision is what `compositeFaultsByFiles` is for, and it names both files
2841
2826
  * there; nothing is asked to explain a charter that has one (SC-006).
2842
2827
  */
2843
2828
  get primitiveById() {
2844
- const byIdentity = /* @__PURE__ */ new Map();
2845
- for (const one of this.primitives) if (!byIdentity.has(one.identity)) byIdentity.set(one.identity, one);
2846
- return byIdentity;
2847
- }
2848
- /** Every corpus, under the identity a primitive cites it by, wherever it was
2849
- * authored: `corpus:<id>`. */
2850
- get corpora() {
2851
- return new Set(
2852
- this.primitives.filter((primitive) => primitive.kind === "corpus").map((one) => one.identity)
2853
- );
2829
+ const primitiveById = /* @__PURE__ */ new Map();
2830
+ for (const one of this.primitives) if (!primitiveById.has(one.headers.id)) primitiveById.set(one.headers.id, one);
2831
+ return primitiveById;
2854
2832
  }
2855
2833
  /** Every mixin one primitive uses, in the order it named them (FR-014). A
2856
- * name nothing answers to is left out: `compositeFaultsByFiles` already
2857
- * names that file as an error. */
2834
+ * name nothing answers to, or that answers with another kind, is left out:
2835
+ * `compositeFaultsByFiles` already names that file as an error. */
2858
2836
  mixinsOf(one) {
2859
- const byIdentity = this.primitiveById;
2860
- return (one.headers.mixins ?? []).flatMap((id) => byIdentity.get(`mixin:${id}`) ?? []);
2837
+ const primitiveById = this.primitiveById;
2838
+ return (one.headers.mixins ?? []).flatMap((id) => {
2839
+ const mixin = primitiveById.get(id);
2840
+ return mixin?.kind === "mixin" ? [mixin] : [];
2841
+ });
2861
2842
  }
2862
2843
  /** The corpus one primitive cites as its rationale, or nothing where it cites
2863
- * none or cites one this charter does not hold — the second is a warning
2844
+ * none or cites one this charter does not hold as a corpus — which
2864
2845
  * `compositeFaultsByFiles` already names (FR-005, FR-014). */
2865
2846
  rationaleOf(one) {
2866
2847
  const { rationale } = one.headers;
2867
- return rationale !== void 0 && this.corpora.has(rationale) ? this.primitiveById.get(rationale) : void 0;
2848
+ const corpusPrimitive = rationale === void 0 ? void 0 : this.primitiveById.get(rationale);
2849
+ return corpusPrimitive?.kind === "corpus" ? corpusPrimitive : void 0;
2868
2850
  }
2869
2851
  /** Every primitive using one mixin; nothing for any other kind (FR-014). */
2870
2852
  hostsOf(mixin) {
@@ -2875,24 +2857,21 @@ var CharterRoot = class {
2875
2857
  * kind (FR-014). */
2876
2858
  citersOf(corpus) {
2877
2859
  if (corpus.kind !== "corpus") return [];
2878
- return this.primitives.filter((citer) => citer.headers.rationale === corpus.identity);
2879
- }
2880
- /** Every primitive naming one place, script or template; nothing for any
2881
- * other kind, since no other is reached by being named (FR-144, FR-163). */
2882
- mentionersOf(named) {
2883
- return this.primitives.filter((mentioner) => this.identitiesMentionedIn(mentioner).includes(named.identity));
2884
- }
2885
- /** The places, scripts and templates one primitive mentions, whether the
2886
- * charter holds them or not: in its body, in the author's own words (FR-143,
2887
- * FR-161); for an agent, each place it holds by listing it among its tools
2888
- * (FR-156); and for a sensor, each script its `run` names (FR-161). */
2889
- identitiesMentionedIn(one) {
2860
+ return this.primitives.filter((citer) => citer.headers.rationale === corpus.headers.id);
2861
+ }
2862
+ /** Every primitive naming one, as `[[<id>]]` (FR-144, FR-163, FR-172). */
2863
+ mentionersOf(referencedPrimitive) {
2864
+ return this.primitives.filter((mentioner) => this.idsMentionedIn(mentioner).includes(referencedPrimitive.headers.id));
2865
+ }
2866
+ /** The ids one primitive names as `[[<id>]]`, whether the charter holds them
2867
+ * or not: in its body (FR-143, FR-172); for an agent, each place it holds by
2868
+ * listing it among its tools (FR-156); and for a sensor, each script its
2869
+ * `run` names (FR-161). */
2870
+ idsMentionedIn(one) {
2890
2871
  return [
2891
- ...[...one.body.matchAll(MCP_MENTION)].map(([, id]) => `mcp:${id}`),
2892
- ...[...one.body.matchAll(SCRIPT_MENTION)].map(([, id]) => `script:${id}`),
2893
- ...[...one.body.matchAll(TEMPLATE_MENTION)].map(([, id]) => `template:${id}`),
2894
- ...one instanceof AgentPrimitive ? one.headers.tools.flatMap((tool) => tool.match(MCP_TOOL_REFERENCE)?.[1] ?? []) : [],
2895
- ...one instanceof SensorPrimitive ? [...one.headers.run.matchAll(SCRIPT_MENTION)].map(([mentionedIdentity]) => mentionedIdentity) : []
2872
+ ...[...one.body.matchAll(REFERENCE)].map(([, id]) => id),
2873
+ ...one instanceof AgentPrimitive ? one.headers.tools.flatMap((tool) => tool.match(TOOL_REFERENCE)?.[1] ?? []) : [],
2874
+ ...one instanceof SensorPrimitive ? [...one.headers.run.matchAll(REFERENCE)].map(([, id]) => id) : []
2896
2875
  ];
2897
2876
  }
2898
2877
  /** Does what a mixin lends reach as far as the host pulling it in, or the host
@@ -2911,8 +2890,8 @@ var CharterRoot = class {
2911
2890
  *
2912
2891
  * Reading refused the files whose own headers do not hold, and said so where
2913
2892
  * it read them; what is left are the questions no single file answers. Every
2914
- * layer is read into one identity space, the way one registry holds one name
2915
- * per package: two files claim one identity; one names a mixin nothing
2893
+ * layer is read into one id space, the way one registry holds one name
2894
+ * per package: two files claim one id; one names a mixin nothing
2916
2895
  * answers to; one pulls in a mixin that speaks about other files than it does
2917
2896
  * — a mixin lends its body at projection time, so what makes the two belong
2918
2897
  * together is the files they both apply to (FR-006, FR-014). One cites a
@@ -2928,52 +2907,46 @@ var CharterRoot = class {
2928
2907
  */
2929
2908
  get compositeFaultsByFiles() {
2930
2909
  const everyPrimitive = this.primitives;
2931
- const mixinsByIdentity = this.mixins;
2932
- const corpusIdentities = this.corpora;
2933
- const toolsByMcpIdentity = new Map(
2934
- everyPrimitive.flatMap((primitive) => primitive instanceof McpPrimitive ? [[primitive.identity, primitive.headers.tools]] : [])
2935
- );
2936
- const everyIdentity = new Set(everyPrimitive.map(({ identity }) => identity));
2937
- const mentionedIdentities = new Set(everyPrimitive.flatMap((one) => this.identitiesMentionedIn(one)));
2938
- const fileByIdentity = /* @__PURE__ */ new Map();
2939
- const identityByNormalizedIdentity = /* @__PURE__ */ new Map();
2910
+ const primitiveById = this.primitiveById;
2911
+ const referencedIds = new Set(everyPrimitive.flatMap((one) => this.idsMentionedIn(one)));
2912
+ const fileById = /* @__PURE__ */ new Map();
2913
+ const idByNormId = /* @__PURE__ */ new Map();
2940
2914
  const faultsByFiles = {};
2941
2915
  const addFault = (file, found) => {
2942
2916
  faultsByFiles[file] = [...faultsByFiles[file] ?? [], found];
2943
2917
  };
2944
- for (const one of everyPrimitive) {
2945
- const { file } = one;
2946
- const primitive = one;
2947
- const { identity } = one;
2948
- const { normIdentity } = primitive;
2949
- const declaredIn = fileByIdentity.get(identity);
2950
- if (declaredIn === void 0) fileByIdentity.set(identity, file);
2918
+ for (const primitive of everyPrimitive) {
2919
+ const { file } = primitive;
2920
+ const { id } = primitive.headers;
2921
+ const declaringFile = fileById.get(id);
2922
+ if (declaringFile === void 0) fileById.set(id, file);
2951
2923
  else
2952
2924
  addFault(
2953
2925
  file,
2954
2926
  new CharterRootFault(
2955
- `"${identity}" is already declared by ${declaredIn}. One identity names one primitive in a charter, whichever layer it was authored in.`,
2927
+ `"${id}" is already declared by ${declaringFile}. One id names one primitive in a charter, whatever its kind and whichever layer it was authored in.`,
2956
2928
  `Give this one an id of its own, or delete it if the other says the same thing. A vendor claiming an id you authored is one to raise with whoever publishes it. An id ${BUILTIN_PRIMITIVE_LAYER.charterFolder} claims is the engine's own and nobody can change it, so the one to rename is yours.`
2957
2929
  )
2958
2930
  );
2959
- const normalizedIdentityClaimedBy = identityByNormalizedIdentity.get(normIdentity);
2960
- if (normalizedIdentityClaimedBy === void 0) identityByNormalizedIdentity.set(normIdentity, identity);
2961
- else if (normalizedIdentityClaimedBy !== identity)
2931
+ const { normId } = primitive;
2932
+ const claimingId = idByNormId.get(normId);
2933
+ if (claimingId === void 0) idByNormId.set(normId, id);
2934
+ else if (claimingId !== id)
2962
2935
  addFault(
2963
2936
  file,
2964
2937
  new CharterRootFault(
2965
- `"${identity}" and "${normalizedIdentityClaimedBy}" are both named "${normIdentity}" in an agent's files, where "/" is written as "-". Only one of them would be written there.`,
2938
+ `"${id}" and "${claimingId}" are both named "${normId}" in an agent's files, where "/" is written as "-". Only one of them would be written there.`,
2966
2939
  `Give this one an id that stays its own once "/" is written as "-".`
2967
2940
  )
2968
2941
  );
2969
- for (const namedMixin of primitive.headers.mixins ?? []) {
2970
- const mixin = mixinsByIdentity.get(namedMixin);
2971
- if (mixin === void 0) {
2942
+ for (const mixinId of primitive.headers.mixins ?? []) {
2943
+ const mixin = primitiveById.get(mixinId);
2944
+ if (mixin?.kind !== "mixin") {
2972
2945
  addFault(
2973
2946
  file,
2974
2947
  new CharterRootFault(
2975
- `This pulls in the mixin "${namedMixin}", and this charter holds no mixin of that id.`,
2976
- `Author it, or drop "${namedMixin}" from "mixins". A mixin is named by its id, whichever layer authored it.`
2948
+ `This pulls in the mixin "${mixinId}", and this charter holds no mixin of that id.`,
2949
+ `Author it, or drop "${mixinId}" from "mixins". A mixin is named by its id, whichever layer authored it.`
2977
2950
  )
2978
2951
  );
2979
2952
  continue;
@@ -2982,30 +2955,29 @@ var CharterRoot = class {
2982
2955
  addFault(
2983
2956
  file,
2984
2957
  new CharterRootFault(
2985
- `This pulls in the mixin "${namedMixin}", and neither one's "globs" covers the other's. The mixin's body would be written into a primitive that applies to different files.`,
2958
+ `This pulls in the mixin "${mixinId}", and neither one's "globs" covers the other's. The mixin's body would be written into a primitive that applies to different files.`,
2986
2959
  `Widen one side's "globs" until it covers the other's, or move the shared text into a corpus and cite it with "rationale".`
2987
2960
  )
2988
2961
  );
2989
2962
  }
2990
2963
  }
2991
- const cited = primitive.headers.rationale;
2992
- if (cited !== void 0 && !corpusIdentities.has(cited)) {
2964
+ const rationaleId = primitive.headers.rationale;
2965
+ if (rationaleId !== void 0 && primitiveById.get(rationaleId)?.kind !== "corpus")
2993
2966
  addFault(
2994
2967
  file,
2995
2968
  new CharterRootFault(
2996
- `This cites "${cited}" as its rationale, and this charter holds no corpus of that identity.`,
2997
- `Author that corpus, correct the reference, or drop "rationale". A corpus is cited as "corpus:<id>", whichever layer authored it.`,
2969
+ `This cites "${rationaleId}" as its rationale, and this charter holds no corpus of that id.`,
2970
+ `Author that corpus, correct the reference, or drop "rationale". A corpus is cited by its id, whichever layer authored it.`,
2998
2971
  "warn"
2999
2972
  )
3000
2973
  );
3001
- }
3002
- for (const mentionedIdentity of new Set(this.identitiesMentionedIn(one)))
3003
- if (!everyIdentity.has(mentionedIdentity))
2974
+ for (const referencedId of new Set(this.idsMentionedIn(primitive)))
2975
+ if (!primitiveById.has(referencedId))
3004
2976
  addFault(
3005
2977
  file,
3006
2978
  new CharterRootFault(
3007
- `This names "${mentionedIdentity}", and this charter holds no primitive of that identity.`,
3008
- `Author it, or correct the name. It is named as "<kind>:<id>", whichever layer authored it.`
2979
+ `This names "${referencedId}", and this charter holds no primitive of that id.`,
2980
+ `Author it, or correct the name. It is named as "[[<id>]]", whichever layer authored it.`
3009
2981
  )
3010
2982
  );
3011
2983
  if (primitive instanceof ScriptPrimitive && !primitive.assets.some((assetFile) => primitive.isExecutionFile(assetFile.file)))
@@ -3017,55 +2989,55 @@ var CharterRoot = class {
3017
2989
  )
3018
2990
  );
3019
2991
  if (primitive instanceof AgentPrimitive)
3020
- for (const tool of primitive.headers.tools.filter((one2) => one2.startsWith("mcp:"))) {
3021
- const [, mcpIdentity, mcpTool] = tool.match(MCP_TOOL_REFERENCE) ?? [];
3022
- const declaredTools = mcpIdentity === void 0 ? void 0 : toolsByMcpIdentity.get(mcpIdentity);
3023
- if (mcpIdentity === void 0)
2992
+ for (const tool of primitive.headers.tools.filter((one) => one.startsWith("[["))) {
2993
+ const [, mcpId, mcpTool] = tool.match(TOOL_REFERENCE) ?? [];
2994
+ const mcpPrimitive = mcpId === void 0 ? void 0 : primitiveById.get(mcpId);
2995
+ if (mcpId === void 0)
3024
2996
  addFault(
3025
2997
  file,
3026
2998
  new CharterRootFault(
3027
2999
  `"${tool}" under "tools" is not a place this role can hold.`,
3028
- `Write a place as "mcp:<id>" for every tool it declares, or "mcp:<id>:<tool>" for one.`
3000
+ `Write a place as "[[<id>]]" for every tool it declares, or "[[<id>]]:<tool>" for one.`
3029
3001
  )
3030
3002
  );
3031
- else if (declaredTools !== void 0 && mcpTool !== void 0 && !declaredTools.includes(mcpTool))
3003
+ else if (mcpPrimitive instanceof McpPrimitive && mcpTool !== void 0 && !mcpPrimitive.headers.tools.includes(mcpTool))
3032
3004
  addFault(
3033
3005
  file,
3034
3006
  new CharterRootFault(
3035
- `"${tool}" under "tools" names a tool "${mcpIdentity}" does not declare; it declares ${declaredTools.join(", ")}.`,
3036
- `Name one of those, or add "${mcpTool}" to the tools of "${mcpIdentity}".`
3007
+ `"${tool}" under "tools" names a tool "${mcpId}" does not declare; it declares ${mcpPrimitive.headers.tools.join(", ")}.`,
3008
+ `Name one of those, or add "${mcpTool}" to the tools of "${mcpId}".`
3037
3009
  )
3038
3010
  );
3039
3011
  }
3040
- if (primitive.kind === "corpus" && this.citersOf(one).length === 0)
3012
+ if (primitive.kind === "corpus" && this.citersOf(primitive).length === 0)
3041
3013
  addFault(
3042
3014
  file,
3043
3015
  new CharterRootFault(
3044
- `No primitive cites "${identity}" as its rationale, so nothing an agent reads leads to it.`,
3045
- `Cite it from the rules it explains with "rationale: ${identity}", or delete it.`,
3016
+ `No primitive cites "${id}" as its rationale, so nothing an agent reads leads to it.`,
3017
+ `Cite it from the rules it explains with "rationale: ${id}", or delete it.`,
3046
3018
  "warn"
3047
3019
  )
3048
3020
  );
3049
- if (primitive.kind === "mixin" && this.hostsOf(one).length === 0)
3021
+ if (primitive.kind === "mixin" && this.hostsOf(primitive).length === 0)
3050
3022
  addFault(
3051
3023
  file,
3052
3024
  new CharterRootFault(
3053
- `No primitive pulls in the mixin "${primitive.headers.id}", so its body is never written anywhere.`,
3054
- `Name "${primitive.headers.id}" under "mixins" of the primitives it was written for, or delete it.`,
3025
+ `No primitive pulls in the mixin "${id}", so its body is never written anywhere.`,
3026
+ `Name "${id}" under "mixins" of the primitives it was written for, or delete it.`,
3055
3027
  "warn"
3056
3028
  )
3057
3029
  );
3058
- if ((primitive.kind === "mcp" || primitive.kind === "script" || primitive.kind === "template") && !mentionedIdentities.has(identity))
3030
+ if ((primitive.kind === "mcp" || primitive.kind === "script" || primitive.kind === "template") && !referencedIds.has(id))
3059
3031
  addFault(
3060
3032
  file,
3061
3033
  new CharterRootFault(
3062
- `No primitive names "${identity}" in its body, so nothing an agent reads leads to it.`,
3063
- `Name it where it is used, as "${identity}", or delete it.`,
3034
+ `No primitive names "${id}" in its body, so nothing an agent reads leads to it.`,
3035
+ `Name it where it is used, as "[[${id}]]", or delete it.`,
3064
3036
  "warn"
3065
3037
  )
3066
3038
  );
3067
3039
  }
3068
- const mcpPrimitives = everyPrimitive.flatMap((primitive) => primitive instanceof McpPrimitive ? [primitive] : []).sort((one, another) => one.identity < another.identity ? -1 : 1);
3040
+ const mcpPrimitives = everyPrimitive.flatMap((primitive) => primitive instanceof McpPrimitive ? [primitive] : []).sort((one, another) => one.headers.id < another.headers.id ? -1 : 1);
3069
3041
  for (const primitive of mcpPrimitives) {
3070
3042
  const { file } = primitive;
3071
3043
  const { tokenEnv } = primitive.headers;
@@ -3076,7 +3048,7 @@ var CharterRoot = class {
3076
3048
  addFault(
3077
3049
  file,
3078
3050
  new CharterRootFault(
3079
- `This hands "${primitive.address}" its token in "${tokenEnv}", and "${conflictingMcp.identity}" in "${conflictingMcp.headers.tokenEnv}". One process reads its token from one variable.`,
3051
+ `This hands "${primitive.address}" its token in "${tokenEnv}", and "${conflictingMcp.headers.id}" in "${conflictingMcp.headers.tokenEnv}". One process reads its token from one variable.`,
3080
3052
  `Name the variable that command reads in both, or drop "tokenEnv" and "auth" from one of them.`
3081
3053
  )
3082
3054
  );
@@ -3107,7 +3079,7 @@ function charterRootOf({
3107
3079
  if (one.pathInLayer !== `${primitive.primitiveFolder}/${primitive.index}`) {
3108
3080
  faultsByFiles[one.path] = [
3109
3081
  new CharterRootFault(
3110
- `This declares "${primitive.identity}", and it is kept at "${one.pathInLayer}"; a primitive is kept at "<kind>/<id>/${BasePrimitive.index}".`,
3082
+ `This declares "${primitive.kind}" "${primitive.headers.id}", and it is kept at "${one.pathInLayer}"; a primitive is kept at "<kind>/<id>/${BasePrimitive.index}".`,
3111
3083
  `Move its folder to "${charterFolder}/${primitive.primitiveFolder}/", or declare the kind and id its folder says.`
3112
3084
  )
3113
3085
  ];
@@ -3144,7 +3116,7 @@ var CwAuthorSkill = class extends SkillPrimitive {
3144
3116
 
3145
3117
  This skill is cw's own. It comes with the engine, is not authored in this
3146
3118
  repository, and cannot be changed here. A repository that wants another way of
3147
- authoring writes a primitive of its own, under an identity of its own.
3119
+ authoring writes a primitive of its own, under an id of its own.
3148
3120
 
3149
3121
  It covers writing a new primitive. Changing or removing one that already exists
3150
3122
  is not what it covers.
@@ -3166,7 +3138,10 @@ refused against.
3166
3138
  cw refuses, it says why and shows the kind's sample: answer again with that
3167
3139
  in hand. Nothing is written until the headers hold.
3168
3140
  4. Write the body into the file cw named. The headers decide when the primitive
3169
- comes up; the body is what an agent reads once it has.
3141
+ comes up; the body is what an agent reads once it has. Name another
3142
+ primitive by its id alone: bare in a header, and as \`[[<id>]]\` in the
3143
+ body, which the build turns into a link to it. An id names one primitive
3144
+ whatever its kind.
3170
3145
  5. Run \`cw build\`. If it refuses, \`cw doctor\` names each file with a problem
3171
3146
  and how to fix it.`,
3172
3147
  [],
@@ -3228,7 +3203,7 @@ async function writeCharter(repo, primitive, fileReader2, fileWriter2) {
3228
3203
  if (await fileReader2.readIfThere(file) !== void 0)
3229
3204
  throw new DomainFault(
3230
3205
  `${primitive.file} is already there, and writing this one would write over what it holds.`,
3231
- `Open it, or run this again with an identity this charter has not got.`
3206
+ `Open it, or run this again with an id this charter has not got.`
3232
3207
  );
3233
3208
  const folder = new URL(".", file).href;
3234
3209
  const primitiveInTheWay = (await fileReader2.readFilesRecursively(new URL(`${primitive.kind}/`, charterFolderIn(repo)))).map((readFile2) => readFile2.file.href).find((href) => href.endsWith(`/${BasePrimitive.index}`) && (folder.startsWith(new URL(".", href).href) || href.startsWith(folder)));
@@ -3354,8 +3329,7 @@ async function ensureVCSReady(repo, vcs2, because) {
3354
3329
  async function addVendor(repo, vcs2, source, version) {
3355
3330
  await ensureVCSReady(repo, vcs2, "installing a vendor commits what it installs");
3356
3331
  const folder = `${VENDOR_DIRECTORY}/${vendorSourceOf(source).name}`;
3357
- await vcs2.subtreeAdd(source, repo, folder, version);
3358
- return folder;
3332
+ return vcs2.subtreeAdd(source, CHARTER_DIRECTORY, repo, folder, version, VENDOR_DIRECTORY);
3359
3333
  }
3360
3334
  async function removeVendor(repo, vcs2, name) {
3361
3335
  await ensureVCSReady(repo, vcs2, "removing a vendor commits that it is gone");
@@ -3393,15 +3367,16 @@ function runSuite(charter, suiteName, suite) {
3393
3367
  return suite.cases.map((one) => runCase(charter, suiteName, one));
3394
3368
  }
3395
3369
  function findUntestedPrimitives(charter, testSuites) {
3396
- const testedIdentities = new Set(testSuites.flatMap((testSuite) => testSuite.cases.map((one) => one.activatedIdentity)));
3370
+ const testedIds = new Set(testSuites.flatMap((testSuite) => testSuite.cases.map((one) => one.activatedId)));
3397
3371
  const faultsByFiles = {};
3398
3372
  for (const primitive of charter.primitives) {
3399
- const { identity, file } = primitive;
3400
- if (primitive.kind !== "guide" && primitive.kind !== "sensor" || testedIdentities.has(identity)) continue;
3373
+ const { file } = primitive;
3374
+ const { id } = primitive.headers;
3375
+ if (primitive.kind !== "guide" && primitive.kind !== "sensor" || testedIds.has(id)) continue;
3401
3376
  faultsByFiles[file] = [
3402
3377
  new TestCaseFault(
3403
- `No test case names "${identity}", so nothing notices when it stops coming up where it should.`,
3404
- primitive.kind === "guide" ? `Add a case to a file under .cw/test/: { "do": { "touchFile": "<a file it speaks about>" }, "expect": { "activate": "${identity}" } }.` : `Add a case to a file under .cw/test/: { "when": "${primitive.headers.signal}", "expect": { "run": "${identity}" } }.`,
3378
+ `No test case names "${id}", so nothing notices when it stops coming up where it should.`,
3379
+ primitive.kind === "guide" ? `Add a case to a file under .cw/test/: { "do": { "touchFile": "<a file it speaks about>" }, "expect": { "activate": "${id}" } }.` : `Add a case to a file under .cw/test/: { "when": "${primitive.headers.signal}", "expect": { "run": "${id}" } }.`,
3405
3380
  "warn"
3406
3381
  )
3407
3382
  ];
@@ -3424,22 +3399,22 @@ function runCase(charter, suiteName, one) {
3424
3399
  }
3425
3400
  throw new Error(`Never happen`);
3426
3401
  }
3427
- function assertPrimitiveActivated(charter, file, identity) {
3428
- const declared = charter.primitiveById.get(identity);
3429
- if (declared === void 0) return primitiveNotFound(identity);
3402
+ function assertPrimitiveActivated(charter, file, id) {
3403
+ const declared = charter.primitiveById.get(id);
3404
+ if (declared === void 0) return primitiveNotFound(id);
3430
3405
  if (declared.kind !== "guide")
3431
3406
  return new TestCaseFault(
3432
- `Coming up when a file is touched is a guide's rule, and "${identity}" is a ${declared.kind}.`,
3407
+ `Coming up when a file is touched is a guide's rule, and "${id}" is a ${declared.kind}.`,
3433
3408
  `Expect a guide here, or put the situation that kind answers.`
3434
3409
  );
3435
3410
  const { globs = [] } = declared.headers;
3436
3411
  if (globs.length === 0)
3437
3412
  return new TestCaseFault(
3438
- `"${identity}" names no files, so touching one never brings it up.`,
3413
+ `"${id}" names no files, so touching one never brings it up.`,
3439
3414
  `Give that guide "globs", or expect nothing of it here.`
3440
3415
  );
3441
3416
  return globs.some((glob) => matches(glob, file)) ? void 0 : new TestCaseFault(
3442
- `This file matches none of the globs "${identity}" speaks about: ${globs.join(", ")}.`,
3417
+ `This file matches none of the globs "${id}" speaks about: ${globs.join(", ")}.`,
3443
3418
  `Widen that guide's "globs", or touch a file it already speaks about.`
3444
3419
  );
3445
3420
  }
@@ -3449,7 +3424,7 @@ function assertAllowed(charter, file, expected) {
3449
3424
  );
3450
3425
  if (expected)
3451
3426
  return denying.length === 0 ? void 0 : new TestCaseFault(
3452
- `${denying.map((one) => `"${one.identity}"`).join(", ")} denies this file.`,
3427
+ `${denying.map((one) => `"${one.headers.id}"`).join(", ")} denies this file.`,
3453
3428
  `Drop it from that posture's "deny", or expect "allow": false.`
3454
3429
  );
3455
3430
  const postures = charter.primitives.filter((primitive) => primitive.kind === "posture");
@@ -3463,24 +3438,24 @@ function assertAllowed(charter, file, expected) {
3463
3438
  `Add it to a posture's "deny", or expect "allow": true.`
3464
3439
  );
3465
3440
  }
3466
- function assertScriptRun(charter, event, identity) {
3467
- const declared = charter.primitiveById.get(identity);
3468
- if (declared === void 0) return primitiveNotFound(identity);
3441
+ function assertScriptRun(charter, event, id) {
3442
+ const declared = charter.primitiveById.get(id);
3443
+ if (declared === void 0) return primitiveNotFound(id);
3469
3444
  if (declared.kind !== "sensor")
3470
3445
  return new TestCaseFault(
3471
- `Running when an event is raised is a sensor's rule, and "${identity}" is a ${declared.kind}.`,
3446
+ `Running when an event is raised is a sensor's rule, and "${id}" is a ${declared.kind}.`,
3472
3447
  `Expect a sensor here, or put the situation that kind answers.`
3473
3448
  );
3474
3449
  const { signal } = declared.headers;
3475
3450
  return signal === event ? void 0 : new TestCaseFault(
3476
- `"${identity}" fires on ${signal}, not on ${event}.`,
3451
+ `"${id}" fires on ${signal}, not on ${event}.`,
3477
3452
  `Raise the event it names, or declare the "signal" this case raises.`
3478
3453
  );
3479
3454
  }
3480
- function primitiveNotFound(identity) {
3455
+ function primitiveNotFound(id) {
3481
3456
  return new TestCaseFault(
3482
- `This charter holds no primitive called "${identity}".`,
3483
- `Author it, or correct the name. "cw list --min" says every identity this charter does hold.`
3457
+ `This charter holds no primitive called "${id}".`,
3458
+ `Author it, or correct the name. "cw list --min" says every id this charter does hold.`
3484
3459
  );
3485
3460
  }
3486
3461
 
@@ -3493,7 +3468,7 @@ var RepoLayerPrimitive = class {
3493
3468
 
3494
3469
  // src/hexagon/domain/models/output/common/Catalogue.ts
3495
3470
  var Catalogue = class _Catalogue {
3496
- /** Entries in the order they are to be listed: by identity (SC-007). */
3471
+ /** Entries in the order they are to be listed: by id (SC-007). */
3497
3472
  constructor(entries) {
3498
3473
  this.entries = entries;
3499
3474
  }
@@ -3519,7 +3494,7 @@ var Catalogue = class _Catalogue {
3519
3494
  *
3520
3495
  * A narrowed listing is a listing: what comes back answers `entries` the way
3521
3496
  * this does, so whoever reads it never has to ask whether it was narrowed. Nothing is re-sorted — the entries keep the order they were
3522
- * put in, which is the order by identity they were made in.
3497
+ * put in, which is the order by id they were made in.
3523
3498
  */
3524
3499
  filterByKind(kind) {
3525
3500
  return new _Catalogue(this.entries.filter((one) => one.kind === kind));
@@ -3529,13 +3504,13 @@ var Catalogue = class _Catalogue {
3529
3504
  // src/hexagon/domain/services/compile/catalogueFactory.ts
3530
3505
  function catalogueOf(charter, fileOf) {
3531
3506
  return new Catalogue(
3532
- // Ordered by identity rather than by the order the files happened to be
3507
+ // Ordered by id rather than by the order the files happened to be
3533
3508
  // read, so the same charter catalogues byte for byte the same (SC-007).
3534
- [...charter.primitives].sort((one, another) => one.identity < another.identity ? -1 : one.identity > another.identity ? 1 : 0).map((one) => {
3509
+ [...charter.primitives].sort((one, another) => one.headers.id < another.headers.id ? -1 : one.headers.id > another.headers.id ? 1 : 0).map((one) => {
3535
3510
  const { description, globs } = one.headers;
3536
3511
  return {
3537
- identity: one.identity,
3538
3512
  kind: one.kind,
3513
+ id: one.headers.id,
3539
3514
  description,
3540
3515
  file: fileOf(one),
3541
3516
  ...globs === void 0 ? {} : { globs }
@@ -3623,11 +3598,11 @@ function charterMdOf(kinds) {
3623
3598
  "# Charter",
3624
3599
  `This repository is governed by a charter \u2014 the standards it authored under \`${CHARTER_DIRECTORY}/\`, which constrain whatever coding agent runs here. Every surface an agent reads, this file included, is generated from that charter: do not edit them, edit the primitive behind them.`,
3625
3600
  "## Read first",
3626
- `[catalog.json](./catalog.json) \u2014 the kind, identity, description and file of every primitive this charter holds, with its globs. Survey it to find what you need, and open a file only once its activation condition below is met.`,
3601
+ `[catalog.json](./catalog.json) \u2014 the kind, id, description and file of every primitive this charter holds, with its globs. Survey it to find what you need, and open a file only once its activation condition below is met.`,
3627
3602
  "## When each kind applies",
3628
3603
  kinds.map((one) => `- **${one.kind}** \u2014 ${one.activatesWhen}.`).join("\n"),
3629
- "## One identity, one primitive",
3630
- `An identity names one primitive in the whole charter: \`kind:id\`, whether this repository authored it, installed it from a vendor, or the engine brought it. Nothing overrides anything \u2014 two files claiming one identity is an error the charter refuses to build with.`
3604
+ "## One id, one primitive",
3605
+ `An id names one primitive in the whole charter, whatever its kind: it is all a primitive is named by \u2014 bare in a header, a test or a command, and as \`[[<id>]]\` in a body, a sensor's \`run\` or an agent's \`tools\` \u2014 whether this repository authored it, installed it from a vendor, or the engine brought it. Nothing overrides anything \u2014 two files claiming one id is an error the charter refuses to build with.`
3631
3606
  ].join("\n\n")}
3632
3607
  `));
3633
3608
  }
@@ -3663,13 +3638,11 @@ var PRIMITIVES_MENTION = new RegExp(
3663
3638
  /^ {0,3}(`{3,}|~{3,})[\s\S]*?(?:^ {0,3}\1[^\n]*$|(?![\s\S]))/.source,
3664
3639
  /\[[^\]\n]*\]\([^)\n]*\)/.source,
3665
3640
  /`[^`\n]*`/.source,
3666
- MCP_MENTION.source,
3667
- SCRIPT_MENTION.source,
3668
- TEMPLATE_MENTION.source
3641
+ REFERENCE.source
3669
3642
  ].join("|"),
3670
3643
  "gm"
3671
3644
  );
3672
- var PRIMITIVES_EXACT_MENTION = new RegExp(`^\`(?:${MCP_MENTION.source}|${SCRIPT_MENTION.source}|${TEMPLATE_MENTION.source})\`$`);
3645
+ var PRIMITIVES_EXACT_MENTION = new RegExp(`^\`${REFERENCE.source}\`$`);
3673
3646
  function compiledPrimitiveOf(charter, primitive) {
3674
3647
  const markdown = primitive.toMarkdown({
3675
3648
  // A mixin nothing answers to is left out: the charter already names that
@@ -3677,9 +3650,11 @@ function compiledPrimitiveOf(charter, primitive) {
3677
3650
  mixins: charter.mixinsOf(primitive).flatMap((mixin) => mixin instanceof MixinPrimitive ? [mixin] : []),
3678
3651
  idReplacer: (body) => body.replace(PRIMITIVES_MENTION, (found) => {
3679
3652
  const exactFound = PRIMITIVES_EXACT_MENTION.test(found);
3680
- if (!exactFound && /^[\s`~[]/.test(found)) return found;
3681
- const mentioned = charter.primitiveById.get(exactFound ? found.slice(1, -1) : found);
3682
- return mentioned === void 0 ? found : `[${found}](${"../".repeat(primitive.primitiveFolder.split("/").length)}${mentioned.primitiveFolder}/${mentioned.index})`;
3653
+ const isReference = /^\[\[[^\]]*\]\]$/.test(found);
3654
+ if (!exactFound && !isReference) return found;
3655
+ const referencedId = (exactFound ? found.slice(1, -1) : found).slice(2, -2);
3656
+ const referencedPrimitive = charter.primitiveById.get(referencedId);
3657
+ return referencedPrimitive === void 0 ? found : `[${exactFound ? `\`${referencedId}\`` : referencedId}](${"../".repeat(primitive.primitiveFolder.split("/").length)}${referencedPrimitive.primitiveFolder}/${referencedPrimitive.index})`;
3683
3658
  })
3684
3659
  });
3685
3660
  return new CompiledPrimitive(
@@ -3836,18 +3811,18 @@ var ClaudeSettings = class _ClaudeSettings extends SettingBasedComponent {
3836
3811
  };
3837
3812
 
3838
3813
  // src/hexagon/domain/services/compile/claudeComponentFactory.ts
3839
- function claudeComponentsOf(charter, compiledPrimitiveByPrimitive, shortenMcpIdentities) {
3814
+ function claudeComponentsOf(charter, compiledPrimitiveByPrimitive, shortMcpIds) {
3840
3815
  const isSettingComponent = (one) => one.kind === PosturePrimitive.kind || one.kind === SensorPrimitive.kind;
3841
3816
  const asSettings = charter.primitives.filter(isSettingComponent);
3842
3817
  const asDocuments = charter.primitives.filter((one) => !isSettingComponent(one));
3843
- const toolsByMcpIdentity = new Map(
3844
- charter.primitives.flatMap((primitive) => primitive instanceof McpPrimitive ? [[primitive.identity, primitive.headers.tools]] : [])
3818
+ const toolsByMcpId = new Map(
3819
+ charter.primitives.flatMap((primitive) => primitive instanceof McpPrimitive ? [[primitive.headers.id, primitive.headers.tools]] : [])
3845
3820
  );
3846
3821
  const agentToolsOf = (agent) => agent.headers.tools.flatMap((tool) => {
3847
- const [, mcpIdentity, mcpTool] = tool.match(MCP_TOOL_REFERENCE) ?? [];
3848
- if (mcpIdentity === void 0) return [tool];
3849
- return (mcpTool === void 0 ? toolsByMcpIdentity.get(mcpIdentity) ?? [] : [mcpTool]).map(
3850
- (oneTool) => `mcp__${ClaudeMcpConfig.cwMcpName}__${shortenMcpIdentities[mcpIdentity]}__${oneTool}`
3822
+ const [, mcpId, mcpTool] = tool.match(TOOL_REFERENCE) ?? [];
3823
+ if (mcpId === void 0) return [tool];
3824
+ return (mcpTool === void 0 ? toolsByMcpId.get(mcpId) ?? [] : [mcpTool]).map(
3825
+ (oneTool) => `mcp__${ClaudeMcpConfig.cwMcpName}__${shortMcpIds[mcpId]}__${oneTool}`
3851
3826
  );
3852
3827
  });
3853
3828
  return [
@@ -3878,10 +3853,10 @@ function claudeSettingsOf(charter, compiledPrimitiveByPrimitive, ones) {
3878
3853
  }
3879
3854
  if (one.kind === SensorPrimitive.kind) {
3880
3855
  const { signal, run: run2 } = one.headers;
3881
- const command = run2.replace(SCRIPT_MENTION, (mentionedIdentity) => {
3882
- const mentioned = charter.primitiveById.get(mentionedIdentity);
3883
- const executionFile = mentioned && compiledPrimitiveByPrimitive.get(mentioned)?.projections.find((projection) => projection.executable)?.file;
3884
- return executionFile ?? mentionedIdentity;
3856
+ const command = run2.replace(REFERENCE, (reference, referencedId) => {
3857
+ const scriptPrimitive = charter.primitiveById.get(referencedId);
3858
+ const executionFile = scriptPrimitive && compiledPrimitiveByPrimitive.get(scriptPrimitive)?.projections.find((projection) => projection.executable)?.file;
3859
+ return executionFile ?? reference;
3885
3860
  });
3886
3861
  if (isClaudeHookEvent(signal))
3887
3862
  hooks[signal] = [...hooks[signal] ?? [], { hooks: [{ type: "command", command }] }];
@@ -3893,14 +3868,14 @@ function claudeSettingsOf(charter, compiledPrimitiveByPrimitive, ones) {
3893
3868
  };
3894
3869
  }
3895
3870
  function claudeDocumentComponentOf(sc, compiledFile, agentTools) {
3896
- const name = sc.normIdentity;
3871
+ const name = sc.normId;
3897
3872
  const compiledFromClaudeFolder = `../../${compiledFile}`;
3898
3873
  const pointerTo = (path) => `Read and follow @${path}.
3899
3874
  `;
3900
3875
  switch (sc.kind) {
3901
3876
  // A guide is a rule this host loads into context whole: when a file it names
3902
3877
  // is touched, which is what `paths` on a rule does, and at the start of every
3903
- // session where it names none (FR-013). Under the identity it is changed by,
3878
+ // session where it names none (FR-013). Under the id it is changed by,
3904
3879
  // so a reader who wants it changed is sent to the primitive rather than
3905
3880
  // editing what the next build overwrites (FR-017, FR-020).
3906
3881
  case GuidePrimitive.kind: {
@@ -3925,9 +3900,9 @@ function claudeDocumentComponentOf(sc, compiledFile, agentTools) {
3925
3900
  }
3926
3901
 
3927
3902
  // src/hexagon/domain/services/compile/mcpOriginsFactory.ts
3928
- function mcpOriginsOf(charter, shortenMcpIdentities) {
3903
+ function mcpOriginsOf(charter, shortMcpIds) {
3929
3904
  const mcpsByKey = /* @__PURE__ */ new Map();
3930
- for (const primitive of [...charter.primitives].sort((one, another) => one.identity < another.identity ? -1 : 1)) {
3905
+ for (const primitive of [...charter.primitives].sort((one, another) => one.headers.id < another.headers.id ? -1 : 1)) {
3931
3906
  if (!(primitive instanceof McpPrimitive)) continue;
3932
3907
  const key = `${primitive.address}
3933
3908
  ${primitive.headers.path ?? ""}`;
@@ -3939,8 +3914,8 @@ ${primitive.headers.path ?? ""}`;
3939
3914
  const tokenEnv = mcpsAtOrigin.find((one) => one.headers.tokenEnv !== void 0)?.headers.tokenEnv;
3940
3915
  const auths = new Set(mcpsAtOrigin.flatMap((one) => one.headers.auth ?? []));
3941
3916
  return {
3942
- identities: mcpsAtOrigin.map((one) => one.identity),
3943
- names: Object.fromEntries(mcpsAtOrigin.map((one) => [one.identity, shortenMcpIdentities[one.identity]])),
3917
+ ids: mcpsAtOrigin.map((one) => one.headers.id),
3918
+ names: Object.fromEntries(mcpsAtOrigin.map((one) => [one.headers.id, shortMcpIds[one.headers.id]])),
3944
3919
  address: firstMcp.address,
3945
3920
  ...endpoint === void 0 ? {} : { endpoint },
3946
3921
  ...command === void 0 ? {} : { command: { command, args, ...tokenEnv === void 0 ? {} : { tokenEnv } } },
@@ -3952,11 +3927,11 @@ ${primitive.headers.path ?? ""}`;
3952
3927
 
3953
3928
  // src/hexagon/domain/services/compile/compileService.ts
3954
3929
  function compile(charter, agents) {
3955
- const shortenMcpIdentities = shortenStringsOf(
3956
- charter.primitives.filter((primitive) => primitive.kind === McpPrimitive.kind).map((one) => one.identity)
3930
+ const shortMcpIds = shortenStringsOf(
3931
+ charter.primitives.filter((primitive) => primitive.kind === McpPrimitive.kind).map((one) => one.headers.id)
3957
3932
  );
3958
3933
  const compiledPrimitiveByPrimitive = new Map(
3959
- [...charter.primitives].sort((one, another) => one.identity < another.identity ? -1 : one.identity > another.identity ? 1 : 0).map((primitive) => [primitive, compiledPrimitiveOf(charter, primitive)])
3934
+ [...charter.primitives].sort((one, another) => one.headers.id < another.headers.id ? -1 : one.headers.id > another.headers.id ? 1 : 0).map((primitive) => [primitive, compiledPrimitiveOf(charter, primitive)])
3960
3935
  );
3961
3936
  return new CharterOutput(
3962
3937
  // What an agent opens from the catalogue is the primitive as it compiled,
@@ -3966,14 +3941,14 @@ function compile(charter, agents) {
3966
3941
  catalogueOf(charter, (one) => compiledPrimitiveByPrimitive.get(one).projections[0].file),
3967
3942
  charterMdOf(PRIMITIVE_CLASSES),
3968
3943
  [...compiledPrimitiveByPrimitive.values()],
3969
- new McpOrigins(mcpOriginsOf(charter, shortenMcpIdentities)),
3970
- agents.flatMap((agent) => providerComponentsOf(agent, charter, compiledPrimitiveByPrimitive, shortenMcpIdentities))
3944
+ new McpOrigins(mcpOriginsOf(charter, shortMcpIds)),
3945
+ agents.flatMap((agent) => providerComponentsOf(agent, charter, compiledPrimitiveByPrimitive, shortMcpIds))
3971
3946
  );
3972
3947
  }
3973
- function providerComponentsOf(agent, charter, compiledPrimitiveByPrimitive, shortenMcpIdentities) {
3948
+ function providerComponentsOf(agent, charter, compiledPrimitiveByPrimitive, shortMcpIds) {
3974
3949
  switch (agent) {
3975
3950
  case "claude":
3976
- return claudeComponentsOf(charter, compiledPrimitiveByPrimitive, shortenMcpIdentities);
3951
+ return claudeComponentsOf(charter, compiledPrimitiveByPrimitive, shortMcpIds);
3977
3952
  }
3978
3953
  }
3979
3954
 
@@ -4176,37 +4151,37 @@ var CharterAuthoring = class {
4176
4151
  );
4177
4152
  }
4178
4153
  /**
4179
- * Which file declares one identity, which layer it arrived in, when it comes
4154
+ * Which file declares one id, which layer it arrived in, when it comes
4180
4155
  * up, the mixins it uses and the corpus it cites, what uses, cites or names
4181
4156
  * it, and the situations this repository wrote down about it (FR-014, FR-017,
4182
4157
  * FR-163).
4183
4158
  *
4184
- * The charter is asked, not searched here: one identity space covers every
4159
+ * The charter is asked, not searched here: one id space covers every
4185
4160
  * layer, and which file answers to a name, and which names one primitive
4186
4161
  * shares with another, are the charter's own questions (FR-014). What is here
4187
4162
  * is the order — read, refuse a charter that does not hold, then ask.
4188
4163
  *
4189
- * An identity nothing answers to is raised rather than reported, the way a
4164
+ * An id nothing answers to is raised rather than reported, the way a
4190
4165
  * word that is no kind is: there is no file it is wrong with, and the next
4191
4166
  * move is to go and look at what the charter does hold.
4192
4167
  *
4193
4168
  * Reads and says: this holds a writing port and never reaches for it (FR-041).
4194
4169
  */
4195
- async explain(identity) {
4196
- const primitiveIdentity = identityOf(identity);
4170
+ async explain(id) {
4171
+ const primitiveId = primitiveIdOf(id);
4197
4172
  const [charter, , faultsByFiles] = await this.#read();
4198
4173
  if (charter === void 0) return faultsByFileDTO(faultsByFiles.errors(), this.#repoPath);
4199
- const declared = charter.primitiveById.get(primitiveIdentity);
4174
+ const declared = charter.primitiveById.get(primitiveId);
4200
4175
  if (declared === void 0)
4201
4176
  throw new DomainFault(
4202
- `This charter holds no "${identity}".`,
4203
- 'Run "cw list --min" to see every identity it does hold.'
4177
+ `This charter holds no "${id}".`,
4178
+ 'Run "cw list --min" to see every id it does hold.'
4204
4179
  );
4205
4180
  const testRoot = await loadTestRoot(this.#repoPath, this.#fileReader);
4206
4181
  const testCasesByFile = Object.fromEntries(
4207
4182
  Object.entries(testRoot.suitesByFile).map(([file, suite]) => [
4208
4183
  file,
4209
- suite.cases.filter((each) => each.activatedIdentity === primitiveIdentity).map((each) => each.describe())
4184
+ suite.cases.filter((each) => each.activatedId === primitiveId).map((each) => each.describe())
4210
4185
  ]).filter(([, situations]) => situations.length > 0)
4211
4186
  );
4212
4187
  return explanationOutcomeDTO(
@@ -4314,15 +4289,15 @@ var CharterAuthoring = class {
4314
4289
  * in an editor afterwards (FR-117).
4315
4290
  *
4316
4291
  * Nothing is validated and nothing is asked of the charter but which
4317
- * identities it already holds. What arrives is what an author answered, and
4292
+ * ids it already holds. What arrives is what an author answered, and
4318
4293
  * reading it as the primitive it claims to be is what refuses an answer its
4319
4294
  * kind will not take — the same reading a file of it would get, so there is no
4320
4295
  * second contract here to keep in step with the kind's (FR-004). Where it goes
4321
4296
  * is the convention: a directory per kind, since nothing reads the directory
4322
4297
  * (FR-002).
4323
4298
  *
4324
- * An identity the charter already holds, in any layer, is refused naming the
4325
- * file holding it: one identity names one primitive in the whole charter, and
4299
+ * An id the charter already holds, in any layer, is refused naming the
4300
+ * file holding it: one id names one primitive in the whole charter, and
4326
4301
  * a second file claiming it is a collision the next read would report
4327
4302
  * (FR-014). The files are read without being validated, so a charter wrong
4328
4303
  * somewhere else can still be added to.
@@ -4337,10 +4312,10 @@ var CharterAuthoring = class {
4337
4312
  return faultsDTO(new Faults(raised.errors));
4338
4313
  }
4339
4314
  const charter = await loadCharterRoot(this.#repoPath, this.#fileReader, this.#yamlParser);
4340
- const claimingPrimitive = charter.primitiveById.get(identityOf({ kind, id }));
4315
+ const claimingPrimitive = charter.primitiveById.get(id);
4341
4316
  if (claimingPrimitive !== void 0)
4342
4317
  throw new DomainFault(
4343
- `"${identityOf({ kind, id })}" is already there, declared by ${claimingPrimitive.file}, and one identity names one primitive in the whole charter.`,
4318
+ `"${id}" is already there, declared by ${claimingPrimitive.file}, and one id names one primitive in the whole charter.`,
4344
4319
  `Open ${claimingPrimitive.file}, or run this again with an id this charter has not got.`
4345
4320
  );
4346
4321
  return primitiveDTO(await writeCharter(this.#repoPath, primitive, this.#fileReader, this.#fileWriter));
@@ -4354,8 +4329,8 @@ var CharterAuthoring = class {
4354
4329
  * needs to open it. A save made over its hash is checked against the
4355
4330
  * primitive read again then.
4356
4331
  */
4357
- async open(identity) {
4358
- return primitiveDTO(await this.#primitiveByIdentity(identity));
4332
+ async open(id) {
4333
+ return primitiveDTO(await this.#primitiveById(id));
4359
4334
  }
4360
4335
  /**
4361
4336
  * One repository primitive's file written over with new headers and a new
@@ -4367,16 +4342,16 @@ var CharterAuthoring = class {
4367
4342
  * this one (FR-078). Answers the kind will not take come back as the faults
4368
4343
  * `add` gives for them, since both read answers the one way.
4369
4344
  *
4370
- * Kind and id are the identity's, never the headers': an edit cannot move a
4345
+ * Kind and id are the id's, never the headers': an edit cannot move a
4371
4346
  * file, and a rename is a new primitive and a deletion. Nothing is compiled
4372
4347
  * and nothing committed (FR-079).
4373
4348
  */
4374
- async rewrite(identity, headers, body, openedHash) {
4375
- const authoredPrimitive = await this.#primitiveByIdentity(identity);
4349
+ async rewrite(id, headers, body, openedHash) {
4350
+ const authoredPrimitive = await this.#primitiveById(id);
4376
4351
  if (!RepoLayerPrimitive.isSatisfiedBy(authoredPrimitive))
4377
4352
  throw new DomainFault(
4378
- `${identity} was not authored in this repository, and ${authoredPrimitive.file} is read-only here.`,
4379
- `To differ from it, author a primitive of your own under an identity of its own.`
4353
+ `${id} was not authored in this repository, and ${authoredPrimitive.file} is read-only here.`,
4354
+ `To differ from it, author a primitive of your own under an id of its own.`
4380
4355
  );
4381
4356
  if (authoredPrimitive.hash !== openedHash)
4382
4357
  throw new DomainFault(
@@ -4405,29 +4380,29 @@ var CharterAuthoring = class {
4405
4380
  * each as dangling, and what to do about them is its author's call. Nothing is
4406
4381
  * compiled and nothing committed (FR-079).
4407
4382
  */
4408
- async remove(identity) {
4409
- const primitive = await this.#primitiveByIdentity(identity);
4383
+ async remove(id) {
4384
+ const primitive = await this.#primitiveById(id);
4410
4385
  if (!RepoLayerPrimitive.isSatisfiedBy(primitive))
4411
4386
  throw new DomainFault(
4412
- `${identity} was not authored in this repository, and ${primitive.file} is read-only here.`,
4413
- `To differ from it, author a primitive of your own under an identity of its own.`
4387
+ `${id} was not authored in this repository, and ${primitive.file} is read-only here.`,
4388
+ `To differ from it, author a primitive of your own under an id of its own.`
4414
4389
  );
4415
4390
  const file = new URL(primitive.file, this.#repoPath);
4416
4391
  await this.#fileWriter.delete(file);
4417
4392
  for (const assetFile of primitive.assets) await this.#fileWriter.delete(new URL(assetFile.file, file));
4418
4393
  return primitiveDTO(primitive);
4419
4394
  }
4420
- /** The primitive one identity names, off the files as read and not the
4395
+ /** The primitive one id names, off the files as read and not the
4421
4396
  * validation. Raised when the charter holds nothing of it, the way `explain`
4422
4397
  * raises it: there is no file it is wrong with. */
4423
- async #primitiveByIdentity(identity) {
4424
- const primitiveIdentity = identityOf(identity);
4398
+ async #primitiveById(id) {
4399
+ const primitiveId = primitiveIdOf(id);
4425
4400
  const charter = await loadCharterRoot(this.#repoPath, this.#fileReader, this.#yamlParser);
4426
- const primitive = charter.primitiveById.get(primitiveIdentity);
4401
+ const primitive = charter.primitiveById.get(primitiveId);
4427
4402
  if (primitive === void 0)
4428
4403
  throw new DomainFault(
4429
- `This charter holds no "${identity}".`,
4430
- 'Run "cw list --min" to see every identity it does hold.'
4404
+ `This charter holds no "${id}".`,
4405
+ 'Run "cw list --min" to see every id it does hold.'
4431
4406
  );
4432
4407
  return primitive;
4433
4408
  }
@@ -4568,7 +4543,7 @@ async function writeCredential(secrets2, credential) {
4568
4543
  async function credentialFor(secrets2, authorizing2, origin, { refused = false } = {}) {
4569
4544
  if (origin.endpoint !== void 0 && !isSecureEndpoint(origin.endpoint))
4570
4545
  throw new DomainFault(`${origin.address} is plain http to another machine, so no credential is sent there.`, 'Declare its endpoint as https://, then run "cw build".');
4571
- const signInAgain = `Run "cw mcp auth ${origin.identities[0] ?? ""}" at a terminal to sign in there.`;
4546
+ const signInAgain = `Run "cw mcp auth ${origin.ids[0] ?? ""}" at a terminal to sign in there.`;
4572
4547
  const credential = await readCredential(secrets2, origin.address);
4573
4548
  if (credential === void 0) throw new DomainFault(`You are not signed in to ${origin.address}.`, signInAgain);
4574
4549
  const expired = refused || credential.expiresAt !== void 0 && Date.parse(credential.expiresAt) <= Date.now();
@@ -4603,18 +4578,18 @@ async function loadMcpTools(repo, fileReader2, yamlParser2) {
4603
4578
  if (Array.isArray(catalogJson)) catalogEntries = catalogJson;
4604
4579
  } catch {
4605
4580
  }
4606
- const toolsByIdentity = /* @__PURE__ */ new Map();
4607
- for (const { identity, kind, file } of catalogEntries) {
4608
- if (kind !== McpPrimitive.kind || typeof identity !== "string" || typeof file !== "string") continue;
4581
+ const toolsById = /* @__PURE__ */ new Map();
4582
+ for (const { id, kind, file } of catalogEntries) {
4583
+ if (kind !== McpPrimitive.kind || typeof id !== "string" || typeof file !== "string") continue;
4609
4584
  const compiledDocument = await fileReader2.readIfThere(new URL(file, repo));
4610
4585
  if (compiledDocument === void 0) continue;
4611
4586
  try {
4612
4587
  const primitive = primitiveOf(compiledDocument, yamlParser2);
4613
- if (primitive instanceof McpPrimitive) toolsByIdentity.set(identity, primitive.headers.tools);
4588
+ if (primitive instanceof McpPrimitive) toolsById.set(id, primitive.headers.tools);
4614
4589
  } catch {
4615
4590
  }
4616
4591
  }
4617
- return toolsByIdentity;
4592
+ return toolsById;
4618
4593
  }
4619
4594
 
4620
4595
  // src/hexagon/port/zdriven/DrivenFault.ts
@@ -4649,11 +4624,11 @@ var McpConnecting = class {
4649
4624
  }
4650
4625
  async signInStatus() {
4651
4626
  return Promise.all(
4652
- (await this.#signInAddresses()).map(async ({ address, identities, auth: auth2 }) => {
4627
+ (await this.#signInAddresses()).map(async ({ address, ids, auth: auth2 }) => {
4653
4628
  const credential = await readCredential(this.#secrets, address);
4654
4629
  return {
4655
4630
  type: "SignInStatus",
4656
- data: { address, identities, auth: auth2, signedIn: credential !== void 0, ...credential && { method: credential.method } }
4631
+ data: { address, ids, auth: auth2, signedIn: credential !== void 0, ...credential && { method: credential.method } }
4657
4632
  };
4658
4633
  })
4659
4634
  );
@@ -4676,8 +4651,8 @@ var McpConnecting = class {
4676
4651
  const toolRoute = toolRoutes.get(name);
4677
4652
  if (toolRoute === void 0)
4678
4653
  return errorAnswerOf(unreachableTools.get(name) ?? `"${name}" is not a tool this server serves; call one it listed.`);
4679
- const { origin, identity, upstream, connection } = toolRoute;
4680
- const signInAgain = `${origin.address} refused your credential. Run "cw mcp auth ${identity}" at a terminal to sign in there again.`;
4654
+ const { origin, id, upstream, connection } = toolRoute;
4655
+ const signInAgain = `${origin.address} refused your credential. Run "cw mcp auth ${id}" at a terminal to sign in there again.`;
4681
4656
  const accessTokenOf = (refused) => origin.endpoint === void 0 ? Promise.resolve(void 0) : credentialFor(this.#secrets, this.#authorizing, origin, { refused });
4682
4657
  try {
4683
4658
  try {
@@ -4701,7 +4676,7 @@ var McpConnecting = class {
4701
4676
  }
4702
4677
  /**
4703
4678
  * Every place the last build listed, reached at once and once per run
4704
- * (FR-152). What each lists is kept where one of its identities
4679
+ * (FR-152). What each lists is kept where one of its ids
4705
4680
  * declares it, renamed `<prefix>__<tool>`; a place down or not signed in to,
4706
4681
  * and a declared tool its place lacks, is said and left out, and the rest
4707
4682
  * are served (FR-153, FR-154, SC-039).
@@ -4709,7 +4684,7 @@ var McpConnecting = class {
4709
4684
  #serving() {
4710
4685
  this.#mcpServing ??= (async () => {
4711
4686
  const origins = await loadMcpOrigins(this.#repoPath, this.#fileReader);
4712
- const toolsByIdentity = await loadMcpTools(this.#repoPath, this.#fileReader, this.#yamlParser);
4687
+ const toolsById = await loadMcpTools(this.#repoPath, this.#fileReader, this.#yamlParser);
4713
4688
  const problems = [];
4714
4689
  const servedTools = [];
4715
4690
  const toolRoutes = /* @__PURE__ */ new Map();
@@ -4728,30 +4703,30 @@ var McpConnecting = class {
4728
4703
  );
4729
4704
  for (const { origin, connection, reason } of reachedPlaces) {
4730
4705
  if (connection !== void 0) connections.push(connection);
4731
- else problems.push(`${origin.identities.join(", ")}: ${reason}`);
4732
- for (const identity of origin.identities) {
4733
- const declaredTools = toolsByIdentity.get(identity);
4706
+ else problems.push(`${origin.ids.join(", ")}: ${reason}`);
4707
+ for (const id of origin.ids) {
4708
+ const declaredTools = toolsById.get(id);
4734
4709
  if (declaredTools === void 0) {
4735
- problems.push(`${identity} has no compiled document under .cw/out/, so none of its tools is served. Run "cw build".`);
4710
+ problems.push(`${id} has no compiled document under .cw/out/, so none of its tools is served. Run "cw build".`);
4736
4711
  continue;
4737
4712
  }
4738
- const identityName = origin.names?.[identity];
4739
- if (identityName === void 0) {
4740
- problems.push(`${identity} has no served name in .cw/out/mcp-origins.json, so none of its tools is served. Run "cw build" again.`);
4713
+ const servedPrefix = origin.names?.[id];
4714
+ if (servedPrefix === void 0) {
4715
+ problems.push(`${id} has no served name in .cw/out/mcp-origins.json, so none of its tools is served. Run "cw build" again.`);
4741
4716
  continue;
4742
4717
  }
4743
4718
  for (const tool of declaredTools) {
4744
- const servedName = `${identityName}__${tool}`;
4719
+ const servedName = `${servedPrefix}__${tool}`;
4745
4720
  if (connection === void 0) {
4746
4721
  unreachableTools.set(servedName, reason ?? "");
4747
4722
  continue;
4748
4723
  }
4749
4724
  const upstreamTool = connection.tools.find(({ name }) => name === tool);
4750
4725
  if (upstreamTool === void 0) {
4751
- problems.push(`${identity} declares "${tool}", which ${origin.address} does not have; it is not served.`);
4726
+ problems.push(`${id} declares "${tool}", which ${origin.address} does not have; it is not served.`);
4752
4727
  continue;
4753
4728
  }
4754
- const placeName = origin.path === void 0 ? identity : `${identity} \u2014 ${origin.path}`;
4729
+ const placeName = origin.path === void 0 ? id : `${id} \u2014 ${origin.path}`;
4755
4730
  servedTools.push({
4756
4731
  type: "ServedTool",
4757
4732
  data: {
@@ -4760,7 +4735,7 @@ var McpConnecting = class {
4760
4735
  inputSchema: upstreamTool.inputSchema
4761
4736
  }
4762
4737
  });
4763
- toolRoutes.set(servedName, { origin, identity, upstream: tool, connection });
4738
+ toolRoutes.set(servedName, { origin, id, upstream: tool, connection });
4764
4739
  }
4765
4740
  }
4766
4741
  }
@@ -4785,16 +4760,16 @@ var McpConnecting = class {
4785
4760
  async #signInAddresses() {
4786
4761
  const origins = await loadMcpOrigins(this.#repoPath, this.#fileReader);
4787
4762
  const addresses = /* @__PURE__ */ new Map();
4788
- for (const { address, endpoint, identities, auth: auth2 } of origins.filter((one) => one.auth.length > 0)) {
4789
- const signInAddress = addresses.get(address) ?? { ...endpoint !== void 0 && { endpoint }, identities: /* @__PURE__ */ new Set(), auth: /* @__PURE__ */ new Set() };
4790
- identities.forEach((identity) => signInAddress.identities.add(identity));
4763
+ for (const { address, endpoint, ids, auth: auth2 } of origins.filter((one) => one.auth.length > 0)) {
4764
+ const signInAddress = addresses.get(address) ?? { ...endpoint !== void 0 && { endpoint }, ids: /* @__PURE__ */ new Set(), auth: /* @__PURE__ */ new Set() };
4765
+ ids.forEach((id) => signInAddress.ids.add(id));
4791
4766
  auth2.forEach((method) => signInAddress.auth.add(method));
4792
4767
  addresses.set(address, signInAddress);
4793
4768
  }
4794
- return [...addresses].sort(([one], [other]) => one.localeCompare(other)).map(([address, { endpoint, identities, auth: auth2 }]) => ({
4769
+ return [...addresses].sort(([one], [other]) => one.localeCompare(other)).map(([address, { endpoint, ids, auth: auth2 }]) => ({
4795
4770
  address,
4796
4771
  ...endpoint !== void 0 && { endpoint },
4797
- identities: [...identities].sort(),
4772
+ ids: [...ids].sort(),
4798
4773
  auth: ["oauth", "token"].filter((method) => auth2.has(method))
4799
4774
  }));
4800
4775
  }
@@ -4900,12 +4875,6 @@ import { promisify } from "util";
4900
4875
  import { fileURLToPath as fileURLToPath2 } from "url";
4901
4876
  var run = promisify(execFile);
4902
4877
  var Git = class {
4903
- /** How it looks at a folder. Reading files is somebody else's port, and this
4904
- * asks it rather than reaching for the filesystem itself. */
4905
- constructor(fileReader2) {
4906
- this.fileReader = fileReader2;
4907
- }
4908
- fileReader;
4909
4878
  async isInstalled(folder) {
4910
4879
  try {
4911
4880
  await run("git", ["rev-parse", "--git-dir"], { cwd: fileURLToPath2(folder) });
@@ -4947,35 +4916,65 @@ var Git = class {
4947
4916
  }
4948
4917
  }
4949
4918
  /**
4950
- * `git subtree`, handed the source exactly as it was written: `add` where the
4951
- * folder is not there yet and `pull` where it is, so installing a source and
4952
- * bringing it up to date are one call (FR-023, FR-030).
4919
+ * `git fetch`, handed the source exactly as it was written, then
4920
+ * `git read-tree` of the one folder asked for into the folder given, and a
4921
+ * commit: a folder already there is removed in the same commit, so
4922
+ * installing a source and bringing it up to date are one call (FR-023,
4923
+ * FR-030, FR-042).
4953
4924
  *
4954
4925
  * Which transport it is, whether the credentials are there, whether the
4955
4926
  * version exists: git answers all three, and what it says is what the user
4956
- * reads (FR-031).
4957
- *
4958
- * `--squash` because what is installed is content to read and not a history
4959
- * to walk: one commit lands, holding the source's files under the folder
4960
- * given (FR-028). `HEAD` where no version is named, which is what the source
4927
+ * reads (FR-031). `HEAD` where no version is named, which is what the source
4961
4928
  * calls its own default.
4929
+ *
4930
+ * `git subtree` takes a source whole and cannot take one folder of it, so
4931
+ * the tree is read straight off what was fetched. Whether that folder is
4932
+ * there, and whether the refused one is, is asked of git before anything is
4933
+ * touched. One commit lands, holding the folder's files and no history to
4934
+ * walk (FR-028); none lands where the copy is what was already there.
4962
4935
  */
4963
- async subtreeAdd(source, repo, intoSubFolder, version) {
4936
+ async subtreeAdd(source, sourceSubFolder, repo, intoSubFolder, version, refusedIfSourceHolds) {
4964
4937
  const cwd = fileURLToPath2(repo);
4965
- const targetFolder = new URL(`${intoSubFolder}/`, repo);
4966
- const targetFolderExist = (await this.fileReader.readFilesRecursively(targetFolder)).length > 0;
4938
+ const ref = version ?? "HEAD";
4967
4939
  try {
4968
- await run(
4969
- "git",
4970
- ["subtree", targetFolderExist ? "pull" : "add", `--prefix=${intoSubFolder}`, "--squash", "--", source, version ?? "HEAD"],
4971
- { cwd }
4972
- );
4940
+ await run("git", ["fetch", "--quiet", "--no-tags", "--", source, ref], { cwd });
4973
4941
  } catch (raised) {
4974
4942
  throw new DrivenFault(
4975
4943
  `${raised}`,
4976
4944
  version === void 0 ? "Check the address, and that you can reach it from here." : `Check the address, and that "${version}" is a tag or branch it has.`
4977
4945
  );
4978
4946
  }
4947
+ const { stdout: fetchedCommit } = await run("git", ["rev-parse", "FETCH_HEAD"], { cwd });
4948
+ const isTreeAt = (folder) => run("git", ["cat-file", "-t", `${fetchedCommit.trim()}:${folder}`], { cwd }).then(
4949
+ ({ stdout }) => stdout.trim() === "tree",
4950
+ () => false
4951
+ );
4952
+ const atVersion = version === void 0 ? "" : ` at ${version}`;
4953
+ if (!await isTreeAt(sourceSubFolder))
4954
+ throw new DrivenFault(
4955
+ `${source} has no folder "${sourceSubFolder}"${atVersion}.`,
4956
+ `Check that the source holds "${sourceSubFolder}" at the version asked for.`
4957
+ );
4958
+ if (refusedIfSourceHolds !== void 0 && await isTreeAt(refusedIfSourceHolds))
4959
+ throw new DrivenFault(
4960
+ `${source} holds "${refusedIfSourceHolds}"${atVersion}, which this copy refuses.`,
4961
+ `Remove "${refusedIfSourceHolds}" from the source, or copy a version without it.`
4962
+ );
4963
+ const sourceTree = `${fetchedCommit.trim()}:${sourceSubFolder}`;
4964
+ try {
4965
+ await run("git", ["rm", "-r", "--quiet", "--ignore-unmatch", "--", intoSubFolder], { cwd });
4966
+ await run("git", ["read-tree", `--prefix=${intoSubFolder}/`, "-u", sourceTree], { cwd });
4967
+ const unchanged = await run("git", ["diff", "--cached", "--quiet"], { cwd }).then(
4968
+ () => true,
4969
+ () => false
4970
+ );
4971
+ if (!unchanged)
4972
+ await run("git", ["commit", "-qm", `Install ${source}${atVersion} into ${intoSubFolder}`], { cwd });
4973
+ return intoSubFolder;
4974
+ } catch (raised) {
4975
+ await run("git", ["restore", "--source=HEAD", "--staged", "--worktree", "--", intoSubFolder], { cwd }).catch(() => void 0);
4976
+ throw new DrivenFault(`${raised}`, `Check that "${intoSubFolder}" holds nothing of your own in hand, and run this again.`);
4977
+ }
4979
4978
  }
4980
4979
  /** `git rm -r` and a commit of its own: the folder is gone from the working
4981
4980
  * tree and from the history from here on, the way adding it put it into
@@ -5258,7 +5257,7 @@ function faultOf(raised, failed, fix) {
5258
5257
  var fileReader = new FileReaders();
5259
5258
  var yamlParser = new YamlParser();
5260
5259
  var fileWriter = new FileOutput();
5261
- var vcs = new Git(fileReader);
5260
+ var vcs = new Git();
5262
5261
  var secrets = new OsSecrets();
5263
5262
  var authorizing = new OAuth();
5264
5263
  var mcpServers = new McpClients();