cherry-works 0.4.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.4.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")
@@ -2494,9 +1967,9 @@ Press Ctrl+C to stop it.
2494
1967
  // src/driver/cli/commands/RemoveCommand.ts
2495
1968
  import prompts4 from "prompts";
2496
1969
  var OPTIONS8 = {
2497
- identity: {
1970
+ id: {
2498
1971
  type: "string",
2499
- describe: 'What the primitive is named by across the whole charter: "guide:no-any"'
1972
+ describe: 'What the primitive is named by across the whole charter, its id: "no-any"'
2500
1973
  },
2501
1974
  yes: {
2502
1975
  type: "boolean",
@@ -2506,16 +1979,16 @@ var OPTIONS8 = {
2506
1979
  }
2507
1980
  };
2508
1981
  var RemoveCommand = class {
2509
- name = "remove <identity>";
1982
+ name = "remove <id>";
2510
1983
  summary = "Delete the file of one primitive this repository authored";
2511
1984
  options = OPTIONS8;
2512
- async run({ charterAuthoringApp: charterAuthoringApp2 }, { identity, yes }) {
2513
- const primitive = (await charterAuthoringApp2.open(identity ?? "")).data;
1985
+ async run({ charterAuthoringApp: charterAuthoringApp2 }, { id, yes }) {
1986
+ const primitive = (await charterAuthoringApp2.open(id ?? "")).data;
2514
1987
  if (!yes && primitive.layerName === REPO_LAYER) {
2515
1988
  if (!process.stdin.isTTY)
2516
1989
  throw new DomainFault(
2517
1990
  `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.`
1991
+ `Run "cw remove ${primitive.id} --yes" to remove it without asking.`
2519
1992
  );
2520
1993
  const { confirmed } = await prompts4({
2521
1994
  type: "confirm",
@@ -2523,288 +1996,807 @@ var RemoveCommand = class {
2523
1996
  message: `Remove ${primitive.file}?`,
2524
1997
  initial: false
2525
1998
  });
2526
- if (confirmed !== true) return { code: EXIT_OK, result: "Nothing was removed.\n" };
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
+ };
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
+ };
2095
+ }
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
+ ];
2102
+ }
2103
+
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"
2113
+ }
2114
+ };
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")}
2141
+ ` };
2142
+ }
2143
+ };
2144
+
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
+ });
2527
2231
  }
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
- };
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
+ });
2537
2253
  }
2538
2254
  };
2539
-
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")
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: [] }
2549
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);
2550
2315
  }
2551
2316
  };
2552
2317
 
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"`
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);
2558
2342
  }
2559
2343
  };
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") };
2344
+
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);
2572
2372
  }
2573
2373
  };
2574
2374
 
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"`
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(" ");
2580
2466
  }
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
- ` };
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);
2590
2472
  }
2591
2473
  };
2592
2474
 
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
- };
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);
2622
2504
  }
2623
2505
  };
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
2506
 
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"
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("; ")}.`;
2640
2536
  }
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
- };
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);
2656
2540
  }
2657
2541
  };
2658
2542
 
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
- ` };
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);
2669
2573
  }
2670
2574
  };
2671
2575
 
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/"
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("; ")}.`;
2605
+ }
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);
2677
2609
  }
2678
2610
  };
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
- };
2611
+
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);
2642
+ }
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;
2693
2652
  }
2694
2653
  };
2695
2654
 
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()
2717
- ];
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;
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);
2740
2675
  }
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;
2676
+ };
2677
+
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
2691
+ ];
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)));
@@ -3392,15 +3367,16 @@ function runSuite(charter, suiteName, suite) {
3392
3367
  return suite.cases.map((one) => runCase(charter, suiteName, one));
3393
3368
  }
3394
3369
  function findUntestedPrimitives(charter, testSuites) {
3395
- 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)));
3396
3371
  const faultsByFiles = {};
3397
3372
  for (const primitive of charter.primitives) {
3398
- const { identity, file } = primitive;
3399
- 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;
3400
3376
  faultsByFiles[file] = [
3401
3377
  new TestCaseFault(
3402
- `No test case names "${identity}", so nothing notices when it stops coming up where it should.`,
3403
- 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}" } }.`,
3404
3380
  "warn"
3405
3381
  )
3406
3382
  ];
@@ -3423,22 +3399,22 @@ function runCase(charter, suiteName, one) {
3423
3399
  }
3424
3400
  throw new Error(`Never happen`);
3425
3401
  }
3426
- function assertPrimitiveActivated(charter, file, identity) {
3427
- const declared = charter.primitiveById.get(identity);
3428
- 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);
3429
3405
  if (declared.kind !== "guide")
3430
3406
  return new TestCaseFault(
3431
- `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}.`,
3432
3408
  `Expect a guide here, or put the situation that kind answers.`
3433
3409
  );
3434
3410
  const { globs = [] } = declared.headers;
3435
3411
  if (globs.length === 0)
3436
3412
  return new TestCaseFault(
3437
- `"${identity}" names no files, so touching one never brings it up.`,
3413
+ `"${id}" names no files, so touching one never brings it up.`,
3438
3414
  `Give that guide "globs", or expect nothing of it here.`
3439
3415
  );
3440
3416
  return globs.some((glob) => matches(glob, file)) ? void 0 : new TestCaseFault(
3441
- `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(", ")}.`,
3442
3418
  `Widen that guide's "globs", or touch a file it already speaks about.`
3443
3419
  );
3444
3420
  }
@@ -3448,7 +3424,7 @@ function assertAllowed(charter, file, expected) {
3448
3424
  );
3449
3425
  if (expected)
3450
3426
  return denying.length === 0 ? void 0 : new TestCaseFault(
3451
- `${denying.map((one) => `"${one.identity}"`).join(", ")} denies this file.`,
3427
+ `${denying.map((one) => `"${one.headers.id}"`).join(", ")} denies this file.`,
3452
3428
  `Drop it from that posture's "deny", or expect "allow": false.`
3453
3429
  );
3454
3430
  const postures = charter.primitives.filter((primitive) => primitive.kind === "posture");
@@ -3462,24 +3438,24 @@ function assertAllowed(charter, file, expected) {
3462
3438
  `Add it to a posture's "deny", or expect "allow": true.`
3463
3439
  );
3464
3440
  }
3465
- function assertScriptRun(charter, event, identity) {
3466
- const declared = charter.primitiveById.get(identity);
3467
- 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);
3468
3444
  if (declared.kind !== "sensor")
3469
3445
  return new TestCaseFault(
3470
- `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}.`,
3471
3447
  `Expect a sensor here, or put the situation that kind answers.`
3472
3448
  );
3473
3449
  const { signal } = declared.headers;
3474
3450
  return signal === event ? void 0 : new TestCaseFault(
3475
- `"${identity}" fires on ${signal}, not on ${event}.`,
3451
+ `"${id}" fires on ${signal}, not on ${event}.`,
3476
3452
  `Raise the event it names, or declare the "signal" this case raises.`
3477
3453
  );
3478
3454
  }
3479
- function primitiveNotFound(identity) {
3455
+ function primitiveNotFound(id) {
3480
3456
  return new TestCaseFault(
3481
- `This charter holds no primitive called "${identity}".`,
3482
- `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.`
3483
3459
  );
3484
3460
  }
3485
3461
 
@@ -3492,7 +3468,7 @@ var RepoLayerPrimitive = class {
3492
3468
 
3493
3469
  // src/hexagon/domain/models/output/common/Catalogue.ts
3494
3470
  var Catalogue = class _Catalogue {
3495
- /** 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). */
3496
3472
  constructor(entries) {
3497
3473
  this.entries = entries;
3498
3474
  }
@@ -3518,7 +3494,7 @@ var Catalogue = class _Catalogue {
3518
3494
  *
3519
3495
  * A narrowed listing is a listing: what comes back answers `entries` the way
3520
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
3521
- * 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.
3522
3498
  */
3523
3499
  filterByKind(kind) {
3524
3500
  return new _Catalogue(this.entries.filter((one) => one.kind === kind));
@@ -3528,13 +3504,13 @@ var Catalogue = class _Catalogue {
3528
3504
  // src/hexagon/domain/services/compile/catalogueFactory.ts
3529
3505
  function catalogueOf(charter, fileOf) {
3530
3506
  return new Catalogue(
3531
- // 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
3532
3508
  // read, so the same charter catalogues byte for byte the same (SC-007).
3533
- [...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) => {
3534
3510
  const { description, globs } = one.headers;
3535
3511
  return {
3536
- identity: one.identity,
3537
3512
  kind: one.kind,
3513
+ id: one.headers.id,
3538
3514
  description,
3539
3515
  file: fileOf(one),
3540
3516
  ...globs === void 0 ? {} : { globs }
@@ -3622,11 +3598,11 @@ function charterMdOf(kinds) {
3622
3598
  "# Charter",
3623
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.`,
3624
3600
  "## Read first",
3625
- `[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.`,
3626
3602
  "## When each kind applies",
3627
3603
  kinds.map((one) => `- **${one.kind}** \u2014 ${one.activatesWhen}.`).join("\n"),
3628
- "## One identity, one primitive",
3629
- `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.`
3630
3606
  ].join("\n\n")}
3631
3607
  `));
3632
3608
  }
@@ -3662,13 +3638,11 @@ var PRIMITIVES_MENTION = new RegExp(
3662
3638
  /^ {0,3}(`{3,}|~{3,})[\s\S]*?(?:^ {0,3}\1[^\n]*$|(?![\s\S]))/.source,
3663
3639
  /\[[^\]\n]*\]\([^)\n]*\)/.source,
3664
3640
  /`[^`\n]*`/.source,
3665
- MCP_MENTION.source,
3666
- SCRIPT_MENTION.source,
3667
- TEMPLATE_MENTION.source
3641
+ REFERENCE.source
3668
3642
  ].join("|"),
3669
3643
  "gm"
3670
3644
  );
3671
- var PRIMITIVES_EXACT_MENTION = new RegExp(`^\`(?:${MCP_MENTION.source}|${SCRIPT_MENTION.source}|${TEMPLATE_MENTION.source})\`$`);
3645
+ var PRIMITIVES_EXACT_MENTION = new RegExp(`^\`${REFERENCE.source}\`$`);
3672
3646
  function compiledPrimitiveOf(charter, primitive) {
3673
3647
  const markdown = primitive.toMarkdown({
3674
3648
  // A mixin nothing answers to is left out: the charter already names that
@@ -3676,9 +3650,11 @@ function compiledPrimitiveOf(charter, primitive) {
3676
3650
  mixins: charter.mixinsOf(primitive).flatMap((mixin) => mixin instanceof MixinPrimitive ? [mixin] : []),
3677
3651
  idReplacer: (body) => body.replace(PRIMITIVES_MENTION, (found) => {
3678
3652
  const exactFound = PRIMITIVES_EXACT_MENTION.test(found);
3679
- if (!exactFound && /^[\s`~[]/.test(found)) return found;
3680
- const mentioned = charter.primitiveById.get(exactFound ? found.slice(1, -1) : found);
3681
- 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})`;
3682
3658
  })
3683
3659
  });
3684
3660
  return new CompiledPrimitive(
@@ -3835,18 +3811,18 @@ var ClaudeSettings = class _ClaudeSettings extends SettingBasedComponent {
3835
3811
  };
3836
3812
 
3837
3813
  // src/hexagon/domain/services/compile/claudeComponentFactory.ts
3838
- function claudeComponentsOf(charter, compiledPrimitiveByPrimitive, shortenMcpIdentities) {
3814
+ function claudeComponentsOf(charter, compiledPrimitiveByPrimitive, shortMcpIds) {
3839
3815
  const isSettingComponent = (one) => one.kind === PosturePrimitive.kind || one.kind === SensorPrimitive.kind;
3840
3816
  const asSettings = charter.primitives.filter(isSettingComponent);
3841
3817
  const asDocuments = charter.primitives.filter((one) => !isSettingComponent(one));
3842
- const toolsByMcpIdentity = new Map(
3843
- 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]] : [])
3844
3820
  );
3845
3821
  const agentToolsOf = (agent) => agent.headers.tools.flatMap((tool) => {
3846
- const [, mcpIdentity, mcpTool] = tool.match(MCP_TOOL_REFERENCE) ?? [];
3847
- if (mcpIdentity === void 0) return [tool];
3848
- return (mcpTool === void 0 ? toolsByMcpIdentity.get(mcpIdentity) ?? [] : [mcpTool]).map(
3849
- (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}`
3850
3826
  );
3851
3827
  });
3852
3828
  return [
@@ -3877,10 +3853,10 @@ function claudeSettingsOf(charter, compiledPrimitiveByPrimitive, ones) {
3877
3853
  }
3878
3854
  if (one.kind === SensorPrimitive.kind) {
3879
3855
  const { signal, run: run2 } = one.headers;
3880
- const command = run2.replace(SCRIPT_MENTION, (mentionedIdentity) => {
3881
- const mentioned = charter.primitiveById.get(mentionedIdentity);
3882
- const executionFile = mentioned && compiledPrimitiveByPrimitive.get(mentioned)?.projections.find((projection) => projection.executable)?.file;
3883
- 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;
3884
3860
  });
3885
3861
  if (isClaudeHookEvent(signal))
3886
3862
  hooks[signal] = [...hooks[signal] ?? [], { hooks: [{ type: "command", command }] }];
@@ -3892,14 +3868,14 @@ function claudeSettingsOf(charter, compiledPrimitiveByPrimitive, ones) {
3892
3868
  };
3893
3869
  }
3894
3870
  function claudeDocumentComponentOf(sc, compiledFile, agentTools) {
3895
- const name = sc.normIdentity;
3871
+ const name = sc.normId;
3896
3872
  const compiledFromClaudeFolder = `../../${compiledFile}`;
3897
3873
  const pointerTo = (path) => `Read and follow @${path}.
3898
3874
  `;
3899
3875
  switch (sc.kind) {
3900
3876
  // A guide is a rule this host loads into context whole: when a file it names
3901
3877
  // is touched, which is what `paths` on a rule does, and at the start of every
3902
- // 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,
3903
3879
  // so a reader who wants it changed is sent to the primitive rather than
3904
3880
  // editing what the next build overwrites (FR-017, FR-020).
3905
3881
  case GuidePrimitive.kind: {
@@ -3924,9 +3900,9 @@ function claudeDocumentComponentOf(sc, compiledFile, agentTools) {
3924
3900
  }
3925
3901
 
3926
3902
  // src/hexagon/domain/services/compile/mcpOriginsFactory.ts
3927
- function mcpOriginsOf(charter, shortenMcpIdentities) {
3903
+ function mcpOriginsOf(charter, shortMcpIds) {
3928
3904
  const mcpsByKey = /* @__PURE__ */ new Map();
3929
- 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)) {
3930
3906
  if (!(primitive instanceof McpPrimitive)) continue;
3931
3907
  const key = `${primitive.address}
3932
3908
  ${primitive.headers.path ?? ""}`;
@@ -3938,8 +3914,8 @@ ${primitive.headers.path ?? ""}`;
3938
3914
  const tokenEnv = mcpsAtOrigin.find((one) => one.headers.tokenEnv !== void 0)?.headers.tokenEnv;
3939
3915
  const auths = new Set(mcpsAtOrigin.flatMap((one) => one.headers.auth ?? []));
3940
3916
  return {
3941
- identities: mcpsAtOrigin.map((one) => one.identity),
3942
- 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]])),
3943
3919
  address: firstMcp.address,
3944
3920
  ...endpoint === void 0 ? {} : { endpoint },
3945
3921
  ...command === void 0 ? {} : { command: { command, args, ...tokenEnv === void 0 ? {} : { tokenEnv } } },
@@ -3951,11 +3927,11 @@ ${primitive.headers.path ?? ""}`;
3951
3927
 
3952
3928
  // src/hexagon/domain/services/compile/compileService.ts
3953
3929
  function compile(charter, agents) {
3954
- const shortenMcpIdentities = shortenStringsOf(
3955
- 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)
3956
3932
  );
3957
3933
  const compiledPrimitiveByPrimitive = new Map(
3958
- [...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)])
3959
3935
  );
3960
3936
  return new CharterOutput(
3961
3937
  // What an agent opens from the catalogue is the primitive as it compiled,
@@ -3965,14 +3941,14 @@ function compile(charter, agents) {
3965
3941
  catalogueOf(charter, (one) => compiledPrimitiveByPrimitive.get(one).projections[0].file),
3966
3942
  charterMdOf(PRIMITIVE_CLASSES),
3967
3943
  [...compiledPrimitiveByPrimitive.values()],
3968
- new McpOrigins(mcpOriginsOf(charter, shortenMcpIdentities)),
3969
- agents.flatMap((agent) => providerComponentsOf(agent, charter, compiledPrimitiveByPrimitive, shortenMcpIdentities))
3944
+ new McpOrigins(mcpOriginsOf(charter, shortMcpIds)),
3945
+ agents.flatMap((agent) => providerComponentsOf(agent, charter, compiledPrimitiveByPrimitive, shortMcpIds))
3970
3946
  );
3971
3947
  }
3972
- function providerComponentsOf(agent, charter, compiledPrimitiveByPrimitive, shortenMcpIdentities) {
3948
+ function providerComponentsOf(agent, charter, compiledPrimitiveByPrimitive, shortMcpIds) {
3973
3949
  switch (agent) {
3974
3950
  case "claude":
3975
- return claudeComponentsOf(charter, compiledPrimitiveByPrimitive, shortenMcpIdentities);
3951
+ return claudeComponentsOf(charter, compiledPrimitiveByPrimitive, shortMcpIds);
3976
3952
  }
3977
3953
  }
3978
3954
 
@@ -4175,37 +4151,37 @@ var CharterAuthoring = class {
4175
4151
  );
4176
4152
  }
4177
4153
  /**
4178
- * 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
4179
4155
  * up, the mixins it uses and the corpus it cites, what uses, cites or names
4180
4156
  * it, and the situations this repository wrote down about it (FR-014, FR-017,
4181
4157
  * FR-163).
4182
4158
  *
4183
- * 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
4184
4160
  * layer, and which file answers to a name, and which names one primitive
4185
4161
  * shares with another, are the charter's own questions (FR-014). What is here
4186
4162
  * is the order — read, refuse a charter that does not hold, then ask.
4187
4163
  *
4188
- * 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
4189
4165
  * word that is no kind is: there is no file it is wrong with, and the next
4190
4166
  * move is to go and look at what the charter does hold.
4191
4167
  *
4192
4168
  * Reads and says: this holds a writing port and never reaches for it (FR-041).
4193
4169
  */
4194
- async explain(identity) {
4195
- const primitiveIdentity = identityOf(identity);
4170
+ async explain(id) {
4171
+ const primitiveId = primitiveIdOf(id);
4196
4172
  const [charter, , faultsByFiles] = await this.#read();
4197
4173
  if (charter === void 0) return faultsByFileDTO(faultsByFiles.errors(), this.#repoPath);
4198
- const declared = charter.primitiveById.get(primitiveIdentity);
4174
+ const declared = charter.primitiveById.get(primitiveId);
4199
4175
  if (declared === void 0)
4200
4176
  throw new DomainFault(
4201
- `This charter holds no "${identity}".`,
4202
- '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.'
4203
4179
  );
4204
4180
  const testRoot = await loadTestRoot(this.#repoPath, this.#fileReader);
4205
4181
  const testCasesByFile = Object.fromEntries(
4206
4182
  Object.entries(testRoot.suitesByFile).map(([file, suite]) => [
4207
4183
  file,
4208
- suite.cases.filter((each) => each.activatedIdentity === primitiveIdentity).map((each) => each.describe())
4184
+ suite.cases.filter((each) => each.activatedId === primitiveId).map((each) => each.describe())
4209
4185
  ]).filter(([, situations]) => situations.length > 0)
4210
4186
  );
4211
4187
  return explanationOutcomeDTO(
@@ -4313,15 +4289,15 @@ var CharterAuthoring = class {
4313
4289
  * in an editor afterwards (FR-117).
4314
4290
  *
4315
4291
  * Nothing is validated and nothing is asked of the charter but which
4316
- * 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
4317
4293
  * reading it as the primitive it claims to be is what refuses an answer its
4318
4294
  * kind will not take — the same reading a file of it would get, so there is no
4319
4295
  * second contract here to keep in step with the kind's (FR-004). Where it goes
4320
4296
  * is the convention: a directory per kind, since nothing reads the directory
4321
4297
  * (FR-002).
4322
4298
  *
4323
- * An identity the charter already holds, in any layer, is refused naming the
4324
- * 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
4325
4301
  * a second file claiming it is a collision the next read would report
4326
4302
  * (FR-014). The files are read without being validated, so a charter wrong
4327
4303
  * somewhere else can still be added to.
@@ -4336,10 +4312,10 @@ var CharterAuthoring = class {
4336
4312
  return faultsDTO(new Faults(raised.errors));
4337
4313
  }
4338
4314
  const charter = await loadCharterRoot(this.#repoPath, this.#fileReader, this.#yamlParser);
4339
- const claimingPrimitive = charter.primitiveById.get(identityOf({ kind, id }));
4315
+ const claimingPrimitive = charter.primitiveById.get(id);
4340
4316
  if (claimingPrimitive !== void 0)
4341
4317
  throw new DomainFault(
4342
- `"${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.`,
4343
4319
  `Open ${claimingPrimitive.file}, or run this again with an id this charter has not got.`
4344
4320
  );
4345
4321
  return primitiveDTO(await writeCharter(this.#repoPath, primitive, this.#fileReader, this.#fileWriter));
@@ -4353,8 +4329,8 @@ var CharterAuthoring = class {
4353
4329
  * needs to open it. A save made over its hash is checked against the
4354
4330
  * primitive read again then.
4355
4331
  */
4356
- async open(identity) {
4357
- return primitiveDTO(await this.#primitiveByIdentity(identity));
4332
+ async open(id) {
4333
+ return primitiveDTO(await this.#primitiveById(id));
4358
4334
  }
4359
4335
  /**
4360
4336
  * One repository primitive's file written over with new headers and a new
@@ -4366,16 +4342,16 @@ var CharterAuthoring = class {
4366
4342
  * this one (FR-078). Answers the kind will not take come back as the faults
4367
4343
  * `add` gives for them, since both read answers the one way.
4368
4344
  *
4369
- * 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
4370
4346
  * file, and a rename is a new primitive and a deletion. Nothing is compiled
4371
4347
  * and nothing committed (FR-079).
4372
4348
  */
4373
- async rewrite(identity, headers, body, openedHash) {
4374
- const authoredPrimitive = await this.#primitiveByIdentity(identity);
4349
+ async rewrite(id, headers, body, openedHash) {
4350
+ const authoredPrimitive = await this.#primitiveById(id);
4375
4351
  if (!RepoLayerPrimitive.isSatisfiedBy(authoredPrimitive))
4376
4352
  throw new DomainFault(
4377
- `${identity} was not authored in this repository, and ${authoredPrimitive.file} is read-only here.`,
4378
- `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.`
4379
4355
  );
4380
4356
  if (authoredPrimitive.hash !== openedHash)
4381
4357
  throw new DomainFault(
@@ -4404,29 +4380,29 @@ var CharterAuthoring = class {
4404
4380
  * each as dangling, and what to do about them is its author's call. Nothing is
4405
4381
  * compiled and nothing committed (FR-079).
4406
4382
  */
4407
- async remove(identity) {
4408
- const primitive = await this.#primitiveByIdentity(identity);
4383
+ async remove(id) {
4384
+ const primitive = await this.#primitiveById(id);
4409
4385
  if (!RepoLayerPrimitive.isSatisfiedBy(primitive))
4410
4386
  throw new DomainFault(
4411
- `${identity} was not authored in this repository, and ${primitive.file} is read-only here.`,
4412
- `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.`
4413
4389
  );
4414
4390
  const file = new URL(primitive.file, this.#repoPath);
4415
4391
  await this.#fileWriter.delete(file);
4416
4392
  for (const assetFile of primitive.assets) await this.#fileWriter.delete(new URL(assetFile.file, file));
4417
4393
  return primitiveDTO(primitive);
4418
4394
  }
4419
- /** 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
4420
4396
  * validation. Raised when the charter holds nothing of it, the way `explain`
4421
4397
  * raises it: there is no file it is wrong with. */
4422
- async #primitiveByIdentity(identity) {
4423
- const primitiveIdentity = identityOf(identity);
4398
+ async #primitiveById(id) {
4399
+ const primitiveId = primitiveIdOf(id);
4424
4400
  const charter = await loadCharterRoot(this.#repoPath, this.#fileReader, this.#yamlParser);
4425
- const primitive = charter.primitiveById.get(primitiveIdentity);
4401
+ const primitive = charter.primitiveById.get(primitiveId);
4426
4402
  if (primitive === void 0)
4427
4403
  throw new DomainFault(
4428
- `This charter holds no "${identity}".`,
4429
- '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.'
4430
4406
  );
4431
4407
  return primitive;
4432
4408
  }
@@ -4567,7 +4543,7 @@ async function writeCredential(secrets2, credential) {
4567
4543
  async function credentialFor(secrets2, authorizing2, origin, { refused = false } = {}) {
4568
4544
  if (origin.endpoint !== void 0 && !isSecureEndpoint(origin.endpoint))
4569
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".');
4570
- 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.`;
4571
4547
  const credential = await readCredential(secrets2, origin.address);
4572
4548
  if (credential === void 0) throw new DomainFault(`You are not signed in to ${origin.address}.`, signInAgain);
4573
4549
  const expired = refused || credential.expiresAt !== void 0 && Date.parse(credential.expiresAt) <= Date.now();
@@ -4602,18 +4578,18 @@ async function loadMcpTools(repo, fileReader2, yamlParser2) {
4602
4578
  if (Array.isArray(catalogJson)) catalogEntries = catalogJson;
4603
4579
  } catch {
4604
4580
  }
4605
- const toolsByIdentity = /* @__PURE__ */ new Map();
4606
- for (const { identity, kind, file } of catalogEntries) {
4607
- 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;
4608
4584
  const compiledDocument = await fileReader2.readIfThere(new URL(file, repo));
4609
4585
  if (compiledDocument === void 0) continue;
4610
4586
  try {
4611
4587
  const primitive = primitiveOf(compiledDocument, yamlParser2);
4612
- if (primitive instanceof McpPrimitive) toolsByIdentity.set(identity, primitive.headers.tools);
4588
+ if (primitive instanceof McpPrimitive) toolsById.set(id, primitive.headers.tools);
4613
4589
  } catch {
4614
4590
  }
4615
4591
  }
4616
- return toolsByIdentity;
4592
+ return toolsById;
4617
4593
  }
4618
4594
 
4619
4595
  // src/hexagon/port/zdriven/DrivenFault.ts
@@ -4648,11 +4624,11 @@ var McpConnecting = class {
4648
4624
  }
4649
4625
  async signInStatus() {
4650
4626
  return Promise.all(
4651
- (await this.#signInAddresses()).map(async ({ address, identities, auth: auth2 }) => {
4627
+ (await this.#signInAddresses()).map(async ({ address, ids, auth: auth2 }) => {
4652
4628
  const credential = await readCredential(this.#secrets, address);
4653
4629
  return {
4654
4630
  type: "SignInStatus",
4655
- 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 } }
4656
4632
  };
4657
4633
  })
4658
4634
  );
@@ -4675,8 +4651,8 @@ var McpConnecting = class {
4675
4651
  const toolRoute = toolRoutes.get(name);
4676
4652
  if (toolRoute === void 0)
4677
4653
  return errorAnswerOf(unreachableTools.get(name) ?? `"${name}" is not a tool this server serves; call one it listed.`);
4678
- const { origin, identity, upstream, connection } = toolRoute;
4679
- 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.`;
4680
4656
  const accessTokenOf = (refused) => origin.endpoint === void 0 ? Promise.resolve(void 0) : credentialFor(this.#secrets, this.#authorizing, origin, { refused });
4681
4657
  try {
4682
4658
  try {
@@ -4700,7 +4676,7 @@ var McpConnecting = class {
4700
4676
  }
4701
4677
  /**
4702
4678
  * Every place the last build listed, reached at once and once per run
4703
- * (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
4704
4680
  * declares it, renamed `<prefix>__<tool>`; a place down or not signed in to,
4705
4681
  * and a declared tool its place lacks, is said and left out, and the rest
4706
4682
  * are served (FR-153, FR-154, SC-039).
@@ -4708,7 +4684,7 @@ var McpConnecting = class {
4708
4684
  #serving() {
4709
4685
  this.#mcpServing ??= (async () => {
4710
4686
  const origins = await loadMcpOrigins(this.#repoPath, this.#fileReader);
4711
- const toolsByIdentity = await loadMcpTools(this.#repoPath, this.#fileReader, this.#yamlParser);
4687
+ const toolsById = await loadMcpTools(this.#repoPath, this.#fileReader, this.#yamlParser);
4712
4688
  const problems = [];
4713
4689
  const servedTools = [];
4714
4690
  const toolRoutes = /* @__PURE__ */ new Map();
@@ -4727,30 +4703,30 @@ var McpConnecting = class {
4727
4703
  );
4728
4704
  for (const { origin, connection, reason } of reachedPlaces) {
4729
4705
  if (connection !== void 0) connections.push(connection);
4730
- else problems.push(`${origin.identities.join(", ")}: ${reason}`);
4731
- for (const identity of origin.identities) {
4732
- 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);
4733
4709
  if (declaredTools === void 0) {
4734
- 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".`);
4735
4711
  continue;
4736
4712
  }
4737
- const identityName = origin.names?.[identity];
4738
- if (identityName === void 0) {
4739
- 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.`);
4740
4716
  continue;
4741
4717
  }
4742
4718
  for (const tool of declaredTools) {
4743
- const servedName = `${identityName}__${tool}`;
4719
+ const servedName = `${servedPrefix}__${tool}`;
4744
4720
  if (connection === void 0) {
4745
4721
  unreachableTools.set(servedName, reason ?? "");
4746
4722
  continue;
4747
4723
  }
4748
4724
  const upstreamTool = connection.tools.find(({ name }) => name === tool);
4749
4725
  if (upstreamTool === void 0) {
4750
- 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.`);
4751
4727
  continue;
4752
4728
  }
4753
- const placeName = origin.path === void 0 ? identity : `${identity} \u2014 ${origin.path}`;
4729
+ const placeName = origin.path === void 0 ? id : `${id} \u2014 ${origin.path}`;
4754
4730
  servedTools.push({
4755
4731
  type: "ServedTool",
4756
4732
  data: {
@@ -4759,7 +4735,7 @@ var McpConnecting = class {
4759
4735
  inputSchema: upstreamTool.inputSchema
4760
4736
  }
4761
4737
  });
4762
- toolRoutes.set(servedName, { origin, identity, upstream: tool, connection });
4738
+ toolRoutes.set(servedName, { origin, id, upstream: tool, connection });
4763
4739
  }
4764
4740
  }
4765
4741
  }
@@ -4784,16 +4760,16 @@ var McpConnecting = class {
4784
4760
  async #signInAddresses() {
4785
4761
  const origins = await loadMcpOrigins(this.#repoPath, this.#fileReader);
4786
4762
  const addresses = /* @__PURE__ */ new Map();
4787
- for (const { address, endpoint, identities, auth: auth2 } of origins.filter((one) => one.auth.length > 0)) {
4788
- const signInAddress = addresses.get(address) ?? { ...endpoint !== void 0 && { endpoint }, identities: /* @__PURE__ */ new Set(), auth: /* @__PURE__ */ new Set() };
4789
- 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));
4790
4766
  auth2.forEach((method) => signInAddress.auth.add(method));
4791
4767
  addresses.set(address, signInAddress);
4792
4768
  }
4793
- 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 }]) => ({
4794
4770
  address,
4795
4771
  ...endpoint !== void 0 && { endpoint },
4796
- identities: [...identities].sort(),
4772
+ ids: [...ids].sort(),
4797
4773
  auth: ["oauth", "token"].filter((method) => auth2.has(method))
4798
4774
  }));
4799
4775
  }