truecourse 0.7.0-next.0 → 0.7.0-next.1

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/cli.mjs CHANGED
@@ -170270,7 +170270,7 @@ function readToolVersion() {
170270
170270
  if (cachedVersion)
170271
170271
  return cachedVersion;
170272
170272
  if (true) {
170273
- cachedVersion = "0.7.0-next.0";
170273
+ cachedVersion = "0.7.0-next.1";
170274
170274
  return cachedVersion;
170275
170275
  }
170276
170276
  try {
@@ -196272,8 +196272,14 @@ var CorpusDocSchema = external_exports.object({
196272
196272
  var OverlapSectionSchema = external_exports.object({
196273
196273
  /** The doc this section lives in, by ref (one of the overlap's two docs). */
196274
196274
  doc: DocRefSchema,
196275
- /** The heading text of the conflicting section (verbatim from the doc). */
196276
- heading: external_exports.string()
196275
+ /**
196276
+ * The heading text of the conflicting section (verbatim from the doc), or
196277
+ * `null` when the conflicting passage sits in the doc's PREAMBLE — the block
196278
+ * before its first heading (README badges/tagline, intro line). A plain string
196279
+ * from older corpora still parses; `null` is the preamble marker the viewer
196280
+ * bands as the pre-first-heading block.
196281
+ */
196282
+ heading: external_exports.string().nullable()
196277
196283
  });
196278
196284
  var OverlapSchema = external_exports.object({
196279
196285
  /** The two docs that overlap, by ref. */
@@ -197210,7 +197216,9 @@ NOT a disagreement (do NOT flag):
197210
197216
 
197211
197217
  Bias: when there is a PLAUSIBLE contradiction a human should check, flag it. When the docs are clearly complementary or agree, do not.
197212
197218
 
197213
- When you flag an overlap, also identify the SECTIONS that conflict: the nearest markdown heading (the \`#\`/\`##\`/\`###\` title, verbatim, WITHOUT the leading #s) above the conflicting text in EACH doc. List one entry per side; omit a side only if it genuinely has no heading.
197219
+ When you flag an overlap, also identify the SECTIONS that conflict: the nearest markdown heading (the \`#\`/\`##\`/\`###\` title, verbatim, WITHOUT the leading #s) above the conflicting text in EACH doc. List one entry per side; omit a side only when it genuinely has no conflicting passage.
197220
+
197221
+ PREAMBLE: when a doc's conflicting passage sits ABOVE its first \`#\` heading \u2014 the preamble block (a README's badges, tagline, or the intro line before any heading) \u2014 there is no heading to name. Set that side's \`heading\` to the JSON literal \`null\` (not the string "null", not ""). Use \`null\` ONLY for that pre-first-heading block; whenever the passage is under a heading, name the heading verbatim.
197214
197222
 
197215
197223
  In the NOTE, refer to each doc by its FILENAME (the basename shown in the header, e.g. \`users.md\`) \u2014 NEVER "doc A" / "doc B", which mean nothing to the reader.
197216
197224
 
@@ -197220,6 +197228,12 @@ Output ONLY a JSON object, no prose, no code fences:
197220
197228
  "note": "users.md uses auth0_id; identity.md uses auth0_sub for the same user column",
197221
197229
  "sections": [ { "side": "A", "heading": "User model" }, { "side": "B", "heading": "Identity" } ] }
197222
197230
 
197231
+ Preamble example \u2014 doc A's claim is a README badge/tagline above any heading, so its side uses null:
197232
+
197233
+ { "overlap": true,
197234
+ "note": "README.md lists C# as a supported language in the preamble; plan.md's Tech Stack omits it",
197235
+ "sections": [ { "side": "A", "heading": null }, { "side": "B", "heading": "Tech Stack" } ] }
197236
+
197223
197237
  Use { "overlap": false, "note": "", "sections": [] } when they are complementary or agree. The note is shown to the user \u2014 name the specific thing that differs.`;
197224
197238
  var OVERLAP_PREVIEW_LINES = 120;
197225
197239
  function docBody2(doc) {
@@ -197271,12 +197285,12 @@ function buildOverlapUserPrompt(areaId, a, b) {
197271
197285
  var LlmOverlapSchema = external_exports.object({
197272
197286
  overlap: external_exports.boolean(),
197273
197287
  note: external_exports.string().default(""),
197274
- sections: external_exports.array(external_exports.object({ side: external_exports.enum(["A", "B"]), heading: external_exports.string() })).default([])
197288
+ sections: external_exports.array(external_exports.object({ side: external_exports.enum(["A", "B"]), heading: external_exports.string().nullable() })).default([])
197275
197289
  });
197276
197290
  var OverlapVerdictSchema = external_exports.object({
197277
197291
  overlap: external_exports.boolean(),
197278
197292
  note: external_exports.string().default(""),
197279
- sections: external_exports.array(external_exports.object({ doc: external_exports.string(), heading: external_exports.string() })).default([])
197293
+ sections: external_exports.array(external_exports.object({ doc: external_exports.string(), heading: external_exports.string().nullable() })).default([])
197280
197294
  });
197281
197295
  function spawnOverlapRunner(opts = {}) {
197282
197296
  const transport = opts.transport ?? cliTransport({ bin: opts.bin });
@@ -197628,7 +197642,7 @@ async function classifyOne(repoRoot5, doc, runner) {
197628
197642
  await writeCache4(repoRoot5, cacheKey, verdict);
197629
197643
  return verdict;
197630
197644
  }
197631
- var RELEVANCE_SYSTEM_PROMPT = `You are a documentation relevance classifier. Classify by CONTENT, not by folder or filename: does this doc state durable, intended behavior or decisions about THE SYSTEM IN THIS REPOSITORY (its endpoints, data, auth, events, invariants, business rules, architecture)?
197645
+ var RELEVANCE_SYSTEM_PROMPT = `You are a documentation relevance classifier. Judge mainly by CONTENT \u2014 does this doc state durable, intended behavior or decisions about THE SYSTEM IN THIS REPOSITORY (its endpoints, data, auth, events, invariants, business rules, architecture)? The doc's PATH (given below) is evidence too, never an automatic verdict: weigh path and content together.
197632
197646
 
197633
197647
  ${OUTPUT_ONLY_GUARDRAIL}
197634
197648
 
@@ -197641,22 +197655,23 @@ INCLUDE (spec-source material):
197641
197655
  SKIP (not spec-source material):
197642
197656
  - Pure status / TODO checklists, kanban boards, release notes / changelog drafts
197643
197657
  - Docs about a THIRD-PARTY / external system (vendor API research, integration notes) \u2014 that is someone else's contract, not ours, and cannot be verified against this codebase
197658
+ - TEST-DATA specs: a doc under a test / fixture / sample / example tree (PATH segments like tests/, fixtures/, __fixtures__/, examples/, sample-*) that describes a FICTIONAL or sample product used as test data for THIS repo's own tooling \u2014 that product is not this repository's system, so its "spec" is not ours. (The path is evidence, not proof: if the doc plainly describes THIS repository's real product or engineering, keep it.)
197644
197659
  - SUPERSEDED docs \u2014 an older version of a newer doc covering the same subject
197645
197660
  - Process / meta docs not about product behavior: contribution / onboarding guides, code-style guides, deployment runbooks (keep a deployment doc ONLY if it states our runtime contracts)
197646
197661
  - Exploratory scratch with no committed decisions (brain dumps, open-questions-only notes)
197647
197662
  - AI-agent instructions / prompt templates; personal engineering journals
197648
197663
 
197649
- Distinguish "states a decision about our system" (INCLUDE) from "tracks status / describes an external system / is superseded / is process" (SKIP). The SKIP categories above are explicit \u2014 they are not "doubt." WHEN GENUINELY AMBIGUOUS: include (dropping a real spec doc costs more than keeping noise).
197664
+ Distinguish "states a decision about our system" (INCLUDE) from "tracks status / describes an external or test-data product / is superseded / is process" (SKIP). The SKIP categories above are explicit \u2014 they are not "doubt." WHEN GENUINELY AMBIGUOUS: include (dropping a real spec doc costs more than keeping noise).
197650
197665
 
197651
197666
  Output ONLY a JSON object:
197652
197667
 
197653
197668
  { "include": true|false, "reason": "short explanation" }
197654
197669
 
197655
- The reason is shown to the user in the dashboard \u2014 be specific ("vendor API research (ServiceTitan)", "superseded by capacity-ml-plan-v3", "deployment runbook, no product contracts") so they can verify the call.`;
197670
+ The reason is shown to the user in the dashboard \u2014 be specific ("vendor API research (ServiceTitan)", "superseded by capacity-ml-plan-v3", "deployment runbook, no product contracts", "test-data spec for a sample product (tests/fixtures/\u2026)") so they can verify the call.`;
197656
197671
  function buildRelevanceUserPrompt(doc) {
197657
197672
  const preview = doc.preview.split("\n").slice(0, 60).join("\n");
197658
197673
  return [
197659
- `Path: ${doc.path}`,
197674
+ `PATH (repo-relative): ${doc.path}`,
197660
197675
  `Detected kind: ${doc.kind}`,
197661
197676
  `Size: ${doc.size} bytes`,
197662
197677
  "",
@@ -210089,12 +210104,18 @@ async function runSpecDocsSkipped(opts = {}) {
210089
210104
  "Force-include a skipped doc with `spec docs include <path>`; force-exclude a kept doc with `spec docs exclude <path>`."
210090
210105
  );
210091
210106
  }
210092
- async function runSpecDocsInclude(docPath, opts = {}) {
210107
+ async function runSpecDocsInclude(docPaths, opts = {}) {
210093
210108
  const root2 = repoRoot3(opts);
210094
- if (!docPath) return fail3("Missing doc path");
210095
- await addManualInclude(root2, docPath);
210109
+ const paths = docPaths.filter(Boolean);
210110
+ if (paths.length === 0) return fail3("Missing doc path");
210111
+ for (const docPath of paths) {
210112
+ await addManualInclude(root2, docPath);
210113
+ O2.step(`Force-included ${docPath}`);
210114
+ }
210096
210115
  await reScan2(root2);
210097
- gt(`Force-include ${docPath} \u2014 re-scanned. Review \`truecourse spec conflicts list\`.`);
210116
+ gt(
210117
+ paths.length === 1 ? `Force-include ${paths[0]} \u2014 re-scanned. Review \`truecourse spec conflicts list\`.` : `Force-included ${paths.length} docs \u2014 re-scanned once. Review \`truecourse spec conflicts list\`.`
210118
+ );
210098
210119
  }
210099
210120
  async function runSpecDocsUninclude(docPath, opts = {}) {
210100
210121
  const root2 = repoRoot3(opts);
@@ -210103,12 +210124,18 @@ async function runSpecDocsUninclude(docPath, opts = {}) {
210103
210124
  await reScan2(root2);
210104
210125
  gt(`Removed force-include for ${docPath} \u2014 re-scanned.`);
210105
210126
  }
210106
- async function runSpecDocsExclude(docPath, opts = {}) {
210127
+ async function runSpecDocsExclude(docPaths, opts = {}) {
210107
210128
  const root2 = repoRoot3(opts);
210108
- if (!docPath) return fail3("Missing doc path");
210109
- await addManualExclude(root2, docPath);
210129
+ const paths = docPaths.filter(Boolean);
210130
+ if (paths.length === 0) return fail3("Missing doc path");
210131
+ for (const docPath of paths) {
210132
+ await addManualExclude(root2, docPath);
210133
+ O2.step(`Force-excluded ${docPath}`);
210134
+ }
210110
210135
  await reScan2(root2);
210111
- gt(`Force-exclude ${docPath} \u2014 re-scanned. Review \`truecourse spec conflicts list\`.`);
210136
+ gt(
210137
+ paths.length === 1 ? `Force-exclude ${paths[0]} \u2014 re-scanned. Review \`truecourse spec conflicts list\`.` : `Force-excluded ${paths.length} docs \u2014 re-scanned once. Review \`truecourse spec conflicts list\`.`
210138
+ );
210112
210139
  }
210113
210140
  async function runSpecDocsUnexclude(docPath, opts = {}) {
210114
210141
  const root2 = repoRoot3(opts);
@@ -211080,7 +211107,7 @@ async function runHooksRun() {
211080
211107
 
211081
211108
  // tools/cli/src/index.ts
211082
211109
  var program2 = new Command();
211083
- program2.name("truecourse").version("0.7.0-next.0").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
211110
+ program2.name("truecourse").version("0.7.0-next.1").description("TrueCourse CLI \u2014 analyze your repository and open the dashboard");
211084
211111
  var dashboardCmd = program2.command("dashboard").description("Start the TrueCourse dashboard and open it in your browser").option("--reconfigure", "Re-prompt for console vs background service mode").option("--service", "Run as a background service (skips mode prompt)").option("--console", "Run in this terminal (skips mode prompt)").action(async (options) => {
211085
211112
  if (options.service && options.console) {
211086
211113
  console.error("error: --service and --console are mutually exclusive");
@@ -211193,14 +211220,14 @@ docsCmd.command("list").description("List the kept (corpus) docs with their area
211193
211220
  docsCmd.command("skipped").description("List docs the relevance filter excluded from extraction").action(async () => {
211194
211221
  await runSpecDocsSkipped();
211195
211222
  });
211196
- docsCmd.command("include <path>").description("Force-include a skipped doc and re-scan").action(async (docPath) => {
211197
- await runSpecDocsInclude(docPath);
211223
+ docsCmd.command("include <path...>").description("Force-include one or more skipped docs and re-scan once").action(async (docPaths) => {
211224
+ await runSpecDocsInclude(docPaths);
211198
211225
  });
211199
211226
  docsCmd.command("uninclude <path>").description("Remove a force-include override").action(async (docPath) => {
211200
211227
  await runSpecDocsUninclude(docPath);
211201
211228
  });
211202
- docsCmd.command("exclude <path>").description("Force-exclude a kept doc from the corpus and re-scan").action(async (docPath) => {
211203
- await runSpecDocsExclude(docPath);
211229
+ docsCmd.command("exclude <path...>").description("Force-exclude one or more kept docs from the corpus and re-scan once").action(async (docPaths) => {
211230
+ await runSpecDocsExclude(docPaths);
211204
211231
  });
211205
211232
  docsCmd.command("unexclude <path>").description("Remove a force-exclude override").action(async (docPath) => {
211206
211233
  await runSpecDocsUnexclude(docPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "truecourse",
3
- "version": "0.7.0-next.0",
3
+ "version": "0.7.0-next.1",
4
4
  "description": "Visualize your codebase architecture as an interactive graph",
5
5
  "type": "module",
6
6
  "bin": {