@inerrata-corporation/errata 2.0.21 → 2.0.22-dev.4020
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/consolidate-worker.mjs +443 -187
- package/errata.mjs +5929 -4474
- package/generalize-worker.mjs +17430 -0
- package/install.ps1 +1 -1
- package/package.json +2 -1
- package/pass-worker.mjs +3101 -2653
- package/resources/claude-mods/errata-minimap/.claude-plugin/plugin.json +2 -2
- package/resources/claude-mods/errata-minimap/hooks/bookcase.ts +450 -0
- package/resources/claude-mods/errata-minimap/hooks/chains.ts +427 -0
- package/resources/claude-mods/errata-minimap/hooks/graph.ts +349 -0
- package/resources/claude-mods/errata-minimap/hooks/minimap.ts +39 -351
- package/resources/claude-mods/errata-minimap/hooks/register.tsx +440 -148
- package/resources/claude-mods/errata-minimap/hooks/tags.ts +129 -0
- package/resources/claude-mods/errata-minimap/types/index.d.ts +42 -8
- package/resources/context-plugin/.codex-plugin/plugin.json +1 -1
- package/resources/context-plugin/SHA256SUMS +1 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The capture protocol's inline tags, tidied for the person reading the chat.
|
|
3
|
+
*
|
|
4
|
+
* Display only: the `AssistantMessage` render hook rewrites what the row
|
|
5
|
+
* draws, never the stored reply, so the daemon still harvests every tag from
|
|
6
|
+
* the transcript. Deterministic — the same text and mode draw the same row.
|
|
7
|
+
*
|
|
8
|
+
* margin (default) — references become marginal marks (◎ cited, ✓ held,
|
|
9
|
+
* ✗ refuted, ⇢ linked); a flag reads as a sentence
|
|
10
|
+
* (⚑ …); asides (constraint, tried, failed, cause) go
|
|
11
|
+
* italic; graph metadata (domain, package, …) is shelved
|
|
12
|
+
* out of sight; an errata-* answer block folds to a line.
|
|
13
|
+
* quiet — every tag gone; a flag keeps its words, unmarked,
|
|
14
|
+
* because it is often the only place a problem is said.
|
|
15
|
+
* raw — drawn as written.
|
|
16
|
+
*
|
|
17
|
+
* Tags inside code (fences, inline spans) are prose ABOUT the protocol and
|
|
18
|
+
* are never touched; neither is a GitHub admonition (`> [!NOTE]`).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export type TagMode = 'margin' | 'quiet' | 'raw'
|
|
22
|
+
export const TAG_MODES: readonly TagMode[] = ['margin', 'quiet', 'raw']
|
|
23
|
+
|
|
24
|
+
/** Every verb the grammar teaches (agent-signals.ts TAG_EXAMPLE); src/claude-mods-tags.test.ts holds them in step. */
|
|
25
|
+
const VERBS = 'fix|confirm|refute|cause|aids|instance|pattern|builds-on|supersedes|alternative|constraint|tried|failed|domain|package|component'
|
|
26
|
+
|
|
27
|
+
const HANDLE = String.raw`\[[^\]\s]{1,120}\]`
|
|
28
|
+
const HANDLES = String.raw`${HANDLE}(?:\s*,\s*${HANDLE})*`
|
|
29
|
+
const THREAD = String.raw`(?:#[a-z][\w-]{0,63})?`
|
|
30
|
+
/** A tag body: text with at most one level of nested parentheses, one line. */
|
|
31
|
+
const BODY = String.raw`(?:[^()\n]|\([^()\n]*\))`
|
|
32
|
+
|
|
33
|
+
/** `([h])`, `([a], [b])` — leaning on a shown prior. */
|
|
34
|
+
const CITE = new RegExp(String.raw`\(\s*${HANDLES}\s*\)`, 'g')
|
|
35
|
+
/** Verdicts and links that name priors and say nothing else. */
|
|
36
|
+
const REF_VERB = new RegExp(
|
|
37
|
+
String.raw`\(\s*(fix|confirm|cause|aids|instance|pattern|builds-on|supersedes|alternative)\s*:\s*${THREAD}\s*${HANDLES}\s*\)`,
|
|
38
|
+
'gi',
|
|
39
|
+
)
|
|
40
|
+
/** `(refute:[h] why)`, `(cause:[h] mechanism)` — a judgment on a prior, with its reason. */
|
|
41
|
+
const REASONED = new RegExp(String.raw`\(\s*(refute|cause)\s*:\s*${HANDLES}\s*(${BODY}+?)\s*\)`, 'gi')
|
|
42
|
+
/** Free-text asides the reader may want: why a choice, what was tried, why it broke. */
|
|
43
|
+
const ASIDE = new RegExp(String.raw`\(\s*(constraint|tried|failed|cause|fix)\s*:\s*${THREAD}\s*(${BODY}{2,}?)\s*\)`, 'gi')
|
|
44
|
+
/** Classification for the graph, not the reader. */
|
|
45
|
+
const LABEL = /\(\s*(?:domain|package|component|pattern)\s*:\s*[^()\n]{2,}?\s*\)/gi
|
|
46
|
+
/** `[!one line @ path:42]`, `[?vuln: …]`, `[!#slug …]` — a problem the agent states. */
|
|
47
|
+
const FLAG = /\[([!?])(?:#[a-z][\w-]{0,63}\s+)?\s*((?:\[[^[\]\n]*\]|[^\]\n])+?)\s*(?:@\s*([^\s\]]+?)(?::(\d+))?\s*)?\]/g
|
|
48
|
+
const ADMONITION = /^(?:NOTE|TIP|IMPORTANT|WARNING|CAUTION)$/
|
|
49
|
+
|
|
50
|
+
const ERRATA_FENCE = /^```errata-([a-z-]+)[^\n]*\n([\s\S]*?)^```[ \t]*$\n?/gm
|
|
51
|
+
|
|
52
|
+
const MARK = { cite: '◎', held: '✓', refute: '✗', link: '⇢', flag: '⚑', suspect: '⚐' } as const
|
|
53
|
+
|
|
54
|
+
/** Where a tag was taken out: the seam `mend` closes, so spacing the agent wrote stays as written. */
|
|
55
|
+
const GONE = '\u0001'
|
|
56
|
+
|
|
57
|
+
/** Code (fences and inline spans) as opaque slots: tags inside are protocol prose, not tags. */
|
|
58
|
+
function shelveCode(text: string): { text: string; code: string[] } {
|
|
59
|
+
const code: string[] = []
|
|
60
|
+
const slot = (m: string) => `\u0000${code.push(m) - 1}\u0000`
|
|
61
|
+
const fenced = text.replace(/^(```|~~~)(?!errata-)[^\n]*\n[\s\S]*?^\1[ \t]*$/gm, slot)
|
|
62
|
+
return { text: fenced.replace(/`[^`\n]+`/g, slot), code }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function unshelveCode(text: string, code: string[]): string {
|
|
66
|
+
return text.replace(/\u0000(\d+)\u0000/g, (_, i: string) => code[Number(i)]!)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function refMark(verb: string): string {
|
|
70
|
+
const v = verb.toLowerCase()
|
|
71
|
+
if (v === 'confirm' || v === 'fix') return MARK.held
|
|
72
|
+
return v === 'cause' ? MARK.cite : MARK.link
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** One errata-* answer block → a single quiet line, or nothing. */
|
|
76
|
+
function answerBlock(kind: string, body: string, mode: TagMode): string {
|
|
77
|
+
if (mode === 'quiet') return GONE
|
|
78
|
+
if (kind === 'intent') {
|
|
79
|
+
const intent = /^\s*intent:\s*(.+)$/m.exec(body)?.[1]?.trim()
|
|
80
|
+
return intent ? `*✎ ${intent}*\n` : GONE
|
|
81
|
+
}
|
|
82
|
+
return `*✎ errata ${kind} noted*\n`
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Closes the seams removals left — a line or bullet with nothing left, a space before punctuation — and only those. */
|
|
86
|
+
function mend(text: string): string {
|
|
87
|
+
return text
|
|
88
|
+
.split('\n')
|
|
89
|
+
.filter(line => !/^[ \t]*(?:(?:[-*+]|\d+\.)[ \t]*)?(?:\u0001[ \t]*)+$/.test(line))
|
|
90
|
+
.join('\n')
|
|
91
|
+
.replace(/[ \t]*(?:\u0001[ \t]*)+(?=[.,;:!?)]|$)/gm, '')
|
|
92
|
+
.replace(/^([ \t]*(?:[-*+>] |\d+\. )?)(?:\u0001[ \t]*)+/gm, '$1')
|
|
93
|
+
.replace(/[ \t]*(?:\u0001[ \t]*)+/g, ' ')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function tidyTags(input: string, mode: TagMode = 'margin'): string {
|
|
97
|
+
if (mode === 'raw' || !input) return input
|
|
98
|
+
const shelved = shelveCode(input)
|
|
99
|
+
const isQuiet = mode === 'quiet'
|
|
100
|
+
let text = shelved.text
|
|
101
|
+
|
|
102
|
+
text = text.replace(ERRATA_FENCE, (_, kind: string, body: string) => answerBlock(kind, body, mode))
|
|
103
|
+
text = text.replace(REASONED, (_, verb: string, why: string) => {
|
|
104
|
+
if (isQuiet) return GONE
|
|
105
|
+
return `${verb.toLowerCase() === 'refute' ? MARK.refute : MARK.cite} *${why}*`
|
|
106
|
+
})
|
|
107
|
+
text = text.replace(REF_VERB, (_, verb: string) => (isQuiet ? GONE : refMark(verb)))
|
|
108
|
+
text = text.replace(CITE, () => (isQuiet ? GONE : MARK.cite))
|
|
109
|
+
text = text.replace(ASIDE, (_, verb: string, body: string) => {
|
|
110
|
+
if (isQuiet) return GONE
|
|
111
|
+
const v = verb.toLowerCase()
|
|
112
|
+
return v === 'constraint' ? `*(${body})*` : `*${v === 'fix' ? 'fixed' : v}: ${body}*`
|
|
113
|
+
})
|
|
114
|
+
text = text.replace(LABEL, GONE)
|
|
115
|
+
text = text.replace(FLAG, (whole: string, bang: string, body: string, path?: string, line?: string) => {
|
|
116
|
+
if (ADMONITION.test(body)) return whole
|
|
117
|
+
const said = body.replace(/\s+(?:<-|←)\s+/g, ' ← ')
|
|
118
|
+
const where = path ? ` (${path}${line ? `:${line}` : ''})` : ''
|
|
119
|
+
return isQuiet ? `${said}${where}` : `${bang === '?' ? MARK.suspect : MARK.flag} ${said}${where}`
|
|
120
|
+
})
|
|
121
|
+
return unshelveCode(mend(text), shelved.code)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const TAGGED = new RegExp(String.raw`\[[!?]|\(\s*\[|\(\s*(?:${VERBS})\s*:|${'`'}{3}errata-`, 'i')
|
|
125
|
+
|
|
126
|
+
/** Whether a reply holds anything `tidyTags` could change: the render hook passes other rows through untouched. */
|
|
127
|
+
export function hasTags(text: string): boolean {
|
|
128
|
+
return TAGGED.test(text)
|
|
129
|
+
}
|
|
@@ -4,6 +4,9 @@ export type BurstOrigin = 'agent' | 'daemon-file' | 'daemon-prompt'
|
|
|
4
4
|
/** Which membrane a prior lives in: this machine only, or the project / team / org membrane, or the public Errata Network. */
|
|
5
5
|
export type Scope = 'machine' | 'project' | 'team' | 'org' | 'public'
|
|
6
6
|
|
|
7
|
+
/** A cloud community as the walker tools report it: tonight's partition number (compare within one answer only) and its theme when labelled. */
|
|
8
|
+
export type CloudCommunity = { id: number; label: string | null }
|
|
9
|
+
|
|
7
10
|
export type BurstNode = {
|
|
8
11
|
id: string
|
|
9
12
|
label: string
|
|
@@ -11,11 +14,14 @@ export type BurstNode = {
|
|
|
11
14
|
/** Burst relevance; daemon-delivered nodes get a rank-derived stand-in. */
|
|
12
15
|
score: number
|
|
13
16
|
hops: number
|
|
14
|
-
/** The node the walk reached this one from, and by which edge. */
|
|
17
|
+
/** The node the walk reached this one from, and by which edge; `forward` ⇒ parent —edge→ node. */
|
|
15
18
|
parent?: string
|
|
16
19
|
edge?: string
|
|
20
|
+
forward?: boolean
|
|
17
21
|
/** Absent when no client-visible signal says. */
|
|
18
22
|
scope?: Scope
|
|
23
|
+
/** Only cloud-merged hits carry one. */
|
|
24
|
+
community?: CloudCommunity
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
/** One neighborhood that entered the agent's context. */
|
|
@@ -23,8 +29,7 @@ export type Burst = {
|
|
|
23
29
|
origin: BurstOrigin
|
|
24
30
|
seed: { id: string; label: string; name: string }
|
|
25
31
|
nodes: BurstNode[]
|
|
26
|
-
/**
|
|
27
|
-
extra: [string, string][]
|
|
32
|
+
/** The seed's real name has been looked up (a burst names it by id). */
|
|
28
33
|
isEnriched: boolean
|
|
29
34
|
at: number
|
|
30
35
|
}
|
|
@@ -35,25 +40,52 @@ export type MapNode = {
|
|
|
35
40
|
name: string
|
|
36
41
|
isSeed: boolean
|
|
37
42
|
score: number
|
|
38
|
-
/**
|
|
43
|
+
/** Steps out from the seed (0 for the seed). */
|
|
39
44
|
hops: number
|
|
40
45
|
scope?: Scope
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
/** Index of the node the walk reached this one from; -1 for the seed. */
|
|
47
|
+
parent: number
|
|
48
|
+
edge?: string
|
|
49
|
+
forward?: boolean
|
|
50
|
+
community?: CloudCommunity
|
|
43
51
|
}
|
|
44
52
|
|
|
53
|
+
/** A burst catalogued: its nodes in walk order, ready to bind into chains (hooks/chains.ts). */
|
|
45
54
|
export type MapGraph = {
|
|
46
55
|
title: string
|
|
47
56
|
/** The seed's node type (File, Function, Prompt, ...). */
|
|
48
57
|
seedLabel?: string
|
|
49
58
|
origin?: BurstOrigin
|
|
50
59
|
nodes: MapNode[]
|
|
51
|
-
/** Index pairs into `nodes`; `true` = an edge of the walk, `false` = a cross edge. */
|
|
52
|
-
edges: [number, number, boolean][]
|
|
53
60
|
at: number
|
|
54
61
|
note?: string
|
|
55
62
|
}
|
|
56
63
|
|
|
64
|
+
/** A node at the far end of an edge, as `errata_neighbors` names it. */
|
|
65
|
+
export type FarNode = { id: string; label: string; name: string; community?: string }
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* What `errata_neighbors` says about one chain's node: the edges that bind a
|
|
69
|
+
* chain (causes, fixes, the problems a lone cause/fix belongs to) and the ones
|
|
70
|
+
* that place it (tech anchors, patterns, the file it is anchored at, its
|
|
71
|
+
* community in the local partition).
|
|
72
|
+
*/
|
|
73
|
+
export type ChainFacts = {
|
|
74
|
+
id: string
|
|
75
|
+
label: string
|
|
76
|
+
name: string
|
|
77
|
+
/** `community_<id>` in the local partition; null = unplaced. */
|
|
78
|
+
community: string | null
|
|
79
|
+
causes: FarNode[]
|
|
80
|
+
fixes: FarNode[]
|
|
81
|
+
/** Problems this node causes or fixes (a lone cause/fix's chain). */
|
|
82
|
+
problems: FarNode[]
|
|
83
|
+
/** Tech anchors in edge order: Package (DEPENDS_ON), Tool/Component (CONCERNS), Language (OCCURS_IN). */
|
|
84
|
+
techs: FarNode[]
|
|
85
|
+
patterns: FarNode[]
|
|
86
|
+
anchors: string[]
|
|
87
|
+
}
|
|
88
|
+
|
|
57
89
|
/** One judgment the agent made on a prior in its reply: cited, confirmed, resolved or refuted. */
|
|
58
90
|
export type Verdict = {
|
|
59
91
|
id: string
|
|
@@ -69,6 +101,8 @@ declare module 'claude-code' {
|
|
|
69
101
|
burst: Burst | null
|
|
70
102
|
graph: MapGraph
|
|
71
103
|
verdicts: Verdict[]
|
|
104
|
+
/** `errata_neighbors` answers by node id, for the chains on the shelves; missing = not asked yet, null = asked, not found. */
|
|
105
|
+
facts: Record<string, ChainFacts | null>
|
|
72
106
|
}
|
|
73
107
|
}
|
|
74
108
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
cefcb61c20b7e27f11cb65c4ab1bf3352957edd54c21cd575122b54dfd7f6581 .codex-plugin/plugin.json
|
|
2
2
|
a7bebae9fb01c838d6c75fc784129e28be571233fa66ff5ee8039b574f35ccf7 assets/icon.png
|
|
3
3
|
fc38b64e4df1e0b72c35764bef6c4c05430d97c9009ad0ecc8a9e75b4deab232 configure-local.mjs
|
|
4
4
|
73dc6028b3b070257c7c31f252d11e55a9e096f4aed0f187f10cb21716e1e6d7 dist/client.js
|