@deftai/directive-core 0.84.0 → 0.85.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/cache/fetch.d.ts +17 -0
  2. package/dist/cache/fetch.js +50 -0
  3. package/dist/doctor/checks.js +16 -1
  4. package/dist/doctor/constants.d.ts +2 -0
  5. package/dist/doctor/constants.js +8 -4
  6. package/dist/doctor/index.d.ts +1 -0
  7. package/dist/doctor/index.js +1 -0
  8. package/dist/doctor/main.js +13 -4
  9. package/dist/doctor/npm-registry.d.ts +23 -0
  10. package/dist/doctor/npm-registry.js +128 -0
  11. package/dist/doctor/npm-view.d.ts +10 -0
  12. package/dist/doctor/npm-view.js +31 -0
  13. package/dist/doctor/payload-staleness.js +2 -9
  14. package/dist/doctor/signpost-checks.d.ts +2 -1
  15. package/dist/doctor/signpost-checks.js +2 -0
  16. package/dist/doctor/types.d.ts +9 -0
  17. package/dist/eval-health-relocation/evaluate.js +15 -1
  18. package/dist/fs/projection-containment.js +1 -1
  19. package/dist/hooks/cursor-hooks.d.ts +6 -20
  20. package/dist/hooks/cursor-hooks.js +7 -92
  21. package/dist/init-deposit/agent-hooks.d.ts +2 -2
  22. package/dist/init-deposit/agent-hooks.js +15 -37
  23. package/dist/init-deposit/hygiene.d.ts +22 -0
  24. package/dist/init-deposit/hygiene.js +136 -4
  25. package/dist/init-deposit/legacy-detect.d.ts +25 -1
  26. package/dist/init-deposit/legacy-detect.js +143 -11
  27. package/dist/init-deposit/refresh.d.ts +2 -0
  28. package/dist/init-deposit/refresh.js +18 -5
  29. package/dist/policy/index.d.ts +2 -0
  30. package/dist/policy/index.js +2 -0
  31. package/dist/policy/org-force-on-migration.d.ts +44 -0
  32. package/dist/policy/org-force-on-migration.js +240 -0
  33. package/dist/policy/product-signal.d.ts +3 -1
  34. package/dist/policy/product-signal.js +15 -4
  35. package/dist/policy/value-feedback.d.ts +18 -1
  36. package/dist/policy/value-feedback.js +78 -5
  37. package/dist/preflight-cache/evaluate.js +12 -1
  38. package/dist/product-signal/consent-prompt.d.ts +13 -0
  39. package/dist/product-signal/consent-prompt.js +30 -0
  40. package/dist/product-signal/submit.js +22 -1
  41. package/dist/render/index.d.ts +1 -0
  42. package/dist/render/index.js +1 -0
  43. package/dist/render/rule-map-template.d.ts +2 -0
  44. package/dist/render/rule-map-template.js +407 -0
  45. package/dist/render/rule-map.d.ts +2 -0
  46. package/dist/render/rule-map.js +703 -0
  47. package/dist/review-monitor/constants.d.ts +7 -1
  48. package/dist/review-monitor/constants.js +40 -14
  49. package/dist/review-monitor/github-lease.d.ts +45 -0
  50. package/dist/review-monitor/github-lease.js +106 -0
  51. package/dist/review-monitor/index.d.ts +2 -0
  52. package/dist/review-monitor/index.js +2 -0
  53. package/dist/review-monitor/lease-comment.d.ts +36 -0
  54. package/dist/review-monitor/lease-comment.js +152 -0
  55. package/dist/review-monitor/record.d.ts +61 -13
  56. package/dist/review-monitor/record.js +379 -132
  57. package/dist/review-monitor/verify.d.ts +2 -0
  58. package/dist/review-monitor/verify.js +32 -13
  59. package/dist/scm/gh-rest.d.ts +7 -1
  60. package/dist/scm/gh-rest.js +35 -0
  61. package/dist/session/session-start.js +5 -0
  62. package/dist/task-surface/index.js +53 -13
  63. package/dist/xbrief-migrate/constants.d.ts +6 -0
  64. package/dist/xbrief-migrate/constants.js +6 -0
  65. package/dist/xbrief-migrate/index.d.ts +2 -2
  66. package/dist/xbrief-migrate/index.js +2 -2
  67. package/dist/xbrief-migrate/migrate-project.d.ts +7 -0
  68. package/dist/xbrief-migrate/migrate-project.js +18 -1
  69. package/package.json +3 -3
@@ -0,0 +1,30 @@
1
+ import { resolveProductSignal } from "../policy/product-signal.js";
2
+ import { isProductSignalConsented } from "./consent.js";
3
+ import { isHeadlessSession } from "./headless.js";
4
+ /** D17 first-time consent ask (#2693 / #2822). */
5
+ export const PRODUCT_SIGNAL_CONSENT_PROMPT = "May we collect usage metrics and related session signal from this install to improve Directive? " +
6
+ "This can include a short check-in plus minimized local summaries (value/health and related ledgers). " +
7
+ "Nothing is sent while this path is off or without your consent.\n\n" +
8
+ "If you are unsure, please check with your company before saying no — they are a Directive partner " +
9
+ "and may already expect this signal to be shared.\n\n" +
10
+ "Reply **yes** to consent (`task product-signal:consent -- --grant`), or **no** to decline.";
11
+ /** True when an interactive session should surface the D17 consent ask (#2822 AC). */
12
+ export function isProductSignalConsentEligible(options) {
13
+ if (isHeadlessSession(options)) {
14
+ return false;
15
+ }
16
+ const policy = resolveProductSignal(options.projectRoot);
17
+ if (!policy.enabled) {
18
+ return false;
19
+ }
20
+ return !isProductSignalConsented({ env: options.env });
21
+ }
22
+ /** Format the D17 consent ask for session start / status surfaces. */
23
+ export function formatProductSignalConsentPrompt() {
24
+ return `[deft product-signal] First-time consent eligible:\n${PRODUCT_SIGNAL_CONSENT_PROMPT}\n`;
25
+ }
26
+ /** Emit the D17 ask when eligible; headless callers get an empty string (#2693 D16). */
27
+ export function maybeFormatProductSignalConsentPrompt(options) {
28
+ return isProductSignalConsentEligible(options) ? formatProductSignalConsentPrompt() : "";
29
+ }
30
+ //# sourceMappingURL=consent-prompt.js.map
@@ -1,9 +1,11 @@
1
1
  import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
2
2
  import { join, resolve } from "node:path";
3
+ import { assertWriteTargetSafe, ProjectionContainmentError } from "../fs/projection-containment.js";
3
4
  import { enableProductSignal, formatProductSignalStatusLine, resolveProductSignal, } from "../policy/product-signal.js";
4
5
  import { resolveProjectRoot } from "../scope/project-context.js";
5
6
  import { resolveActorName } from "./actor-name.js";
6
7
  import { authorizeProductSignalSink, grantProductSignalConsent, readProductSignalConsent, revokeProductSignalConsent, } from "./consent.js";
8
+ import { maybeFormatProductSignalConsentPrompt } from "./consent-prompt.js";
7
9
  import { evaluateProductSignalGates } from "./gates.js";
8
10
  import { GitHubPrivateSinkAdapter } from "./github-private-sink-adapter.js";
9
11
  import { collectInstallContext } from "./install-context.js";
@@ -13,6 +15,7 @@ import { bootstrapProductSignalSink } from "./sink-bootstrap.js";
13
15
  export const PRODUCT_SIGNAL_LAST_SUBMIT_REL = join(".deft-cache", "product-signal-last-submit.json");
14
16
  function recordLastSubmit(projectRoot, outcome, url) {
15
17
  const path = resolve(projectRoot, PRODUCT_SIGNAL_LAST_SUBMIT_REL);
18
+ assertWriteTargetSafe(projectRoot, path);
16
19
  try {
17
20
  mkdirSync(join(path, ".."), { recursive: true });
18
21
  appendFileSync(path, `${JSON.stringify({
@@ -127,7 +130,21 @@ export async function submitProductSignal(options) {
127
130
  const adapter = new GitHubPrivateSinkAdapter({ sinkRepo: policy.sinkRepo });
128
131
  const result = await adapter.submit(payload, { gapText: options.gapText });
129
132
  if (result.outcome === "submitted") {
130
- recordLastSubmit(root, result.outcome, result.issueUrl ?? null);
133
+ try {
134
+ recordLastSubmit(root, result.outcome, result.issueUrl ?? null);
135
+ }
136
+ catch (err) {
137
+ if (err instanceof ProjectionContainmentError) {
138
+ return {
139
+ outcome: "error-config",
140
+ exitCode: 2,
141
+ message: `${err.message}\n`,
142
+ issueUrl: result.issueUrl,
143
+ payload,
144
+ };
145
+ }
146
+ throw err;
147
+ }
131
148
  }
132
149
  const urlLine = result.issueUrl ? ` url=${result.issueUrl}` : "";
133
150
  return {
@@ -150,6 +167,10 @@ export function runProductSignalStatus(projectRoot) {
150
167
  `[deft product-signal] consented=${String(consent !== null)} configuredSink=${configuredSink} consentedSink=${sinkAuth.consentedSink ?? "none"} sinksMatch=${String(sinkAuth.sinksMatch)}`,
151
168
  last ? `[deft product-signal] ${last}` : "[deft product-signal] last submit: none",
152
169
  ];
170
+ const consentPrompt = maybeFormatProductSignalConsentPrompt({ projectRoot: root });
171
+ if (consentPrompt.length > 0) {
172
+ lines.push(consentPrompt.trimEnd());
173
+ }
153
174
  return { exitCode: 0, text: `${lines.join("\n")}\n` };
154
175
  }
155
176
  export function runProductSignalEnable(projectRoot, confirm) {
@@ -8,6 +8,7 @@ export * as projectRender from "./project-render.js";
8
8
  export { acknowledgeProjectDefinitionStaleness, buildStalenessAcknowledgement, computeStalenessFlags, flagStaleNarratives, main as projectRenderMain, parseStalenessReview, renderProjectDefinition, scanLifecycleFolders, unacknowledgedCompletedItems, } from "./project-render.js";
9
9
  export * as roadmapRender from "./roadmap-render.js";
10
10
  export { checkDrift, generateRoadmapContent, main as roadmapRenderMain, renderRoadmap, renderRoadmapToBuffer, } from "./roadmap-render.js";
11
+ export { main as ruleMapMain } from "./rule-map.js";
11
12
  export { aggregateScopeSection, buildScopeOutlookSection } from "./scope-outlook.js";
12
13
  export * as specRender from "./spec-render.js";
13
14
  export { main as specRenderMain, parseIncludeScopesFlag, renderSpec } from "./spec-render.js";
@@ -8,6 +8,7 @@ export * as projectRender from "./project-render.js";
8
8
  export { acknowledgeProjectDefinitionStaleness, buildStalenessAcknowledgement, computeStalenessFlags, flagStaleNarratives, main as projectRenderMain, parseStalenessReview, renderProjectDefinition, scanLifecycleFolders, unacknowledgedCompletedItems, } from "./project-render.js";
9
9
  export * as roadmapRender from "./roadmap-render.js";
10
10
  export { checkDrift, generateRoadmapContent, main as roadmapRenderMain, renderRoadmap, renderRoadmapToBuffer, } from "./roadmap-render.js";
11
+ export { main as ruleMapMain } from "./rule-map.js";
11
12
  export { aggregateScopeSection, buildScopeOutlookSection } from "./scope-outlook.js";
12
13
  export * as specRender from "./spec-render.js";
13
14
  export { main as specRenderMain, parseIncludeScopesFlag, renderSpec } from "./spec-render.js";
@@ -0,0 +1,2 @@
1
+ export declare const TEMPLATE = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Directive \u2014 Rule Map</title>\n<style>\n :root{\n --bg:#0f1115; --panel:#171a21; --panel2:#1d222b; --line:#2a303b;\n --ink:#e7ebf0; --dim:#96a0ad; --dim2:#6b7482; --accent:#6ea8fe; --accent2:#8be0c0;\n --must:#ff6b6b; --mustnot:#c0392b; --should:#f0b429; --shouldnot:#9a7b12; --may:#7f8a99;\n --radius:12px;\n }\n *{box-sizing:border-box}\n html,body{margin:0;height:100%}\n body{background:var(--bg);color:var(--ink);\n font:15px/1.5 -apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif}\n code,.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}\n a{color:var(--accent);text-decoration:none}\n .wrap{max-width:1120px;margin:0 auto;padding:22px 24px 80px}\n header.top{display:flex;align-items:center;gap:18px;flex-wrap:wrap;\n border-bottom:1px solid var(--line);padding-bottom:16px;margin-bottom:20px}\n .brand{font-size:20px;font-weight:700;letter-spacing:.2px}\n .brand small{display:block;font-size:12px;color:var(--dim);font-weight:400;margin-top:2px}\n nav.spines{display:flex;gap:6px;margin-left:auto}\n nav.spines button{background:var(--panel);color:var(--dim);border:1px solid var(--line);\n padding:7px 14px;border-radius:999px;cursor:pointer;font-size:13px}\n nav.spines button.active{background:var(--accent);color:#0b0d10;border-color:var(--accent);font-weight:600}\n .search{width:100%;margin:0 0 18px}\n .search input{width:100%;background:var(--panel);border:1px solid var(--line);color:var(--ink);\n padding:11px 14px;border-radius:10px;font-size:14px}\n .search input::placeholder{color:var(--dim2)}\n .crumbs{display:flex;align-items:center;gap:8px;flex-wrap:wrap;color:var(--dim);font-size:13px;margin-bottom:16px}\n .crumbs a{cursor:pointer}\n .crumbs .sep{color:var(--dim2)}\n .crumbs .here{color:var(--ink)}\n .lead{color:var(--dim);margin:-4px 0 20px;max-width:760px}\n .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:12px}\n .card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);\n padding:15px 16px;cursor:pointer;transition:.12s;display:flex;flex-direction:column;gap:7px;min-height:96px}\n .card:hover{border-color:var(--accent);background:var(--panel2);transform:translateY(-1px)}\n .card .name{font-weight:600;font-size:15px;display:flex;align-items:center;gap:8px}\n .card .name .ic{color:var(--dim2);font-size:13px}\n .card .desc{color:var(--dim);font-size:13px;line-height:1.45}\n .card .meta{margin-top:auto;display:flex;align-items:center;gap:10px;color:var(--dim2);font-size:12px}\n .rows{display:flex;flex-direction:column;gap:8px}\n .row{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:12px 14px;\n cursor:pointer;transition:.12s;display:flex;align-items:center;gap:12px}\n .row:hover{border-color:var(--accent);background:var(--panel2)}\n .row .rname{font-weight:600;min-width:0}\n .row .rname .sub{font-weight:400;color:var(--dim);font-size:13px;display:block;margin-top:2px;\n overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n .row .rt{margin-left:auto;display:flex;gap:5px;flex-shrink:0}\n .row .chev{color:var(--dim2);flex-shrink:0}\n .tier{font-size:11px;padding:2px 7px;border-radius:999px;font-weight:600;white-space:nowrap;\n color:#0b0d10;font-family:ui-monospace,monospace}\n .t-MUST{background:var(--must)} .t-MUST-NOT{background:var(--mustnot);color:#fff}\n .t-SHOULD{background:var(--should)} .t-SHOULD-NOT{background:var(--shouldnot);color:#fff}\n .t-MAY{background:var(--may);color:#fff}\n .bar{display:flex;height:6px;border-radius:999px;overflow:hidden;background:var(--panel2);flex:1;max-width:120px}\n .bar span{display:block;height:100%}\n .detail{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:22px 24px}\n .detail h2{margin:0 0 4px;font-size:22px}\n .detail .kind{color:var(--dim2);font-size:12px;text-transform:uppercase;letter-spacing:.08em}\n .detail .summary{color:var(--dim);margin:12px 0 18px;max-width:720px}\n .sectionlist{display:flex;flex-wrap:wrap;gap:7px;margin:6px 0 4px}\n .sectionlist .s{background:var(--panel2);border:1px solid var(--line);border-radius:7px;\n padding:5px 10px;font-size:12.5px;color:var(--ink)}\n .srcbox{margin-top:20px;border-top:1px solid var(--line);padding-top:16px}\n .srcbox .path{font-size:12.5px;color:var(--dim);word-break:break-all;margin-bottom:10px}\n .btns{display:flex;gap:8px;flex-wrap:wrap}\n button.act{background:var(--accent);color:#0b0d10;border:none;padding:8px 14px;border-radius:8px;\n cursor:pointer;font-size:13px;font-weight:600}\n button.act.ghost{background:transparent;color:var(--accent);border:1px solid var(--line)}\n button.act:hover{filter:brightness(1.08)}\n h3.grouphdr{font-size:13px;text-transform:uppercase;letter-spacing:.08em;color:var(--dim2);margin:26px 0 10px}\n .legend{display:flex;gap:8px;flex-wrap:wrap;font-size:12px;color:var(--dim);margin:2px 0 18px}\n .toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%);background:var(--panel2);\n border:1px solid var(--line);color:var(--ink);padding:11px 18px;border-radius:10px;font-size:13px;\n opacity:0;transition:.2s;pointer-events:none;box-shadow:0 8px 30px rgba(0,0,0,.4);z-index:50}\n .toast.show{opacity:1}\n .toast.err{border-color:var(--must)}\n .flow{display:flex;flex-wrap:wrap;align-items:stretch;gap:0}\n .flow .node{background:var(--panel2);border:1px solid var(--line);border-radius:9px;padding:10px 14px;text-align:center;min-width:110px}\n .flow .node .st{font-weight:600}\n .flow .node .via{font-size:11px;color:var(--dim2);margin-top:3px;font-family:ui-monospace,monospace}\n .flow .arw{align-self:center;color:var(--dim2);padding:0 8px;font-size:18px}\n .ladder{display:flex;flex-direction:column;gap:8px;margin:6px 0 20px}\n .ladder .lv{display:flex;gap:12px;align-items:baseline;background:var(--panel);border:1px solid var(--line);border-radius:9px;padding:11px 14px}\n .ladder .lv b{min-width:190px}\n .ladder .lv .d{color:var(--dim);font-size:13px}\n .pill{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--dim);\n background:var(--panel2);border:1px solid var(--line);padding:4px 9px;border-radius:999px;margin:0 6px 6px 0}\n .muted{color:var(--dim2);font-size:12px}\n .empty{color:var(--dim);padding:30px;text-align:center}\n .foot{margin-top:34px;color:var(--dim2);font-size:12px;border-top:1px solid var(--line);padding-top:14px}\n /* source viewer */\n .src{margin-top:16px;background:#0b0d12;border:1px solid var(--line);border-radius:10px;padding:16px 18px;\n max-height:60vh;overflow:auto}\n .src h1,.src h2,.src h3{color:var(--ink);margin:14px 0 6px;line-height:1.3}\n .src h1{font-size:19px} .src h2{font-size:16px} .src h3{font-size:14px}\n .src p{margin:8px 0;color:#c7cfda}\n .src ul{margin:8px 0;padding-left:22px;color:#c7cfda}\n .src li{margin:3px 0}\n .src code{background:#161b24;border:1px solid var(--line);border-radius:5px;padding:1px 5px;font-size:12.5px;color:var(--accent2)}\n .src pre{background:#161b24;border:1px solid var(--line);border-radius:8px;padding:12px 14px;overflow:auto}\n .src pre code{background:none;border:none;padding:0;color:#c7cfda}\n .src blockquote{border-left:3px solid var(--line);margin:8px 0;padding:2px 12px;color:var(--dim)}\n .src .trunc{color:var(--dim2);font-size:12px;margin-top:10px}\n</style>\n</head>\n<body>\n<div class=\"wrap\">\n <header class=\"top\">\n <div class=\"brand\">Directive &mdash; Rule Map<small id=\"sub\">maintainer map</small></div>\n <nav class=\"spines\">\n <button data-spine=\"rules\">Rules</button>\n <button data-spine=\"tasks\">Tasks</button>\n <button data-spine=\"lifecycle\">Lifecycle</button>\n </nav>\n </header>\n\n <div class=\"search\"><input id=\"q\" placeholder=\"Search groupings, rules, tasks\u2026 (Esc to clear)\"></div>\n <div class=\"crumbs\" id=\"crumbs\"></div>\n <div id=\"view\"></div>\n <div class=\"foot\" id=\"foot\"></div>\n</div>\n<div class=\"toast\" id=\"toast\"></div>\n\n<script>window.DIRECTIVE_DATA = /*__DATA__*/ null;</script>\n<script>\nlet DATA=window.DIRECTIVE_DATA, spine=\"rules\", stack=[];\nconst el=(t,c,txt)=>{const e=document.createElement(t);if(c)e.className=c;if(txt!=null)e.textContent=txt;return e;};\nconst tierClass=t=>\"t-\"+t.replace(/\\s|_/g,\"-\");\nconst TIER_ORDER=[\"MUST\",\"MUST NOT\",\"SHOULD\",\"SHOULD NOT\",\"MAY\"];\nconst TIER_COLOR={\"MUST\":\"var(--must)\",\"MUST NOT\":\"var(--mustnot)\",\"SHOULD\":\"var(--should)\",\"SHOULD NOT\":\"var(--shouldnot)\",\"MAY\":\"var(--may)\"};\nconst MARK2TIER={\"!\":\"MUST\",\"\u2297\":\"MUST NOT\",\"~\":\"SHOULD\",\"\u2249\":\"SHOULD NOT\",\"?\":\"MAY\"};\n\nfunction toast(msg,err){const t=document.getElementById('toast');t.textContent=msg;\n t.className='toast show'+(err?' err':'');setTimeout(()=>t.className='toast',1800);}\nfunction copyPath(p){\n const ok=()=>toast(\"Path copied\");\n const fail=()=>toast(\"Copy failed\",true);\n const fallback=()=>{\n try{\n const ta=document.createElement(\"textarea\");\n ta.value=p;ta.setAttribute(\"readonly\",\"\");\n ta.style.position=\"fixed\";ta.style.left=\"-9999px\";\n document.body.appendChild(ta);ta.select();\n const done=document.execCommand(\"copy\");\n document.body.removeChild(ta);\n done?ok():fail();\n }catch(_){fail();}\n };\n if(navigator.clipboard&&typeof navigator.clipboard.writeText===\"function\"){\n navigator.clipboard.writeText(p).then(ok,fallback);\n }else fallback();\n}\n\n/* tiny zero-dependency markdown renderer (headings, lists, code, quote, inline) */\nfunction esc(s){return s.replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/>/g,\"&gt;\");}\nfunction inlineMd(s){\n s=esc(s);\n s=s.replace(/`([^`]+)`/g,'<code>$1</code>');\n s=s.replace(/\\*\\*([^*]+)\\*\\*/g,'<strong>$1</strong>');\n s=s.replace(/(^|[^*])\\*([^*]+)\\*/g,'$1<em>$2</em>');\n s=s.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g,function(_,t,u){return /^(?:https?:|[/#.])/i.test(u)?'<a href=\"'+u+'\">'+t+'</a>':t;});\n return s;\n}\nfunction mdToHtml(md){\n const lines=(md||\"\").split(\"\\n\");\n let out=[], i=0, inCode=false, code=[], list=false;\n const closeList=()=>{if(list){out.push(\"</ul>\");list=false;}};\n while(i<lines.length){\n let ln=lines[i];\n if(/^```/.test(ln)){\n if(!inCode){inCode=true;code=[];}\n else{inCode=false;out.push(\"<pre><code>\"+esc(code.join(\"\\n\"))+\"</code></pre>\");}\n i++;continue;\n }\n if(inCode){code.push(ln);i++;continue;}\n let m;\n if((m=ln.match(/^(#{1,3})\\s+(.*)$/))){closeList();out.push(`<h${m[1].length}>`+inlineMd(m[2])+`</h${m[1].length}>`);}\n else if(/^\\s*[-*]\\s+/.test(ln)){if(!list){out.push(\"<ul>\");list=true;}out.push(\"<li>\"+inlineMd(ln.replace(/^\\s*[-*]\\s+/,\"\"))+\"</li>\");}\n else if(/^\\s*>\\s?/.test(ln)){closeList();out.push(\"<blockquote>\"+inlineMd(ln.replace(/^\\s*>\\s?/,\"\"))+\"</blockquote>\");}\n else if(ln.trim()===\"\"){closeList();}\n else{closeList();out.push(\"<p>\"+inlineMd(ln)+\"</p>\");}\n i++;\n }\n closeList();\n if(inCode)out.push(\"<pre><code>\"+esc(code.join(\"\\n\"))+\"</code></pre>\");\n return out.join(\"\\n\");\n}\n\nfunction markerBar(markers){\n const total=Object.values(markers||{}).reduce((a,b)=>a+b,0);\n const bar=el('div','bar'); if(!total) return bar;\n TIER_ORDER.forEach(t=>{const v=markers[t]||0;if(!v)return;\n const s=el('span');s.style.width=(v/total*100)+'%';s.style.background=TIER_COLOR[t];s.title=t+\": \"+v;bar.appendChild(s);});\n return bar;\n}\nfunction markersFromMarks(m){const o={};for(const k in (m||{})){const t=MARK2TIER[k];if(t)o[t]=(o[t]||0)+m[k];}return o;}\nfunction totalMarks(m){return Object.values(m||{}).reduce((a,b)=>a+b,0);}\n\nfunction go(node){stack.push(node);render();}\nfunction reset(s){spine=s;stack=[];render();}\nfunction crumbTo(i){stack=stack.slice(0,i);render();}\nfunction setSpine(s){document.querySelectorAll('nav.spines button').forEach(b=>b.classList.toggle('active',b.dataset.spine===s));}\n\nfunction render(){\n setSpine(spine);\n const view=document.getElementById('view');view.innerHTML='';\n renderCrumbs();\n if(document.getElementById('q').value.trim()){renderSearch(view);return;}\n if(stack.length===0){ ({rules:overviewRules,tasks:overviewTasks,lifecycle:renderLifecycle})[spine](view); return; }\n stack[stack.length-1].render(view);\n}\nfunction renderCrumbs(){\n const c=document.getElementById('crumbs');c.innerHTML='';\n const root=el('a','',spine[0].toUpperCase()+spine.slice(1));root.onclick=()=>{stack=[];render();};c.appendChild(root);\n stack.forEach((n,i)=>{c.appendChild(el('span','sep','\u203A'));\n if(i<stack.length-1){const a=el('a','',n.label);a.onclick=()=>crumbTo(i+1);c.appendChild(a);}\n else c.appendChild(el('span','here',n.label));});\n}\nfunction intro(t){return el('div','lead',t);}\nfunction ghdr(t){return el('h3','grouphdr',t);}\nfunction pathBar(p){const box=el('div','srcbox');box.appendChild(el('div','path',p));\n const b=el('button','act ghost','Copy path');b.onclick=e=>{e.stopPropagation();copyPath(p);};\n const btns=el('div','btns');btns.appendChild(b);box.appendChild(btns);return box;}\n\nfunction overviewRules(view){\n document.getElementById('foot').textContent=\n `${DATA.groupings.length} rule groupings \u00B7 ${DATA.groupings.reduce((a,g)=>a+g.doc_count,0)} docs \u00B7 derived from content/`;\n view.appendChild(intro(\"Major rule groupings \u2014 lazy-loaded bodies of guidance the agent pulls in only when the work needs it. Click to drill in.\"));\n const grid=el('div','grid');\n DATA.groupings.forEach(g=>{\n const card=el('div','card');\n card.appendChild(el('div','name',g.name));\n card.appendChild(el('div','desc',g.purpose||''));\n const meta=el('div','meta');meta.appendChild(el('span','',g.doc_count+' docs'));meta.appendChild(markerBar(g.markers));card.appendChild(meta);\n card.onclick=()=>go({label:g.name,render:v=>groupView(v,g)});\n grid.appendChild(card);\n });\n view.appendChild(grid);\n}\nfunction groupView(view,g){\n view.appendChild(intro(g.purpose||''));\n const files=g.items.filter(i=>i.kind==='file'), dirs=g.items.filter(i=>i.kind==='dir');\n if(files.length){view.appendChild(ghdr(\"Documents\"));view.appendChild(rowsOf(files));}\n if(dirs.length){view.appendChild(ghdr(\"Topics\"));\n const grid=el('div','grid');\n dirs.forEach(d=>{const card=el('div','card');card.appendChild(el('div','name',d.title||d.name));\n if(d.summary)card.appendChild(el('div','desc',d.summary));\n const meta=el('div','meta');meta.appendChild(el('span','',d.count+' files'));card.appendChild(meta);\n card.onclick=()=>go({label:d.name,render:v=>dirView(v,d)});grid.appendChild(card);});\n view.appendChild(grid);\n }\n}\nfunction dirView(view,d){\n view.appendChild(intro(d.summary||''));\n if(d.readme){view.appendChild(ghdr(\"Overview\"));view.appendChild(rowsOf([d.readme]));}\n view.appendChild(ghdr(\"Files\"));view.appendChild(rowsOf(d.files));\n}\nfunction rowsOf(files){\n const box=el('div','rows');\n files.forEach(f=>{\n const row=el('div','row');\n const nm=el('div','rname');nm.appendChild(document.createTextNode(f.title||f.name));\n if(f.summary)nm.appendChild(el('span','sub',f.summary));\n row.appendChild(nm);\n const rt=el('div','rt');const mk=markersFromMarks(f.markers);\n TIER_ORDER.forEach(t=>{if(mk[t]){const b=el('span','tier '+tierClass(t),mk[t]+\" \"+t.replace(\" NOT\",\"\u0338\"));b.title=mk[t]+\" \"+t;rt.appendChild(b);}});\n row.appendChild(rt);row.appendChild(el('span','chev','\u203A'));\n row.onclick=()=>go({label:f.name,render:v=>docDetail(v,f)});\n box.appendChild(row);\n });\n return box;\n}\nfunction docDetail(view,f){\n const d=el('div','detail');\n d.appendChild(el('div','kind',(f.generated?'generated view \u00B7 ':'')+(f.lines?f.lines+' lines':'document')));\n d.appendChild(el('h2',null,f.title||f.name));\n if(f.summary)d.appendChild(el('div','summary',f.summary));\n const mk=markersFromMarks(f.markers);\n if(totalMarks(f.markers)){const p=el('div');p.style.margin='0 0 14px';\n TIER_ORDER.forEach(t=>{if(mk[t]){const b=el('span','tier '+tierClass(t));b.textContent=mk[t]+\" \"+t;b.style.marginRight='6px';p.appendChild(b);}});\n d.appendChild(p);}\n if(f.sections&&f.sections.length){d.appendChild(el('div','muted','Sections'));\n const sl=el('div','sectionlist');f.sections.forEach(s=>sl.appendChild(el('div','s',s)));d.appendChild(sl);}\n if(f.generated)d.appendChild(Object.assign(el('div','muted'),{textContent:'\u26A0 Auto-generated from a pack \u2014 edit the source pack, not this file.',style:'margin-top:12px'}));\n\n const box=el('div','srcbox');\n box.appendChild(el('div','path',f.path));\n const btns=el('div','btns');\n const srcPane=el('div','src');srcPane.style.display='none';\n let shown=false;\n const view_=el('button','act','View source');\n view_.onclick=e=>{e.stopPropagation();shown=!shown;\n if(shown&&!srcPane.dataset.rendered){srcPane.innerHTML=mdToHtml(f.body||'(source not captured)');\n if(f.truncated)srcPane.appendChild(Object.assign(el('div','trunc'),{textContent:'\u2026 truncated (large file); open the file directly for the rest.'}));\n srcPane.dataset.rendered='1';}\n srcPane.style.display=shown?'block':'none';view_.textContent=shown?'Hide source':'View source';};\n const copy=el('button','act ghost','Copy path');copy.onclick=e=>{e.stopPropagation();copyPath(f.path);};\n btns.appendChild(view_);btns.appendChild(copy);box.appendChild(btns);box.appendChild(srcPane);\n d.appendChild(box);\n view.appendChild(d);\n}\n\nfunction overviewTasks(view){\n document.getElementById('foot').textContent=\n `${DATA.tasks.length} task namespaces \u00B7 ${DATA.tasks.reduce((a,t)=>a+t.task_count,0)} tasks \u00B7 run: task <namespace>:<name>`;\n view.appendChild(intro(\"The executable layer. Rules are enforced by Taskfile targets \u2014 deterministic gates the agent and CI run. Each card is a namespace; drill in for its commands.\"));\n const grid=el('div','grid');\n DATA.tasks.forEach(t=>{const card=el('div','card');\n const nm=el('div','name');nm.appendChild(document.createTextNode(t.namespace));\n if(t.unlisted)nm.appendChild(Object.assign(el('span','ic'),{textContent:'unlisted'}));\n card.appendChild(nm);card.appendChild(el('div','desc',t.purpose||''));\n const meta=el('div','meta');meta.appendChild(el('span','',t.task_count+' tasks'));card.appendChild(meta);\n card.onclick=()=>go({label:t.namespace,render:v=>taskDetail(v,t)});grid.appendChild(card);});\n view.appendChild(grid);\n}\nfunction taskDetail(view,t){\n view.appendChild(intro(t.purpose||''));\n view.appendChild(ghdr(\"Commands\"));\n const box=el('div','rows');\n t.tasks.forEach(tk=>{const row=el('div','row');row.style.cursor='default';\n const nm=el('div','rname');nm.appendChild(Object.assign(el('code'),{textContent:'task '+t.namespace+':'+tk.name}));\n if(tk.desc)nm.appendChild(el('span','sub',tk.desc));row.appendChild(nm);box.appendChild(row);});\n view.appendChild(box);\n view.appendChild(pathBar(t.path));\n}\nfunction renderLifecycle(view){\n const L=DATA.lifecycle;\n document.getElementById('foot').textContent=\"Lifecycle & gates \u00B7 source: \"+L.source;\n view.appendChild(intro(L.summary));\n view.appendChild(ghdr(\"Rule strength \u2014 prefer enforceable over remembered\"));\n const lad=el('div','ladder');\n L.rule_strength.forEach((r,i)=>{const lv=el('div','lv');lv.appendChild(Object.assign(el('b'),{textContent:(i+1)+\". \"+r.level}));lv.appendChild(el('span','d',r.detail));lad.appendChild(lv);});\n view.appendChild(lad);\n view.appendChild(ghdr(\"Scope lifecycle\"));\n const flow=el('div','flow');\n L.scope_states.forEach((s,i)=>{if(i)flow.appendChild(el('div','arw','\u2192'));\n const n=el('div','node');n.appendChild(el('div','st',s.state));n.appendChild(el('div','via',s.via));flow.appendChild(n);});\n view.appendChild(flow);\n view.appendChild(ghdr(\"vBRIEF \u2014 the durable state\"));\n const box=el('div','rows');\n L.vbrief_files.forEach(v=>{const row=el('div','row');row.style.cursor='default';\n const nm=el('div','rname');nm.appendChild(Object.assign(el('code'),{textContent:v.file}));nm.appendChild(el('span','sub',v.role));row.appendChild(nm);box.appendChild(row);});\n view.appendChild(box);\n view.appendChild(ghdr(\"Quality gates\"));\n const g=el('div');g.style.marginBottom='14px';\n L.gates.forEach(x=>{const p=el('span','pill');p.appendChild(Object.assign(el('code'),{textContent:x}));g.appendChild(p);});\n view.appendChild(g);\n view.appendChild(ghdr(\"Key docs\"));\n const kd=el('div','rows');\n L.key_docs.forEach(doc=>{const row=el('div','row');row.style.cursor='default';\n const nm=el('div','rname');nm.appendChild(document.createTextNode(doc.title));nm.appendChild(el('span','sub',doc.path));row.appendChild(nm);\n const b=el('button','act ghost','Copy path');b.onclick=e=>{e.stopPropagation();copyPath(doc.path);};\n const rt=el('div','rt');rt.appendChild(b);row.appendChild(rt);kd.appendChild(row);});\n view.appendChild(kd);\n}\nfunction renderSearch(view){\n const q=document.getElementById('q').value.trim().toLowerCase();\n const hits=[];\n const push=(label,sub,onclick,tag)=>hits.push({label,sub,onclick,tag});\n DATA.groupings.forEach(g=>{\n if((g.name+\" \"+g.purpose).toLowerCase().includes(q))\n push(g.name,g.purpose,()=>{spine='rules';stack=[{label:g.name,render:v=>groupView(v,g)}];document.getElementById('q').value='';render();},\"grouping\");\n g.items.forEach(it=>{\n const scan=f=>{if((f.title+\" \"+f.name+\" \"+(f.summary||\"\")).toLowerCase().includes(q))\n push(f.title||f.name,f.summary||g.name,()=>{spine='rules';stack=[{label:g.name,render:v=>groupView(v,g)},{label:f.name,render:v=>docDetail(v,f)}];document.getElementById('q').value='';render();},g.name);};\n if(it.kind==='file')scan(it); else{if(it.readme)scan(it.readme);it.files.forEach(scan);}\n });\n });\n DATA.tasks.forEach(t=>{\n if((t.namespace+\" \"+t.purpose).toLowerCase().includes(q))\n push(\"task \"+t.namespace,t.purpose,()=>{spine='tasks';stack=[{label:t.namespace,render:v=>taskDetail(v,t)}];document.getElementById('q').value='';render();},\"tasks\");\n t.tasks.forEach(tk=>{if((tk.name+\" \"+tk.desc).toLowerCase().includes(q))\n push(\"task \"+t.namespace+\":\"+tk.name,tk.desc,()=>{spine='tasks';stack=[{label:t.namespace,render:v=>taskDetail(v,t)}];document.getElementById('q').value='';render();},\"task\");});\n });\n document.getElementById('foot').textContent=hits.length+\" matches\";\n if(!hits.length){view.appendChild(el('div','empty','No matches for \"'+q+'\"'));return;}\n const box=el('div','rows');\n hits.slice(0,120).forEach(h=>{const row=el('div','row');\n const nm=el('div','rname');nm.appendChild(document.createTextNode(h.label));if(h.sub)nm.appendChild(el('span','sub',h.sub));row.appendChild(nm);\n if(h.tag){const rt=el('div','rt');rt.appendChild(el('span','pill',h.tag));row.appendChild(rt);}\n row.appendChild(el('span','chev','\u203A'));row.onclick=h.onclick;box.appendChild(row);});\n view.appendChild(box);\n}\n\ndocument.querySelectorAll('nav.spines button').forEach(b=>b.onclick=()=>reset(b.dataset.spine));\nconst qEl=document.getElementById('q');\nqEl.addEventListener('input',render);\nqEl.addEventListener('keydown',e=>{if(e.key==='Escape'){qEl.value='';render();}});\n\nif(!DATA){document.getElementById('view').innerHTML='<div class=\"empty\">No data embedded. Rebuild with <code>task docs:rule-map</code>.</div>';}\nelse{document.getElementById('sub').textContent=\"Deft Directive \u00B7 \"+DATA.groupings.length+\" rule groups \u00B7 \"+DATA.tasks.length+\" task namespaces \u00B7 maintainer map\";render();}\n</script>\n</body>\n</html>\n";
2
+ //# sourceMappingURL=rule-map-template.d.ts.map
@@ -0,0 +1,407 @@
1
+ // Inlined Rule Map explorer template (zero runtime deps). The build (tsc) does not
2
+ // copy non-.ts assets, so the HTML shell ships as a string constant compiled with
3
+ // the code. It is a plain template literal — edit the HTML/CSS/JS in place here;
4
+ // keep it a literal (escape only a backtick as \` and a literal ${ as \${), since
5
+ // rule-map.ts injects the data by string-replacing the `/*__DATA__*/ null` token.
6
+ export const TEMPLATE = `<!DOCTYPE html>
7
+ <html lang="en">
8
+ <head>
9
+ <meta charset="utf-8">
10
+ <meta name="viewport" content="width=device-width, initial-scale=1">
11
+ <title>Directive — Rule Map</title>
12
+ <style>
13
+ :root{
14
+ --bg:#0f1115; --panel:#171a21; --panel2:#1d222b; --line:#2a303b;
15
+ --ink:#e7ebf0; --dim:#96a0ad; --dim2:#6b7482; --accent:#6ea8fe; --accent2:#8be0c0;
16
+ --must:#ff6b6b; --mustnot:#c0392b; --should:#f0b429; --shouldnot:#9a7b12; --may:#7f8a99;
17
+ --radius:12px;
18
+ }
19
+ *{box-sizing:border-box}
20
+ html,body{margin:0;height:100%}
21
+ body{background:var(--bg);color:var(--ink);
22
+ font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
23
+ code,.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
24
+ a{color:var(--accent);text-decoration:none}
25
+ .wrap{max-width:1120px;margin:0 auto;padding:22px 24px 80px}
26
+ header.top{display:flex;align-items:center;gap:18px;flex-wrap:wrap;
27
+ border-bottom:1px solid var(--line);padding-bottom:16px;margin-bottom:20px}
28
+ .brand{font-size:20px;font-weight:700;letter-spacing:.2px}
29
+ .brand small{display:block;font-size:12px;color:var(--dim);font-weight:400;margin-top:2px}
30
+ nav.spines{display:flex;gap:6px;margin-left:auto}
31
+ nav.spines button{background:var(--panel);color:var(--dim);border:1px solid var(--line);
32
+ padding:7px 14px;border-radius:999px;cursor:pointer;font-size:13px}
33
+ nav.spines button.active{background:var(--accent);color:#0b0d10;border-color:var(--accent);font-weight:600}
34
+ .search{width:100%;margin:0 0 18px}
35
+ .search input{width:100%;background:var(--panel);border:1px solid var(--line);color:var(--ink);
36
+ padding:11px 14px;border-radius:10px;font-size:14px}
37
+ .search input::placeholder{color:var(--dim2)}
38
+ .crumbs{display:flex;align-items:center;gap:8px;flex-wrap:wrap;color:var(--dim);font-size:13px;margin-bottom:16px}
39
+ .crumbs a{cursor:pointer}
40
+ .crumbs .sep{color:var(--dim2)}
41
+ .crumbs .here{color:var(--ink)}
42
+ .lead{color:var(--dim);margin:-4px 0 20px;max-width:760px}
43
+ .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:12px}
44
+ .card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
45
+ padding:15px 16px;cursor:pointer;transition:.12s;display:flex;flex-direction:column;gap:7px;min-height:96px}
46
+ .card:hover{border-color:var(--accent);background:var(--panel2);transform:translateY(-1px)}
47
+ .card .name{font-weight:600;font-size:15px;display:flex;align-items:center;gap:8px}
48
+ .card .name .ic{color:var(--dim2);font-size:13px}
49
+ .card .desc{color:var(--dim);font-size:13px;line-height:1.45}
50
+ .card .meta{margin-top:auto;display:flex;align-items:center;gap:10px;color:var(--dim2);font-size:12px}
51
+ .rows{display:flex;flex-direction:column;gap:8px}
52
+ .row{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:12px 14px;
53
+ cursor:pointer;transition:.12s;display:flex;align-items:center;gap:12px}
54
+ .row:hover{border-color:var(--accent);background:var(--panel2)}
55
+ .row .rname{font-weight:600;min-width:0}
56
+ .row .rname .sub{font-weight:400;color:var(--dim);font-size:13px;display:block;margin-top:2px;
57
+ overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
58
+ .row .rt{margin-left:auto;display:flex;gap:5px;flex-shrink:0}
59
+ .row .chev{color:var(--dim2);flex-shrink:0}
60
+ .tier{font-size:11px;padding:2px 7px;border-radius:999px;font-weight:600;white-space:nowrap;
61
+ color:#0b0d10;font-family:ui-monospace,monospace}
62
+ .t-MUST{background:var(--must)} .t-MUST-NOT{background:var(--mustnot);color:#fff}
63
+ .t-SHOULD{background:var(--should)} .t-SHOULD-NOT{background:var(--shouldnot);color:#fff}
64
+ .t-MAY{background:var(--may);color:#fff}
65
+ .bar{display:flex;height:6px;border-radius:999px;overflow:hidden;background:var(--panel2);flex:1;max-width:120px}
66
+ .bar span{display:block;height:100%}
67
+ .detail{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:22px 24px}
68
+ .detail h2{margin:0 0 4px;font-size:22px}
69
+ .detail .kind{color:var(--dim2);font-size:12px;text-transform:uppercase;letter-spacing:.08em}
70
+ .detail .summary{color:var(--dim);margin:12px 0 18px;max-width:720px}
71
+ .sectionlist{display:flex;flex-wrap:wrap;gap:7px;margin:6px 0 4px}
72
+ .sectionlist .s{background:var(--panel2);border:1px solid var(--line);border-radius:7px;
73
+ padding:5px 10px;font-size:12.5px;color:var(--ink)}
74
+ .srcbox{margin-top:20px;border-top:1px solid var(--line);padding-top:16px}
75
+ .srcbox .path{font-size:12.5px;color:var(--dim);word-break:break-all;margin-bottom:10px}
76
+ .btns{display:flex;gap:8px;flex-wrap:wrap}
77
+ button.act{background:var(--accent);color:#0b0d10;border:none;padding:8px 14px;border-radius:8px;
78
+ cursor:pointer;font-size:13px;font-weight:600}
79
+ button.act.ghost{background:transparent;color:var(--accent);border:1px solid var(--line)}
80
+ button.act:hover{filter:brightness(1.08)}
81
+ h3.grouphdr{font-size:13px;text-transform:uppercase;letter-spacing:.08em;color:var(--dim2);margin:26px 0 10px}
82
+ .legend{display:flex;gap:8px;flex-wrap:wrap;font-size:12px;color:var(--dim);margin:2px 0 18px}
83
+ .toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%);background:var(--panel2);
84
+ border:1px solid var(--line);color:var(--ink);padding:11px 18px;border-radius:10px;font-size:13px;
85
+ opacity:0;transition:.2s;pointer-events:none;box-shadow:0 8px 30px rgba(0,0,0,.4);z-index:50}
86
+ .toast.show{opacity:1}
87
+ .toast.err{border-color:var(--must)}
88
+ .flow{display:flex;flex-wrap:wrap;align-items:stretch;gap:0}
89
+ .flow .node{background:var(--panel2);border:1px solid var(--line);border-radius:9px;padding:10px 14px;text-align:center;min-width:110px}
90
+ .flow .node .st{font-weight:600}
91
+ .flow .node .via{font-size:11px;color:var(--dim2);margin-top:3px;font-family:ui-monospace,monospace}
92
+ .flow .arw{align-self:center;color:var(--dim2);padding:0 8px;font-size:18px}
93
+ .ladder{display:flex;flex-direction:column;gap:8px;margin:6px 0 20px}
94
+ .ladder .lv{display:flex;gap:12px;align-items:baseline;background:var(--panel);border:1px solid var(--line);border-radius:9px;padding:11px 14px}
95
+ .ladder .lv b{min-width:190px}
96
+ .ladder .lv .d{color:var(--dim);font-size:13px}
97
+ .pill{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--dim);
98
+ background:var(--panel2);border:1px solid var(--line);padding:4px 9px;border-radius:999px;margin:0 6px 6px 0}
99
+ .muted{color:var(--dim2);font-size:12px}
100
+ .empty{color:var(--dim);padding:30px;text-align:center}
101
+ .foot{margin-top:34px;color:var(--dim2);font-size:12px;border-top:1px solid var(--line);padding-top:14px}
102
+ /* source viewer */
103
+ .src{margin-top:16px;background:#0b0d12;border:1px solid var(--line);border-radius:10px;padding:16px 18px;
104
+ max-height:60vh;overflow:auto}
105
+ .src h1,.src h2,.src h3{color:var(--ink);margin:14px 0 6px;line-height:1.3}
106
+ .src h1{font-size:19px} .src h2{font-size:16px} .src h3{font-size:14px}
107
+ .src p{margin:8px 0;color:#c7cfda}
108
+ .src ul{margin:8px 0;padding-left:22px;color:#c7cfda}
109
+ .src li{margin:3px 0}
110
+ .src code{background:#161b24;border:1px solid var(--line);border-radius:5px;padding:1px 5px;font-size:12.5px;color:var(--accent2)}
111
+ .src pre{background:#161b24;border:1px solid var(--line);border-radius:8px;padding:12px 14px;overflow:auto}
112
+ .src pre code{background:none;border:none;padding:0;color:#c7cfda}
113
+ .src blockquote{border-left:3px solid var(--line);margin:8px 0;padding:2px 12px;color:var(--dim)}
114
+ .src .trunc{color:var(--dim2);font-size:12px;margin-top:10px}
115
+ </style>
116
+ </head>
117
+ <body>
118
+ <div class="wrap">
119
+ <header class="top">
120
+ <div class="brand">Directive &mdash; Rule Map<small id="sub">maintainer map</small></div>
121
+ <nav class="spines">
122
+ <button data-spine="rules">Rules</button>
123
+ <button data-spine="tasks">Tasks</button>
124
+ <button data-spine="lifecycle">Lifecycle</button>
125
+ </nav>
126
+ </header>
127
+
128
+ <div class="search"><input id="q" placeholder="Search groupings, rules, tasks… (Esc to clear)"></div>
129
+ <div class="crumbs" id="crumbs"></div>
130
+ <div id="view"></div>
131
+ <div class="foot" id="foot"></div>
132
+ </div>
133
+ <div class="toast" id="toast"></div>
134
+
135
+ <script>window.DIRECTIVE_DATA = /*__DATA__*/ null;</script>
136
+ <script>
137
+ let DATA=window.DIRECTIVE_DATA, spine="rules", stack=[];
138
+ const el=(t,c,txt)=>{const e=document.createElement(t);if(c)e.className=c;if(txt!=null)e.textContent=txt;return e;};
139
+ const tierClass=t=>"t-"+t.replace(/\\s|_/g,"-");
140
+ const TIER_ORDER=["MUST","MUST NOT","SHOULD","SHOULD NOT","MAY"];
141
+ const TIER_COLOR={"MUST":"var(--must)","MUST NOT":"var(--mustnot)","SHOULD":"var(--should)","SHOULD NOT":"var(--shouldnot)","MAY":"var(--may)"};
142
+ const MARK2TIER={"!":"MUST","⊗":"MUST NOT","~":"SHOULD","≉":"SHOULD NOT","?":"MAY"};
143
+
144
+ function toast(msg,err){const t=document.getElementById('toast');t.textContent=msg;
145
+ t.className='toast show'+(err?' err':'');setTimeout(()=>t.className='toast',1800);}
146
+ function copyPath(p){
147
+ const ok=()=>toast("Path copied");
148
+ const fail=()=>toast("Copy failed",true);
149
+ const fallback=()=>{
150
+ try{
151
+ const ta=document.createElement("textarea");
152
+ ta.value=p;ta.setAttribute("readonly","");
153
+ ta.style.position="fixed";ta.style.left="-9999px";
154
+ document.body.appendChild(ta);ta.select();
155
+ const done=document.execCommand("copy");
156
+ document.body.removeChild(ta);
157
+ done?ok():fail();
158
+ }catch(_){fail();}
159
+ };
160
+ if(navigator.clipboard&&typeof navigator.clipboard.writeText==="function"){
161
+ navigator.clipboard.writeText(p).then(ok,fallback);
162
+ }else fallback();
163
+ }
164
+
165
+ /* tiny zero-dependency markdown renderer (headings, lists, code, quote, inline) */
166
+ function esc(s){return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");}
167
+ function inlineMd(s){
168
+ s=esc(s);
169
+ s=s.replace(/\`([^\`]+)\`/g,'<code>$1</code>');
170
+ s=s.replace(/\\*\\*([^*]+)\\*\\*/g,'<strong>$1</strong>');
171
+ s=s.replace(/(^|[^*])\\*([^*]+)\\*/g,'$1<em>$2</em>');
172
+ s=s.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g,function(_,t,u){return /^(?:https?:|[/#.])/i.test(u)?'<a href="'+u+'">'+t+'</a>':t;});
173
+ return s;
174
+ }
175
+ function mdToHtml(md){
176
+ const lines=(md||"").split("\\n");
177
+ let out=[], i=0, inCode=false, code=[], list=false;
178
+ const closeList=()=>{if(list){out.push("</ul>");list=false;}};
179
+ while(i<lines.length){
180
+ let ln=lines[i];
181
+ if(/^\`\`\`/.test(ln)){
182
+ if(!inCode){inCode=true;code=[];}
183
+ else{inCode=false;out.push("<pre><code>"+esc(code.join("\\n"))+"</code></pre>");}
184
+ i++;continue;
185
+ }
186
+ if(inCode){code.push(ln);i++;continue;}
187
+ let m;
188
+ if((m=ln.match(/^(#{1,3})\\s+(.*)$/))){closeList();out.push(\`<h\${m[1].length}>\`+inlineMd(m[2])+\`</h\${m[1].length}>\`);}
189
+ else if(/^\\s*[-*]\\s+/.test(ln)){if(!list){out.push("<ul>");list=true;}out.push("<li>"+inlineMd(ln.replace(/^\\s*[-*]\\s+/,""))+"</li>");}
190
+ else if(/^\\s*>\\s?/.test(ln)){closeList();out.push("<blockquote>"+inlineMd(ln.replace(/^\\s*>\\s?/,""))+"</blockquote>");}
191
+ else if(ln.trim()===""){closeList();}
192
+ else{closeList();out.push("<p>"+inlineMd(ln)+"</p>");}
193
+ i++;
194
+ }
195
+ closeList();
196
+ if(inCode)out.push("<pre><code>"+esc(code.join("\\n"))+"</code></pre>");
197
+ return out.join("\\n");
198
+ }
199
+
200
+ function markerBar(markers){
201
+ const total=Object.values(markers||{}).reduce((a,b)=>a+b,0);
202
+ const bar=el('div','bar'); if(!total) return bar;
203
+ TIER_ORDER.forEach(t=>{const v=markers[t]||0;if(!v)return;
204
+ const s=el('span');s.style.width=(v/total*100)+'%';s.style.background=TIER_COLOR[t];s.title=t+": "+v;bar.appendChild(s);});
205
+ return bar;
206
+ }
207
+ function markersFromMarks(m){const o={};for(const k in (m||{})){const t=MARK2TIER[k];if(t)o[t]=(o[t]||0)+m[k];}return o;}
208
+ function totalMarks(m){return Object.values(m||{}).reduce((a,b)=>a+b,0);}
209
+
210
+ function go(node){stack.push(node);render();}
211
+ function reset(s){spine=s;stack=[];render();}
212
+ function crumbTo(i){stack=stack.slice(0,i);render();}
213
+ function setSpine(s){document.querySelectorAll('nav.spines button').forEach(b=>b.classList.toggle('active',b.dataset.spine===s));}
214
+
215
+ function render(){
216
+ setSpine(spine);
217
+ const view=document.getElementById('view');view.innerHTML='';
218
+ renderCrumbs();
219
+ if(document.getElementById('q').value.trim()){renderSearch(view);return;}
220
+ if(stack.length===0){ ({rules:overviewRules,tasks:overviewTasks,lifecycle:renderLifecycle})[spine](view); return; }
221
+ stack[stack.length-1].render(view);
222
+ }
223
+ function renderCrumbs(){
224
+ const c=document.getElementById('crumbs');c.innerHTML='';
225
+ const root=el('a','',spine[0].toUpperCase()+spine.slice(1));root.onclick=()=>{stack=[];render();};c.appendChild(root);
226
+ stack.forEach((n,i)=>{c.appendChild(el('span','sep','›'));
227
+ if(i<stack.length-1){const a=el('a','',n.label);a.onclick=()=>crumbTo(i+1);c.appendChild(a);}
228
+ else c.appendChild(el('span','here',n.label));});
229
+ }
230
+ function intro(t){return el('div','lead',t);}
231
+ function ghdr(t){return el('h3','grouphdr',t);}
232
+ function pathBar(p){const box=el('div','srcbox');box.appendChild(el('div','path',p));
233
+ const b=el('button','act ghost','Copy path');b.onclick=e=>{e.stopPropagation();copyPath(p);};
234
+ const btns=el('div','btns');btns.appendChild(b);box.appendChild(btns);return box;}
235
+
236
+ function overviewRules(view){
237
+ document.getElementById('foot').textContent=
238
+ \`\${DATA.groupings.length} rule groupings · \${DATA.groupings.reduce((a,g)=>a+g.doc_count,0)} docs · derived from content/\`;
239
+ view.appendChild(intro("Major rule groupings — lazy-loaded bodies of guidance the agent pulls in only when the work needs it. Click to drill in."));
240
+ const grid=el('div','grid');
241
+ DATA.groupings.forEach(g=>{
242
+ const card=el('div','card');
243
+ card.appendChild(el('div','name',g.name));
244
+ card.appendChild(el('div','desc',g.purpose||''));
245
+ const meta=el('div','meta');meta.appendChild(el('span','',g.doc_count+' docs'));meta.appendChild(markerBar(g.markers));card.appendChild(meta);
246
+ card.onclick=()=>go({label:g.name,render:v=>groupView(v,g)});
247
+ grid.appendChild(card);
248
+ });
249
+ view.appendChild(grid);
250
+ }
251
+ function groupView(view,g){
252
+ view.appendChild(intro(g.purpose||''));
253
+ const files=g.items.filter(i=>i.kind==='file'), dirs=g.items.filter(i=>i.kind==='dir');
254
+ if(files.length){view.appendChild(ghdr("Documents"));view.appendChild(rowsOf(files));}
255
+ if(dirs.length){view.appendChild(ghdr("Topics"));
256
+ const grid=el('div','grid');
257
+ dirs.forEach(d=>{const card=el('div','card');card.appendChild(el('div','name',d.title||d.name));
258
+ if(d.summary)card.appendChild(el('div','desc',d.summary));
259
+ const meta=el('div','meta');meta.appendChild(el('span','',d.count+' files'));card.appendChild(meta);
260
+ card.onclick=()=>go({label:d.name,render:v=>dirView(v,d)});grid.appendChild(card);});
261
+ view.appendChild(grid);
262
+ }
263
+ }
264
+ function dirView(view,d){
265
+ view.appendChild(intro(d.summary||''));
266
+ if(d.readme){view.appendChild(ghdr("Overview"));view.appendChild(rowsOf([d.readme]));}
267
+ view.appendChild(ghdr("Files"));view.appendChild(rowsOf(d.files));
268
+ }
269
+ function rowsOf(files){
270
+ const box=el('div','rows');
271
+ files.forEach(f=>{
272
+ const row=el('div','row');
273
+ const nm=el('div','rname');nm.appendChild(document.createTextNode(f.title||f.name));
274
+ if(f.summary)nm.appendChild(el('span','sub',f.summary));
275
+ row.appendChild(nm);
276
+ const rt=el('div','rt');const mk=markersFromMarks(f.markers);
277
+ TIER_ORDER.forEach(t=>{if(mk[t]){const b=el('span','tier '+tierClass(t),mk[t]+" "+t.replace(" NOT","̸"));b.title=mk[t]+" "+t;rt.appendChild(b);}});
278
+ row.appendChild(rt);row.appendChild(el('span','chev','›'));
279
+ row.onclick=()=>go({label:f.name,render:v=>docDetail(v,f)});
280
+ box.appendChild(row);
281
+ });
282
+ return box;
283
+ }
284
+ function docDetail(view,f){
285
+ const d=el('div','detail');
286
+ d.appendChild(el('div','kind',(f.generated?'generated view · ':'')+(f.lines?f.lines+' lines':'document')));
287
+ d.appendChild(el('h2',null,f.title||f.name));
288
+ if(f.summary)d.appendChild(el('div','summary',f.summary));
289
+ const mk=markersFromMarks(f.markers);
290
+ if(totalMarks(f.markers)){const p=el('div');p.style.margin='0 0 14px';
291
+ TIER_ORDER.forEach(t=>{if(mk[t]){const b=el('span','tier '+tierClass(t));b.textContent=mk[t]+" "+t;b.style.marginRight='6px';p.appendChild(b);}});
292
+ d.appendChild(p);}
293
+ if(f.sections&&f.sections.length){d.appendChild(el('div','muted','Sections'));
294
+ const sl=el('div','sectionlist');f.sections.forEach(s=>sl.appendChild(el('div','s',s)));d.appendChild(sl);}
295
+ if(f.generated)d.appendChild(Object.assign(el('div','muted'),{textContent:'⚠ Auto-generated from a pack — edit the source pack, not this file.',style:'margin-top:12px'}));
296
+
297
+ const box=el('div','srcbox');
298
+ box.appendChild(el('div','path',f.path));
299
+ const btns=el('div','btns');
300
+ const srcPane=el('div','src');srcPane.style.display='none';
301
+ let shown=false;
302
+ const view_=el('button','act','View source');
303
+ view_.onclick=e=>{e.stopPropagation();shown=!shown;
304
+ if(shown&&!srcPane.dataset.rendered){srcPane.innerHTML=mdToHtml(f.body||'(source not captured)');
305
+ if(f.truncated)srcPane.appendChild(Object.assign(el('div','trunc'),{textContent:'… truncated (large file); open the file directly for the rest.'}));
306
+ srcPane.dataset.rendered='1';}
307
+ srcPane.style.display=shown?'block':'none';view_.textContent=shown?'Hide source':'View source';};
308
+ const copy=el('button','act ghost','Copy path');copy.onclick=e=>{e.stopPropagation();copyPath(f.path);};
309
+ btns.appendChild(view_);btns.appendChild(copy);box.appendChild(btns);box.appendChild(srcPane);
310
+ d.appendChild(box);
311
+ view.appendChild(d);
312
+ }
313
+
314
+ function overviewTasks(view){
315
+ document.getElementById('foot').textContent=
316
+ \`\${DATA.tasks.length} task namespaces · \${DATA.tasks.reduce((a,t)=>a+t.task_count,0)} tasks · run: task <namespace>:<name>\`;
317
+ view.appendChild(intro("The executable layer. Rules are enforced by Taskfile targets — deterministic gates the agent and CI run. Each card is a namespace; drill in for its commands."));
318
+ const grid=el('div','grid');
319
+ DATA.tasks.forEach(t=>{const card=el('div','card');
320
+ const nm=el('div','name');nm.appendChild(document.createTextNode(t.namespace));
321
+ if(t.unlisted)nm.appendChild(Object.assign(el('span','ic'),{textContent:'unlisted'}));
322
+ card.appendChild(nm);card.appendChild(el('div','desc',t.purpose||''));
323
+ const meta=el('div','meta');meta.appendChild(el('span','',t.task_count+' tasks'));card.appendChild(meta);
324
+ card.onclick=()=>go({label:t.namespace,render:v=>taskDetail(v,t)});grid.appendChild(card);});
325
+ view.appendChild(grid);
326
+ }
327
+ function taskDetail(view,t){
328
+ view.appendChild(intro(t.purpose||''));
329
+ view.appendChild(ghdr("Commands"));
330
+ const box=el('div','rows');
331
+ t.tasks.forEach(tk=>{const row=el('div','row');row.style.cursor='default';
332
+ const nm=el('div','rname');nm.appendChild(Object.assign(el('code'),{textContent:'task '+t.namespace+':'+tk.name}));
333
+ if(tk.desc)nm.appendChild(el('span','sub',tk.desc));row.appendChild(nm);box.appendChild(row);});
334
+ view.appendChild(box);
335
+ view.appendChild(pathBar(t.path));
336
+ }
337
+ function renderLifecycle(view){
338
+ const L=DATA.lifecycle;
339
+ document.getElementById('foot').textContent="Lifecycle & gates · source: "+L.source;
340
+ view.appendChild(intro(L.summary));
341
+ view.appendChild(ghdr("Rule strength — prefer enforceable over remembered"));
342
+ const lad=el('div','ladder');
343
+ L.rule_strength.forEach((r,i)=>{const lv=el('div','lv');lv.appendChild(Object.assign(el('b'),{textContent:(i+1)+". "+r.level}));lv.appendChild(el('span','d',r.detail));lad.appendChild(lv);});
344
+ view.appendChild(lad);
345
+ view.appendChild(ghdr("Scope lifecycle"));
346
+ const flow=el('div','flow');
347
+ L.scope_states.forEach((s,i)=>{if(i)flow.appendChild(el('div','arw','→'));
348
+ const n=el('div','node');n.appendChild(el('div','st',s.state));n.appendChild(el('div','via',s.via));flow.appendChild(n);});
349
+ view.appendChild(flow);
350
+ view.appendChild(ghdr("vBRIEF — the durable state"));
351
+ const box=el('div','rows');
352
+ L.vbrief_files.forEach(v=>{const row=el('div','row');row.style.cursor='default';
353
+ const nm=el('div','rname');nm.appendChild(Object.assign(el('code'),{textContent:v.file}));nm.appendChild(el('span','sub',v.role));row.appendChild(nm);box.appendChild(row);});
354
+ view.appendChild(box);
355
+ view.appendChild(ghdr("Quality gates"));
356
+ const g=el('div');g.style.marginBottom='14px';
357
+ L.gates.forEach(x=>{const p=el('span','pill');p.appendChild(Object.assign(el('code'),{textContent:x}));g.appendChild(p);});
358
+ view.appendChild(g);
359
+ view.appendChild(ghdr("Key docs"));
360
+ const kd=el('div','rows');
361
+ L.key_docs.forEach(doc=>{const row=el('div','row');row.style.cursor='default';
362
+ const nm=el('div','rname');nm.appendChild(document.createTextNode(doc.title));nm.appendChild(el('span','sub',doc.path));row.appendChild(nm);
363
+ const b=el('button','act ghost','Copy path');b.onclick=e=>{e.stopPropagation();copyPath(doc.path);};
364
+ const rt=el('div','rt');rt.appendChild(b);row.appendChild(rt);kd.appendChild(row);});
365
+ view.appendChild(kd);
366
+ }
367
+ function renderSearch(view){
368
+ const q=document.getElementById('q').value.trim().toLowerCase();
369
+ const hits=[];
370
+ const push=(label,sub,onclick,tag)=>hits.push({label,sub,onclick,tag});
371
+ DATA.groupings.forEach(g=>{
372
+ if((g.name+" "+g.purpose).toLowerCase().includes(q))
373
+ push(g.name,g.purpose,()=>{spine='rules';stack=[{label:g.name,render:v=>groupView(v,g)}];document.getElementById('q').value='';render();},"grouping");
374
+ g.items.forEach(it=>{
375
+ const scan=f=>{if((f.title+" "+f.name+" "+(f.summary||"")).toLowerCase().includes(q))
376
+ push(f.title||f.name,f.summary||g.name,()=>{spine='rules';stack=[{label:g.name,render:v=>groupView(v,g)},{label:f.name,render:v=>docDetail(v,f)}];document.getElementById('q').value='';render();},g.name);};
377
+ if(it.kind==='file')scan(it); else{if(it.readme)scan(it.readme);it.files.forEach(scan);}
378
+ });
379
+ });
380
+ DATA.tasks.forEach(t=>{
381
+ if((t.namespace+" "+t.purpose).toLowerCase().includes(q))
382
+ push("task "+t.namespace,t.purpose,()=>{spine='tasks';stack=[{label:t.namespace,render:v=>taskDetail(v,t)}];document.getElementById('q').value='';render();},"tasks");
383
+ t.tasks.forEach(tk=>{if((tk.name+" "+tk.desc).toLowerCase().includes(q))
384
+ push("task "+t.namespace+":"+tk.name,tk.desc,()=>{spine='tasks';stack=[{label:t.namespace,render:v=>taskDetail(v,t)}];document.getElementById('q').value='';render();},"task");});
385
+ });
386
+ document.getElementById('foot').textContent=hits.length+" matches";
387
+ if(!hits.length){view.appendChild(el('div','empty','No matches for "'+q+'"'));return;}
388
+ const box=el('div','rows');
389
+ hits.slice(0,120).forEach(h=>{const row=el('div','row');
390
+ const nm=el('div','rname');nm.appendChild(document.createTextNode(h.label));if(h.sub)nm.appendChild(el('span','sub',h.sub));row.appendChild(nm);
391
+ if(h.tag){const rt=el('div','rt');rt.appendChild(el('span','pill',h.tag));row.appendChild(rt);}
392
+ row.appendChild(el('span','chev','›'));row.onclick=h.onclick;box.appendChild(row);});
393
+ view.appendChild(box);
394
+ }
395
+
396
+ document.querySelectorAll('nav.spines button').forEach(b=>b.onclick=()=>reset(b.dataset.spine));
397
+ const qEl=document.getElementById('q');
398
+ qEl.addEventListener('input',render);
399
+ qEl.addEventListener('keydown',e=>{if(e.key==='Escape'){qEl.value='';render();}});
400
+
401
+ if(!DATA){document.getElementById('view').innerHTML='<div class="empty">No data embedded. Rebuild with <code>task docs:rule-map</code>.</div>';}
402
+ else{document.getElementById('sub').textContent="Deft Directive · "+DATA.groupings.length+" rule groups · "+DATA.tasks.length+" task namespaces · maintainer map";render();}
403
+ </script>
404
+ </body>
405
+ </html>
406
+ `;
407
+ //# sourceMappingURL=rule-map-template.js.map
@@ -0,0 +1,2 @@
1
+ export declare function main(argv: readonly string[]): number;
2
+ //# sourceMappingURL=rule-map.d.ts.map