@azure-id/orc 1.8.1 → 1.8.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 (46) hide show
  1. package/CHANGELOG.md +220 -0
  2. package/README-id.md +90 -71
  3. package/README.md +77 -31
  4. package/bin/cli.js +45460 -44867
  5. package/bin/graph-extract.js +2409 -120
  6. package/bin/graph-gain.js +404 -0
  7. package/bin/graph-map.js +232 -0
  8. package/bin/graph-notes.js +49 -8
  9. package/bin/graph-query.js +1770 -808
  10. package/bin/graph-resolve.js +93 -16
  11. package/bin/graph-shard.js +325 -0
  12. package/bin/graph.js +658 -605
  13. package/bin/verify-contracts.js +140 -0
  14. package/bin/verify-package.js +14 -0
  15. package/bin/webui/api.js +6 -0
  16. package/bin/webui/fixtures/index.js +6 -1
  17. package/bin/webui/fixtures/knowledge.js +41 -1
  18. package/bin/webui/fixtures/stats.js +107 -104
  19. package/bin/webui/i18n/en/knowledge.json +16 -1
  20. package/bin/webui/i18n/id/knowledge.json +16 -1
  21. package/bin/webui/js/panels/knowledge.js +68 -3
  22. package/package.json +1 -1
  23. package/templates/agents/orc-executor-haiku-4-5.md +8 -13
  24. package/templates/agents/orc-executor-opus-4-7-high.md +8 -13
  25. package/templates/agents/orc-executor-opus-4-7-med.md +8 -13
  26. package/templates/agents/orc-executor-opus-4-8-high.md +8 -13
  27. package/templates/agents/orc-executor-opus-5-high.md +8 -13
  28. package/templates/agents/orc-executor-opus-5-low.md +8 -13
  29. package/templates/agents/orc-executor-opus-5-med.md +8 -13
  30. package/templates/agents/orc-executor-sonnet-4-6-high.md +8 -13
  31. package/templates/agents/orc-executor-sonnet-4-6-med.md +8 -13
  32. package/templates/agents/orc-executor-sonnet-5-high.md +8 -13
  33. package/templates/agents/orc-graph-noter-sonnet-4-6-med.md +15 -12
  34. package/templates/hooks/README.md +13 -3
  35. package/templates/hooks/orc-graph-hook.js +148 -13
  36. package/templates/skills/_shared/code-graph.md +148 -20
  37. package/templates/skills/_shared/phases/execution.md +13 -11
  38. package/templates/skills/_shared/phases/planning.md +8 -1
  39. package/templates/skills/_shared/phases/ship.md +5 -1
  40. package/templates/skills/_shared/phases/trace.md +2 -0
  41. package/templates/skills/_shared/phases/wiki-consult.md +1 -1
  42. package/templates/skills/_shared/read-ladder.md +10 -2
  43. package/templates/skills/orc/SKILL.md +1 -1
  44. package/templates/skills/orc-analyze/SKILL.md +13 -13
  45. package/templates/skills/orc-diy/references/flow-schema.md +1 -1
  46. package/templates/skills/orc-wiki/references/staleness.md +1 -1
@@ -82,19 +82,33 @@ function noteIndex(claudeDir) {
82
82
  return { byKey, bySym, rows: rows.length };
83
83
  }
84
84
 
85
+ // The ONE resolution rule, shared by every reader:
86
+ //
87
+ // 1. a CURRENT model note — somebody paid for it and it still describes
88
+ // this body
89
+ // 2. the DOC note (N1) — the author's own first sentence, re-extracted
90
+ // with the body, so it is never stale on its own
91
+ // 3. a STALE model note — reported as stale, never repeated as a fact
92
+ //
93
+ // A doc outranks a stale note because a sentence that matches the current
94
+ // bytes beats one that matched a body nobody has any more. It does NOT
95
+ // outrank a current model note: a comment can lie, and the model read the code.
96
+ // That is why the shared precedence line reads `graph notes and doc notes` as
97
+ // ONE rung, below a stale wiki — this function is the code half of it.
85
98
  function noteFor(idx, sym) {
86
- if (!idx || !sym) return null;
87
- const cur = idx.byKey.get(`${sym.id}\0${sym.body_hash}`);
88
- if (cur) return { text: cur.note, model: cur.model, at: cur.at, current: true };
89
- const any = idx.bySym.get(sym.id);
90
- if (any) return { text: null, model: any.model, at: any.at, current: false };
99
+ if (!sym) return null;
100
+ const cur = idx && idx.byKey.get(`${sym.id}\0${sym.body_hash}`);
101
+ if (cur) return { text: cur.note, model: cur.model, at: cur.at, current: true, source: "model" };
102
+ if (sym.doc) return { text: sym.doc, model: "parser", at: null, current: true, source: "doc" };
103
+ const any = idx && idx.bySym.get(sym.id);
104
+ if (any) return { text: null, model: any.model, at: any.at, current: false, source: "model" };
91
105
  return null;
92
106
  }
93
107
 
94
108
  const normPath = (f) => String(f).replace(/\\/g, "/").replace(/^\.\//, "");
95
109
 
96
110
  // exit 0 = rows to note · 1 = no index / no --files · 5 = none, or fewer than --min
97
- function notesPending(claudeDir, opts) {
111
+ function notesPending(claudeDir, opts, root) {
98
112
  const index = readIndex(claudeDir);
99
113
  if (!index || !index.by_file) return { ok: false, state: "none", reason: "no-index", exit: 1 };
100
114
  const files = [...new Set((opts.files || []).map(normPath).filter(Boolean))];
@@ -104,6 +118,7 @@ function notesPending(claudeDir, opts) {
104
118
  const idx = noteIndex(claudeDir);
105
119
  const missing = [];
106
120
  const rows = [];
121
+ let documented = 0;
107
122
  for (const rel of files) {
108
123
  const f = index.by_file[rel];
109
124
  if (!f) {
@@ -114,14 +129,40 @@ function notesPending(claudeDir, opts) {
114
129
  if (!NOTE_KINDS.has(s.kind)) continue;
115
130
  if (s.lines[1] - s.lines[0] + 1 < MIN_LINES) continue;
116
131
  if (idx.byKey.has(`${s.id}\0${s.body_hash}`)) continue;
132
+ // N1 (v1.8.2 W4): the author already wrote the sentence. Paying a
133
+ // subagent to write it again is the one cost this layer must not have.
134
+ if (s.doc) {
135
+ documented++;
136
+ continue;
137
+ }
117
138
  rows.push({ sym: s.id, file: rel, lines: s.lines, body_hash: s.body_hash, restale: idx.bySym.has(s.id) });
118
139
  }
119
140
  }
120
- const base = { ok: true, files, missing, total: rows.length, cap, min };
141
+ const base = { ok: true, files, missing, total: rows.length, documented, cap, min };
121
142
  if (!rows.length) return { ...base, state: "none", rows: [], more: 0, exit: 5 };
122
143
  if (rows.length < min) return { ...base, state: "below-min", rows: [], waiting: rows.map((r) => r.sym), more: 0, exit: 5 };
123
144
  const out = rows.slice(0, cap);
124
- return { ...base, state: "pending", rows: out, more: rows.length - out.length, exit: 0 };
145
+ // N2 (v1.8.2 W4) — `--with-source`: the ranges, in the SAME call. The noter
146
+ // used to open every symbol with a `Read`, so a 40-symbol batch was 40 round
147
+ // trips before it wrote a word. One call, `SRC_PER_ROW` lines each, and the
148
+ // noter reads nothing.
149
+ if (opts.withSource) for (const r of out) r.source = readRange(root, r.file, r.lines);
150
+ return { ...base, state: "pending", rows: out, more: rows.length - out.length, with_source: !!opts.withSource, exit: 0 };
151
+ }
152
+
153
+ const SRC_PER_ROW = 120;
154
+
155
+ function readRange(root, rel, lines) {
156
+ if (!root) return null;
157
+ try {
158
+ const all = require("fs").readFileSync(require("path").join(root, ...rel.split("/")), "utf8").split(/\r?\n/);
159
+ const from = Math.max(1, lines[0]);
160
+ const to = Math.min(all.length, Math.min(lines[1], from + SRC_PER_ROW - 1));
161
+ if (to < from) return null;
162
+ return { from, to, cut: Math.max(0, lines[1] - to), text: all.slice(from - 1, to).join("\n") };
163
+ } catch (_) {
164
+ return null; // a file that moved between the index and now: the noter reads it
165
+ }
125
166
  }
126
167
 
127
168
  // exit 0 = every row applied · 1 = no index / locked · 6 = one or more rows rejected