@north-light/cli 0.3.569 → 0.3.571
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/bin/runtime-selector.mjs +15 -0
- package/dist/clients/attach/viewer.js +151 -151
- package/dist/clients/inbox/tui/render.js +2 -2
- package/dist/core/canvas/export-sqlite.js +2 -2
- package/dist/core/canvas/schema-pg/008-import.sql +126 -0
- package/dist/core/canvas/schema-version.d.ts +1 -1
- package/dist/core/canvas/schema-version.js +1 -1
- package/package.json +8 -3
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +17 -13
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
`){
|
|
1
|
+
var U=Object.defineProperty;var a=(n,s)=>U(n,"name",{value:s,configurable:!0});import v from"string-width";import{isResponseBearingSlot as A}from"../../../core/human/page-schema.js";import{answerCommentAnchorLabel as X,describePageAnswer as Z}from"../../../core/human/answer.js";import{renderMarkdownBlockAwareLines as nn}from"../../../core/termrender/termrender.js";import{rewriteMarkdownDocLinks as en}from"../../attach/render/markdown-source.js";import{commentAnchors as tn,describeSlot as j,pageComplete as sn,slotActions as on,slotAnswered as R,tableMarkdown as rn,terminalAnswerable as C}from"./slots.js";import{RESET as r,BOLD as w,DIM as u,GREEN as B,YELLOW as I,CYAN as E,REVERSE as T,sanitize as x,singleLine as b,truncate as H,hline as O,wrap as M,centerHorizontal as D,clipLine as P,panLine as cn,visibleWidth as N}from"./ansi.js";const ln=8,L=a((n,s,t)=>nn(en(n),s,t),"mdLines");function z(n){return Z(n.manifest,Object.fromEntries(n.responses),{completedAt:""})}a(z,"pageAnswer");function fn(n,s){return s.id===void 0?void 0:n.slots.find(t=>t.id===s.id)}a(fn,"answerSlot");function F(n){if(n===void 0||n.state==="unanswered")return"unanswered";if(n.raw!==void 0)return"custom response";const s=n.text!==void 0?[n.text.edited?"edited":"accepted"]:n.groups.map(t=>t.picked.length===0?"none":t.picked.map(e=>e.label).join(", "));return n.freetext!==void 0&&s.push(n.freetext),n.comments.length>0&&s.push(`${n.comments.length} comment${n.comments.length===1?"":"s"}`),s.join("; ")||"answered"}a(F,"answerSummary");function Y(n,s){return X(n,s)}a(Y,"commentLabel");function kn(n,s,t){const e=Math.min(Math.max(20,s-4),120),i=Math.max(20,s-4),c=["",...W(b(n.manifest.title),e,"",0,`${w}${E}`)];if(n.manifest.subtitle)for(const d of M(x(n.manifest.subtitle),e))c.push(` ${u}${d}${r}`);if(n.displayMarkdown!==""){c.push("");for(const d of L(n.displayMarkdown,e,i))c.push(` ${d}`)}else n.manifest.dialect==="html"&&c.push("",` ${u}HTML page \u2014 open in Northlight to read this${r}`);const o=n.slots.length>0;o&&c.push(` ${u}${O(e)}${r}`,"");const f=z(n);let l=-1,$;for(let d=0;d<n.slots.length;d++){const p=n.slots[d];n.manifest.steps>1&&p.step!==l&&(l!==-1&&c.push(""),c.push(` ${w}Step ${p.step+1}/${n.manifest.steps}${r}`),l=p.step);const y=p.id===void 0?void 0:n.responses.get(p.id),g=A(p)?R(n,p)?`${B}\u2713${r}`:`${u}\u25CB${r}`:`${u}\xB7${r}`,k=d===n.currentIndex?`${E}\u25B8${r} `:" ";d===n.currentIndex&&($=c.length),c.push(` ${k}${g} ${H(b(j(p)),Math.max(10,s-16))}`),y!==void 0&&c.push(` ${u}${H(b(F(fn(f,p))),Math.max(10,s-10))}${r}`)}if(n.manifest.slots.some(d=>A(d)&&!C(d))){c.push("");for(const d of M("This page must be answered in Northlight. Leaving it here keeps it in your inbox; x on the list cancels it.",e-2))c.push(` ${I}${d}${r}`)}o&&c.push(""),c.push(` ${u}${O(e)}${r}`);const h=!n.manifest.slots.some(A)?` ${u}u/d${r} scroll ${u}q${r} dismiss`:` ${u}enter${r} review ${u}\u2191\u2193/jk${r} navigate ${u}u/d${r} scroll ${u}q${r} close`;return K(c,h,n,s,t,e+2,n.followSelection?$:void 0)}a(kn,"renderOverview");function un(n,s,t){const e=[...n],i=Math.max(0,Math.min(s,e.length)),c=G(n,t);let o=0;for(let $=0;$<c.length;$++)c[$].start<=i&&(o=$);const f=c.map(($,m)=>{if(m!==o)return e.slice($.start,$.end).join("");const h=e.slice($.start,i).join(""),d=i<$.end?e[i]:" ",p=i<$.end?e.slice(i+1,$.end).join(""):"";return`${h}${T}${d}${r}${p}`}),l=c[o];return i===l.end&&v(e.slice(l.start,l.end).join(""))>=t&&(f[o]=e.slice(l.start,l.end).join(""),f.splice(o+1,0,`${T} ${r}`)),f}a(un,"renderInputBuffer");function bn(n,s){const t=[...n];let e=Math.max(0,Math.min(s,t.length));for(;e>0&&/\s/.test(t[e-1]);)e--;for(;e>0&&!/\s/.test(t[e-1]);)e--;return e}a(bn,"wordLeftIndex");function On(n,s){const t=[...n];let e=Math.max(0,Math.min(s,t.length));for(;e<t.length&&/\s/.test(t[e]);)e++;for(;e<t.length&&!/\s/.test(t[e]);)e++;return e}a(On,"wordRightIndex");function G(n,s){const t=[...n],e=Math.max(1,s),i=[];let c=0,o=0;for(let f=0;f<t.length;f++){const l=t[f];if(l===`
|
|
2
|
+
`){i.push({start:c,end:f}),c=f+1,o=0;continue}const $=v(l);o+$>e?(i.push({start:c,end:f}),c=f,o=$):o+=$}return i.push({start:c,end:t.length}),i}a(G,"wrappedRowBounds");function yn(n,s,t,e){const i=G(n,e),c=Math.max(0,Math.min(s,[...n].length));let o=0;for(let l=0;l<i.length;l++)i[l].start<=c&&(o=l);const f=i[o+t];return f===void 0?c:Math.min(f.start+(c-i[o].start),f.end)}a(yn,"verticalCursor");function $n(n,s){return s.id===void 0?[]:n.responses.get(s.id)?.comments??[]}a($n,"responseComments");function W(n,s,t,e,i){return M(n,Math.max(10,s-e)).map((c,o)=>` ${o===0?t:" ".repeat(e)}${i}${c}${r}`)}a(W,"hangingWrap");function hn(n,s,t,e){if(s.id===void 0)return!1;const i=n.responses.get(s.id);return t==="option"?i?.selectedOptionIds?.includes(e)===!0:t==="card"?i?.selectedCardIds?.includes(e)===!0:t==="row"?i?.selectedRowIds?.includes(e)===!0:i?.selectedColumnIds?.includes(e)===!0}a(hn,"selected");function V(n,s){const t=n.slots[n.currentIndex],e=Math.min(Math.max(20,s-4),120),i=Math.max(20,s-4),c=`[${n.currentIndex+1}/${n.slots.length}]`,o=["",...W(b(n.manifest.title),e,`${w}${E}${c}${r} `,v(c)+2,u),` ${u}${O(e)}${r}`,"",...W(b(j(t)),e,"",0,w)],f=t.config.body;if(typeof f=="string"&&f.length>0){o.push("");for(const m of L(f,e,i))o.push(` ${m}`)}if(C(t)){if(t.kind==="chart"){const m=t.config,h=m.title??`${m.x} vs ${(m.y??[]).map(d=>d.label??d.field).join(", ")}`;o.push("",` ${u}chart \u2014 ${x(m.kind)}: ${x(h)}${r}`)}else if(t.kind==="table"){o.push("");for(const h of L(rn(t.config),e,i))o.push(` ${h}`);const m=t.config.label;m&&o.push(` ${u}${x(m)}${r}`)}else if(t.kind==="text"){const h=(t.id===void 0?void 0:n.responses.get(t.id))?.text??t.config.initialText;o.push("");for(const d of L(h,e,i))o.push(` ${d}`)}}else{o.push("");for(const m of M(`${x(t.kind)} \u2014 must be answered in Northlight; the terminal cannot submit this page`,Math.max(10,e-2)))o.push(` ${I}${m}${r}`);o.push(` ${u}q leaves it in your inbox; x on the list cancels it${r}`)}o.push("",` ${u}${O(e)}${r}`);let l;if(n.inputMode!==null){const m=n.inputMode.kind==="comment"?`Comment on ${Y(t,n.inputMode.anchor)}`:n.inputMode.kind==="text"?"Edit text":"Other response";o.push(` ${w}${m}${r}`);for(const h of un(n.inputMode.buffer,n.inputMode.cursor,Math.max(10,e-4)))o.push(` ${h}`);l=` ${u}enter save esc cancel${n.editorAvailable?" ^o editor":""}${r}`}else{on(t).forEach((h,d)=>{const p=d===n.selectedAction?`${E}\u25B8${r}`:" ";if(h.kind==="select"){const y=hn(n,t,h.group,h.id)?`${B}\u2713${r}`:" ",g=h.shortcut?`[${h.shortcut}] `:"",k=v(g);if(M(x(h.label),Math.max(10,e-6-k)).forEach((S,Q)=>o.push(Q===0?` ${p} [${y}] ${g}${S}`:`${" ".repeat(8+k)}${S}`)),h.description)for(const S of M(x(h.description),Math.max(10,e-6)))o.push(` ${u}${S}${r}`)}else{const y=h.kind==="freetext"?"r":h.kind==="edit"?"e":"a";M(x(h.label),Math.max(10,e-6)).forEach((g,k)=>o.push(k===0?` ${p} [${y}] ${g}`:` ${g}`))}});for(const h of $n(n,t))for(const d of M(`attached: ${Y(t,h.anchor)} \u2014 ${x(h.text)}`,Math.max(10,e-2)))o.push(` ${u}${d}${r}`);n.hint&&o.push(` ${I}${x(n.hint)}${r}`),l=` ${u}n/p next/previous \u2191\u2193/jk actions${tn(t).length>0?" c comment":""} u/d scroll \u2190\u2192/hl pan q close${r}`}const $=Math.max(0,...o.map(N));return{lines:o,footer:l,maxW:e,maxH:Math.max(0,$-Math.max(1,s))}}a(V,"itemLines");function In(n,s,t){if(n.slots[n.currentIndex]===void 0){n.scrollOffset=0,n.hscrollOffset=0,n.hscrollMax=0;return}const e=V(n,s);n.hscrollMax=e.maxH,n.hscrollOffset=Math.max(0,Math.min(n.hscrollOffset,n.hscrollMax)),n.scrollOffset=Math.max(0,Math.min(n.scrollOffset,Math.max(0,e.lines.length-q(t))))}a(In,"clampItemReviewScroll");function En(n,s){n.hscrollOffset=Math.max(0,Math.min(n.hscrollMax,n.hscrollOffset+s*ln))}a(En,"panItemReview");function Sn(n,s,t){const e=V(n,s),i=q(t),c=n.scrollOffset,o=e.lines.slice(c,c+i);for(;o.length<i;)o.push("");const f=n.hscrollOffset>0?o.map($=>cn($,n.hscrollOffset,s)):o,l=Math.min(s,e.maxW+2);return i<t&&f.push(J(e.footer,_(c,i,e.lines.length),e.maxW+2)),D(f.map($=>P($,s)),s,l)}a(Sn,"renderItemReview");function vn(n,s,t){const e=Math.min(Math.max(20,s-4),120),i=["",...W(`${b(n.manifest.title)} \u2014 Summary`,e,"",0,`${w}${E}`),` ${u}${O(e)}${r}`,""],c=z(n);for(const l of c.slots){const $=n.manifest.slots.find(d=>d.id===l.id),h=$!==void 0&&R(n,$)?`${B}\u2713${r}`:`${I}\u25CB${r}`;i.push(` ${h} ${w}${x($===void 0?l.kind:j($))}${r} ${u}${x(F(l))}${r}`)}const o=sn(n);if(!o){i.push("",` ${I}Cannot submit yet.${r}`);for(const l of n.slots.filter(A))R(n,l)||(i.push(` ${u}${l.id??l.kind} is unanswered${r}`),C(l)||i.push(` ${u}${l.id} must be answered in Northlight${r}`))}i.push("",` ${u}${O(e)}${r}`);const f=o?` ${u}enter${r} submit ${u}u/d${r} scroll ${u}q${r} back`:` ${u}u/d${r} scroll ${u}q${r} back`;return K(i,f,n,s,t,e+2)}a(vn,"renderFinal");function q(n){return n>=2?n-1:n}a(q,"bodyRows");function _(n,s,t){if(s<=0||t<=s)return{marks:"",full:""};const e=Math.min(t,n+s),i=`${n>0?"\u25B4":" "}${e<t?"\u25BE":" "}`;return{marks:`${u}${i}${r}`,full:`${u}${i} ${n+1}\u2013${e}/${t}${r}`}}a(_,"scrollBadge");function J(n,s,t){if(s.full==="")return n;const e=a(i=>t-N(n)-N(i)-2,"room");for(const i of[s.full,s.marks])if(e(i)>=2)return`${n}${" ".repeat(e(i))}${i}`;return` ${s.marks} ${n.trimStart()}`}a(J,"pinnedFooter");function K(n,s,t,e,i,c,o){const f=q(i),l=Math.max(0,n.length-f);t.scrollOffset=Math.max(0,Math.min(t.scrollOffset,l)),o!==void 0&&f>0&&(o<t.scrollOffset?t.scrollOffset=o:o>=t.scrollOffset+f&&(t.scrollOffset=Math.min(l,o-f+1)));const $=n.slice(t.scrollOffset,t.scrollOffset+f);for(;$.length<f;)$.push("");return f<i&&$.push(J(s,_(t.scrollOffset,f,n.length),c)),D($.map(m=>P(m,e)),e,Math.min(e,c))}a(K,"centeredWindow");export{In as clampItemReviewScroll,En as panItemReview,vn as renderFinal,un as renderInputBuffer,Sn as renderItemReview,kn as renderOverview,yn as verticalCursor,bn as wordLeftIndex,On as wordRightIndex,G as wrappedRowBounds};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var V=Object.defineProperty;var
|
|
1
|
+
var V=Object.defineProperty;var d=(i,a)=>V(i,"name",{value:a,configurable:!0});import{DatabaseSync as W}from"node:sqlite";import{existsSync as Y,mkdirSync as D,mkdtempSync as J,renameSync as X,rmSync as P}from"node:fs";import{tmpdir as Q}from"node:os";import{join as A}from"node:path";import j from"pg";import{migrate as z,MIGRATIONS as I}from"./migrations.js";import{canvasDbPath as Z}from"./paths.js";import{canvasSearchPathOptions as ee}from"./schema-version.js";import{EXPORT_MARK_KEY as F,IMPORT_MARK_KEY as te,OBJECT_COLUMNS as ne,pgColumns as se,quote as p,TABLE_ORDER as C}from"./import-sqlite.js";const re=5e3,oe=new Set(["environments","relations","schemas","charges","charge_totals","limits","viewer_attachments","reconciler_leases","environment_repos","conversation_entries","conversation_parts","charge_chunks","profiles","profile_projects","profile_defaults","scope_settings","scope_bookkeeping","scope_marketplaces","scope_plugins","person_settings","model_accounts","model_account_cooldowns","model_api_keys","model_settings","model_sign_in_flows","env_vars","import_runs","import_key_map","import_manifest","import_id_map","machine_links","machine_calls","machine_credentials","import_node_files","usage","grantee_usage","provider_receipts"]),ae={exposures:"node, object, channel",rules:"object, position",edges:"type, src, dst",unresolved_links:"src, name",revision_parents:"child, parent",canvas_meta:"key",runtime_state:"key",message_causes:"message_id",peer_ingested:"key",peer_ingested_destinations:"key",message_sequence:"id",messages:"seq",review_comment_events:"seq",audit_rows:"id",peer_outbox:"id",app_users:"uid"},ie={objects:"id",revisions:"rev_id",watches:"watch_id"},H=new Set(["daemon_owner","schema_version","schema_min_reader","ledger_migrated",te,F]);function ce(i){const a=J(A(Q(),"crtr-export-")),s=process.env.CRTR_HOME;process.env.CRTR_HOME=a,D(A(a,"runtime","nodes"),{recursive:!0});try{const r=new W(i);return r.exec("PRAGMA journal_mode = DELETE;"),r.exec("PRAGMA foreign_keys = ON;"),z(r),r.exec("DELETE FROM canvas_meta; DELETE FROM message_sequence;"),r}finally{s===void 0?delete process.env.CRTR_HOME:process.env.CRTR_HOME=s,P(a,{recursive:!0,force:!0})}}d(ce,"createEmptyDatabase");async function Re(i,a=()=>{}){const s=Z();if(Y(s))throw new Error(`${s} already exists; refusing to overwrite it`);D(A(s,".."),{recursive:!0,mode:448});const r=`${s}.exporting-${process.pid}`,u=Date.now(),t=new j.Client({connectionString:i,application_name:`crtr-export-${process.pid}`,options:ee(),types:{getTypeParser:d(((f,o)=>f===20?w=>Number(w):j.types.getTypeParser(f,o)),"getTypeParser")}});await t.connect();let _;try{if((await t.query("SELECT value FROM canvas_meta WHERE key = 'schema_version'").catch(()=>({rows:[]}))).rows.length===0)throw new Error("the Postgres database has no canvas schema; nothing to export");_=ce(r);const o=_;o.exec("PRAGMA foreign_keys = OFF;");const w=await se(t),L=[...w.keys()].filter(e=>!oe.has(e)&&!C.includes(e));if(L.length>0)throw new Error(`export: Postgres tables with no export rule: ${L.join(", ")}`);await t.query("BEGIN READ ONLY ISOLATION LEVEL REPEATABLE READ");const E={};for(const[e,S]of Object.entries(ie)){const h=new Map;for(const l of(await t.query(`SELECT ${S} AS id, seq FROM ${e}`)).rows)h.set(l.id,Number(l.seq));E[e]=h}const B=E.objects;let M=0;o.exec("BEGIN");for(const e of C){const S=Date.now(),h=new Set(o.prepare(`PRAGMA table_info(${p(e)})`).all().map(n=>n.name)),l=w.get(e);if(l===void 0)throw new Error(`export: Postgres has no table ${e}`);const G=l.some(n=>n.name==="seq"),O=l.filter(n=>h.has(n.name)),K=new Set(ne[e]??[]),g=e==="objects"||e==="revisions"||e==="watches"||e==="watch_subscriptions",$=O.map(n=>n.type==="jsonb"?`${p(n.name)}::text AS ${p(n.name)}`:p(n.name));e==="watches"&&$.push("watch_id AS _watch_id"),g&&$.push("seq AS _seq");const R=O.map(n=>p(n.name)),U=o.prepare(`INSERT INTO ${p(e)} (${g?["rowid",...R]:R}) VALUES (${(g?["?",...R]:R).map(()=>"?").join(", ")})`),k=G?"seq":ae[e],b=`export_${e}`;await t.query(`DECLARE ${b} NO SCROLL CURSOR FOR SELECT ${$.join(", ")} FROM ${p(e)}${e==="canvas_meta"?` WHERE key NOT IN (${[...H].map(n=>`'${n}'`).join(", ")})`:""}${k===void 0?"":` ORDER BY ${k}`}`);let T=0;for(;;){const n=await t.query(`FETCH ${re} FROM ${b}`);if(n.rows.length===0)break;for(const q of n.rows){const N=g?[Number(q._seq)]:[];for(const c of O){let m=q[c.name];e==="revision_parents"&&(c.name==="child"||c.name==="parent")?m=x(E.revisions,"revision",e,c.name,m):e==="watch_subscriptions"&&c.name==="watch"?m=x(E.watches,"watch",e,c.name,m):K.has(c.name)?m=x(B,"object",e,c.name,m):e==="jobs"&&(c.name==="job_dir"||c.name==="log_path")&&(m=m??""),N.push(m??null)}U.run(...N)}T+=n.rows.length}await t.query(`CLOSE ${b}`),M+=T,a(`export ${e}: ${T} rows in ${Date.now()-S} ms`)}o.exec("COMMIT"),await t.query("COMMIT");const y=o.prepare("PRAGMA foreign_key_check").all();if(y.length>0)throw new Error(`export: ${y.length} foreign key violation(s) in the exported canvas.db, first: ${JSON.stringify(y[0])}`);await me(t,o);const v=o.prepare("PRAGMA user_version").get().user_version;if(v!==I.length)throw new Error(`export: exported canvas.db is at user_version ${v}, expected ${I.length}`);return o.close(),_=void 0,await t.query("INSERT INTO canvas_meta (key, value) VALUES ($1, $2) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value",[F,JSON.stringify({at:new Date().toISOString(),path:s})]),X(r,s),{path:s,rows:M,ms:Date.now()-u,userVersion:v}}catch(f){await t.query("ROLLBACK").catch(()=>{});try{_?.close()}catch{}for(const o of["","-wal","-shm","-journal"])P(`${r}${o}`,{force:!0});throw f}finally{await t.end().catch(()=>{})}}d(Re,"exportPostgresToSqlite");function x(i,a,s,r,u){if(u==null)return null;const t=i.get(u);if(t===void 0)throw new Error(`export: ${s}.${r} references ${a} ${String(u)}, which was not exported (`);return t}d(x,"mapId");async function me(i,a){const s=[];for(const r of C){const u=Number((await i.query(`SELECT count(*) AS n FROM ${p(r)}`)).rows[0].n);let t=Number(a.prepare(`SELECT count(*) AS n FROM ${p(r)}`).get().n),_=u;r==="canvas_meta"&&(_=Number((await i.query("SELECT count(*) AS n FROM canvas_meta WHERE key <> ALL($1)",[[...H]])).rows[0].n),t=Number(a.prepare("SELECT count(*) AS n FROM canvas_meta").get().n)),_!==t&&s.push(`${r}: Postgres ${_} rows, SQLite ${t}`)}if(s.length>0)throw new Error(`Postgres \u2192 SQLite export verification failed:
|
|
2
2
|
${s.join(`
|
|
3
|
-
`)}`)}
|
|
3
|
+
`)}`)}d(me,"verify");export{Re as exportPostgresToSqlite};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
-- 008-import.sql — cycle 6 I-S (design-import "Data model"): the tables the import lane, the remote machine runner and the
|
|
2
|
+
-- sandbox import step share, and the third runner kind. One transaction, additions only: `schema_min_reader` is not touched
|
|
3
|
+
-- and stays 2, so the previous build (v0.3.569, schema 7) still opens a version-8 database. It never names the new tables.
|
|
4
|
+
-- Timestamps are text, as in 002; `*_json` columns are text holding JSON, as in 002; a lane's claim is `claimed_by` +
|
|
5
|
+
-- `lease_expires_at`, as on the cycle 5 lanes' rows.
|
|
6
|
+
|
|
7
|
+
-- ---------------------------------------------------------------- the remote machine runner is a third runner (design-import I13)
|
|
8
|
+
-- Widening a CHECK is rollback-safe (007 did the same for `limits_source_check`): the previous build never writes 'machine'.
|
|
9
|
+
ALTER TABLE executions DROP CONSTRAINT IF EXISTS executions_runner_check;
|
|
10
|
+
ALTER TABLE executions ADD CONSTRAINT executions_runner_check CHECK (runner IN ('process', 'blaxel', 'machine'));
|
|
11
|
+
|
|
12
|
+
-- ---------------------------------------------------------------- import runs
|
|
13
|
+
|
|
14
|
+
-- One row per attempt. A run is open in `uploading`, `loading` and `committed`; `done` closes it for good. At most one run per
|
|
15
|
+
-- source install id is open or `done` (a `failed` or `rolled_back` run does not count), which is the rule behind the API's
|
|
16
|
+
-- `already_imported` and `import_running` refusals.
|
|
17
|
+
CREATE TABLE import_runs (
|
|
18
|
+
run_id text PRIMARY KEY,
|
|
19
|
+
source_install_id text NOT NULL,
|
|
20
|
+
source_kind text NOT NULL CHECK (source_kind IN ('machine', 'hosted')),
|
|
21
|
+
person text NOT NULL,
|
|
22
|
+
release text NOT NULL,
|
|
23
|
+
state text NOT NULL CHECK (state IN ('uploading', 'loading', 'committed', 'done', 'failed', 'rolled_back')),
|
|
24
|
+
committed_at text,
|
|
25
|
+
step text,
|
|
26
|
+
counts_json text,
|
|
27
|
+
verify_json text,
|
|
28
|
+
failure_json text,
|
|
29
|
+
manifest_key text,
|
|
30
|
+
created_at text NOT NULL,
|
|
31
|
+
loaded_at text,
|
|
32
|
+
finished_at text,
|
|
33
|
+
claimed_by text,
|
|
34
|
+
lease_expires_at text
|
|
35
|
+
);
|
|
36
|
+
CREATE UNIQUE INDEX import_runs_one_per_install ON import_runs(source_install_id) WHERE state IN ('uploading', 'loading', 'committed', 'done');
|
|
37
|
+
-- The lane's SKIP LOCKED claim: `loading` rows, and `committed` rows whose lease expired (resume at verify).
|
|
38
|
+
CREATE INDEX import_runs_claim ON import_runs(state, lease_expires_at) WHERE state IN ('loading', 'committed');
|
|
39
|
+
|
|
40
|
+
-- The three identity-keyed tables' source keys → the keys the target assigned (`audit_rows.id`, `review_comment_events.seq`,
|
|
41
|
+
-- `app_users.uid`). Written in the copy transaction.
|
|
42
|
+
CREATE TABLE import_key_map (
|
|
43
|
+
source_install_id text NOT NULL,
|
|
44
|
+
table_name text NOT NULL,
|
|
45
|
+
source_key text NOT NULL,
|
|
46
|
+
target_key text NOT NULL,
|
|
47
|
+
PRIMARY KEY (source_install_id, table_name, source_key)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
-- The primary keys each run inserted, per table (a compressed list): the authority for verify and rollback.
|
|
51
|
+
CREATE TABLE import_manifest (
|
|
52
|
+
run_id text NOT NULL REFERENCES import_runs(run_id),
|
|
53
|
+
table_name text NOT NULL,
|
|
54
|
+
inserted_keys bytea NOT NULL,
|
|
55
|
+
PRIMARY KEY (run_id, table_name)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
-- The id map and path map a run persisted, so a later import that maps onto this run's rows is visible to rollback.
|
|
59
|
+
CREATE TABLE import_id_map (
|
|
60
|
+
run_id text NOT NULL REFERENCES import_runs(run_id),
|
|
61
|
+
kind text NOT NULL CHECK (kind IN ('object', 'grant', 'kind', 'path')),
|
|
62
|
+
source_value text NOT NULL,
|
|
63
|
+
target_value text NOT NULL,
|
|
64
|
+
PRIMARY KEY (run_id, kind, source_value)
|
|
65
|
+
);
|
|
66
|
+
CREATE INDEX import_id_map_target ON import_id_map(kind, target_value);
|
|
67
|
+
|
|
68
|
+
-- ---------------------------------------------------------------- the remote machine runner
|
|
69
|
+
|
|
70
|
+
-- One live link per machine environment; the API process holding it renews `lease_expires_at`, and a delete is fenced by `generation`.
|
|
71
|
+
CREATE TABLE machine_links (
|
|
72
|
+
environment text PRIMARY KEY REFERENCES environments(object) ON DELETE CASCADE,
|
|
73
|
+
generation bigint NOT NULL,
|
|
74
|
+
api_address text NOT NULL,
|
|
75
|
+
connected_at text NOT NULL,
|
|
76
|
+
lease_expires_at text NOT NULL
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
-- The machine credential (principal `machine:<environment id>`): one live credential per environment, stored as the sha256 hex of
|
|
80
|
+
-- the secret (as `node_tokens`). Issued once when a machine source's run is `done`; `crtr sys machine rotate` replaces the row;
|
|
81
|
+
-- rollback and the console set `revoked_at`, which closes the link within one heartbeat.
|
|
82
|
+
CREATE TABLE machine_credentials (
|
|
83
|
+
environment text PRIMARY KEY REFERENCES environments(object) ON DELETE CASCADE,
|
|
84
|
+
token_hash text NOT NULL UNIQUE,
|
|
85
|
+
issued_at text NOT NULL,
|
|
86
|
+
revoked_at text
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
-- A runner call to a machine: `pending` until the holder of the link claims it (`claimed_generation`, `lease_expires_at`), `sent`
|
|
90
|
+
-- once forwarded, then `done` or `failed` with `result_json`. Deleted a day after `finished_at`.
|
|
91
|
+
CREATE TABLE machine_calls (
|
|
92
|
+
call_id text PRIMARY KEY,
|
|
93
|
+
environment text NOT NULL REFERENCES environments(object) ON DELETE CASCADE,
|
|
94
|
+
op text NOT NULL CHECK (op IN ('start', 'wake', 'stop', 'status', 'delete', 'viewer', 'cron.run', 'cron.cancel')),
|
|
95
|
+
args_json text NOT NULL DEFAULT '{}',
|
|
96
|
+
state text NOT NULL DEFAULT 'pending' CHECK (state IN ('pending', 'sent', 'done', 'failed')),
|
|
97
|
+
claimed_generation bigint,
|
|
98
|
+
lease_expires_at text,
|
|
99
|
+
result_json text,
|
|
100
|
+
created_at text NOT NULL,
|
|
101
|
+
finished_at text
|
|
102
|
+
);
|
|
103
|
+
-- The holder's SKIP LOCKED claim of an environment's open calls, and the lease sweep.
|
|
104
|
+
CREATE INDEX machine_calls_open ON machine_calls(environment, state, created_at) WHERE state IN ('pending', 'sent');
|
|
105
|
+
CREATE INDEX machine_calls_finished ON machine_calls(finished_at) WHERE finished_at IS NOT NULL;
|
|
106
|
+
|
|
107
|
+
-- ---------------------------------------------------------------- hosted running nodes' files
|
|
108
|
+
|
|
109
|
+
-- The archive a hosted running node's sandbox unpacks at its next start; `unpacked_at` is set when the start script reports it.
|
|
110
|
+
-- Storage maintenance deletes the blob 30 days after unpack.
|
|
111
|
+
CREATE TABLE import_node_files (
|
|
112
|
+
node text PRIMARY KEY REFERENCES nodes(node_id) ON DELETE CASCADE,
|
|
113
|
+
blob_key text NOT NULL,
|
|
114
|
+
unpacked_at text
|
|
115
|
+
);
|
|
116
|
+
CREATE INDEX import_node_files_unpacked ON import_node_files(unpacked_at) WHERE unpacked_at IS NOT NULL;
|
|
117
|
+
|
|
118
|
+
-- ---------------------------------------------------------------- the 30-day physical purge (I-8)
|
|
119
|
+
|
|
120
|
+
-- The purge's candidate scan (soft-deleted rows other than nodes, which 005's index and D100's pass cover) and its reference
|
|
121
|
+
-- checks on authorship and kind ownership.
|
|
122
|
+
CREATE INDEX objects_deleted ON objects(deleted_at) WHERE deleted_at IS NOT NULL AND type <> 'node';
|
|
123
|
+
CREATE INDEX revisions_author ON revisions(author) WHERE author IS NOT NULL;
|
|
124
|
+
CREATE INDEX object_kinds_owner ON object_kinds(owner);
|
|
125
|
+
|
|
126
|
+
INSERT INTO canvas_meta (key, value) VALUES ('schema_min_reader', '2') ON CONFLICT (key) DO NOTHING;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** The canvas schema version this build supports: the number of the highest delta in `schema-pg/` (the baseline
|
|
2
2
|
* `schema-pg.sql` is version 1). `scripts/install-runtime.mjs` reads this module from a candidate generation to refuse
|
|
3
3
|
* one below the live database's `schema_min_reader`. */
|
|
4
|
-
export declare const CANVAS_SCHEMA_VERSION =
|
|
4
|
+
export declare const CANVAS_SCHEMA_VERSION = 8;
|
|
5
5
|
/** The Postgres schema holding the canvas tables: `CRTR_DATABASE_SCHEMA` (`crtr` in the cloud deploy). Unset or empty
|
|
6
6
|
* means the role's own search_path (`public` on a Mac and on a VM). A name that is not a plain identifier is an error:
|
|
7
7
|
* it is put in a `search_path` connection option. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var m=Object.defineProperty;var r=(n,e)=>m(n,"name",{value:e,configurable:!0});const A=
|
|
1
|
+
var m=Object.defineProperty;var r=(n,e)=>m(n,"name",{value:e,configurable:!0});const A=8;function _(n=process.env){const e=n.CRTR_DATABASE_SCHEMA?.trim();if(e){if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(e))throw new Error(`CRTR_DATABASE_SCHEMA must be a plain identifier (letters, digits, underscore); got ${JSON.stringify(e)}`);return e}}r(_,"canvasDatabaseSchema");function h(n=process.env){return n.CRTR_SCHEMA_DATABASE_URL?.trim()||void 0}r(h,"canvasSchemaDatabaseUrl");function E(n=process.env){const e=_(n);return e===void 0?void 0:`-c search_path=${e}`}r(E,"canvasSearchPathOptions");async function v(n,e){const t=e===void 0?"canvas_meta":`"${e.replace(/"/g,'""')}".canvas_meta`;if((await n.query(`SELECT to_regclass('${t.replace(/'/g,"''")}') IS NOT NULL AS found`)).rows[0].found!==!0)return;const u=(await n.query(`SELECT key, value FROM ${t} WHERE key IN ('schema_version', 'schema_min_reader')`)).rows,o=r(c=>{const i=u.find(f=>f.key===c);if(i===void 0)return;const d=Number(i.value);if(!Number.isSafeInteger(d))throw new Error(`canvas_meta.${c} is not an integer: ${String(i.value)}`);return d},"value"),s=o("schema_version");return s===void 0?void 0:{version:s,minReader:o("schema_min_reader")??s}}r(v,"readStoredVersions");async function l(n,e,t){const a=await v(n,t);if(a!==void 0&&a.minReader>e)throw new Error(`refusing to select runtime with canvas schema ${e}: the live database requires readers at version ${a.minReader} or above (it is at ${a.version}); install a descendant build instead`)}r(l,"assertCandidateMayOpen");export{A as CANVAS_SCHEMA_VERSION,l as assertCandidateMayOpen,_ as canvasDatabaseSchema,h as canvasSchemaDatabaseUrl,E as canvasSearchPathOptions,v as readStoredVersions};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.571",
|
|
4
4
|
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -102,10 +102,11 @@
|
|
|
102
102
|
"typecheck": "tsc --noEmit && tsc -p src/doc-editor/tsconfig.json",
|
|
103
103
|
"typecheck:pi-packages": "npx tsc -p src/builtin-pi-packages/pi-crtr-extensions/tsconfig.json",
|
|
104
104
|
"test:runtime-packaging": "node --test scripts/runtime-smoke.test.mjs scripts/pack-args.test.mjs scripts/ensure-native-linux.test.mjs scripts/release-version.test.mjs scripts/sandbox-start.test.mjs",
|
|
105
|
+
"check:consumer-resolution": "node scripts/check-consumer-resolution.mjs",
|
|
105
106
|
"contract:check": "node scripts/contract.mjs check",
|
|
106
107
|
"contract:surface": "node scripts/contract.mjs generate",
|
|
107
108
|
"docs:check-reference": "npm exec --workspace @north-light/docs -- tsx scripts/check-reference.ts",
|
|
108
|
-
"test:contract": "node --conditions=crtr-src --import tsx/esm --test scripts/contract.test.mjs scripts/promote-sdk.test.mjs scripts/release-version.test.mjs scripts/sdk-docs-commands.test.mjs scripts/ci-image.test.mjs scripts/ci-miss-triage.test.mjs scripts/ci-test-pick.test.mjs",
|
|
109
|
+
"test:contract": "node --conditions=crtr-src --import tsx/esm --test scripts/contract.test.mjs scripts/promote-sdk.test.mjs scripts/release-version.test.mjs scripts/sdk-docs-commands.test.mjs scripts/ci-image.test.mjs scripts/ci-miss-triage.test.mjs scripts/ci-test-pick.test.mjs scripts/runtime-selector.test.mjs",
|
|
109
110
|
"test:build-output": "node scripts/build-concurrency-test.mjs",
|
|
110
111
|
"check:cli-no-canvas": "node scripts/check-cli-no-canvas.mjs",
|
|
111
112
|
"check:cli-cold-start": "node scripts/check-cli-cold-start.mjs",
|
|
@@ -144,10 +145,14 @@
|
|
|
144
145
|
},
|
|
145
146
|
"license": "UNLICENSED",
|
|
146
147
|
"dependencies": {
|
|
147
|
-
"@north-light/identity": "0.3.
|
|
148
|
+
"@north-light/identity": "0.3.571",
|
|
149
|
+
"@earendil-works/chord": "1.1.0",
|
|
148
150
|
"@earendil-works/pi-agent-core": "1.1.0",
|
|
149
151
|
"@earendil-works/pi-ai": "1.1.0",
|
|
152
|
+
"@earendil-works/pi-codemode": "1.1.0",
|
|
150
153
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
154
|
+
"@earendil-works/pi-mcp": "1.1.0",
|
|
155
|
+
"@earendil-works/pi-telemetry": "1.1.0",
|
|
151
156
|
"@earendil-works/pi-tui": "1.1.0",
|
|
152
157
|
"@milkdown/core": "^7.22.3",
|
|
153
158
|
"@milkdown/plugin-history": "^7.22.3",
|
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.571",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/cli",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.571",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "UNLICENSED",
|
|
12
12
|
"workspaces": [
|
|
@@ -14,9 +14,13 @@
|
|
|
14
14
|
"apps/*"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
+
"@earendil-works/chord": "1.1.0",
|
|
17
18
|
"@earendil-works/pi-agent-core": "1.1.0",
|
|
18
19
|
"@earendil-works/pi-ai": "1.1.0",
|
|
20
|
+
"@earendil-works/pi-codemode": "1.1.0",
|
|
19
21
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
22
|
+
"@earendil-works/pi-mcp": "1.1.0",
|
|
23
|
+
"@earendil-works/pi-telemetry": "1.1.0",
|
|
20
24
|
"@earendil-works/pi-tui": "1.1.0",
|
|
21
25
|
"@milkdown/core": "^7.22.3",
|
|
22
26
|
"@milkdown/plugin-history": "^7.22.3",
|
|
@@ -24,7 +28,7 @@
|
|
|
24
28
|
"@milkdown/preset-gfm": "^7.22.3",
|
|
25
29
|
"@milkdown/prose": "^7.22.3",
|
|
26
30
|
"@milkdown/utils": "^7.22.3",
|
|
27
|
-
"@north-light/identity": "0.3.
|
|
31
|
+
"@north-light/identity": "0.3.571",
|
|
28
32
|
"cron-parser": "^5.6.0",
|
|
29
33
|
"esbuild": "^0.27.7",
|
|
30
34
|
"jose": "^6.2.12",
|
|
@@ -12455,17 +12459,17 @@
|
|
|
12455
12459
|
},
|
|
12456
12460
|
"packages/crouter-api": {
|
|
12457
12461
|
"name": "@north-light/api",
|
|
12458
|
-
"version": "0.3.
|
|
12462
|
+
"version": "0.3.571",
|
|
12459
12463
|
"license": "UNLICENSED"
|
|
12460
12464
|
},
|
|
12461
12465
|
"packages/crouter-env-docker": {
|
|
12462
12466
|
"name": "@north-light/env-docker",
|
|
12463
|
-
"version": "0.3.
|
|
12467
|
+
"version": "0.3.571",
|
|
12464
12468
|
"license": "UNLICENSED"
|
|
12465
12469
|
},
|
|
12466
12470
|
"packages/crouter-identity": {
|
|
12467
12471
|
"name": "@north-light/identity",
|
|
12468
|
-
"version": "0.3.
|
|
12472
|
+
"version": "0.3.571",
|
|
12469
12473
|
"license": "UNLICENSED",
|
|
12470
12474
|
"dependencies": {
|
|
12471
12475
|
"jose": "^6.2.1"
|
|
@@ -12473,21 +12477,21 @@
|
|
|
12473
12477
|
},
|
|
12474
12478
|
"packages/crouter-plugin": {
|
|
12475
12479
|
"name": "@north-light/plugin",
|
|
12476
|
-
"version": "0.3.
|
|
12480
|
+
"version": "0.3.571",
|
|
12477
12481
|
"license": "UNLICENSED",
|
|
12478
12482
|
"dependencies": {
|
|
12479
|
-
"@north-light/api": "0.3.
|
|
12480
|
-
"@north-light/identity": "0.3.
|
|
12483
|
+
"@north-light/api": "0.3.571",
|
|
12484
|
+
"@north-light/identity": "0.3.571"
|
|
12481
12485
|
}
|
|
12482
12486
|
},
|
|
12483
12487
|
"packages/crouter-sdk": {
|
|
12484
12488
|
"name": "@north-light/sdk",
|
|
12485
|
-
"version": "0.3.
|
|
12489
|
+
"version": "0.3.571",
|
|
12486
12490
|
"license": "UNLICENSED",
|
|
12487
12491
|
"dependencies": {
|
|
12488
|
-
"@north-light/api": "0.3.
|
|
12489
|
-
"@north-light/identity": "0.3.
|
|
12490
|
-
"@north-light/plugin": "0.3.
|
|
12492
|
+
"@north-light/api": "0.3.571",
|
|
12493
|
+
"@north-light/identity": "0.3.571",
|
|
12494
|
+
"@north-light/plugin": "0.3.571",
|
|
12491
12495
|
"jose": "^6.2.1"
|
|
12492
12496
|
},
|
|
12493
12497
|
"bin": {
|