@basou/core 0.31.0 → 0.32.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/index.js CHANGED
@@ -5481,6 +5481,65 @@ function shortId(id) {
5481
5481
  return id.slice(0, sep + 1) + id.slice(sep + 1, sep + 1 + 10);
5482
5482
  }
5483
5483
 
5484
+ // src/project/anchor-starter.ts
5485
+ function renderAnchorStarter(input) {
5486
+ const lines = [];
5487
+ const title = input.projectName ?? input.anchorName;
5488
+ lines.push(`# AGENTS.md (${input.anchorName})`);
5489
+ lines.push("");
5490
+ lines.push(
5491
+ `> \u3053\u306E\u30EA\u30DD\u30B8\u30C8\u30EA\u306F **${title} \u306E planning master(anchor)** \u3067\u3059\u3002\u3053\u3053\u3067\u4F5C\u696D\u3059\u308B AI \u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u306F\u3001\u307E\u305A\u3053\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u8AAD\u3093\u3067\u304F\u3060\u3055\u3044\u3002`
5492
+ );
5493
+ lines.push(">");
5494
+ lines.push(
5495
+ "> \u3053\u306E\u30D5\u30A1\u30A4\u30EB\u306F `basou project derive` \u304C greenfield \u7ACB\u3061\u4E0A\u3052\u6642\u306B **\u4E00\u5EA6\u3060\u3051\u751F\u6210\u3057\u305F starter** \u3067\u3059\u3002\u4EE5\u5F8C\u306F\u624B\u7BA1\u7406\u3057\u3066\u304F\u3060\u3055\u3044 \u2014 basou \u306F\u518D\u751F\u6210\u3082\u4E0A\u66F8\u304D\u3082\u3057\u307E\u305B\u3093(BASOU:GENERATED \u30DE\u30FC\u30AB\u30FC\u306F\u7121\u304F\u3001\u81EA\u7531\u306B\u7DE8\u96C6\u3067\u304D\u307E\u3059)\u3002"
5496
+ );
5497
+ lines.push("");
5498
+ lines.push("## \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u57FA\u672C\u60C5\u5831");
5499
+ lines.push("");
5500
+ lines.push("<!-- TODO: manifest \u304B\u3089\u306F\u5C0E\u51FA\u3067\u304D\u306A\u3044\u9805\u76EE\u3067\u3059\u3002\u57CB\u3081\u3066\u304F\u3060\u3055\u3044\u3002 -->");
5501
+ lines.push("");
5502
+ lines.push("```text");
5503
+ lines.push(`Product name: ${input.projectName ?? "<!-- TODO -->"}`);
5504
+ lines.push("Domain: <!-- TODO -->");
5505
+ lines.push("GitHub Organization: <!-- TODO -->");
5506
+ lines.push("Public repository: <!-- TODO -->");
5507
+ lines.push("Planning repository: <!-- TODO -->");
5508
+ lines.push("License: <!-- TODO -->");
5509
+ lines.push("```");
5510
+ lines.push("");
5511
+ lines.push("## \u3069\u3053\u3067 commit \u3059\u308B\u304B");
5512
+ lines.push("");
5513
+ lines.push("- **\u3053\u306E\u30EA\u30DD\u30B8\u30C8\u30EA(planning master)**: \u69CB\u60F3\u30FB\u8A08\u753B\u30FB\u8A2D\u8A08\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u3002");
5514
+ lines.push("- **\u5404\u5B9F\u88C5 repo**: \u5B9F\u88C5\u30B3\u30FC\u30C9\u3002\u5FC5\u305A\u5BFE\u8C61 repo \u306B `cd` \u3057\u3066\u304B\u3089 commit \u3057\u3066\u304F\u3060\u3055\u3044\u3002");
5515
+ lines.push("- **workspace view**: git \u7BA1\u7406\u5916\u3002view \u3067\u306F commit \u3067\u304D\u307E\u305B\u3093\u3002");
5516
+ lines.push("");
5517
+ lines.push("## \u5FC5\u305A\u8AAD\u3080\u3079\u304D\u898F\u7D04");
5518
+ lines.push("");
5519
+ lines.push("\u4F5C\u696D\u898F\u7D04\u306F\u5404 repo \u306E AGENTS.md \u306B\u3042\u308A\u307E\u3059\u3002\u4EE5\u4E0B\u3092\u8AAD\u3093\u3067\u304B\u3089\u4F5C\u696D\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
5520
+ lines.push("");
5521
+ for (const r of input.repos) {
5522
+ if (r.anchor === true) continue;
5523
+ lines.push(`- ${r.name}/AGENTS.md`);
5524
+ }
5525
+ if (input.viewName !== void 0) {
5526
+ lines.push(
5527
+ `- ${input.viewName}/AGENTS.md(workspace view\u30FBbasou \u304C\u751F\u6210)\u2014 **\u6700\u65B0\u306E repo \u69CB\u6210(roster)\u306F\u3053\u3053\u3092\u6B63\u3068\u3059\u308B**`
5528
+ );
5529
+ }
5530
+ lines.push("");
5531
+ lines.push("## \u4F5C\u696D\u65B9\u91DD(\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u56FA\u6709\u4E8B\u9805)");
5532
+ lines.push("");
5533
+ lines.push("<!-- TODO: \u4EE5\u4E0B\u3092\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306B\u5408\u308F\u305B\u3066\u8A18\u8FF0\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
5534
+ lines.push(" - \u73FE\u5728\u306E\u30D5\u30A7\u30FC\u30BA / \u91CD\u8981\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8");
5535
+ lines.push(" - \u6A5F\u5BC6\u60C5\u5831\u306E\u6271\u3044(\u3069\u3053\u306B\u66F8\u304B\u306A\u3044\u304B)");
5536
+ lines.push(" - \u8A00\u8A9E\u30DD\u30EA\u30B7\u30FC(commit / \u30B3\u30E1\u30F3\u30C8 / \u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306E\u8A00\u8A9E)");
5537
+ lines.push(" - commit \u904B\u7528(\u6DF7\u5728\u30B3\u30DF\u30C3\u30C8\u3092\u907F\u3051\u308B \u7B49)");
5538
+ lines.push("-->");
5539
+ return `${lines.join("\n")}
5540
+ `;
5541
+ }
5542
+
5484
5543
  // src/project/relative-path.ts
5485
5544
  function normalizeRelativePath(p) {
5486
5545
  const trimmed = p.trim();
@@ -5657,10 +5716,69 @@ function renderPresetBlock(repo) {
5657
5716
  }
5658
5717
  return lines.join("\n");
5659
5718
  }
5719
+ function visibilityShortLabel(v) {
5720
+ return v ?? "\u672A\u8A2D\u5B9A";
5721
+ }
5722
+ function languageShortLabel(l) {
5723
+ return l ?? "\u672A\u8A2D\u5B9A";
5724
+ }
5725
+ function instructionsLabel(repo) {
5726
+ if (repo.anchor === true) return "anchor(\u624B\u7BA1\u7406)";
5727
+ return repo.self === true ? "self(repo \u304C\u81EA\u5DF1\u7BA1\u7406)" : "hub(basou \u304C\u751F\u6210)";
5728
+ }
5729
+ function renderViewPresetBlock(input) {
5730
+ const lines = [];
5731
+ lines.push("## workspace view \u69CB\u6210(basou \u304C\u751F\u6210 \u2014 manifest \u304C\u6B63\u672C)");
5732
+ lines.push("");
5733
+ lines.push(
5734
+ "\u3053\u306E\u30BB\u30AF\u30B7\u30E7\u30F3\u306F `.basou/manifest.yaml` \u306E\u5BA3\u8A00\u304B\u3089 `basou project preset` \u304C\u751F\u6210\u3057\u307E\u3059\u3002\u7DE8\u96C6\u306F manifest \u5074\u3067\u884C\u3063\u3066\u304F\u3060\u3055\u3044(\u30DE\u30FC\u30AB\u30FC\u5916\u306E\u8A18\u8FF0\u306F\u4FDD\u6301\u3055\u308C\u307E\u3059)\u3002"
5735
+ );
5736
+ lines.push(
5737
+ `\u3053\u306E AGENTS.md \u81EA\u8EAB\u3082 basou \u306E\u751F\u6210\u7269\u3067\u3059(\u5B9F\u4F53: \`agents/${input.viewName}/AGENTS.md\`\u3001\u30DE\u30FC\u30AB\u30FC\u5916\u306E\u8A18\u8FF0\u306F\u4FDD\u6301\u3055\u308C\u307E\u3059)\u3002`
5738
+ );
5739
+ lines.push("");
5740
+ lines.push(
5741
+ `\u3053\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306F\u3001\u5BA3\u8A00\u3055\u308C\u305F ${input.repos.length} \u500B\u306E repo \u3092 symlink \u3067\u96C6\u7D04\u3059\u308B **view** \u3067\u3059\u3002\u5B9F\u4F53\u3092\u6301\u305F\u305A\u3001git \u7BA1\u7406\u5916\u3067\u3059\u3002`
5742
+ );
5743
+ lines.push("");
5744
+ lines.push("### \u96C6\u7D04\u3057\u3066\u3044\u308B repo");
5745
+ lines.push("");
5746
+ lines.push("| repo | \u53EF\u8996\u6027 | \u8A00\u8A9E | \u6307\u793A\u66F8 |");
5747
+ lines.push("|---|---|---|---|");
5748
+ for (const r of input.repos) {
5749
+ lines.push(
5750
+ `| ${r.name} | ${visibilityShortLabel(r.visibility)} | ${languageShortLabel(r.language)} | ${instructionsLabel(r)} |`
5751
+ );
5752
+ }
5753
+ lines.push("");
5754
+ lines.push("### \u3069\u3053\u3067 commit \u3059\u308B\u304B");
5755
+ lines.push("");
5756
+ lines.push(
5757
+ "view \u3067\u306F commit \u3067\u304D\u307E\u305B\u3093(git \u7BA1\u7406\u5916)\u3002\u5909\u66F4\u306F\u5FC5\u305A\u5B9F\u4F53\u306E repo \u306B `cd` \u3057\u3066\u304B\u3089 commit \u3057\u3066\u304F\u3060\u3055\u3044\u3002"
5758
+ );
5759
+ lines.push("");
5760
+ for (const r of input.repos) {
5761
+ lines.push(`- ${r.name} \u2192 \`cd ${r.name}\``);
5762
+ }
5763
+ lines.push("");
5764
+ lines.push("### \u5FC5\u305A\u8AAD\u3080\u3079\u304D\u898F\u7D04");
5765
+ lines.push("");
5766
+ lines.push("\u4F5C\u696D\u898F\u7D04\u306F\u5404 repo \u306E AGENTS.md \u306B\u3042\u308A\u307E\u3059\u3002\u4EE5\u4E0B\u3092\u8AAD\u3093\u3067\u304B\u3089\u4F5C\u696D\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
5767
+ lines.push("");
5768
+ for (const r of input.repos) {
5769
+ lines.push(`- ${r.name}/AGENTS.md`);
5770
+ }
5771
+ lines.push("");
5772
+ lines.push("### \u91CD\u8981\u539F\u5247");
5773
+ lines.push("");
5774
+ lines.push("- \u3053\u306E\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306F\u72B6\u614B\u3092\u6301\u305F\u306A\u3044(git \u7BA1\u7406\u5916)");
5775
+ lines.push("- \u91CD\u8981\u306A\u30D5\u30A1\u30A4\u30EB\u3092\u3053\u3053\u306B\u76F4\u63A5\u7F6E\u304B\u306A\u3044(\u5B9F\u4F53\u306F\u5404 repo \u306B\u7F6E\u304F)");
5776
+ return lines.join("\n");
5777
+ }
5660
5778
  function normalizeBlock(s) {
5661
5779
  return s.replace(/\r\n/g, "\n").replace(/\n+$/, "");
5662
5780
  }
5663
- function summarizePresetPlan(facts) {
5781
+ function summarizePresetPlan(facts, opts) {
5664
5782
  const deduped = [];
5665
5783
  const seenPath = /* @__PURE__ */ new Set();
5666
5784
  for (const f of facts) {
@@ -5680,8 +5798,9 @@ function summarizePresetPlan(facts) {
5680
5798
  const collisions = [];
5681
5799
  const collidingPaths = /* @__PURE__ */ new Set();
5682
5800
  for (const [canonicalName, repos] of byCanonical) {
5683
- if (repos.length > 1) {
5684
- collisions.push({ canonicalName, repos });
5801
+ const viewCollision = opts?.viewCanonicalName !== void 0 && canonicalName === opts.viewCanonicalName;
5802
+ if (repos.length > 1 || viewCollision) {
5803
+ collisions.push({ canonicalName, repos, ...viewCollision ? { view: true } : {} });
5685
5804
  for (const r of repos) collidingPaths.add(r);
5686
5805
  }
5687
5806
  }
@@ -5846,6 +5965,8 @@ function classifyRetrofit(facts) {
5846
5965
  if (facts.agentsState === "symlink")
5847
5966
  return { ...base, action: "skip", reason: "already-symlink" };
5848
5967
  if (facts.agentsState === "absent") return { ...base, action: "skip", reason: "absent" };
5968
+ if (facts.viewCanonicalName !== void 0 && facts.canonicalName === facts.viewCanonicalName)
5969
+ return { ...base, action: "refuse", reason: "view-collision" };
5849
5970
  if (facts.canonicalExists) return { ...base, action: "refuse", reason: "canonical-exists" };
5850
5971
  return {
5851
5972
  ...base,
@@ -5942,7 +6063,7 @@ function summarizeSymlinkPlan(facts) {
5942
6063
  const selfAgentsMissing = [];
5943
6064
  const unreachable = [];
5944
6065
  for (const f of deduped) {
5945
- if (f.isAnchor) continue;
6066
+ if (f.isAnchor && !f.canonicalPresent) continue;
5946
6067
  if (!f.reachable) {
5947
6068
  unreachable.push(f.path);
5948
6069
  continue;
@@ -6021,6 +6142,68 @@ function summarizeWiring(facts) {
6021
6142
  };
6022
6143
  }
6023
6144
 
6145
+ // src/project/wiring-drift.ts
6146
+ function summarizeWiringDrift(input) {
6147
+ const plan = summarizeSymlinkPlan(input.repos);
6148
+ const missingCanonicals = [
6149
+ ...plan.missingCanonical.map((path2) => ({ target: "repo-hub", name: path2 })),
6150
+ ...plan.selfAgentsMissing.map(
6151
+ (path2) => ({ target: "repo-self", name: path2 })
6152
+ )
6153
+ ];
6154
+ const incompleteWiring = plan.plans.map((p) => ({
6155
+ target: "repo",
6156
+ path: p.path,
6157
+ files: p.toCreate.map((c) => c.name)
6158
+ }));
6159
+ const conflicts = plan.conflicts.map((c) => ({
6160
+ target: "repo",
6161
+ path: c.repo,
6162
+ file: c.file,
6163
+ reason: c.reason,
6164
+ ...c.actualTarget !== void 0 ? { actualTarget: c.actualTarget } : {}
6165
+ }));
6166
+ const collisions = plan.collisions.map((c) => ({
6167
+ canonicalName: c.canonicalName,
6168
+ repos: c.repos
6169
+ }));
6170
+ const view = input.view;
6171
+ if (view.kind === "collision") {
6172
+ collisions.push({ canonicalName: view.viewName, repos: [view.repoPath], view: true });
6173
+ } else if (view.kind === "missing-canonical") {
6174
+ missingCanonicals.push({ target: "view", name: view.viewName });
6175
+ } else if (view.kind === "gathered") {
6176
+ const missingSpokes = [];
6177
+ for (const f of view.files) {
6178
+ if (f.state === "missing") {
6179
+ missingSpokes.push(f.name);
6180
+ } else if (f.state === "mismatch" || f.state === "occupied" || f.state === "blocked") {
6181
+ conflicts.push({
6182
+ target: "view",
6183
+ path: view.viewName,
6184
+ file: f.name,
6185
+ reason: f.state,
6186
+ ...f.actualTarget !== void 0 ? { actualTarget: f.actualTarget } : {}
6187
+ });
6188
+ }
6189
+ }
6190
+ if (missingSpokes.length > 0) {
6191
+ incompleteWiring.push({ target: "view", path: view.viewName, files: missingSpokes });
6192
+ }
6193
+ }
6194
+ return {
6195
+ missingCanonicals,
6196
+ incompleteWiring,
6197
+ conflicts,
6198
+ collisions,
6199
+ unreachable: plan.unreachable,
6200
+ // `unreachable` is intentionally NOT part of `ok`: a declared repo that is not
6201
+ // cloned on this machine is an advisory fact (partial checkout), not drift the
6202
+ // operator must fix here. Only actionable drift denies `ok`.
6203
+ ok: missingCanonicals.length === 0 && incompleteWiring.length === 0 && conflicts.length === 0 && collisions.length === 0
6204
+ };
6205
+ }
6206
+
6024
6207
  // src/project/workspace-view.ts
6025
6208
  function planWorkspaceView(facts, existing = [], rosterNames = []) {
6026
6209
  const deduped = [];
@@ -7545,6 +7728,33 @@ ${normalized}${markers.end}${section.after}`;
7545
7728
  throw new Error(`Markers mismatched in ${fileLabel}`);
7546
7729
  }
7547
7730
  }
7731
+ function seedMarkers(existing, generated, fileLabel, markers = DEFAULT_MARKERS) {
7732
+ const normalized = generated.endsWith("\n") ? generated : `${generated}
7733
+ `;
7734
+ if (existing === null) {
7735
+ return `${markers.start}
7736
+ ${normalized}${markers.end}
7737
+ `;
7738
+ }
7739
+ const section = parseMarkers(existing, markers);
7740
+ switch (section.kind) {
7741
+ case "ok":
7742
+ return renderWithMarkers(existing, generated, fileLabel, markers);
7743
+ case "no_markers": {
7744
+ const bom = existing.charCodeAt(0) === 65279 ? "\uFEFF" : "";
7745
+ const body = bom === "" ? existing : existing.slice(1);
7746
+ return `${bom}${markers.start}
7747
+ ${normalized}${markers.end}
7748
+
7749
+ ${body}`;
7750
+ }
7751
+ case "missing_start":
7752
+ case "missing_end":
7753
+ case "multiple_pairs":
7754
+ case "wrong_order":
7755
+ throw new Error(`Markers mismatched in ${fileLabel}`);
7756
+ }
7757
+ }
7548
7758
  function removeMarkerSection(existing, fileLabel, markers = DEFAULT_MARKERS) {
7549
7759
  const section = parseMarkers(existing, markers);
7550
7760
  switch (section.kind) {
@@ -8113,11 +8323,13 @@ export {
8113
8323
  reimportPreservingId,
8114
8324
  removeMarkerSection,
8115
8325
  removeStopHook,
8326
+ renderAnchorStarter,
8116
8327
  renderDecisions,
8117
8328
  renderHandoff,
8118
8329
  renderOrientation,
8119
8330
  renderPresetBlock,
8120
8331
  renderReport,
8332
+ renderViewPresetBlock,
8121
8333
  renderWithMarkers,
8122
8334
  replayEvents,
8123
8335
  resolveBasouRepositoryRoot,
@@ -8130,6 +8342,7 @@ export {
8130
8342
  sanitizePath,
8131
8343
  sanitizeRelatedFiles,
8132
8344
  sanitizeWorkingDirectory,
8345
+ seedMarkers,
8133
8346
  serializeEventLine,
8134
8347
  serializeJsonSchema,
8135
8348
  sessionWorkStatsFromEvents,
@@ -8139,6 +8352,7 @@ export {
8139
8352
  summarizeRosterDrift,
8140
8353
  summarizeSymlinkPlan,
8141
8354
  summarizeWiring,
8355
+ summarizeWiringDrift,
8142
8356
  tryRemoteUrl,
8143
8357
  ulid,
8144
8358
  unknownManifestKeys,