runbrief 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +3 -3
  2. package/dist/cli.js +650 -126
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -636,6 +636,13 @@ var init_dist = __esm({
636
636
  sources: z.array(z.string()),
637
637
  tokenEstimate: z.number().int().nonnegative(),
638
638
  omitted: z.array(z.string()),
639
+ valueSignals: z.object({
640
+ relevantSourceCount: z.number().int().nonnegative(),
641
+ reusablePrimitiveCount: z.number().int().nonnegative(),
642
+ parserBackedEntityCount: z.number().int().nonnegative(),
643
+ appliedTeamGuidanceCount: z.number().int().nonnegative(),
644
+ suggestedTestCount: z.number().int().nonnegative()
645
+ }).optional(),
639
646
  teamGuidance: teamGuidanceDeliverySchema.optional()
640
647
  });
641
648
  contextReceiptRequestSchema = z.object({
@@ -2732,6 +2739,7 @@ function saveLocalContextReceiptUnlocked(repoRoot, packet, input) {
2732
2739
  mapNodeCount: packet.map.length,
2733
2740
  memoryCount: packet.memories.length,
2734
2741
  suggestedTests: packet.suggestedTests,
2742
+ ...packet.valueSignals ? { valueSignals: packet.valueSignals } : {},
2735
2743
  ...packet.teamGuidance ? { teamGuidance: packet.teamGuidance } : {},
2736
2744
  git
2737
2745
  };
@@ -2830,6 +2838,18 @@ function buildLocalValueReport(repoRoot, repoName = path3.basename(repoRoot)) {
2830
2838
  const receiptCount = receipts.length + handoffs.length;
2831
2839
  const proofLedger = buildProofLedger(receipts, handoffs, proofLoop);
2832
2840
  const impact = impactReportFor(receipts);
2841
+ const valueSignals = receipts.reduce((summary, receipt) => {
2842
+ summary.reusablePrimitiveCount += receipt.valueSignals?.reusablePrimitiveCount ?? 0;
2843
+ summary.parserBackedEntityCount += receipt.valueSignals?.parserBackedEntityCount ?? 0;
2844
+ summary.appliedTeamGuidanceCount += receipt.valueSignals?.appliedTeamGuidanceCount ?? 0;
2845
+ summary.suggestedTestTargetCount += receipt.valueSignals?.suggestedTestCount ?? 0;
2846
+ return summary;
2847
+ }, {
2848
+ reusablePrimitiveCount: 0,
2849
+ parserBackedEntityCount: 0,
2850
+ appliedTeamGuidanceCount: 0,
2851
+ suggestedTestTargetCount: 0
2852
+ });
2833
2853
  const report = {
2834
2854
  repoName,
2835
2855
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -2839,6 +2859,7 @@ function buildLocalValueReport(repoRoot, repoName = path3.basename(repoRoot)) {
2839
2859
  reviewCheckCount: receipts.filter((receipt) => receipt.kind === "review").length,
2840
2860
  handoffCount: handoffs.length,
2841
2861
  estimatedTokensSaved,
2862
+ ...valueSignals,
2842
2863
  averagePacketTokens,
2843
2864
  topSources,
2844
2865
  recentTasks: receipts.slice(0, 8).map((receipt) => ({
@@ -7470,15 +7491,15 @@ function criticalPathBoost(filePath) {
7470
7491
  return 0;
7471
7492
  }
7472
7493
  function compactMetadata(metadata) {
7473
- const compact = {};
7494
+ const compact2 = {};
7474
7495
  for (const [key, value] of Object.entries(metadata)) {
7475
7496
  if (Array.isArray(value) && value.length === 0)
7476
7497
  continue;
7477
7498
  if (value === "" || value === null)
7478
7499
  continue;
7479
- compact[key] = value;
7500
+ compact2[key] = value;
7480
7501
  }
7481
- return Object.keys(compact).length > 0 ? compact : void 0;
7502
+ return Object.keys(compact2).length > 0 ? compact2 : void 0;
7482
7503
  }
7483
7504
  function isCodeFilePath(filePath) {
7484
7505
  return /\.(?:[tj]sx?|py|go|rb|sql|graphql|gql)$/.test(filePath.replaceAll("\\", "/"));
@@ -11948,14 +11969,14 @@ function contextForTask(scan, request) {
11948
11969
  const scoped = files.length > 0;
11949
11970
  const rankedRules = rankRules(scan.rules, task, files);
11950
11971
  const initialRules = rankedRules.slice(0, scoped ? 8 : 12);
11972
+ const initialSkills = selectSkills(scan.skills, task, files, scoped).map(compactSkillForContext);
11951
11973
  const mapCandidates = mapCandidatesForTask(scan, task, files);
11952
11974
  const rankedMap = rankMap(mapCandidates, task, files);
11953
- const initialGroundingRules = rulesStronglyRelevantForGrounding(initialRules, task);
11954
- const selectedMap = takeRuleGroundedMapNodes(mapCandidates, initialGroundingRules, rankedMap, scoped ? 14 : 18).map(compactMapNodeForContext);
11975
+ const selectedMap = takeGuidanceGroundedMapNodes(mapCandidates, scan.sources, rulesStronglyRelevantForGrounding(initialRules, task), initialSkills, rankedMap, files, scoped ? 14 : 18).map(compactMapNodeForContext);
11955
11976
  const suggestedTests = selectValidationForContext(scan.map, scan.sources, task, files, selectedMap, request.repoRoot);
11956
11977
  const initialSelection = {
11957
11978
  rules: initialRules,
11958
- skills: selectSkills(scan.skills, task, files, scoped).map(compactSkillForContext),
11979
+ skills: initialSkills,
11959
11980
  map: selectedMap,
11960
11981
  wikiPages: selectWikiPages(buildContextWiki(scan).pages, task, files, scoped, suggestedTests).map(compactWikiPageForContext),
11961
11982
  memories: rankMemories(scan.memories, task, files).slice(0, scoped ? 4 : 8).map(compactMemoryForContext),
@@ -11968,7 +11989,7 @@ function contextForTask(scan, request) {
11968
11989
  files
11969
11990
  });
11970
11991
  const { rules: selectedRules, skills: selectedSkills, map: budgetedMap, wikiPages: selectedWikiPages, memories: selectedMemories } = selection;
11971
- const finalMap = takeRuleGroundedMapNodes(mapCandidates, rulesStronglyRelevantForGrounding(selectedRules, task), budgetedMap, Math.max(budgetedMap.length, scoped ? 2 : 4)).map(compactMapNodeForContext);
11992
+ const finalMap = takeGuidanceGroundedMapNodes(mapCandidates, scan.sources, rulesStronglyRelevantForGrounding(selectedRules, task), selectedSkills, budgetedMap, files, Math.max(budgetedMap.length, scoped ? 2 : 4)).map(compactMapNodeForContext);
11972
11993
  const finalSuggestedTests = selectValidationForContext(scan.map, scan.sources, task, files, finalMap, request.repoRoot);
11973
11994
  const owners = selectOwners(scan.map, files);
11974
11995
  const sources = unique([
@@ -11978,6 +11999,7 @@ function contextForTask(scan, request) {
11978
11999
  ...selectedWikiPages.flatMap((page2) => page2.sourcePaths),
11979
12000
  ...selectedMemories.flatMap((memory) => memory.sourcePaths)
11980
12001
  ]);
12002
+ const teamGuidance = scan.teamGuidanceCatalog ? teamGuidanceDeliveryFor(scan, selectedRules, selectedSkills, selectedMemories) : void 0;
11981
12003
  const packet = {
11982
12004
  packetId: packetId(),
11983
12005
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -11993,19 +12015,49 @@ function contextForTask(scan, request) {
11993
12015
  sources,
11994
12016
  tokenEstimate,
11995
12017
  omitted,
11996
- ...scan.teamGuidanceCatalog ? {
11997
- teamGuidance: teamGuidanceDeliveryFor(scan, selectedRules, selectedSkills, selectedMemories)
11998
- } : {}
12018
+ valueSignals: contextValueSignals(finalMap, finalSuggestedTests, sources.length, teamGuidance?.applied.length ?? 0),
12019
+ ...teamGuidance ? { teamGuidance } : {}
11999
12020
  };
12000
12021
  return enforceContextPacketBudget(packet, maxTokens, files);
12001
12022
  }
12023
+ function contextValueSignals(map, suggestedTests, relevantSourceCount, appliedTeamGuidanceCount) {
12024
+ const reusablePrimitiveCount = map.filter((node) => {
12025
+ if (!["component", "route", "source", "risk"].includes(node.type)) {
12026
+ return false;
12027
+ }
12028
+ const metadata = node.metadata ?? {};
12029
+ return [
12030
+ "exports",
12031
+ "astFunctions",
12032
+ "astClasses",
12033
+ "astComponents",
12034
+ "hooks",
12035
+ "services",
12036
+ "models",
12037
+ "commands",
12038
+ "domainEntities"
12039
+ ].some((key) => Array.isArray(metadata[key]) && metadata[key].length > 0);
12040
+ }).length;
12041
+ const parserBackedEntityCount = map.reduce((total, node) => {
12042
+ const value = node.metadata?.parserBackedEntityCount;
12043
+ return total + (typeof value === "number" && value > 0 ? value : 0);
12044
+ }, 0);
12045
+ return {
12046
+ relevantSourceCount,
12047
+ reusablePrimitiveCount,
12048
+ parserBackedEntityCount,
12049
+ appliedTeamGuidanceCount,
12050
+ suggestedTestCount: suggestedTests.length
12051
+ };
12052
+ }
12002
12053
  function codebaseMapForTask(scan, request, limit = 80) {
12003
12054
  const files = request.files ?? [];
12004
12055
  const hasSpecificScope = files.length > 0 || wordsFor3(request.task).length > 1;
12005
12056
  const mapCandidates = mapCandidatesForTask(scan, request.task, files);
12006
12057
  const rankedMap = rankMap(mapCandidates, request.task, files);
12007
- const groundedRules = rankRules(scan.rules, request.task, files).filter((rule) => ruleIsStronglyRelevantForGrounding(rule, request.task)).slice(0, 3);
12008
- const ruleGroundedMap = takeRuleGroundedMapNodes(mapCandidates, groundedRules, [], Math.min(8, limit));
12058
+ const selectedRules = rankRules(scan.rules, request.task, files).filter((rule) => ruleIsStronglyRelevantForGrounding(rule, request.task)).slice(0, files.length > 0 ? 8 : 12);
12059
+ const selectedSkills = selectSkills(scan.skills, request.task, files, files.length > 0);
12060
+ const ruleGroundedMap = takeGuidanceGroundedMapNodes(mapCandidates, scan.sources, selectedRules, selectedSkills, [], files, Math.min(8, limit));
12009
12061
  const selected = hasSpecificScope ? diversifyMap(uniqueMapNodes([...ruleGroundedMap, ...rankedMap]), limit) : broadCodebaseOverview(scan.map, limit);
12010
12062
  return withMapCoverageNotice(selected, scan, request, limit);
12011
12063
  }
@@ -12100,58 +12152,100 @@ function sourceFallbackMapNode(sourcePath) {
12100
12152
  }
12101
12153
  };
12102
12154
  }
12103
- function takeRuleGroundedMapNodes(scanMap, rules, rankedMap, limit) {
12104
- const groundedPaths = unique(rules.flatMap(explicitRuleGroundedPaths));
12105
- const groundedNodes = groundedPaths.flatMap((sourcePath) => {
12106
- const mappedNode = scanMap.find((node) => mapNodeSourcePath(node) === sourcePath);
12107
- return [
12108
- mappedNode ? markRuleGroundedMapNode(mappedNode) : ruleSourceFallbackMapNode(sourcePath)
12109
- ];
12155
+ function takeGuidanceGroundedMapNodes(scanMap, sources, rules, skills, rankedMap, files, limit) {
12156
+ const groundedPaths = guidanceReferencedSourcePaths(sources, rules, skills);
12157
+ const nodeBySourcePath = /* @__PURE__ */ new Map();
12158
+ for (const node of scanMap) {
12159
+ const sourcePath = mapNodeSourcePath(node);
12160
+ if (!nodeBySourcePath.has(sourcePath))
12161
+ nodeBySourcePath.set(sourcePath, node);
12162
+ }
12163
+ const explicitNodes = rankedMap.filter((node) => files.includes(mapNodeSourcePath(node)));
12164
+ const groundedNodes = groundedPaths.map((sourcePath) => {
12165
+ const mappedNode = nodeBySourcePath.get(sourcePath);
12166
+ return mappedNode ? markGuidanceGroundedMapNode(mappedNode) : guidanceSourceFallbackMapNode(sourcePath);
12110
12167
  });
12111
- const groundedLimit = Math.min(limit, 8, Math.max(3, Math.ceil(limit / 2)));
12112
12168
  return uniqueMapNodes([
12113
- ...groundedNodes.slice(0, groundedLimit),
12169
+ ...explicitNodes,
12170
+ ...groundedNodes,
12114
12171
  ...rankedMap
12115
12172
  ]).slice(0, limit);
12116
12173
  }
12117
- function explicitRuleGroundedPaths(rule) {
12118
- const codePaths = rule.sourcePaths.filter((sourcePath) => isCodeOrTestPath(sourcePath));
12119
- const normalizedBody = rule.body.toLowerCase().replaceAll("\\", "/");
12120
- const explicitPaths = codePaths.filter((sourcePath) => {
12121
- const normalizedPath = sourcePath.toLowerCase().replaceAll("\\", "/");
12122
- const basename = pathBasename(sourcePath);
12123
- const stem = basename.replace(/\.[^.]+$/, "");
12124
- return normalizedBody.includes(normalizedPath) || normalizedBody.includes(pathBasename(normalizedPath)) || /[A-Z_$]/.test(stem) && normalizedBody.includes(stem.toLowerCase());
12125
- });
12126
- return explicitPaths;
12174
+ function guidanceReferencedSourcePaths(sources, rules, skills) {
12175
+ const sourcePaths = new Map(sources.filter((source) => isCodeOrTestPath(source.path)).map((source) => [source.path.toLowerCase(), source.path]));
12176
+ const pathsByStem = /* @__PURE__ */ new Map();
12177
+ for (const sourcePath of sourcePaths.values()) {
12178
+ const rawStem = pathBasename(sourcePath).replace(/\.[^.]+$/, "");
12179
+ if (rawStem.length < 6 || !/[A-Z_$]/.test(rawStem))
12180
+ continue;
12181
+ const stem = rawStem.toLowerCase();
12182
+ pathsByStem.set(stem, [...pathsByStem.get(stem) ?? [], sourcePath]);
12183
+ }
12184
+ const guidanceText = [
12185
+ ...rules.map((rule) => `${rule.title}
12186
+ ${rule.body}`),
12187
+ ...skills.map((skill) => [
12188
+ skill.name,
12189
+ skill.description,
12190
+ skill.body,
12191
+ skill.triggers.join(" "),
12192
+ skill.teamShare?.rationale ?? "",
12193
+ skill.teamShare?.guardrails.join(" ") ?? ""
12194
+ ].join("\n"))
12195
+ ].join("\n");
12196
+ const selected = [];
12197
+ for (const rule of rules) {
12198
+ const body = rule.body.toLowerCase().replaceAll("\\", "/");
12199
+ for (const sourcePath of rule.sourcePaths) {
12200
+ if (!isCodeOrTestPath(sourcePath))
12201
+ continue;
12202
+ const normalizedPath = sourcePath.toLowerCase().replaceAll("\\", "/");
12203
+ const rawStem = pathBasename(sourcePath).replace(/\.[^.]+$/, "");
12204
+ if (body.includes(normalizedPath) || body.includes(pathBasename(normalizedPath)) || rawStem.length >= 6 && /[A-Z_$]/.test(rawStem) && body.includes(rawStem.toLowerCase())) {
12205
+ selected.push(sourcePath);
12206
+ }
12207
+ }
12208
+ }
12209
+ for (const match of guidanceText.matchAll(/[A-Za-z0-9_.@/-]+\.(?:[cm]?[tj]sx?|py|go|rb|sql|graphql|gql)\b/g)) {
12210
+ const referencedPath = match[0]?.replace(/^\.\//, "").toLowerCase();
12211
+ const canonicalPath = referencedPath ? sourcePaths.get(referencedPath) : void 0;
12212
+ if (canonicalPath)
12213
+ selected.push(canonicalPath);
12214
+ }
12215
+ for (const match of guidanceText.matchAll(/\b[A-Za-z_$][A-Za-z0-9_$-]{5,}\b/g)) {
12216
+ const matches = pathsByStem.get(match[0]?.toLowerCase() ?? "") ?? [];
12217
+ if (matches.length === 1)
12218
+ selected.push(matches[0]);
12219
+ }
12220
+ return unique(selected);
12127
12221
  }
12128
12222
  function pathBasename(sourcePath) {
12129
12223
  return sourcePath.split("/").at(-1) ?? sourcePath;
12130
12224
  }
12131
- function markRuleGroundedMapNode(node) {
12225
+ function markGuidanceGroundedMapNode(node) {
12132
12226
  return {
12133
12227
  ...node,
12134
12228
  metadata: {
12135
12229
  ...node.metadata ?? {},
12136
12230
  evidenceKinds: unique([
12137
12231
  ...metadataStringsForScore(node.metadata, "evidenceKinds"),
12138
- "rule_reference"
12232
+ "guidance_reference"
12139
12233
  ])
12140
12234
  }
12141
12235
  };
12142
12236
  }
12143
- function ruleSourceFallbackMapNode(sourcePath) {
12237
+ function guidanceSourceFallbackMapNode(sourcePath) {
12144
12238
  return {
12145
- id: idFor("map", `rule-source:${sourcePath}`),
12239
+ id: idFor("map", `guidance-source:${sourcePath}`),
12146
12240
  type: isLikelyTestPath(sourcePath) ? "test" : "source",
12147
12241
  name: titleFromPath(sourcePath),
12148
12242
  path: sourcePath,
12149
- summary: "Source file cited by a selected repo rule; included even when the broad map cap omits it.",
12150
- tags: unique(["source", ...fallbackTagsForPath(sourcePath)]),
12243
+ summary: "Source file cited by selected repo or team guidance; included even when the broad map cap omits it.",
12244
+ tags: unique(["source", "guidance", ...fallbackTagsForPath(sourcePath)]),
12151
12245
  metadata: {
12152
12246
  sourcePath,
12153
- evidenceKinds: ["rule_reference"],
12154
- entityConfidence: 72
12247
+ evidenceKinds: ["guidance_reference"],
12248
+ entityConfidence: 82
12155
12249
  }
12156
12250
  };
12157
12251
  }
@@ -12190,6 +12284,9 @@ function uniqueMapNodes(nodes) {
12190
12284
  function mapNodeSourcePath(node) {
12191
12285
  return typeof node.metadata?.sourcePath === "string" ? node.metadata.sourcePath : node.path;
12192
12286
  }
12287
+ function mapNodeHasGuidanceEvidence(node) {
12288
+ return metadataStringsForScore(node.metadata, "evidenceKinds").some((kind) => ["guidance_reference", "rule_reference"].includes(kind));
12289
+ }
12193
12290
  function isCodeOrTestPath(sourcePath) {
12194
12291
  return /\.(?:[cm]?[tj]sx?|py|go|rb|sql|graphql|gql)$/.test(sourcePath);
12195
12292
  }
@@ -12793,17 +12890,17 @@ function ruleIsStronglyRelevantForGrounding(rule, task) {
12793
12890
  function fitSelectionToBudget(initialSelection, options2) {
12794
12891
  const selection = cloneSelection(initialSelection);
12795
12892
  const omitted = [];
12796
- const protectedMapPaths = new Set(selection.map.filter((node) => mapNodeRelatesToExplicitFile(node, options2.files)).map(mapNodeSourcePath));
12893
+ const protectedMapPaths = new Set(selection.map.filter((node) => mapNodeRelatesToExplicitFile(node, options2.files) || mapNodeHasGuidanceEvidence(node)).map(mapNodeSourcePath));
12797
12894
  const minimums = {
12798
12895
  rules: options2.scoped ? Math.min(selection.rules.length, 3) : 5,
12799
- skills: 0,
12896
+ skills: selection.skills.some(isApprovedSharedSkill) ? 1 : 0,
12800
12897
  map: options2.scoped ? Math.min(selection.map.length, 8) : 10,
12801
12898
  wikiPages: options2.scoped ? Math.min(selection.wikiPages.length, 1) : 2,
12802
12899
  memories: 0
12803
12900
  };
12804
12901
  const hardMinimums = {
12805
12902
  rules: Math.min(selection.rules.length, options2.scoped ? 1 : 2),
12806
- skills: 0,
12903
+ skills: selection.skills.some(isApprovedSharedSkill) ? 1 : 0,
12807
12904
  map: Math.max(Math.min(selection.map.length, options2.scoped ? 2 : 4), protectedMapPaths.size),
12808
12905
  wikiPages: 0,
12809
12906
  memories: 0
@@ -12867,7 +12964,7 @@ function enforceContextPacketBudget(packet, maxTokens, explicitFiles) {
12867
12964
  let trimmed = packet.omitted.length > 0;
12868
12965
  if (trimmed)
12869
12966
  packet.omitted = [omittedReason];
12870
- const protectedMapPaths = new Set(packet.map.filter((node) => mapNodeRelatesToExplicitFile(node, explicitFiles)).map(mapNodeSourcePath));
12967
+ const protectedMapPaths = new Set(packet.map.filter((node) => mapNodeRelatesToExplicitFile(node, explicitFiles) || mapNodeHasGuidanceEvidence(node)).map(mapNodeSourcePath));
12871
12968
  let tokenEstimate = estimateContextPacketTokens(packet);
12872
12969
  const maxTrimSteps = removableContextItemCount(packet) + 1;
12873
12970
  let trimSteps = 0;
@@ -12987,32 +13084,49 @@ function compactProtectedMapNodes(map, protectedMapPaths) {
12987
13084
  function compactProtectedMapMetadata(metadata) {
12988
13085
  if (!metadata)
12989
13086
  return void 0;
12990
- const compact = {};
13087
+ const compact2 = {};
12991
13088
  for (const key of [
12992
13089
  "sourcePath",
12993
13090
  "symbolKind",
12994
13091
  "symbolName",
12995
13092
  "role",
12996
- "entityConfidence"
13093
+ "entityConfidence",
13094
+ "parserBackedEntityCount"
12997
13095
  ]) {
12998
13096
  const value = metadata[key];
12999
13097
  if (value !== void 0)
13000
- compact[key] = value;
13098
+ compact2[key] = value;
13001
13099
  }
13002
13100
  for (const key of [
13101
+ "evidenceKinds",
13003
13102
  "exports",
13004
13103
  "imports",
13005
13104
  "importedBy",
13006
13105
  "relatedTests",
13007
13106
  "owners",
13008
13107
  "validationCommands",
13009
- "changeRisk"
13108
+ "changeRisk",
13109
+ "astClasses",
13110
+ "astCommands",
13111
+ "astComponents",
13112
+ "astFunctions",
13113
+ "astHooks",
13114
+ "astJobs",
13115
+ "astModels",
13116
+ "astServices",
13117
+ "commands",
13118
+ "domainEntities",
13119
+ "hooks",
13120
+ "jobs",
13121
+ "models",
13122
+ "procedures",
13123
+ "services"
13010
13124
  ]) {
13011
13125
  const value = metadata[key];
13012
13126
  if (Array.isArray(value))
13013
- compact[key] = value.slice(0, 2);
13127
+ compact2[key] = value.slice(0, 2);
13014
13128
  }
13015
- return compact;
13129
+ return compact2;
13016
13130
  }
13017
13131
  function refreshContextPacketDerivedFields(packet) {
13018
13132
  packet.summary = summarizeContext(packet.task, packet.rules, packet.suggestedTests, packet.map);
@@ -13025,6 +13139,7 @@ function refreshContextPacketDerivedFields(packet) {
13025
13139
  suggestedTests: packet.suggestedTests
13026
13140
  });
13027
13141
  refreshTeamGuidanceDelivery(packet);
13142
+ packet.valueSignals = contextValueSignals(packet.map, packet.suggestedTests, packet.sources.length, packet.teamGuidance?.applied.length ?? 0);
13028
13143
  }
13029
13144
  function teamGuidanceDeliveryFor(scan, rules, skills, memories) {
13030
13145
  const catalog = scan.teamGuidanceCatalog;
@@ -13127,6 +13242,9 @@ function lastDroppableRuleIndex(rules) {
13127
13242
  }
13128
13243
  return -1;
13129
13244
  }
13245
+ function isApprovedSharedSkill(skill) {
13246
+ return skill.status === "approved";
13247
+ }
13130
13248
  function compactSkillForContext(skill) {
13131
13249
  return {
13132
13250
  ...skill,
@@ -13184,17 +13302,17 @@ function compactWikiPageForContext(page2) {
13184
13302
  function compactMetadata2(metadata) {
13185
13303
  if (!metadata)
13186
13304
  return void 0;
13187
- const compact = {};
13305
+ const compact2 = {};
13188
13306
  for (const [key, value] of Object.entries(metadata)) {
13189
13307
  if (!contextMetadataKeys.has(key))
13190
13308
  continue;
13191
13309
  if (Array.isArray(value)) {
13192
- compact[key] = value.slice(0, metadataArrayLimit(key));
13310
+ compact2[key] = value.slice(0, metadataArrayLimit(key));
13193
13311
  } else {
13194
- compact[key] = value;
13312
+ compact2[key] = value;
13195
13313
  }
13196
13314
  }
13197
- return compact;
13315
+ return compact2;
13198
13316
  }
13199
13317
  function metadataArrayLimit(key) {
13200
13318
  if (["imports", "importedBy"].includes(key))
@@ -13248,11 +13366,27 @@ var init_context = __esm({
13248
13366
  ]);
13249
13367
  contextMetadataKeys = /* @__PURE__ */ new Set([
13250
13368
  "accessControls",
13369
+ "agentTools",
13370
+ "astClasses",
13371
+ "astCommands",
13372
+ "astComponents",
13373
+ "astFunctions",
13374
+ "astHooks",
13375
+ "astJobs",
13376
+ "astModels",
13377
+ "astServices",
13251
13378
  "changeRisk",
13379
+ "commands",
13380
+ "domainEntities",
13252
13381
  "entityConfidence",
13253
13382
  "envVars",
13254
13383
  "evidenceKinds",
13255
13384
  "exports",
13385
+ "hooks",
13386
+ "jobs",
13387
+ "models",
13388
+ "parserBackedEntityCount",
13389
+ "procedures",
13256
13390
  "importedBy",
13257
13391
  "imports",
13258
13392
  "loopHints",
@@ -13260,6 +13394,7 @@ var init_context = __esm({
13260
13394
  "relatedTests",
13261
13395
  "role",
13262
13396
  "routes",
13397
+ "services",
13263
13398
  "sourcePath",
13264
13399
  "symbolKind",
13265
13400
  "symbolName",
@@ -26085,7 +26220,7 @@ var init_agentSetup = __esm({
26085
26220
  "ide",
26086
26221
  "generic"
26087
26222
  ];
26088
- briefPublishedPackageSpec = "runbrief@0.1.0";
26223
+ briefPublishedPackageSpec = "runbrief@0.1.2";
26089
26224
  TARGET_LABELS = {
26090
26225
  terminal: "Terminal agent",
26091
26226
  vscode: "VS Code",
@@ -27136,6 +27271,41 @@ var init_agentStart = __esm({
27136
27271
  });
27137
27272
 
27138
27273
  // ../core/dist/agentBeforeYouCode.js
27274
+ function summarizeBeforeYouCodeSharedContext(delivery) {
27275
+ if (!delivery) {
27276
+ return {
27277
+ status: "not_available",
27278
+ applied: [],
27279
+ availableCount: 0,
27280
+ omittedCount: 0,
27281
+ next: "Shared guidance is not available in this session; keep new learning personal until the workspace connection is ready."
27282
+ };
27283
+ }
27284
+ const next = delivery.status === "applied" ? "Use the applied shared guidance, then save a focused learning or reference when the pass proves a reusable pattern." : delivery.status === "available_not_applied" ? "Shared guidance exists but did not match this task; inspect the relevant team item before creating a new pattern." : "No approved shared guidance exists yet; keep this pass personal and publish only after the pattern is proven.";
27285
+ return {
27286
+ status: delivery.status,
27287
+ workspaceId: delivery.workspaceId,
27288
+ revision: delivery.revision,
27289
+ availableCount: delivery.availableCount,
27290
+ applied: delivery.applied.slice(0, 4),
27291
+ omittedCount: delivery.omittedCount,
27292
+ next
27293
+ };
27294
+ }
27295
+ function summarizeBeforeYouCodeReferences(beforeYouCode) {
27296
+ return {
27297
+ status: beforeYouCode.referenceFirst.status,
27298
+ availableCount: beforeYouCode.referenceFirst.availableCount,
27299
+ decision: beforeYouCode.referenceFirst.decision,
27300
+ references: beforeYouCode.referenceFirst.references.slice(0, 2).map((reference) => ({
27301
+ title: reference.title,
27302
+ kind: reference.kind,
27303
+ sourcePaths: reference.sourcePaths.slice(0, 4),
27304
+ useWhen: reference.useWhen.slice(0, 2),
27305
+ doNotCopy: reference.doNotCopy.slice(0, 2)
27306
+ }))
27307
+ };
27308
+ }
27139
27309
  function missionScopeFilesFromBeforeYouCode(beforeYouCode, requestedFiles = []) {
27140
27310
  const explicitFiles = unique(requestedFiles);
27141
27311
  if (explicitFiles.length > 0)
@@ -27170,6 +27340,7 @@ function buildBeforeYouCodeMap(scan, input) {
27170
27340
  files,
27171
27341
  maxTokens: 2500
27172
27342
  });
27343
+ const referenceFirst = referenceFirstFor(loadLocalReferenceImplementations(input.repoRoot), input.task);
27173
27344
  const taskAwareSources = scan.sources.map((source, index) => ({
27174
27345
  source,
27175
27346
  index,
@@ -27192,7 +27363,7 @@ function buildBeforeYouCodeMap(scan, input) {
27192
27363
  ...context.map.map((node) => ({
27193
27364
  ...node,
27194
27365
  evidenceKinds: Array.isArray(node.metadata?.evidenceKinds) ? node.metadata.evidenceKinds.filter((kind) => typeof kind === "string") : [],
27195
- priority: Array.isArray(node.metadata?.evidenceKinds) && node.metadata.evidenceKinds.includes("rule_reference") ? 3 : 0
27366
+ priority: Array.isArray(node.metadata?.evidenceKinds) && node.metadata.evidenceKinds.some((kind) => ["rule_reference", "guidance_reference"].includes(kind)) ? 3 : 0
27196
27367
  })),
27197
27368
  ...taskAwareSources.map((node) => ({ ...node, priority: 0 })),
27198
27369
  ...taskAwareMap.map((node) => ({ ...node, priority: 0 })),
@@ -27203,26 +27374,26 @@ function buildBeforeYouCodeMap(scan, input) {
27203
27374
  priority: 0
27204
27375
  }))
27205
27376
  ], input.task);
27206
- const mappedReuseCandidates = insights.agentPacket.reuseGuard.candidates.map((candidate, index) => ({
27377
+ const mappedReuseCandidateScores = insights.agentPacket.reuseGuard.candidates.map((candidate, index) => ({
27207
27378
  candidate,
27208
27379
  index,
27209
- intentScore: beforeYouCodePathIntentScore(candidate.path, input.task)
27210
- })).filter(({ intentScore }) => intentScore > -100).sort((a, b) => b.intentScore - a.intentScore || a.index - b.index).map(({ candidate }) => reuseCandidateFor(candidate));
27211
- const inspectReuseCandidates = inspectFirst.filter((item) => (beforeYouCodePathIntentScore(item.path, input.task) >= 40 || item.evidenceKinds.includes("rule_reference")) && !/\.(test|spec)\.[cm]?[tj]sx?$/i.test(item.path)).map((item) => ({
27380
+ intentScore: beforeYouCodeReuseScore(candidate, input.task)
27381
+ })).filter(({ candidate, intentScore }) => intentScore > 0 || intentScore >= 0 && candidate.evidenceKinds.some((kind) => ["ast", "parser"].includes(kind)) && candidate.symbols.length > 0).sort((a, b) => b.intentScore - a.intentScore || a.index - b.index).map(({ candidate }) => reuseCandidateFor(candidate));
27382
+ const inspectReuseCandidates = inspectFirst.filter((item) => (beforeYouCodePathIntentScore(item.path, input.task) >= 40 || item.evidenceKinds.some((kind) => ["rule_reference", "guidance_reference"].includes(kind))) && !/\.(test|spec)\.[cm]?[tj]sx?$/i.test(item.path)).map((item) => ({
27212
27383
  path: item.path,
27213
27384
  action: "Extend this existing implementation or rule it out.",
27214
27385
  why: item.why,
27215
27386
  evidenceKinds: item.evidenceKinds
27216
27387
  }));
27217
27388
  const reuseCandidates = uniqueReuseCandidates([
27218
- ...mappedReuseCandidates,
27389
+ ...mappedReuseCandidateScores,
27219
27390
  ...inspectReuseCandidates
27220
27391
  ]).sort((a, b) => {
27221
27392
  const inspectRank = (candidate) => {
27222
27393
  const index = inspectFirst.findIndex((item) => item.path === candidate.path);
27223
27394
  return index < 0 ? 0 : Math.max(0, 6 - index) * 60;
27224
27395
  };
27225
- return beforeYouCodePathIntentScore(b.path, input.task) + inspectRank(b) - (beforeYouCodePathIntentScore(a.path, input.task) + inspectRank(a));
27396
+ return beforeYouCodeReuseScore(b, input.task) + inspectRank(b) - (beforeYouCodeReuseScore(a, input.task) + inspectRank(a));
27226
27397
  }).slice(0, 5);
27227
27398
  const taskDerivedTestFiles = inspectFirstTestTargets(inspectFirst, prefersPrimaryWorkspaceTask(input.task));
27228
27399
  const testScopeFiles = files.length > 0 ? files : taskDerivedTestFiles.length > 0 ? taskDerivedTestFiles : target.changedFiles;
@@ -27245,7 +27416,7 @@ function buildBeforeYouCodeMap(scan, input) {
27245
27416
  const validationChecklist = validationChecklistFor({
27246
27417
  task: input.task,
27247
27418
  likelyTests,
27248
- reuseStatus: insights.agentPacket.reuseGuard.status
27419
+ reuseStatus: reuseStatusFor(reuseCandidates)
27249
27420
  });
27250
27421
  const productOperatingContext = buildProductOperatingContext(scan, {
27251
27422
  task: input.task,
@@ -27261,6 +27432,7 @@ function buildBeforeYouCodeMap(scan, input) {
27261
27432
  ...target.dirty && files.length === 0 ? ["Dirty worktree is broad; classify baseline before editing."] : []
27262
27433
  ]).slice(0, 5);
27263
27434
  const status = inspectFirst.length === 0 && reuseCandidates.length === 0 ? "needs_narrower_scope" : "ready";
27435
+ const reuseSummary = reuseCandidates.length > 0 ? `${reuseCandidates.length} focused reuse candidate${reuseCandidates.length === 1 ? "" : "s"} matched this task; extend or explicitly rule them out before creating new code.` : "No task-relevant reuse candidate is grounded yet; narrow the task or search once more before creating new code.";
27264
27436
  const headline = status === "ready" ? `${scan.repoName}: inspect ${inspectFirst.length} file${inspectFirst.length === 1 ? "" : "s"} and rule out ${reuseCandidates.length} reuse candidate${reuseCandidates.length === 1 ? "" : "s"} before coding.` : `${scan.repoName}: no focused code map yet; narrow by folder, feature, or proposed files before coding.`;
27265
27437
  const taskSize = taskSizeFor({
27266
27438
  task: input.task,
@@ -27276,6 +27448,8 @@ function buildBeforeYouCodeMap(scan, input) {
27276
27448
  reuseCandidates,
27277
27449
  likelyTests,
27278
27450
  productOperatingContext,
27451
+ ...context.teamGuidance ? { teamGuidance: context.teamGuidance } : {},
27452
+ referenceFirst,
27279
27453
  validationChecklist,
27280
27454
  stopSignals: stopSignals2
27281
27455
  });
@@ -27288,6 +27462,8 @@ function buildBeforeYouCodeMap(scan, input) {
27288
27462
  productOperatingContext,
27289
27463
  validationChecklist,
27290
27464
  stopSignals: stopSignals2,
27465
+ ...context.teamGuidance ? { teamGuidance: context.teamGuidance } : {},
27466
+ referenceFirst,
27291
27467
  maxLines: input.maxLines ?? 30
27292
27468
  });
27293
27469
  return {
@@ -27298,10 +27474,13 @@ function buildBeforeYouCodeMap(scan, input) {
27298
27474
  cockpit,
27299
27475
  inspectFirst,
27300
27476
  reuseFirst: {
27301
- status: insights.agentPacket.reuseGuard.status === "missing" && reuseCandidates.length > 0 ? "partial" : insights.agentPacket.reuseGuard.status,
27302
- summary: insights.agentPacket.reuseGuard.summary,
27303
- candidates: reuseCandidates
27477
+ status: reuseStatusFor(reuseCandidates),
27478
+ summary: reuseSummary,
27479
+ candidates: reuseCandidates,
27480
+ decision: reuseCandidates.length > 0 ? "For each candidate, choose reuse, adapt, or rule out and record the decision before creating a new primitive." : "No reuse candidate is grounded yet; run one focused search before creating a new primitive."
27304
27481
  },
27482
+ ...context.teamGuidance ? { teamGuidance: context.teamGuidance } : {},
27483
+ referenceFirst,
27305
27484
  likelyTests,
27306
27485
  exactTests,
27307
27486
  productOperatingContext,
@@ -27312,6 +27491,71 @@ function buildBeforeYouCodeMap(scan, input) {
27312
27491
  next: status === "ready" ? "Inspect these files and reuse candidates before editing; cite the reuse decision in the final handoff." : "Run brief.codebase_map or brief.context_for_task with a narrower task, folder, or file list before editing."
27313
27492
  };
27314
27493
  }
27494
+ function reuseStatusFor(candidates) {
27495
+ if (candidates.length === 0)
27496
+ return "missing";
27497
+ return candidates.length >= 3 || candidates.some((candidate) => candidate.evidenceKinds.includes("ast")) ? "strong" : "partial";
27498
+ }
27499
+ function beforeYouCodeReuseScore(candidate, task) {
27500
+ const candidateText2 = "symbols" in candidate ? [
27501
+ candidate.path,
27502
+ candidate.name,
27503
+ ...candidate.symbols,
27504
+ ...candidate.relatedEntities
27505
+ ].join(" ") : [candidate.path, candidate.action, candidate.why].join(" ");
27506
+ const taskTerms = new Set(reuseTerms(task));
27507
+ const candidateTerms = new Set(reuseTerms(candidateText2));
27508
+ const symbolMatches = [...taskTerms].filter((term) => candidateTerms.has(term)).length;
27509
+ return beforeYouCodePathIntentScore(candidate.path, task) + Math.min(48, symbolMatches * 12);
27510
+ }
27511
+ function reuseTerms(input) {
27512
+ return referenceQueryTerms(input.replace(/([a-z0-9])([A-Z])/g, "$1 $2"));
27513
+ }
27514
+ function referenceFirstFor(references, task) {
27515
+ const active = references.filter((reference) => reference.status !== "archived");
27516
+ const terms = referenceQueryTerms(task);
27517
+ const scored = active.map((reference, index) => ({
27518
+ reference,
27519
+ index,
27520
+ score: terms.reduce((score, term) => {
27521
+ const haystack = [
27522
+ reference.title,
27523
+ reference.summary,
27524
+ reference.kind,
27525
+ ...reference.tags,
27526
+ ...reference.appliesTo,
27527
+ ...reference.useWhen,
27528
+ ...reference.sourcePaths
27529
+ ].join(" ").toLowerCase();
27530
+ return score + (haystack.includes(term) ? 1 : 0);
27531
+ }, 0)
27532
+ })).sort((a, b) => b.score - a.score || b.reference.updatedAt.localeCompare(a.reference.updatedAt) || a.index - b.index);
27533
+ const matched = scored.filter((item) => item.score > 0).map((item) => item.reference);
27534
+ const selected = (matched.length > 0 ? matched : []).slice(0, 4);
27535
+ const status = selected.length > 0 ? "matched" : active.length > 0 ? "available_unmatched" : "none";
27536
+ return {
27537
+ status,
27538
+ availableCount: active.length,
27539
+ references: selected,
27540
+ decision: status === "matched" ? "Inspect the cited source paths and reuse or adapt the reference; honor its do-not-copy guardrails." : status === "available_unmatched" ? "Saved references exist, but none match this task; search the reference library before creating a new pattern." : "No saved reference matches this task; prove the new pattern before saving it for reuse."
27541
+ };
27542
+ }
27543
+ function referenceQueryTerms(input) {
27544
+ const ignored = /* @__PURE__ */ new Set([
27545
+ "after",
27546
+ "before",
27547
+ "create",
27548
+ "existing",
27549
+ "make",
27550
+ "new",
27551
+ "reuse",
27552
+ "task",
27553
+ "the",
27554
+ "this",
27555
+ "with"
27556
+ ]);
27557
+ return unique(input.toLowerCase().split(/[^a-z0-9]+/).filter((term) => term.length >= 4 && !ignored.has(term)));
27558
+ }
27315
27559
  function testRecommendationMatchesWorkspace(recommendation, targetFiles) {
27316
27560
  const scopes = unique(targetFiles.map(workspaceScopeForFile).filter(Boolean));
27317
27561
  if (scopes.length === 0)
@@ -27344,7 +27588,13 @@ function cockpitFor(input) {
27344
27588
  ...input.inspectFirst[0] ? [`Inspect ${input.inspectFirst[0].path}.`] : ["Narrow the task until Brief can name an inspect-first file."],
27345
27589
  ...input.reuseCandidates[0] ? [`Reuse or rule out ${input.reuseCandidates[0].path}.`] : ["Search once more before creating a new primitive."]
27346
27590
  ]).slice(0, 4);
27347
- const productMemory = input.productOperatingContext.status === "not_applicable" ? [] : input.productOperatingContext.productMemoryCandidates.slice(0, 3);
27591
+ const sharedMemory = input.teamGuidance?.applied.slice(0, 2).map((item) => `Shared ${item.kind}: ${item.label}`) ?? [];
27592
+ const productMemory = unique([
27593
+ ...sharedMemory,
27594
+ ...input.referenceFirst.status === "matched" ? input.referenceFirst.references.slice(0, 1).map((reference) => `Saved reference: ${reference.title}`) : input.referenceFirst.status === "available_unmatched" ? ["Saved references exist, but none match this task yet."] : [],
27595
+ ...input.teamGuidance?.status === "available_not_applied" ? ["Shared guidance is available, but none matched this task yet."] : [],
27596
+ ...input.productOperatingContext.status === "not_applicable" ? [] : input.productOperatingContext.productMemoryCandidates
27597
+ ]).slice(0, 3);
27348
27598
  const reuseDecision = input.reuseCandidates.slice(0, 3).map((candidate) => `${candidate.path} - ${candidate.action}`);
27349
27599
  const validation = unique([
27350
27600
  ...input.likelyTests.slice(0, mode === "mission" ? 3 : 2),
@@ -27484,7 +27734,7 @@ function inspectFilesFor(nodes, contextMap, task) {
27484
27734
  })).filter(({ intentScore }) => intentScore > -100);
27485
27735
  const seen = /* @__PURE__ */ new Set();
27486
27736
  const candidates = [...fromNodes, ...fromContext];
27487
- const focusedCandidates = candidates.filter((item) => item.intentScore > 0);
27737
+ const focusedCandidates = candidates.filter((item) => item.intentScore > 0 || item.evidenceKinds.some((kind) => ["rule_reference", "guidance_reference"].includes(kind)));
27488
27738
  const ranked = (focusedCandidates.length >= 3 ? focusedCandidates : candidates).sort((a, b) => b.intentScore - a.intentScore || b.originPriority - a.originPriority || a.index - b.index).filter((item) => {
27489
27739
  const sourcePath = item.path.split("#", 1)[0] ?? item.path;
27490
27740
  if (seen.has(sourcePath))
@@ -27609,7 +27859,7 @@ function beforeYouCodePathIntentScore(path20, task) {
27609
27859
  const wantsBilling = /\b(bill(?:ing)?|checkout|paid|payment|price|pricing|stripe|subscription)\b/.test(lowerTask);
27610
27860
  const wantsWorkspaceBootstrap = /\b(onboarding|workspace creation|workspace bootstrap)\b/.test(lowerTask);
27611
27861
  const wantsConnector = /\b(agent action|connector|first useful|mcp|setup)\b/.test(lowerTask);
27612
- const wantsTeam = /\b(invite|member|team)\b/.test(lowerTask);
27862
+ const wantsTeam = /\b(invite|member|team (?:member|access|setup|management)|workspace team)\b/.test(lowerTask);
27613
27863
  const wantsAutoEngagement = /\b(auto[- ]?engage|automatically|by default|default engagement|reminder)\b/.test(lowerTask);
27614
27864
  const wantsRecommendations = /\b(context|recommendations?|reuse|tests?|test guidance|test recommendations?)\b/.test(lowerTask);
27615
27865
  if (wantsInterface && wantsLanding && /(landinginteractive|landing-page|src\/app\/page\.[cm]?[tj]sx?$)/.test(lowerPath)) {
@@ -27868,10 +28118,20 @@ function compactTextFor2(input) {
27868
28118
  `Target: ${input.target.repoName} | ${input.target.branch ?? "branch unknown"} | ${input.target.repoRoot}`,
27869
28119
  `Worktree: ${input.target.dirty ? "dirty" : "clean"}${input.target.changedFiles.length ? `; changed ${input.target.changedFiles.slice(0, 4).join(", ")}` : ""}${input.target.untrackedFiles.length ? `; untracked ${input.target.untrackedFiles.slice(0, 3).join(", ")}` : ""}`,
27870
28120
  ...input.target.requestedFiles.length ? [`Scope files: ${input.target.requestedFiles.slice(0, 5).join(", ")}`] : [],
28121
+ ...input.teamGuidance ? [
28122
+ `Shared guidance: ${input.teamGuidance.applied.length > 0 ? input.teamGuidance.applied.slice(0, 2).map((item) => item.label).join(", ") : input.teamGuidance.status === "available_not_applied" ? "available, but none matched this task" : "none approved yet"}`
28123
+ ] : [],
28124
+ ...input.referenceFirst.status === "matched" ? [
28125
+ `Saved reference: ${input.referenceFirst.references.slice(0, 2).map((reference) => reference.title).join(", ")}`
28126
+ ] : input.referenceFirst.status === "available_unmatched" ? [
28127
+ "Saved references exist, but none match this task; search before creating."
28128
+ ] : [],
27871
28129
  "Inspect first:",
27872
28130
  ...itemLines2(input.inspectFirst, (item) => `${item.path} - ${item.why}`, "No focused files yet; narrow the request.", 5),
27873
28131
  "Reuse before create:",
27874
28132
  ...itemLines2(input.reuseCandidates, (item) => `${item.path} - ${item.action}`, "No reuse candidates yet; run a narrower codebase_map query.", 4),
28133
+ "Reuse decision: reuse, adapt, or rule out each candidate before creating a new primitive.",
28134
+ `Reference decision: ${input.referenceFirst.decision}`,
27875
28135
  ...input.productOperatingContext.status === "not_applicable" ? [] : [
27876
28136
  "Product guardrails:",
27877
28137
  ...itemLines2(input.productOperatingContext.productRules, (item) => item.rule, "No product rules found; capture acceptance criteria before editing.", 3),
@@ -27899,10 +28159,107 @@ var init_agentBeforeYouCode = __esm({
27899
28159
  init_productOperatingContext();
27900
28160
  init_pathIntent();
27901
28161
  init_testRecommendations();
28162
+ init_localReferenceImplementations();
27902
28163
  init_utils();
27903
28164
  }
27904
28165
  });
27905
28166
 
28167
+ // ../core/dist/agentWorkPacket.js
28168
+ function buildAgentWorkPacket(input) {
28169
+ const before = input.beforeYouCode;
28170
+ const rules = [
28171
+ ...(before.teamGuidance?.applied ?? []).map((item) => ({
28172
+ rule: item.label,
28173
+ source: `team:${item.kind}`
28174
+ })),
28175
+ ...before.productOperatingContext.productRules.map((item) => ({
28176
+ rule: item.rule,
28177
+ source: item.source
28178
+ }))
28179
+ ].slice(0, 3);
28180
+ const tests = before.exactTests.length > 0 ? before.exactTests.slice(0, 3).map((test) => ({
28181
+ command: compact(test.command, 180),
28182
+ reason: compact(test.reason, 180),
28183
+ confidence: test.confidence
28184
+ })) : before.likelyTests.slice(0, 3).map((command2) => ({
28185
+ command: compact(command2, 180),
28186
+ reason: "Nearest validation signal Brief found for this task.",
28187
+ confidence: "medium"
28188
+ }));
28189
+ const acceptance = unique2([
28190
+ ...before.productOperatingContext.acceptanceCriteria,
28191
+ ...before.validationChecklist
28192
+ ]).slice(0, 3);
28193
+ const stopConditions = unique2([
28194
+ ...before.stopSignals,
28195
+ ...before.productOperatingContext.stopSignals
28196
+ ]).slice(0, 3);
28197
+ const nextAction = input.nextAction ?? before.next ?? "Inspect the listed files and make the reuse decision before editing.";
28198
+ const packet = {
28199
+ schemaVersion: 1,
28200
+ objective: compact(input.task, 240),
28201
+ interpretation: compact(input.interpretation ?? before.productOperatingContext.summary ?? before.headline, 160),
28202
+ target: {
28203
+ repoRoot: before.target.repoRoot,
28204
+ repoName: before.target.repoName,
28205
+ ...before.target.branch ? { branch: before.target.branch } : {},
28206
+ ...before.target.baseRef ? { baseRef: before.target.baseRef } : {},
28207
+ dirty: before.target.dirty,
28208
+ changedFiles: before.target.changedFiles.slice(0, 4)
28209
+ },
28210
+ inspectFirst: before.inspectFirst.slice(0, 3).map((item) => ({
28211
+ path: item.path,
28212
+ why: compact(item.why, 160)
28213
+ })),
28214
+ reuse: {
28215
+ status: before.reuseFirst.status,
28216
+ decision: compact(before.reuseFirst.decision, 220),
28217
+ candidates: before.reuseFirst.candidates.slice(0, 2).map((item) => ({
28218
+ path: item.path,
28219
+ action: compact(item.action, 140),
28220
+ why: compact(item.why, 140)
28221
+ }))
28222
+ },
28223
+ rules,
28224
+ tests,
28225
+ acceptance,
28226
+ stopConditions,
28227
+ nextAction: compact(nextAction, 200)
28228
+ };
28229
+ const compactText = formatAgentWorkPacket(packet);
28230
+ return { ...packet, compactText, lineCount: compactText.split("\n").length };
28231
+ }
28232
+ function formatAgentWorkPacket(packet) {
28233
+ const lines = [
28234
+ `Objective: ${packet.objective}`,
28235
+ `Target: ${packet.target.repoName}${packet.target.branch ? ` @ ${packet.target.branch}` : ""} (${packet.target.dirty ? "dirty" : "clean"})`,
28236
+ `Interpretation: ${packet.interpretation}`,
28237
+ `Inspect first: ${inlineList(packet.inspectFirst.map((item) => `${item.path} - ${item.why}`))}`,
28238
+ `Reuse (${packet.reuse.status}): ${packet.reuse.decision}; ${inlineList(packet.reuse.candidates.map((item) => `${item.path} - ${item.action}`))}`,
28239
+ `Rules: ${inlineList(packet.rules.map((item) => `${item.rule} [${item.source}]`))}`,
28240
+ `Focused tests: ${inlineList(packet.tests.map((item) => `${item.command} - ${item.reason}`))}`,
28241
+ `Acceptance: ${inlineList(packet.acceptance)}`,
28242
+ `Stop if: ${inlineList(packet.stopConditions)}`,
28243
+ `Next: ${packet.nextAction}`
28244
+ ];
28245
+ return lines.join("\n");
28246
+ }
28247
+ function inlineList(items) {
28248
+ return items.length > 0 ? items.join("; ") : "none found";
28249
+ }
28250
+ function compact(value, maxLength) {
28251
+ const normalized = value.replace(/\s+/g, " ").trim();
28252
+ return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength - 3).trimEnd()}...`;
28253
+ }
28254
+ function unique2(values) {
28255
+ return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
28256
+ }
28257
+ var init_agentWorkPacket = __esm({
28258
+ "../core/dist/agentWorkPacket.js"() {
28259
+ "use strict";
28260
+ }
28261
+ });
28262
+
27906
28263
  // ../core/dist/ticketMissionRuntime.js
27907
28264
  var init_ticketMissionRuntime = __esm({
27908
28265
  "../core/dist/ticketMissionRuntime.js"() {
@@ -28542,7 +28899,7 @@ function codeMapBetaReadiness(input) {
28542
28899
  score: Math.min(100, Math.round((betaScore + input.qualityScore) / 2)),
28543
28900
  summary: status === "beta_plus" ? "Beta+ ready: agents have source-grounded code surfaces, parser facts, ownership, validation, operational context, and focused map proof." : status === "beta" ? "Beta: source-grounded enough to use, with remaining proof gaps that should be explicit in missions." : status === "alpha" ? "Alpha: useful orientation, but agents need narrower source, proof, or operational context before autonomous edits." : "Blocked: this map is not safe to use as architecture proof yet.",
28544
28901
  checks,
28545
- blockingGaps: unique2(blockingGaps),
28902
+ blockingGaps: unique3(blockingGaps),
28546
28903
  nextActions: status === "beta_plus" ? [
28547
28904
  "Use this map as the pre-edit context gate for agent missions.",
28548
28905
  "Preserve mapQuality.betaReadiness in review_diff and save_handoff proof."
@@ -28615,7 +28972,7 @@ function metadataList(node, key) {
28615
28972
  return [];
28616
28973
  return value.filter((item) => typeof item === "string");
28617
28974
  }
28618
- function unique2(items) {
28975
+ function unique3(items) {
28619
28976
  return [...new Set(items)];
28620
28977
  }
28621
28978
  var CODE_SURFACE_TYPES2, SOURCE_AWARE_TYPES, OBSERVABILITY_SYSTEMS, TICKET_SYSTEMS, DATA_SYSTEMS;
@@ -28759,7 +29116,16 @@ function collectFindings(input) {
28759
29116
  findings.push(...bugBarFindings(input.diff, input.changedFiles));
28760
29117
  }
28761
29118
  if (input.policy.enabledGates.includes("tests")) {
28762
- findings.push(...missingTestFindings(input.changedFiles, input.context.suggestedTests, input.validationEvidence));
29119
+ const behaviorChangeInput = {
29120
+ changedFiles: input.changedFiles,
29121
+ diff: input.diff,
29122
+ suggestedTests: input.context.suggestedTests
29123
+ };
29124
+ if (input.validationEvidence) {
29125
+ behaviorChangeInput.validationEvidence = input.validationEvidence;
29126
+ }
29127
+ const behaviorFindings = behaviorChangeFindings(behaviorChangeInput);
29128
+ findings.push(...behaviorFindings.length > 0 ? [] : missingTestFindings(input.changedFiles, input.context.suggestedTests, input.validationEvidence), ...behaviorFindings);
28763
29129
  }
28764
29130
  if (input.policy.enabledGates.includes("runtime_evidence")) {
28765
29131
  const runtimeEvidenceInput = {
@@ -29637,12 +30003,12 @@ function humanQuestionsFor(advisory, omittedFindingCount) {
29637
30003
  return unique(questions.map((question) => compactReviewQuestion(question))).slice(0, 8);
29638
30004
  }
29639
30005
  function compactReviewQuestion(value, maxLength = 800) {
29640
- const compact = value.replace(/\s+/g, " ").trim();
29641
- if (compact.length <= maxLength)
29642
- return compact;
30006
+ const compact2 = value.replace(/\s+/g, " ").trim();
30007
+ if (compact2.length <= maxLength)
30008
+ return compact2;
29643
30009
  if (maxLength <= 3)
29644
- return compact.slice(0, maxLength);
29645
- return `${compact.slice(0, maxLength - 3).trimEnd()}...`;
30010
+ return compact2.slice(0, maxLength);
30011
+ return `${compact2.slice(0, maxLength - 3).trimEnd()}...`;
29646
30012
  }
29647
30013
  function reviewReadinessScore(counts, proofStatus, review) {
29648
30014
  const penalty = counts.blocker * 35 + counts.high * 28 + counts.medium * 12 + counts.low * 5 + counts.info * 1 + review.omittedFindingCount * 2;
@@ -29767,6 +30133,50 @@ function missingTestFindings(changedFiles, suggestedTests, validationEvidence) {
29767
30133
  }
29768
30134
  ];
29769
30135
  }
30136
+ function behaviorChangeFindings(input) {
30137
+ const changedTestFiles = input.changedFiles.filter(isTestLikePath);
30138
+ if (changedTestFiles.length > 0)
30139
+ return [];
30140
+ const hits = addedLinesMatching(input.diff, /(?:\b(?:router\.(?:get|post|put|patch|delete|use)|app\.(?:get|post|put|patch|delete|use)|registerTool|publicProcedure|protectedProcedure|zaniaInternalProcedure|fetch|sendEmail|enqueue|publish|writeFile(?:Sync)?|requireAuth|authorize|permission|featureFlag|process\.env\.[A-Z0-9_]+)\b|\b(?:insert|update|delete|upsert)\s*\()/i).filter((hit) => !isTestLikePath(hit.file));
30141
+ if (hits.length === 0)
30142
+ return [];
30143
+ const proofTargets = input.suggestedTests.slice(0, 8);
30144
+ if (validationEvidenceCoversSuggestedTests(input.validationEvidence, proofTargets)) {
30145
+ return [];
30146
+ }
30147
+ const behaviorKinds = unique(hits.flatMap((hit) => behaviorKindForLine(hit.line))).slice(0, 5);
30148
+ const files = unique(hits.map((hit) => hit.file));
30149
+ return [
30150
+ {
30151
+ id: idFor("finding", `behavior-change:${locationsKey(hits)}:${behaviorKinds.join(",")}`),
30152
+ gateId: "tests",
30153
+ severity: "medium",
30154
+ title: `Behavior change: ${behaviorKinds.join(", ")} needs focused proof`,
30155
+ body: [
30156
+ `Brief found added ${behaviorKinds.join(", ")} signals in ${files.join(", ")}. This is more than a structural edit: it can change a user path, data write, access boundary, external side effect, or agent contract.`,
30157
+ proofTargets.length > 0 ? `Run the nearest mapped proof first: ${proofTargets.join(", ")}.` : "Add the nearest page, route, persistence, auth, or integration proof before handoff.",
30158
+ "A broad typecheck alone does not prove this behavior stayed correct."
30159
+ ].join(" "),
30160
+ files,
30161
+ ruleIds: [],
30162
+ suggestedTests: proofTargets
30163
+ }
30164
+ ];
30165
+ }
30166
+ function behaviorKindForLine(line) {
30167
+ const kinds = [];
30168
+ if (/\b(?:router\.|app\.|registerTool|publicProcedure|protectedProcedure|zaniaInternalProcedure)\b/i.test(line))
30169
+ kinds.push("route or agent contract");
30170
+ if (/\b(?:insert|update|delete|upsert)\s*\(/i.test(line))
30171
+ kinds.push("persistence");
30172
+ if (/\b(?:requireAuth|authorize|permission|process\.env\.)\b/i.test(line))
30173
+ kinds.push("access or configuration");
30174
+ if (/\b(?:fetch|sendEmail|enqueue|publish|writeFile)\b/i.test(line))
30175
+ kinds.push("external side effect");
30176
+ if (/\bfeatureFlag\b/i.test(line))
30177
+ kinds.push("feature flag");
30178
+ return kinds.length > 0 ? kinds : ["runtime behavior"];
30179
+ }
29770
30180
  function validationEvidenceCoversSuggestedTests(validationEvidence, suggestedTests) {
29771
30181
  const passedCommands = (validationEvidence ?? []).filter((item) => item.status === "passed").map((item) => item.command.toLowerCase());
29772
30182
  if (passedCommands.length === 0)
@@ -32664,6 +33074,7 @@ var init_dist2 = __esm({
32664
33074
  init_missionPlan();
32665
33075
  init_agentStart();
32666
33076
  init_agentBeforeYouCode();
33077
+ init_agentWorkPacket();
32667
33078
  init_productOperatingContext();
32668
33079
  init_ticketMissionRuntime();
32669
33080
  init_governance();
@@ -34507,9 +34918,9 @@ var init_serverInstructions = __esm({
34507
34918
  "../mcp/src/serverInstructions.ts"() {
34508
34919
  "use strict";
34509
34920
  briefMcpInstructions = [
34510
- "Brief is the default repo-context, reuse, review, and handoff companion for non-trivial coding work. Do not wait for the user to repeat 'use Brief'.",
34921
+ "Brief is the default repo-context, reuse, review, and handoff companion for non-trivial coding work. This is the normal path, not an optional reminder. Do not wait for the user to repeat 'use Brief'.",
34511
34922
  "At the first Brief-relevant task in a session, call brief.install_status once and confirm the repo target and connector freshness.",
34512
- "Before non-trivial edits, call brief.next with the user's actual request and follow its compact recommendation. Keep micro changes lightweight.",
34923
+ "When the user asks for non-trivial work, call brief.next with the user's actual request before inspecting or editing files, then follow its compact workPacket and recommendation. Keep micro changes lightweight.",
34513
34924
  "Before creating a helper, component, route, workflow, command, or skill, use the returned reuse candidates or call brief.reference_implementations and brief.codebase_map.",
34514
34925
  "Refresh Brief context when the task, files, risk, or validation plan changes.",
34515
34926
  "Before a meaningful handoff, call brief.review_diff. Save and verify a handoff only for multi-step, high-risk, or durable work.",
@@ -34547,7 +34958,7 @@ function compactBlockedInstallStatus(input) {
34547
34958
  fresh: input.serverFreshness.status === "current",
34548
34959
  summary: input.connectorReadiness.summary
34549
34960
  },
34550
- next: unique3(input.repoTarget.next).slice(0, 2),
34961
+ next: unique4(input.repoTarget.next).slice(0, 2),
34551
34962
  detailHint: "Open a Git repository or pass its path, then run install-status again."
34552
34963
  };
34553
34964
  }
@@ -34559,10 +34970,10 @@ function compactInstallStatus(input) {
34559
34970
  const mcpContractActive = input.serverInstructionsActive && input.connectorReadiness.safeToUseBrief;
34560
34971
  const totalMapCandidates = stats.mapTotalCandidateCount ?? stats.mapNodeCount + (stats.mapOmittedCount ?? 0);
34561
34972
  const mapCoveragePercent = totalMapCandidates ? Math.round(stats.mapNodeCount / totalMapCandidates * 100) : 100;
34562
- const repoGuidanceSignals = unique3(
34973
+ const repoGuidanceSignals = unique4(
34563
34974
  input.workflowWiring.surfaces.filter((surface) => surface.kind === "always_on_guidance").flatMap((surface) => surface.signals)
34564
34975
  );
34565
- const next = unique3([
34976
+ const next = unique4([
34566
34977
  ...blocked ? [input.connectorReadiness.firstAction] : [],
34567
34978
  ...cloudIssue ? [cloudIssue] : [],
34568
34979
  ...input.readiness.nextBestActions,
@@ -34609,7 +35020,7 @@ function compactInstallStatus(input) {
34609
35020
  score: input.readiness.score,
34610
35021
  verdict: input.readiness.verdict,
34611
35022
  summary: input.readiness.summary,
34612
- gaps: unique3([
35023
+ gaps: unique4([
34613
35024
  ...input.readiness.quickWins,
34614
35025
  ...input.readiness.nextBestActions
34615
35026
  ]).slice(0, 3)
@@ -34636,7 +35047,7 @@ function compactInstallStatus(input) {
34636
35047
  detailHint: 'Use detail: "expanded" in MCP or --full in the CLI only when diagnosing setup, workflow wiring, or receipt history.'
34637
35048
  };
34638
35049
  }
34639
- function unique3(values) {
35050
+ function unique4(values) {
34640
35051
  return [...new Set(values.filter((value) => value.trim()))];
34641
35052
  }
34642
35053
  var briefConnectorVersion;
@@ -34644,7 +35055,7 @@ var init_installStatus = __esm({
34644
35055
  "../mcp/src/installStatus.ts"() {
34645
35056
  "use strict";
34646
35057
  init_serverInstructions();
34647
- briefConnectorVersion = "0.1.0";
35058
+ briefConnectorVersion = "0.1.2";
34648
35059
  }
34649
35060
  });
34650
35061
 
@@ -34667,19 +35078,26 @@ function buildCompactStartEnvelope(input) {
34667
35078
  ...start.intent.autonomy ? { autonomy: start.intent.autonomy } : {},
34668
35079
  ...start.intent.reviewBar ? { reviewBar: start.intent.reviewBar } : {}
34669
35080
  },
35081
+ workPacket: (() => {
35082
+ const packet = buildAgentWorkPacket({
35083
+ task: start.normalizedInput.task,
35084
+ beforeYouCode,
35085
+ interpretation: start.summary,
35086
+ nextAction: input.next
35087
+ });
35088
+ return {
35089
+ schemaVersion: packet.schemaVersion,
35090
+ compactText: packet.compactText
35091
+ };
35092
+ })(),
34670
35093
  inspectFirst: beforeYouCode.inspectFirst.slice(0, 3).map((item) => ({
34671
35094
  path: item.path,
34672
35095
  why: compactLine(item.why, 160)
34673
35096
  })),
34674
- reuse: beforeYouCode.reuseFirst.candidates.slice(0, 2).map((item) => ({
34675
- path: item.path,
34676
- action: compactLine(item.action, 160)
34677
- })),
34678
35097
  validation: beforeYouCode.likelyTests.slice(0, 3),
34679
35098
  result: input.result,
34680
- stopSignals: beforeYouCode.stopSignals.slice(0, 2),
34681
- next: compactLine(input.next, 320),
34682
- detailHint: 'Request expanded detail only when needed: CLI --json/--full or MCP detail: "expanded".'
35099
+ next: compactLine(input.next, 240),
35100
+ detailHint: 'Expand with MCP detail: "expanded" or CLI --full.'
34683
35101
  };
34684
35102
  }
34685
35103
  function formatCompactStartText(envelope) {
@@ -34694,23 +35112,13 @@ function formatCompactStartText(envelope) {
34694
35112
  `Target: ${target} | ${envelope.target.dirty ? "dirty" : "clean"}`,
34695
35113
  `Job: ${envelope.job}`,
34696
35114
  `Route: ${route}`,
34697
- "Inspect first:",
34698
- ...listLines(
34699
- envelope.inspectFirst.map((item) => `${item.path} - ${item.why}`)
34700
- ),
34701
- "Reuse:",
34702
- ...listLines(envelope.reuse.map((item) => `${item.path} - ${item.action}`)),
34703
- "Validate:",
34704
- ...listLines(envelope.validation),
35115
+ envelope.workPacket.compactText,
34705
35116
  `Result: ${envelope.result.summary}`,
34706
35117
  `Next: ${envelope.next}`,
34707
35118
  `Details: ${envelope.detailHint}`
34708
35119
  ];
34709
35120
  return lines.join("\n");
34710
35121
  }
34711
- function listLines(items) {
34712
- return items.length > 0 ? items.map((item) => `- ${item}`) : ["- none"];
34713
- }
34714
35122
  function compactLine(value, maxLength) {
34715
35123
  const normalized = value.replace(/\s+/g, " ").trim();
34716
35124
  if (normalized.length <= maxLength) return normalized;
@@ -35142,7 +35550,7 @@ function renderWikiRefreshWorkflow(options2 = {}) {
35142
35550
  " with:",
35143
35551
  " node-version: 22",
35144
35552
  " - name: Refresh wiki",
35145
- ' run: npx -y runbrief@0.1.0 wiki init --repo "$GITHUB_WORKSPACE" --update --no-agent-files',
35553
+ ' run: npx -y runbrief@0.1.2 wiki init --repo "$GITHUB_WORKSPACE" --update --no-agent-files',
35146
35554
  " - name: Open refresh PR",
35147
35555
  " uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7.0.11",
35148
35556
  " with:",
@@ -35242,7 +35650,7 @@ function resolveHandoffAutofill(repoRoot, input) {
35242
35650
  sources,
35243
35651
  missionReceiptId,
35244
35652
  reviewReceiptId,
35245
- autoFilled: unique4(autoFilled)
35653
+ autoFilled: unique5(autoFilled)
35246
35654
  });
35247
35655
  }
35248
35656
  function bestMatchingReceipt(receipts, kind, input) {
@@ -35322,10 +35730,10 @@ function compactResult(result) {
35322
35730
  }
35323
35731
  function cleanValues(values, limit = 300) {
35324
35732
  if (!values) return void 0;
35325
- const cleaned = unique4(values.map((value) => value.trim()).filter(Boolean)).sort().slice(0, limit);
35733
+ const cleaned = unique5(values.map((value) => value.trim()).filter(Boolean)).sort().slice(0, limit);
35326
35734
  return cleaned.length > 0 ? cleaned : void 0;
35327
35735
  }
35328
- function unique4(values) {
35736
+ function unique5(values) {
35329
35737
  return [...new Set(values)];
35330
35738
  }
35331
35739
  function normalizeText(value) {
@@ -35382,35 +35790,35 @@ function compactCodebaseMapResponse(input) {
35382
35790
  };
35383
35791
  }
35384
35792
  function formatCompactCodebaseMap(input) {
35385
- const compact = compactCodebaseMapResponse(input);
35793
+ const compact2 = compactCodebaseMapResponse(input);
35386
35794
  const lines = [
35387
- `Codebase map: ${compact.summary}`,
35388
- `Target: ${compact.target.repoName} | ${compact.target.repoRoot}${compact.target.mapPartial ? " | partial map" : ""}`,
35795
+ `Codebase map: ${compact2.summary}`,
35796
+ `Target: ${compact2.target.repoName} | ${compact2.target.repoRoot}${compact2.target.mapPartial ? " | partial map" : ""}`,
35389
35797
  "Inspect first:",
35390
- ...listLines2(
35391
- compact.inspectFirst,
35798
+ ...listLines(
35799
+ compact2.inspectFirst,
35392
35800
  (item) => `${item.path} - ${item.reason}`,
35393
35801
  "No focused source matched; narrow the query before editing."
35394
35802
  ),
35395
35803
  "Reuse before creating:",
35396
- ...listLines2(
35397
- compact.reuse.candidates,
35804
+ ...listLines(
35805
+ compact2.reuse.candidates,
35398
35806
  (item) => `${item.path}${item.symbols.length > 0 ? ` - ${item.symbols.join(", ")}` : ""}`,
35399
35807
  "No reusable primitive is proven yet; run a narrower map query."
35400
35808
  ),
35401
35809
  "Validate:",
35402
- ...listLines2(
35403
- compact.validate,
35810
+ ...listLines(
35811
+ compact2.validate,
35404
35812
  (item) => item,
35405
35813
  "No focused validation command was found."
35406
35814
  ),
35407
- ...compact.warnings.length > 0 ? ["Warnings:", ...listLines2(compact.warnings, (item) => item, "")] : [],
35815
+ ...compact2.warnings.length > 0 ? ["Warnings:", ...listLines(compact2.warnings, (item) => item, "")] : [],
35408
35816
  "Next:",
35409
- ...listLines2(compact.next, (item) => item, "Inspect the first source.")
35817
+ ...listLines(compact2.next, (item) => item, "Inspect the first source.")
35410
35818
  ];
35411
35819
  return lines.slice(0, 30).join("\n");
35412
35820
  }
35413
- function listLines2(items, render, empty) {
35821
+ function listLines(items, render, empty) {
35414
35822
  if (items.length === 0) return empty ? [`- ${empty}`] : [];
35415
35823
  return items.map((item) => `- ${render(item)}`);
35416
35824
  }
@@ -35420,6 +35828,40 @@ var init_mapResponse = __esm({
35420
35828
  }
35421
35829
  });
35422
35830
 
35831
+ // ../mcp/src/scanFreshness.ts
35832
+ function scanFreshnessFor(repoRoot, scan) {
35833
+ const gitRoot = runGit(repoRoot, ["rev-parse", "--show-toplevel"]);
35834
+ const gitAvailable = Boolean(gitRoot);
35835
+ const branch = runGit(repoRoot, ["branch", "--show-current"]) || null;
35836
+ const commit = runGit(repoRoot, ["rev-parse", "HEAD"]) || null;
35837
+ const statusLines = (gitAvailable ? runGit(repoRoot, ["status", "--short"]) : "").split("\n").map((line) => line.trim()).filter(Boolean);
35838
+ return {
35839
+ status: !gitAvailable ? "git_unavailable" : scan.stats.mapPartial ? "partial_coverage" : statusLines.length > 0 ? "working_tree_changed" : "current_at_scan",
35840
+ git: {
35841
+ available: gitAvailable,
35842
+ detachedHead: gitAvailable && !branch
35843
+ },
35844
+ scannedAt: scan.scannedAt,
35845
+ branch,
35846
+ commit,
35847
+ changedPathCount: statusLines.length,
35848
+ changedPaths: statusLines.map((line) => line.replace(/^[ MADRCU?!]{1,3}\s+/, "")).slice(0, 24),
35849
+ mapCoverage: {
35850
+ nodes: scan.stats.mapNodeCount,
35851
+ candidates: scan.stats.mapTotalCandidateCount ?? scan.stats.mapNodeCount,
35852
+ omitted: scan.stats.mapOmittedCount ?? 0,
35853
+ partial: Boolean(scan.stats.mapPartial)
35854
+ },
35855
+ next: !gitAvailable ? "Git metadata is unavailable; verify the repo target before trusting map freshness." : statusLines.length > 0 ? "Rescan after the current edits settle; changed paths may invalidate reuse and wiki evidence." : scan.stats.mapPartial ? "Narrow the scan by area or raise maxFiles before treating the map as complete." : !branch ? "The map was generated from a detached commit and clean working tree; verify the intended branch before editing." : "The map was generated from the current commit and clean working tree."
35856
+ };
35857
+ }
35858
+ var init_scanFreshness = __esm({
35859
+ "../mcp/src/scanFreshness.ts"() {
35860
+ "use strict";
35861
+ init_dist2();
35862
+ }
35863
+ });
35864
+
35423
35865
  // ../mcp/src/workflowWiringResponse.ts
35424
35866
  function selectWorkflowWiringResponse(report, detail) {
35425
35867
  return detail === "expanded" ? report : summarizeAgentWorkflowWiring(report);
@@ -35712,6 +36154,7 @@ function summarizePacket(packet) {
35712
36154
  memories: packet.memories,
35713
36155
  sources: packet.sources,
35714
36156
  omitted: packet.omitted,
36157
+ ...packet.valueSignals ? { valueSignals: packet.valueSignals } : {},
35715
36158
  ...packet.teamGuidance ? { teamGuidance: packet.teamGuidance } : {}
35716
36159
  };
35717
36160
  }
@@ -36147,8 +36590,13 @@ function summarizeBeforeYouCodeForStart(beforeYouCode) {
36147
36590
  reuseFirst: {
36148
36591
  status: beforeYouCode.reuseFirst.status,
36149
36592
  summary: beforeYouCode.reuseFirst.summary,
36593
+ decision: beforeYouCode.reuseFirst.decision,
36150
36594
  candidates: beforeYouCode.reuseFirst.candidates.slice(0, 2)
36151
36595
  },
36596
+ sharedContext: summarizeBeforeYouCodeSharedContext(
36597
+ beforeYouCode.teamGuidance
36598
+ ),
36599
+ referenceFirst: summarizeBeforeYouCodeReferences(beforeYouCode),
36152
36600
  likelyTests: beforeYouCode.likelyTests.slice(0, 3),
36153
36601
  productOperatingContext: {
36154
36602
  status: beforeYouCode.productOperatingContext.status,
@@ -36307,10 +36755,11 @@ var init_server = __esm({
36307
36755
  init_wikiInit();
36308
36756
  init_workspace();
36309
36757
  init_handoffAutofill();
36758
+ init_scanFreshness();
36310
36759
  server = new McpServer(
36311
36760
  {
36312
36761
  name: "brief",
36313
- version: "0.1.0"
36762
+ version: "0.1.2"
36314
36763
  },
36315
36764
  {
36316
36765
  instructions: briefMcpInstructions
@@ -37076,6 +37525,12 @@ var init_server = __esm({
37076
37525
  }) : void 0;
37077
37526
  const autoEngage = buildAgentAutoEngagementPlan(scan, skillLearning);
37078
37527
  const workflowWiring = evaluateAgentWorkflowWiring(scan);
37528
+ const workPacket = buildAgentWorkPacket({
37529
+ task,
37530
+ beforeYouCode,
37531
+ interpretation: recommendation.reason,
37532
+ nextAction: `Call ${recommendation.mcpTool} next. ${recommendation.stopUntil}`
37533
+ });
37079
37534
  const fullResponse = {
37080
37535
  status: "brief_next",
37081
37536
  repoRoot,
@@ -37084,6 +37539,7 @@ var init_server = __esm({
37084
37539
  stage: resolvedStage,
37085
37540
  recommendation,
37086
37541
  cockpit: beforeYouCode.cockpit,
37542
+ workPacket,
37087
37543
  beforeYouCode: summarizeBeforeYouCodeForStart(beforeYouCode),
37088
37544
  ...start && recommendation.mcpTool !== "brief.before_you_code" ? { start: summarizeStartForStart(start) } : {},
37089
37545
  ...readinessPreview ? { readinessPreview } : {},
@@ -37107,6 +37563,7 @@ var init_server = __esm({
37107
37563
  },
37108
37564
  stage: resolvedStage,
37109
37565
  recommendation,
37566
+ workPacket,
37110
37567
  cockpit: {
37111
37568
  taskSize: beforeYouCode.cockpit.taskSize,
37112
37569
  mode: beforeYouCode.cockpit.mode,
@@ -37115,6 +37572,7 @@ var init_server = __esm({
37115
37572
  },
37116
37573
  reuse: {
37117
37574
  status: beforeYouCode.reuseFirst.status,
37575
+ decision: beforeYouCode.reuseFirst.decision,
37118
37576
  candidates: beforeYouCode.reuseFirst.candidates.slice(0, 3).map(({ path: candidatePath, action, why }) => ({
37119
37577
  path: candidatePath,
37120
37578
  action,
@@ -37126,6 +37584,18 @@ var init_server = __esm({
37126
37584
  status: beforeYouCode.productOperatingContext.status,
37127
37585
  taskClasses: beforeYouCode.productOperatingContext.taskClasses
37128
37586
  },
37587
+ autoEngage: {
37588
+ status: autoEngage.status,
37589
+ workflowWiring: workflowWiring.status,
37590
+ firstCall: "brief.next",
37591
+ beforeEditing: "brief.before_you_code or brief.start",
37592
+ beforeHandoff: "brief.review_diff",
37593
+ finalRecap: "one or two truthful lines; no receipt dump"
37594
+ },
37595
+ sharedContext: summarizeBeforeYouCodeSharedContext(
37596
+ beforeYouCode.teamGuidance
37597
+ ),
37598
+ referenceFirst: summarizeBeforeYouCodeReferences(beforeYouCode),
37129
37599
  ...learnedWorkflow ? {
37130
37600
  learnedWorkflow: {
37131
37601
  name: learnedWorkflow.name,
@@ -37133,7 +37603,12 @@ var init_server = __esm({
37133
37603
  preservedGates: learnedWorkflow.preservedGates
37134
37604
  }
37135
37605
  } : {},
37136
- teamContext: { status: teamContext.status },
37606
+ teamContext: {
37607
+ status: teamContext.status,
37608
+ sharedContext: summarizeBeforeYouCodeSharedContext(
37609
+ beforeYouCode.teamGuidance
37610
+ )
37611
+ },
37137
37612
  detailHint: 'Call brief.next again with detail: "expanded" only for expanded proof and workflow diagnostics.',
37138
37613
  next: fullResponse.next
37139
37614
  });
@@ -37594,6 +38069,7 @@ var init_server = __esm({
37594
38069
  const cloudSync = await syncScanSummary(scan, repoRoot);
37595
38070
  return jsonText({
37596
38071
  ...summarizeScan(scan),
38072
+ scanFreshness: scanFreshnessFor(repoRoot, scan),
37597
38073
  rootResolution,
37598
38074
  repoTarget,
37599
38075
  cloudSync
@@ -39036,6 +39512,7 @@ init_startSummary();
39036
39512
  init_wikiInit();
39037
39513
  init_handoffAutofill();
39038
39514
  init_mapResponse();
39515
+ init_scanFreshness();
39039
39516
  import { chmodSync as chmodSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync7 } from "node:fs";
39040
39517
  import path19 from "node:path";
39041
39518
  import { fileURLToPath as fileURLToPath2 } from "node:url";
@@ -39239,6 +39716,7 @@ async function runCli(commandName, commandArgs) {
39239
39716
  repoTarget,
39240
39717
  scannedAt: scan.scannedAt,
39241
39718
  stats: scan.stats,
39719
+ scanFreshness: scanFreshnessFor(repoRoot, scan),
39242
39720
  cloudSync,
39243
39721
  webAppStatus: webAppStatusForScan(cloudSync),
39244
39722
  next: nextScanStep(cloudSync)
@@ -39287,6 +39765,12 @@ async function runCli(commandName, commandArgs) {
39287
39765
  beforeYouCode,
39288
39766
  baseRef
39289
39767
  });
39768
+ const workPacket = buildAgentWorkPacket({
39769
+ task,
39770
+ beforeYouCode,
39771
+ interpretation: recommendation.reason,
39772
+ nextAction: recommendation.stopUntil
39773
+ });
39290
39774
  const fullResponse = {
39291
39775
  status: "brief_next",
39292
39776
  repoRoot,
@@ -39295,6 +39779,7 @@ async function runCli(commandName, commandArgs) {
39295
39779
  stage,
39296
39780
  recommendation,
39297
39781
  cockpit: beforeYouCode.cockpit,
39782
+ workPacket,
39298
39783
  beforeYouCode: summarizeBeforeYouCodeForCli(beforeYouCode),
39299
39784
  ...start && recommendation.mcpTool !== "brief.before_you_code" ? { start: summarizeStartForCli(start) } : {},
39300
39785
  workflowWiring: summarizeWorkflowWiringForCli(workflowWiring),
@@ -39317,6 +39802,11 @@ async function runCli(commandName, commandArgs) {
39317
39802
  },
39318
39803
  stage,
39319
39804
  recommendation,
39805
+ workPacket: {
39806
+ schemaVersion: workPacket.schemaVersion,
39807
+ compactText: workPacket.compactText,
39808
+ lineCount: workPacket.lineCount
39809
+ },
39320
39810
  cockpit: {
39321
39811
  taskSize: beforeYouCode.cockpit.taskSize,
39322
39812
  mode: beforeYouCode.cockpit.mode,
@@ -39325,6 +39815,7 @@ async function runCli(commandName, commandArgs) {
39325
39815
  },
39326
39816
  reuse: {
39327
39817
  status: beforeYouCode.reuseFirst.status,
39818
+ decision: beforeYouCode.reuseFirst.decision,
39328
39819
  candidates: beforeYouCode.reuseFirst.candidates.slice(0, 3).map(({ path: candidatePath, action, why }) => ({
39329
39820
  path: candidatePath,
39330
39821
  action,
@@ -39336,6 +39827,19 @@ async function runCli(commandName, commandArgs) {
39336
39827
  status: beforeYouCode.productOperatingContext.status,
39337
39828
  taskClasses: beforeYouCode.productOperatingContext.taskClasses
39338
39829
  },
39830
+ sharedContext: summarizeBeforeYouCodeSharedContext(
39831
+ beforeYouCode.teamGuidance
39832
+ ),
39833
+ autoEngage: {
39834
+ status: autoEngage.status,
39835
+ chatFeedback: autoEngage.chatFeedback.slice(0, 1),
39836
+ finalRecapPolicy: {
39837
+ maxLines: autoEngage.finalRecapPolicy.maxLines,
39838
+ defaultTemplate: autoEngage.finalRecapPolicy.defaultTemplate,
39839
+ fallbackWhenNotHelpful: autoEngage.finalRecapPolicy.fallbackWhenNotHelpful
39840
+ }
39841
+ },
39842
+ referenceFirst: summarizeBeforeYouCodeReferences(beforeYouCode),
39339
39843
  ...learnedWorkflow ? {
39340
39844
  learnedWorkflow: {
39341
39845
  name: learnedWorkflow.name,
@@ -39343,7 +39847,12 @@ async function runCli(commandName, commandArgs) {
39343
39847
  preservedGates: learnedWorkflow.preservedGates
39344
39848
  }
39345
39849
  } : {},
39346
- teamContext: { status: teamContext.status },
39850
+ teamContext: {
39851
+ status: teamContext.status,
39852
+ sharedContext: summarizeBeforeYouCodeSharedContext(
39853
+ beforeYouCode.teamGuidance
39854
+ )
39855
+ },
39347
39856
  detailHint: "Run the same command with --full for expanded proof and workflow diagnostics.",
39348
39857
  next: fullResponse.next
39349
39858
  }
@@ -39803,6 +40312,10 @@ async function runCli(commandName, commandArgs) {
39803
40312
  repoTarget,
39804
40313
  cockpit: beforeYouCode.cockpit,
39805
40314
  beforeYouCode: summarizeBeforeYouCodeForCli(beforeYouCode),
40315
+ sharedContext: summarizeBeforeYouCodeSharedContext(
40316
+ beforeYouCode.teamGuidance
40317
+ ),
40318
+ referenceFirst: summarizeBeforeYouCodeReferences(beforeYouCode),
39806
40319
  teamContext: summarizeTeamContext(teamContext),
39807
40320
  next: "Read cockpit.compactText first. For micro/small passes, stay lightweight unless scope grows; for medium/large passes, call brief.start or mission_plan before editing."
39808
40321
  });
@@ -40299,7 +40812,7 @@ async function runCli(commandName, commandArgs) {
40299
40812
  });
40300
40813
  return;
40301
40814
  }
40302
- if (isCommand(commandName, "review-diff", "review_diff")) {
40815
+ if (isCommand(commandName, "review-diff", "review", "review_diff")) {
40303
40816
  const baseRef = option2(commandArgs, "base");
40304
40817
  const task = option2(commandArgs, "task");
40305
40818
  const files = filesOption2(commandArgs);
@@ -40479,14 +40992,14 @@ async function runCli(commandName, commandArgs) {
40479
40992
  if (isCommand(commandName, "workflow-wiring", "workflow_wiring")) {
40480
40993
  const scan = scanRepo(repoRoot, { maxFiles: 400 });
40481
40994
  const workflowWiring = evaluateAgentWorkflowWiring(scan);
40482
- const compact = hasFlag(commandArgs, "compact") && !hasFlag(commandArgs, "full");
40995
+ const compact2 = hasFlag(commandArgs, "compact") && !hasFlag(commandArgs, "full");
40483
40996
  const explicitlyExpanded = hasFlag(commandArgs, "full");
40484
40997
  printJson({
40485
40998
  status: "workflow_wiring",
40486
40999
  repoRoot,
40487
41000
  repoName: scan.repoName,
40488
- workflowWiring: compact ? summarizeAgentWorkflowWiring(workflowWiring) : workflowWiring,
40489
- ...compact ? {
41001
+ workflowWiring: compact2 ? summarizeAgentWorkflowWiring(workflowWiring) : workflowWiring,
41002
+ ...compact2 ? {
40490
41003
  detailHint: "Use --full only when diagnosing wiring evidence, contracts, or copyable prompts."
40491
41004
  } : explicitlyExpanded ? { detail: "expanded" } : {
40492
41005
  compatibility: "Expanded detail was returned for backward compatibility. Use --compact for the agent-safe response."
@@ -40961,7 +41474,7 @@ function cliCommandHelp() {
40961
41474
  },
40962
41475
  {
40963
41476
  command: "review-diff",
40964
- aliases: ["review_diff"],
41477
+ aliases: ["review", "review_diff"],
40965
41478
  purpose: "Review the current diff for bugs, missing tests, reuse gaps, trust boundaries, design adherence, and proof.",
40966
41479
  repoBound: true,
40967
41480
  usage: 'brief review-diff --repo /path/to/repo --base main --task "Prepare PR" --json',
@@ -41686,6 +42199,7 @@ function printContextSummary(packet, localReceipt, teamContext) {
41686
42199
  `Sources: ${packet.sources.length}`,
41687
42200
  teamContextLine(teamContext),
41688
42201
  teamGuidanceLine(packet),
42202
+ valueSignalLine(packet),
41689
42203
  "",
41690
42204
  "Rules:",
41691
42205
  ...packet.rules.length > 0 ? packet.rules.slice(0, 8).map((rule) => `- [${rule.enforcement}] ${rule.title}`) : ["- none"],
@@ -41730,6 +42244,11 @@ function teamGuidanceLine(packet) {
41730
42244
  if (!delivery) return "Team guidance applied: not connected";
41731
42245
  return `Team guidance applied: ${delivery.applied.length}/${delivery.availableCount} approved items (${delivery.revision})`;
41732
42246
  }
42247
+ function valueSignalLine(packet) {
42248
+ const signals = packet.valueSignals;
42249
+ if (!signals) return "Value signals: not available";
42250
+ return `Value signals: ${signals.relevantSourceCount} relevant sources, ${signals.reusablePrimitiveCount} reusable primitives, ${signals.parserBackedEntityCount} parser-backed entities, ${signals.appliedTeamGuidanceCount} team guidance items, ${signals.suggestedTestCount} test targets`;
42251
+ }
41733
42252
  function writeHookFiles2(repoRoot, files) {
41734
42253
  const written = [];
41735
42254
  for (const file of files) {
@@ -41773,8 +42292,13 @@ function summarizeBeforeYouCodeForCli(beforeYouCode) {
41773
42292
  reuseFirst: {
41774
42293
  status: beforeYouCode.reuseFirst.status,
41775
42294
  summary: beforeYouCode.reuseFirst.summary,
42295
+ decision: beforeYouCode.reuseFirst.decision,
41776
42296
  candidates: beforeYouCode.reuseFirst.candidates.slice(0, 2)
41777
42297
  },
42298
+ sharedContext: summarizeBeforeYouCodeSharedContext(
42299
+ beforeYouCode.teamGuidance
42300
+ ),
42301
+ referenceFirst: summarizeBeforeYouCodeReferences(beforeYouCode),
41778
42302
  likelyTests: beforeYouCode.likelyTests.slice(0, 3),
41779
42303
  productOperatingContext: {
41780
42304
  status: beforeYouCode.productOperatingContext.status,