@zibby/skills 0.1.70 β†’ 0.1.71

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/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/skills",
3
- "version": "0.1.70",
3
+ "version": "0.1.71",
4
4
  "description": "Built-in skill definitions for the Zibby agent-workflow framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -69,6 +69,10 @@
69
69
  "./sentry": {
70
70
  "types": "./dist/sentry.d.ts",
71
71
  "default": "./dist/sentry.js"
72
+ },
73
+ "./review": {
74
+ "types": "./dist/review.d.ts",
75
+ "default": "./dist/review.js"
72
76
  }
73
77
  },
74
78
  "scripts": {
@@ -0,0 +1,2 @@
1
+ export { REVIEW_RECORD_SCHEMA_VERSION, REVIEW_RECORD_KIND, CONTENT_MAX_BYTES, FIELD_MAX_CHARS, SEVERITY_TIERS, FINDING_STATUSES, normalizeSeverity, buildReviewRecord, upsertReplyOutcome, serializeReviewRecord, parseReviewMemory, summarizeForPrompt } from "./reviewRecord.js";
2
+ export { scopeForReviewMemory, storeReviewRecord, recallReviewRecord } from "./reviewMemoryIo.js";
package/dist/review.js ADDED
@@ -0,0 +1,4 @@
1
+ var A=1,l="review-record",O=204800,T=2e3,I=["blocker","should-fix","nit"],_={blocker:0,"should-fix":1,nit:2},g=["open","conceded","held","resolved"];function v(e){let r=String(e??"").trim().toLowerCase();return r?r.includes("\u{1F534}")||r.includes("blocker")||r.includes("critical")||r.includes("high")?"blocker":r.includes("\u{1F7E2}")||r.includes("nit")||r.includes("minor")||r.includes("low")||r.includes("info")?"nit":(r.includes("\u{1F7E1}")||r.includes("should")||r.includes("medium")||r.includes("warn"),"should-fix"):"should-fix"}var c=(e,r)=>{let n=e==null?"":String(e);return n.length>r?n.slice(0,r):n},E=e=>typeof Buffer<"u"&&typeof Buffer.byteLength=="function"?Buffer.byteLength(e,"utf8"):new TextEncoder().encode(e).length;function k({headSha:e=null,verdict:r="COMMENT",objectivesChecked:n=!1,findings:i=[],nowIso:t=null}={}){let s=Array.isArray(i)?i:[];return{schemaVersion:1,kind:l,headSha:e||null,verdict:String(r||"COMMENT"),objectivesChecked:!!n,reviewedAt:t||null,findings:s.map((o,u)=>({id:`f${u+1}`,file:c(o?.file,512),line:o?.line==null?null:o.line,severity:v(o?.severity),category:c(o?.category,64),claim:c(o?.claim,2e3),evidence:c(o?.evidence,2e3),suggestion:c(o?.suggestion,2e3),confidence:typeof o?.confidence=="number"?o.confidence:null,status:"open"}))}}function C(e,{findingId:r,status:n,note:i}={}){if(!e||!Array.isArray(e.findings))return e;let t=g.includes(n)?n:"held";return{...e,findings:e.findings.map(s=>s.id===r?{...s,status:t,replyNote:c(i,2e3)}:s)}}function a(e){if(!e)return"";let r=[...e.findings||[]].sort((s,o)=>{let u=(_[s.severity]??9)-(_[o.severity]??9);if(u!==0)return u;let y=s.file||"",p=o.file||"";if(y!==p)return y<p?-1:1;let m=Number(s.line)||0,R=Number(o.line)||0;return m!==R?m-R:(s.id||"")<(o.id||"")?-1:1}),n={...e,findings:r},i=JSON.stringify(n);if(E(i)<=204800)return i;let t=[...r];for(n={...e,findings:t,truncated:!0};t.length>0&&E(JSON.stringify(n))>204800;)t.pop(),n={...e,findings:t,truncated:!0};return JSON.stringify(n)}var S=e=>e&&typeof e=="object"&&!Array.isArray(e)&&e.kind===l;function d(e){if(e==null)return{kind:"empty"};if(typeof e=="object"){if(!Array.isArray(e)&&typeof e.error=="string")return{kind:"empty"};if(S(e)){let i=Number(e.schemaVersion)>1;return{kind:"record",record:e,future:i}}return{kind:"legacy",legacyNote:h(e)}}if(typeof e!="string")return{kind:"empty"};let r=e.trim();if(!r)return{kind:"empty"};let n;try{n=JSON.parse(r)}catch{return{kind:"legacy",legacyNote:r}}if(n&&typeof n=="object"&&typeof n.error=="string")return{kind:"empty"};if(S(n)){let i=Number(n.schemaVersion)>1;return{kind:"record",record:n,future:i}}return{kind:"legacy",legacyNote:r}}function h(e){try{return JSON.stringify(e)}catch{return String(e)}}function w(e){if(!e||e.kind==="empty")return"";if(e.kind==="legacy")return`Prior review memory (legacy note, advisory only):
2
+ ${e.legacyNote}`;let r=e.record||{};if(e.future)return`Prior review memory (newer format ${r.schemaVersion} \u2014 advisory; verify against the live thread):
3
+ ${h(r).slice(0,2e3)}`;let n=[`Prior review of this change (verdict: ${r.verdict||"COMMENT"}${r.headSha?`, commit ${r.headSha}`:""}):`],i=(r.findings||[]).map(t=>{let s=t.file?`${t.file}${t.line!=null?`:${t.line}`:""}`:"(general)",o=t.status&&t.status!=="open"?` [${t.status}]`:"";return`- [${t.severity}] ${s} \u2014 ${t.claim||""}${o}`});return r.truncated&&i.push("- (\u2026older/lower-severity findings were truncated to fit memory)"),[...n,...i].join(`
4
+ `)}import{existsSync as M,readFileSync as x}from"node:fs";import{homedir as $}from"node:os";import{join as b}from"node:path";function B(){if(process.env.PROJECT_API_TOKEN)return process.env.PROJECT_API_TOKEN;if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let e=b($(),".zibby","config.json");return M(e)&&JSON.parse(x(e,"utf-8")).sessionToken||null}catch{return null}}function V(){return process.env.ZIBBY_ACCOUNT_API_URL?process.env.ZIBBY_ACCOUNT_API_URL.replace(/\/$/,""):(process.env.ZIBBY_ENV||"prod")==="local"?"http://localhost:3001":process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://api-prod.zibby.app"}function D(){return(typeof process.env.WORKFLOW_TYPE=="string"?process.env.WORKFLOW_TYPE.trim():"")||"agent"}function f(e){return`${D()}:${e}`}async function N(e,r){let n=B();if(!n)return{__noToken:!0};let i=`${V()}/credits/review-memory`,t=await fetch(i,{method:"POST",headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json"},body:JSON.stringify({op:e,...r})});if(!t.ok){let s=await t.text().catch(()=>"");throw new Error(`review-memory ${e} failed (${t.status}): ${s.slice(0,300)}`)}return t.json()}async function F(e,r){try{let n=a(r);if(!n)return{ok:!1,reason:"empty-record"};let i=await N("store",{scope:f(e),content:n});return i&&i.__noToken?{ok:!1,reason:"no-token"}:{ok:!0}}catch(n){return{ok:!1,reason:n?.message||"store-error"}}}async function L(e){try{let r=await N("recall",{scope:f(e)});if(!r||r.__noToken)return{kind:"empty"};let n=r.found&&r.memory?r.memory:null;if(!n)return{kind:"empty"};let i=n.content!=null?n.content:n.metadata!=null?n.metadata:null;return d(i)}catch{return{kind:"empty"}}}export{O as CONTENT_MAX_BYTES,T as FIELD_MAX_CHARS,g as FINDING_STATUSES,l as REVIEW_RECORD_KIND,A as REVIEW_RECORD_SCHEMA_VERSION,I as SEVERITY_TIERS,k as buildReviewRecord,v as normalizeSeverity,d as parseReviewMemory,L as recallReviewRecord,f as scopeForReviewMemory,a as serializeReviewRecord,F as storeReviewRecord,w as summarizeForPrompt,C as upsertReplyOutcome};
@@ -0,0 +1,43 @@
1
+ /** Effective backend scope for a plain per-PR/MR key. IDENTICAL to kvMemory scopeFor. */
2
+ export function scopeForReviewMemory(key: any): string;
3
+ /**
4
+ * Store a review record under a plain per-PR/MR key. Serializes via
5
+ * serializeReviewRecord (deterministic, byte-capped 200KB) and POSTs
6
+ * { op:'store', scope, content }.
7
+ *
8
+ * BEST-EFFORT: never throws. { ok:true } on success; { ok:false, reason:'no-token' }
9
+ * with no backend credential (local dev / self-host); { ok:false, reason } otherwise.
10
+ * The caller must treat a false result as a no-op β€” memory NEVER blocks a run.
11
+ */
12
+ export function storeReviewRecord(key: any, record: any): Promise<{
13
+ ok: boolean;
14
+ reason?: undefined;
15
+ } | {
16
+ ok: boolean;
17
+ reason: any;
18
+ }>;
19
+ /**
20
+ * Recall the review record stored under a plain per-PR/MR key. POSTs
21
+ * { op:'recall', scope } and hands the returned `content` to the tolerant
22
+ * parseReviewMemory (which never throws over any input).
23
+ *
24
+ * BEST-EFFORT: never throws. Returns parseReviewMemory's result
25
+ * ({ kind:'empty' | 'record' | 'legacy', ... }); { kind:'empty' } on missing
26
+ * token or ANY failure, so the caller degrades to "no prior memory".
27
+ */
28
+ export function recallReviewRecord(key: any): Promise<{
29
+ kind: string;
30
+ record?: undefined;
31
+ future?: undefined;
32
+ legacyNote?: undefined;
33
+ } | {
34
+ kind: string;
35
+ record: any;
36
+ future: boolean;
37
+ legacyNote?: undefined;
38
+ } | {
39
+ kind: string;
40
+ legacyNote: string;
41
+ record?: undefined;
42
+ future?: undefined;
43
+ }>;
@@ -0,0 +1 @@
1
+ import{existsSync as S,readFileSync as v}from"node:fs";import{homedir as N}from"node:os";import{join as A}from"node:path";var R="review-record";var d={blocker:0,"should-fix":1,nit:2};var y=e=>typeof Buffer<"u"&&typeof Buffer.byteLength=="function"?Buffer.byteLength(e,"utf8"):new TextEncoder().encode(e).length;function m(e){if(!e)return"";let t=[...e.findings||[]].sort((o,s)=>{let c=(d[o.severity]??9)-(d[s.severity]??9);if(c!==0)return c;let u=o.file||"",l=s.file||"";if(u!==l)return u<l?-1:1;let a=Number(o.line)||0,f=Number(s.line)||0;return a!==f?a-f:(o.id||"")<(s.id||"")?-1:1}),n={...e,findings:t},r=JSON.stringify(n);if(y(r)<=204800)return r;let i=[...t];for(n={...e,findings:i,truncated:!0};i.length>0&&y(JSON.stringify(n))>204800;)i.pop(),n={...e,findings:i,truncated:!0};return JSON.stringify(n)}var p=e=>e&&typeof e=="object"&&!Array.isArray(e)&&e.kind===R;function _(e){if(e==null)return{kind:"empty"};if(typeof e=="object"){if(!Array.isArray(e)&&typeof e.error=="string")return{kind:"empty"};if(p(e)){let r=Number(e.schemaVersion)>1;return{kind:"record",record:e,future:r}}return{kind:"legacy",legacyNote:h(e)}}if(typeof e!="string")return{kind:"empty"};let t=e.trim();if(!t)return{kind:"empty"};let n;try{n=JSON.parse(t)}catch{return{kind:"legacy",legacyNote:t}}if(n&&typeof n=="object"&&typeof n.error=="string")return{kind:"empty"};if(p(n)){let r=Number(n.schemaVersion)>1;return{kind:"record",record:n,future:r}}return{kind:"legacy",legacyNote:t}}function h(e){try{return JSON.stringify(e)}catch{return String(e)}}function O(){if(process.env.PROJECT_API_TOKEN)return process.env.PROJECT_API_TOKEN;if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let e=A(N(),".zibby","config.json");return S(e)&&JSON.parse(v(e,"utf-8")).sessionToken||null}catch{return null}}function k(){return process.env.ZIBBY_ACCOUNT_API_URL?process.env.ZIBBY_ACCOUNT_API_URL.replace(/\/$/,""):(process.env.ZIBBY_ENV||"prod")==="local"?"http://localhost:3001":process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://api-prod.zibby.app"}function T(){return(typeof process.env.WORKFLOW_TYPE=="string"?process.env.WORKFLOW_TYPE.trim():"")||"agent"}function E(e){return`${T()}:${e}`}async function g(e,t){let n=O();if(!n)return{__noToken:!0};let r=`${k()}/credits/review-memory`,i=await fetch(r,{method:"POST",headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json"},body:JSON.stringify({op:e,...t})});if(!i.ok){let o=await i.text().catch(()=>"");throw new Error(`review-memory ${e} failed (${i.status}): ${o.slice(0,300)}`)}return i.json()}async function $(e,t){try{let n=m(t);if(!n)return{ok:!1,reason:"empty-record"};let r=await g("store",{scope:E(e),content:n});return r&&r.__noToken?{ok:!1,reason:"no-token"}:{ok:!0}}catch(n){return{ok:!1,reason:n?.message||"store-error"}}}async function b(e){try{let t=await g("recall",{scope:E(e)});if(!t||t.__noToken)return{kind:"empty"};let n=t.found&&t.memory?t.memory:null;if(!n)return{kind:"empty"};let r=n.content!=null?n.content:n.metadata!=null?n.metadata:null;return _(r)}catch{return{kind:"empty"}}}export{b as recallReviewRecord,E as scopeForReviewMemory,$ as storeReviewRecord};
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Normalize the review's free-form / emoji severity into a stable tier.
3
+ * The real review schema defaults severity to '🟑'; reviews also emit πŸ”΄/🟒 and
4
+ * words. Anything unrecognized falls back to 'should-fix' (never throws).
5
+ */
6
+ export function normalizeSeverity(raw: any): "should-fix" | "blocker" | "nit";
7
+ /**
8
+ * Build a fresh review record from the review node's (post-verification)
9
+ * findings. `findings` is the REAL review shape:
10
+ * { file, line?, severity, category, claim, evidence, suggestion?, confidence? }
11
+ * Assigns stable ids (f1..fN), normalizes severity, caps long text, status:'open'.
12
+ * `nowIso` is injected (callers pass new Date().toISOString()) so this stays pure.
13
+ */
14
+ export function buildReviewRecord({ headSha, verdict, objectivesChecked, findings, nowIso, }?: {
15
+ headSha?: any;
16
+ verdict?: string;
17
+ objectivesChecked?: boolean;
18
+ findings?: any[];
19
+ nowIso?: any;
20
+ }): {
21
+ schemaVersion: number;
22
+ kind: string;
23
+ headSha: any;
24
+ verdict: string;
25
+ objectivesChecked: boolean;
26
+ reviewedAt: any;
27
+ findings: {
28
+ id: string;
29
+ file: string;
30
+ line: any;
31
+ severity: string;
32
+ category: string;
33
+ claim: string;
34
+ evidence: string;
35
+ suggestion: string;
36
+ confidence: any;
37
+ status: string;
38
+ }[];
39
+ };
40
+ /**
41
+ * Record the OUTCOME of a comment_reply against a finding. IDEMPOTENT: it SETS
42
+ * findings[id].status (and an optional one-line note) β€” running the same reply
43
+ * twice (webhook redelivery) yields the identical record, no double-append.
44
+ * Returns a NEW record (does not mutate the input). If findingId is unknown, the
45
+ * record is returned unchanged (best-effort, never throws).
46
+ */
47
+ export function upsertReplyOutcome(record: any, { findingId, status, note }?: {}): any;
48
+ /**
49
+ * Serialize a record to a string that FITS CONTENT_MAX_BYTES. Deterministic:
50
+ * findings are stably sorted by (severityRank, file, line, id); if still over
51
+ * budget, the LOWEST-priority findings are dropped until it fits and
52
+ * `truncated:true` is set. Text fields are already capped by buildReviewRecord.
53
+ */
54
+ export function serializeReviewRecord(record: any): string;
55
+ /**
56
+ * Tolerant reader β€” NEVER throws. Accepts whatever kv_recall returns for the
57
+ * value (a JSON string, an already-parsed metadata object, a legacy prose
58
+ * string, an {error} envelope, null/'').
59
+ * Returns one of:
60
+ * { kind:'empty' } β€” nothing usable
61
+ * { kind:'record', record, future?:bool } β€” a structured record (future=newer schemaVersion)
62
+ * { kind:'legacy', legacyNote:string } β€” an old freeform note; advisory only
63
+ */
64
+ export function parseReviewMemory(raw: any): {
65
+ kind: string;
66
+ record?: undefined;
67
+ future?: undefined;
68
+ legacyNote?: undefined;
69
+ } | {
70
+ kind: string;
71
+ record: any;
72
+ future: boolean;
73
+ legacyNote?: undefined;
74
+ } | {
75
+ kind: string;
76
+ legacyNote: string;
77
+ record?: undefined;
78
+ future?: undefined;
79
+ };
80
+ /**
81
+ * Render a parsed memory into prompt text for the review/reply LLM. Compact,
82
+ * human-readable, and it NEVER assumes a shape it didn't verify (a future
83
+ * schemaVersion is surfaced as advisory). Empty β†’ '' (caller omits the block).
84
+ */
85
+ export function summarizeForPrompt(parsed: any): string;
86
+ /**
87
+ * reviewRecord β€” a GENERIC, provider-agnostic structured record for the
88
+ * code-review β†’ comment_reply memory (shared by gitlab-code-review and
89
+ * github-code-review). Replaces the freeform prose kv note with a versioned,
90
+ * queryable record.
91
+ *
92
+ * DELIBERATELY TRANSPORT-AGNOSTIC. This module does NO I/O: it only builds,
93
+ * serializes, parses and renders the record. WHO stores/recalls it (the JS node
94
+ * vs the LLM via kv_store/kv_recall) is a separate wiring decision β€” these pure
95
+ * functions are correct either way. The per-PR/MR KEY stays provider-specific
96
+ * (reviewMemoryScopeFor in each review-node.js); the record BODY here carries
97
+ * zero provider fields (identity lives in the key, not the body).
98
+ *
99
+ * Contract facts this module mirrors (source of truth = backend
100
+ * src/handlers/review-memory.js + packages/skills/src/kvMemory.js):
101
+ * - kv `content` is a STRING, hard-capped at 200KB (CONTENT_MAX). We serialize
102
+ * to a string and truncate deterministically to fit β€” an over-cap store is
103
+ * rejected (HTTP 400) and SILENTLY lost, so truncation must happen here,
104
+ * before the write.
105
+ * - kv also has an optional `metadata` OBJECT channel; parseReviewMemory
106
+ * therefore accepts an already-parsed object too, so the record can ride in
107
+ * either channel without changing this code.
108
+ *
109
+ * Reviewed by two adversarial design agents (2026-07-04): schema aligned to the
110
+ * REAL finding shape ({file,line,severity,category,claim,evidence,suggestion,
111
+ * confidence}); replies modeled as an IDEMPOTENT findingId→status set (NOT an
112
+ * append log, which double-appends on webhook redelivery); headSha carried but
113
+ * treated as advisory (its plumbing is deferred β€” today it is undefined).
114
+ */
115
+ export const REVIEW_RECORD_SCHEMA_VERSION: 1;
116
+ export const REVIEW_RECORD_KIND: "review-record";
117
+ export const CONTENT_MAX_BYTES: number;
118
+ export const FIELD_MAX_CHARS: 2000;
119
+ export const SEVERITY_TIERS: string[];
120
+ export const FINDING_STATUSES: string[];
@@ -0,0 +1,4 @@
1
+ var h=1,m="review-record",_=204800,N=2e3,A=["blocker","should-fix","nit"],a={blocker:0,"should-fix":1,nit:2},S=["open","conceded","held","resolved"];function R(e){let n=String(e??"").trim().toLowerCase();return n?n.includes("\u{1F534}")||n.includes("blocker")||n.includes("critical")||n.includes("high")?"blocker":n.includes("\u{1F7E2}")||n.includes("nit")||n.includes("minor")||n.includes("low")||n.includes("info")?"nit":(n.includes("\u{1F7E1}")||n.includes("should")||n.includes("medium")||n.includes("warn"),"should-fix"):"should-fix"}var u=(e,n)=>{let t=e==null?"":String(e);return t.length>n?t.slice(0,n):t},g=e=>typeof Buffer<"u"&&typeof Buffer.byteLength=="function"?Buffer.byteLength(e,"utf8"):new TextEncoder().encode(e).length;function v({headSha:e=null,verdict:n="COMMENT",objectivesChecked:t=!1,findings:o=[],nowIso:i=null}={}){let s=Array.isArray(o)?o:[];return{schemaVersion:1,kind:m,headSha:e||null,verdict:String(n||"COMMENT"),objectivesChecked:!!t,reviewedAt:i||null,findings:s.map((r,c)=>({id:`f${c+1}`,file:u(r?.file,512),line:r?.line==null?null:r.line,severity:R(r?.severity),category:u(r?.category,64),claim:u(r?.claim,2e3),evidence:u(r?.evidence,2e3),suggestion:u(r?.suggestion,2e3),confidence:typeof r?.confidence=="number"?r.confidence:null,status:"open"}))}}function k(e,{findingId:n,status:t,note:o}={}){if(!e||!Array.isArray(e.findings))return e;let i=S.includes(t)?t:"held";return{...e,findings:e.findings.map(s=>s.id===n?{...s,status:i,replyNote:u(o,2e3)}:s)}}function C(e){if(!e)return"";let n=[...e.findings||[]].sort((s,r)=>{let c=(a[s.severity]??9)-(a[r.severity]??9);if(c!==0)return c;let l=s.file||"",d=r.file||"";if(l!==d)return l<d?-1:1;let f=Number(s.line)||0,y=Number(r.line)||0;return f!==y?f-y:(s.id||"")<(r.id||"")?-1:1}),t={...e,findings:n},o=JSON.stringify(t);if(g(o)<=204800)return o;let i=[...n];for(t={...e,findings:i,truncated:!0};i.length>0&&g(JSON.stringify(t))>204800;)i.pop(),t={...e,findings:i,truncated:!0};return JSON.stringify(t)}var E=e=>e&&typeof e=="object"&&!Array.isArray(e)&&e.kind===m;function I(e){if(e==null)return{kind:"empty"};if(typeof e=="object"){if(!Array.isArray(e)&&typeof e.error=="string")return{kind:"empty"};if(E(e)){let o=Number(e.schemaVersion)>1;return{kind:"record",record:e,future:o}}return{kind:"legacy",legacyNote:p(e)}}if(typeof e!="string")return{kind:"empty"};let n=e.trim();if(!n)return{kind:"empty"};let t;try{t=JSON.parse(n)}catch{return{kind:"legacy",legacyNote:n}}if(t&&typeof t=="object"&&typeof t.error=="string")return{kind:"empty"};if(E(t)){let o=Number(t.schemaVersion)>1;return{kind:"record",record:t,future:o}}return{kind:"legacy",legacyNote:n}}function p(e){try{return JSON.stringify(e)}catch{return String(e)}}function O(e){if(!e||e.kind==="empty")return"";if(e.kind==="legacy")return`Prior review memory (legacy note, advisory only):
2
+ ${e.legacyNote}`;let n=e.record||{};if(e.future)return`Prior review memory (newer format ${n.schemaVersion} \u2014 advisory; verify against the live thread):
3
+ ${p(n).slice(0,2e3)}`;let t=[`Prior review of this change (verdict: ${n.verdict||"COMMENT"}${n.headSha?`, commit ${n.headSha}`:""}):`],o=(n.findings||[]).map(i=>{let s=i.file?`${i.file}${i.line!=null?`:${i.line}`:""}`:"(general)",r=i.status&&i.status!=="open"?` [${i.status}]`:"";return`- [${i.severity}] ${s} \u2014 ${i.claim||""}${r}`});return n.truncated&&o.push("- (\u2026older/lower-severity findings were truncated to fit memory)"),[...t,...o].join(`
4
+ `)}export{_ as CONTENT_MAX_BYTES,N as FIELD_MAX_CHARS,S as FINDING_STATUSES,m as REVIEW_RECORD_KIND,h as REVIEW_RECORD_SCHEMA_VERSION,A as SEVERITY_TIERS,v as buildReviewRecord,R as normalizeSeverity,I as parseReviewMemory,C as serializeReviewRecord,O as summarizeForPrompt,k as upsertReplyOutcome};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zibby/skills",
3
- "version": "0.1.70",
3
+ "version": "0.1.71",
4
4
  "description": "Built-in skill definitions for the Zibby agent-workflow framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -69,6 +69,10 @@
69
69
  "./sentry": {
70
70
  "types": "./dist/sentry.d.ts",
71
71
  "default": "./dist/sentry.js"
72
+ },
73
+ "./review": {
74
+ "types": "./dist/review.d.ts",
75
+ "default": "./dist/review.js"
72
76
  }
73
77
  },
74
78
  "scripts": {