@north-light/cli 0.3.428 → 0.3.429

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.
@@ -1,2 +1,2 @@
1
- var f=Object.defineProperty;var o=(e,t)=>f(e,"name",{value:t,configurable:!0});import{usage as m}from"../../core/errors.js";import{ApiError as w}from"../../api/errors.js";import{rethrowAsCliError as c}from"../api-client.js";import{RULE_ON as v,RULE_DELIVER as y,DOC_KINDS as g}from"../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as b}from"../../api/dto/objects.js";const O="A document name (with or without [[ ]]) or a raw object id.",p="node | user | profile | profile:<name> | app | repo | repo:<handle>";function j(e){return{kind:"flag",name:"owner",type:"string",required:!1,constraint:e,focusedHelp:{whenToUse:"Omit it for a document only this node and the nodes it points at need: the writing node owns it and it is deleted with the node, unless a kept document links to it. Give another owner when the document must outlive this node or reach other nodes by itself. A document worth another owner carries reusable current truth: a non-obvious procedure, a gotcha, a lasting preference, a convention across repos. Task notes, conversation summaries and facts the repo already records stay with the node or are not written. Before writing one, search for a document that already covers it (`crtr canvas search`) and revise that one with `crtr doc edit` instead of adding a near copy. When one document grows long, keep the most important content in it and move separate subjects into documents named under it (`topic/part`), each pointed at with a `[[link]]`. Choose the narrowest owner that still reaches the next agent who needs it.",value:`One of ${p}. \`node\` \u2014 the writing node; only this node loads it by rule, other nodes read it when pointed at it; deleted with the node. \`profile\` \u2014 the node's profile, or \`profile:<name>\`; loads for nodes running in that profile; stays on this runtime. \`app\` \u2014 the app that runs the node; kept until deleted; readable by that app's nodes. \`repo\` \u2014 the repo the node works in (from its working directory), or \`repo:<handle>\`; every clone and worktree of the repo shares it, and it syncs to collaborators over the repo's \`refs/crtr/docs\`. A repo owns only public documents: a private or friends document that should load in one repo is owned by \`user\` and carries a rule with \`if: {"repo": "<handle>"}\`. \`user\` \u2014 you, the person; loads for every node by its rules; readable by apps by privacy level. Default: the writing node; a person's own run (not a node) defaults to \`user\`. The owner becomes the start of the document's full name (\`<owner-handle>/<name>\`); \`crtr doc move --owner\` changes it later and keeps the id and every link.`,effects:["Decides who may read and change the document, where it syncs, and what deleting takes it with."]}}}o(j,"ownerParam");const k="`if` is a condition on the receiving node. Fields: `kind`, `mode`, `lifecycle`, `cwd`, `repo` (the handle of a repo the node works in), `profile`, `depth`. A field map is ANDed across fields; dotted fields resolve nested values. A scalar matches by equality (a list value matches when any element is equal); a list matcher matches by membership or overlap; an object matcher takes `eq`, `ne`, `in`, `nin`, `exists`, `contains`, `containsAll`, `containsAny`, `matches`, `imatches`, `gt`, `gte`, `lt`, `lte`. `all`, `any` and `not` combine conditions; field matchers beside them are ANDed in. An empty condition always matches; an unknown operator never matches. `match_frontmatter` uses the same language against the read file's YAML frontmatter.";function S(e){return{kind:"flag",name:"rule",type:"string",required:!1,repeatable:!0,constraint:e,focusedHelp:{whenToUse:"Omit it for most documents: a document with no rule is read when a node is pointed at it (`[[name]]`), finds it with `crtr canvas search`, or sees it in a listing. Add a rule only when the document must load on its own because of what a node is doing; every rule costs context in every node it fires on. Prefer the narrowest trigger: a `file-read` rule with a real glob over `boot` for knowledge about specific code; `boot` for knowledge about a person or process with no file boundary. When the whole document is one sentence, deliver `content` \u2014 a preview line would be longer than the document.",value:`One JSON object per occurrence: \`{"on": \u2026, "match"?: [globs], "match_frontmatter"?: {\u2026}, "if"?: {\u2026}, "deliver": \u2026}\`. \`on\` is the node's activity: ${v.join(" | ")}. \`boot\` \u2014 every session start of the node. \`workspace-open\` \u2014 the node's first message when it works in the document's repo. \`file-read\` \u2014 the node reads a file whose absolute path or basename matches a \`match\` glob, or whose frontmatter matches \`match_frontmatter\`. \`document-read\` \u2014 another document whose name matches is delivered at content, including an explicit read. \`command\` \u2014 a shell segment of a bash command matches (segments split on \`&&\`, \`||\`, \`;\`, \`|\` and newlines outside quotes, leading \`VAR=value\` dropped; \`*\` spans whole whitespace-separated tokens, \`?\` one character, quoted text is opaque). \`pre-command\` \u2014 as \`command\`, but runs before the command: when the node has not read the document, the command does not run and the document is returned instead; the node re-issues the command. \`slash-command\` \u2014 the document is a \`/<name>\` slash command whose body is the injected prompt. \`match\` is required on \`file-read\` (unless \`match_frontmatter\` is given), \`document-read\`, \`command\` and \`pre-command\`, and not allowed on \`boot\`, \`workspace-open\` and \`slash-command\`. `+k+` \`deliver\` is ${y.join(" | ")}: the bare name, the preview line, or the whole body. The flag set replaces the document's whole rule list; on \`crtr doc edit\`, \`--unset rules\` removes every rule.`,effects:["When several rules deliver one document to a node, the highest delivery wins: content over preview over name; content already in the node's context is not delivered again.","A document delivered at content is a read: it records the node as a watcher, so the node is pushed later edits.","The profile's delivery limit per owner caps what `boot` and `workspace-open` rules deliver for that owner.",'A rule that delivers at `preview` requires the preview in the shape "When <situation in the reader\'s work>, read this because <what the reader gains>"; `crtr doc lint` checks it. There the line alone decides whether a node that did not ask for the document opens it.']}}}o(S,"ruleParam");const N={preview:o(e=>({kind:"flag",name:"preview",type:"string",required:!1,constraint:e}),"preview"),kind:{kind:"flag",name:"kind",type:"enum",choices:[...g],required:!1,constraint:"knowledge is consulted for facts or procedures; preference directs behavior. Default knowledge."},summary:{kind:"flag",name:"summary",type:"string",required:!1,constraint:"A very short version of the content, shown in `crtr canvas list`."},privacy:o(e=>({kind:"flag",name:"privacy",type:"enum",choices:[...b],required:!1,constraint:e}),"privacy"),whyItExists:{kind:"flag",name:"why-it-exists",type:"string",required:!1,constraint:"The observed failure this document exists to prevent; shown only with `crtr canvas read --fields`."},unlisted:o(e=>({kind:"flag",name:"unlisted",type:"bool",required:!1,constraint:e}),"unlisted"),lintIgnore:{kind:"flag",name:"lint-ignore",type:"string",required:!1,repeatable:!0,constraint:"A `crtr doc lint` rule name to skip for this document."},extension:{kind:"flag",name:"extension",type:"string",required:!1,repeatable:!0,constraint:"One declared plugin field as `<plugin>.<field>=<json value>`."}};function h(e){return e===void 0?[]:Array.isArray(e)?e.map(String):[String(e)]}o(h,"list");function T(e){const t=[],n={};for(const[r,a]of[["preview","preview"],["kind","kind"],["summary","summary"],["privacy","privacy"],["why-it-exists","why_it_exists"]])typeof e[r]=="string"&&(n[a]=e[r]);typeof n.preview=="string"&&/[\r\n]/.test(n.preview)&&t.push("--preview must be one line"),e.unlisted===!0&&(n.unlisted=!0);const s=h(e["lint-ignore"]);s.length>0&&(n.lint_ignore=s);const i=h(e.rule);if(i.length>0){const r=[];i.forEach((a,u)=>{try{const d=JSON.parse(a);typeof d!="object"||d===null||Array.isArray(d)?t.push(`--rule #${u+1} must be a JSON object`):r.push(d)}catch{t.push(`--rule #${u+1} is not valid JSON: ${a}`)}}),n.rules=r}const l={};for(const r of h(e.extension)){const a=/^([^.=]+)\.([^=]+)=(.*)$/s.exec(r);if(!a){t.push(`--extension ${r} is not <plugin>.<field>=<json value>`);continue}try{(l[a[1]]??={})[a[2]]=JSON.parse(a[3])}catch{t.push(`--extension ${r}: the value after = is not valid JSON`)}}if(Object.keys(l).length>0&&(n.extensions=l),t.length>0)throw m(t.join("; "),{next:"Fix every value above and rerun; `--rule -h` gives the rule grammar."});return n}o(T,"fieldsFromInput");function D(e){const t=e.owner;if(t===void 0)return{};const n=String(t);if(!/^(node|user|profile|app|repo)$|^(profile|repo):.+$/.test(n))throw m(`invalid --owner ${n}`,{field:"owner",next:`Pass one of ${p}.`});return{owner:n}}o(D,"ownerFromInput");function R(e,t){e instanceof w&&(e.code==="read_first"&&c(e,`Read it first with \`crtr canvas read ${t}\`, then rerun the edit.`),e.code==="stale_revision"&&c(e,`Someone edited it after your read. Read it again with \`crtr canvas read ${t}\`, make your change on the current text, and rerun the edit.`)),c(e)}o(R,"rethrowDocError");function I(e){const t=[],n=e.unresolved_links,s=e.remote_links;return n?.length&&t.push(`Unresolved links (no document by these names yet): ${n.map(i=>`[[${i}]]`).join(", ")}`),s?.length&&t.push(`Not on this runtime: ${s.map(i=>`[[${i}]]`).join(", ")} \u2014 each may be on another runtime, or the name may be misspelled.`),t.map(i=>`
2
- ${i}`).join("")}o(I,"renderLinkReport");export{N as FIELD_FLAGS,p as OWNER_VALUES,O as REF_CONSTRAINT,T as fieldsFromInput,D as ownerFromInput,j as ownerParam,I as renderLinkReport,R as rethrowDocError,S as ruleParam};
1
+ var f=Object.defineProperty;var o=(e,t)=>f(e,"name",{value:t,configurable:!0});import{usage as m}from"../../core/errors.js";import{ApiError as w}from"../../api/errors.js";import{rethrowAsCliError as c}from"../api-client.js";import{RULE_ON as v,RULE_DELIVER as y,DOC_KINDS as g}from"../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as b}from"../../api/dto/objects.js";const O="A document name (with or without [[ ]]) or a raw object id.",p="node | user | profile | profile:<name> | app | repo | repo:<handle>";function j(e){return{kind:"flag",name:"owner",type:"string",required:!1,constraint:e,focusedHelp:{whenToUse:"Omit it for a document only this node and the nodes it points at need: the writing node owns it and it is deleted with the node, unless a kept document links to it. Give another owner when the document must outlive this node or reach other nodes by itself. A document worth another owner carries reusable current truth: a non-obvious procedure, a gotcha, a lasting preference, a convention across repos. Task notes, conversation summaries and facts the repo already records stay with the node or are not written. Before writing one, search for a document that already covers it (`crtr canvas search`) and revise that one with `crtr doc edit` instead of adding a near copy. When one document grows long, keep the most important content in it and move separate subjects into documents named under it (`topic/part`), each pointed at with a `[[link]]`. Choose the narrowest owner that still reaches the next agent who needs it.",value:`One of ${p}. \`node\` \u2014 the writing node; only this node loads it by rule, other nodes read it when pointed at it; deleted with the node. \`profile\` \u2014 the node's profile, or \`profile:<name>\`; loads for nodes running in that profile; stays on this runtime. \`app\` \u2014 the app that runs the node; kept until deleted; readable by that app's nodes. \`repo\` \u2014 the repo the node works in (from its working directory), or \`repo:<handle>\`; every clone and worktree of the repo shares it, and it syncs to collaborators over the repo's \`refs/crtr/docs\`. A repo owns only public documents: a private or friends document that should load in one repo is owned by \`user\` and carries a rule with \`if: {"repo": "<handle>"}\`. \`user\` \u2014 you, the person; loads for every node by its rules; readable by apps by privacy level. Default: the writing node; a person's own run (not a node) defaults to \`user\`. The owner becomes the start of the document's full name (\`<owner-handle>/<name>\`); \`crtr doc move --owner\` changes it later and keeps the id and every link.`,effects:["Decides who may read and change the document, where it syncs, and what deleting takes it with."]}}}o(j,"ownerParam");const k="`if` is a condition on the receiving node. Fields: `kind`, `mode`, `lifecycle`, `cwd`, `repo` (the handle of a repo the node works in), `profile`, `depth`. A field map is ANDed across fields; dotted fields resolve nested values. A scalar matches by equality (a list value matches when any element is equal); a list matcher matches by membership or overlap; an object matcher takes `eq`, `ne`, `in`, `nin`, `exists`, `contains`, `containsAll`, `containsAny`, `matches`, `imatches`, `gt`, `gte`, `lt`, `lte`. `all`, `any` and `not` combine conditions; field matchers beside them are ANDed in. An empty condition always matches; an unknown operator never matches. `match_frontmatter` uses the same language against the read file's YAML frontmatter.";function S(e){return{kind:"flag",name:"rule",type:"string",required:!1,repeatable:!0,constraint:e,focusedHelp:{whenToUse:"Omit it for most documents: a document with no rule is read when a node is pointed at it (`[[name]]`), finds it with `crtr canvas search`, or sees it in a listing. Add a rule only when the document must load on its own because of what a node is doing; every rule costs context in every node it fires on. Prefer the narrowest trigger: a `file-read` rule with a real glob over `boot` for knowledge about specific code; `boot` for knowledge about a person or process with no file boundary. When the whole document is one sentence, deliver `content` \u2014 a preview line would be longer than the document.",value:`One JSON object per occurrence: \`{"on": \u2026, "match"?: [globs], "match_frontmatter"?: {\u2026}, "if"?: {\u2026}, "deliver": \u2026}\`. \`on\` is the node's activity: ${v.join(" | ")}. \`boot\` \u2014 every session start of the node. \`workspace-open\` \u2014 the node's first message when it works in the document's repo. \`file-read\` \u2014 the node reads a file whose absolute path or basename matches a \`match\` glob, or whose frontmatter matches \`match_frontmatter\`. \`document-read\` \u2014 another document whose name matches is delivered at content, including an explicit read. \`command\` \u2014 a shell segment of a bash command matches (segments split on \`&&\`, \`||\`, \`;\`, \`|\` and newlines outside quotes, leading \`VAR=value\` dropped; \`*\` spans whole whitespace-separated tokens, \`?\` one character, quoted text is opaque). \`pre-command\` \u2014 as \`command\`, but runs before the command: when the node has not read the document, the command does not run and the document is returned instead; the node re-issues the command. \`slash-command\` \u2014 the document is a \`/<name>\` slash command whose body is the injected prompt. \`match\` is required on \`file-read\` (unless \`match_frontmatter\` is given), \`document-read\`, \`command\` and \`pre-command\`, and not allowed on \`boot\`, \`workspace-open\` and \`slash-command\`. `+k+` \`deliver\` is ${y.join(" | ")}: the bare name, the preview line, or the whole body. The flag set replaces the document's whole rule list; on \`crtr doc edit\`, \`--unset rules\` removes every rule.`,effects:["When several rules deliver one document to a node, the highest delivery wins: content over preview over name; content already in the node's context is not delivered again.","A document delivered at content is a read: it records the node as a watcher, so the node is pushed later edits.","The profile's delivery limit per owner caps what `boot` and `workspace-open` rules deliver for that owner.",'A rule that delivers at `preview` requires the preview in the shape "When <situation in the reader\'s work>, read this because <what the reader gains>"; `crtr doc lint` checks it. There the line alone decides whether a node that did not ask for the document opens it.']}}}o(S,"ruleParam");const N={preview:o(e=>({kind:"flag",name:"preview",type:"string",required:!1,constraint:e}),"preview"),kind:{kind:"flag",name:"kind",type:"enum",choices:[...g],required:!1,constraint:"knowledge is consulted for facts or procedures; preference directs behavior. Default knowledge."},summary:{kind:"flag",name:"summary",type:"string",required:!1,constraint:"A very short version of the content, shown in `crtr canvas list`."},privacy:o(e=>({kind:"flag",name:"privacy",type:"enum",choices:[...b],required:!1,constraint:e}),"privacy"),whyItExists:{kind:"flag",name:"why-it-exists",type:"string",required:!1,constraint:"The observed failure this document exists to prevent; shown only with `crtr canvas read --fields`."},unlisted:o(e=>({kind:"flag",name:"unlisted",type:"bool",required:!1,constraint:e}),"unlisted"),lintIgnore:{kind:"flag",name:"lint-ignore",type:"string",required:!1,repeatable:!0,constraint:"A `crtr doc lint` rule name to skip for this document."},extension:{kind:"flag",name:"extension",type:"string",required:!1,repeatable:!0,constraint:"One declared plugin field as `<plugin>.<field>=<json value>`."}};function h(e){return e===void 0?[]:Array.isArray(e)?e.map(String):[String(e)]}o(h,"list");function T(e){const t=[],n={};for(const[r,a]of[["preview","preview"],["kind","kind"],["summary","summary"],["privacy","privacy"],["whyItExists","why_it_exists"]])typeof e[r]=="string"&&(n[a]=e[r]);typeof n.preview=="string"&&/[\r\n]/.test(n.preview)&&t.push("--preview must be one line"),e.unlisted===!0&&(n.unlisted=!0);const s=h(e.lintIgnore);s.length>0&&(n.lint_ignore=s);const i=h(e.rule);if(i.length>0){const r=[];i.forEach((a,u)=>{try{const d=JSON.parse(a);typeof d!="object"||d===null||Array.isArray(d)?t.push(`--rule #${u+1} must be a JSON object`):r.push(d)}catch{t.push(`--rule #${u+1} is not valid JSON: ${a}`)}}),n.rules=r}const l={};for(const r of h(e.extension)){const a=/^([^.=]+)\.([^=]+)=(.*)$/s.exec(r);if(!a){t.push(`--extension ${r} is not <plugin>.<field>=<json value>`);continue}try{(l[a[1]]??={})[a[2]]=JSON.parse(a[3])}catch{t.push(`--extension ${r}: the value after = is not valid JSON`)}}if(Object.keys(l).length>0&&(n.extensions=l),t.length>0)throw m(t.join("; "),{next:"Fix every value above and rerun; `--rule -h` gives the rule grammar."});return n}o(T,"fieldsFromInput");function D(e){const t=e.owner;if(t===void 0)return{};const n=String(t);if(!/^(node|user|profile|app|repo)$|^(profile|repo):.+$/.test(n))throw m(`invalid --owner ${n}`,{field:"owner",next:`Pass one of ${p}.`});return{owner:n}}o(D,"ownerFromInput");function I(e,t){e instanceof w&&(e.code==="read_first"&&c(e,`Read it first with \`crtr canvas read ${t}\`, then rerun the edit.`),e.code==="stale_revision"&&c(e,`Someone edited it after your read. Read it again with \`crtr canvas read ${t}\`, make your change on the current text, and rerun the edit.`)),c(e)}o(I,"rethrowDocError");function R(e){const t=[],n=e.unresolved_links,s=e.remote_links;return n?.length&&t.push(`Unresolved links (no document by these names yet): ${n.map(i=>`[[${i}]]`).join(", ")}`),s?.length&&t.push(`Not on this runtime: ${s.map(i=>`[[${i}]]`).join(", ")} \u2014 each may be on another runtime, or the name may be misspelled.`),t.map(i=>`
2
+ ${i}`).join("")}o(R,"renderLinkReport");export{N as FIELD_FLAGS,p as OWNER_VALUES,O as REF_CONSTRAINT,T as fieldsFromInput,D as ownerFromInput,j as ownerParam,R as renderLinkReport,I as rethrowDocError,S as ruleParam};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.428",
3
+ "version": "0.3.429",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -137,7 +137,7 @@
137
137
  },
138
138
  "license": "UNLICENSED",
139
139
  "dependencies": {
140
- "@north-light/identity": "0.3.428",
140
+ "@north-light/identity": "0.3.429",
141
141
  "@earendil-works/pi-agent-core": "1.1.0",
142
142
  "@earendil-works/pi-ai": "1.1.0",
143
143
  "@earendil-works/pi-coding-agent": "1.1.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/identity",
3
- "version": "0.3.428",
3
+ "version": "0.3.429",
4
4
  "description": "crouter cloud access-token verification and scope rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.428",
3
+ "version": "0.3.429",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.428",
9
+ "version": "0.3.429",
10
10
  "hasInstallScript": true,
11
11
  "license": "UNLICENSED",
12
12
  "workspaces": [
@@ -18,7 +18,7 @@
18
18
  "@earendil-works/pi-ai": "1.1.0",
19
19
  "@earendil-works/pi-coding-agent": "1.1.0",
20
20
  "@earendil-works/pi-tui": "1.1.0",
21
- "@north-light/identity": "0.3.428",
21
+ "@north-light/identity": "0.3.429",
22
22
  "cron-parser": "^5.6.0",
23
23
  "esbuild": "^0.27.7",
24
24
  "jose": "^6.2.12",
@@ -12095,17 +12095,17 @@
12095
12095
  },
12096
12096
  "packages/crouter-api": {
12097
12097
  "name": "@north-light/api",
12098
- "version": "0.3.428",
12098
+ "version": "0.3.429",
12099
12099
  "license": "UNLICENSED"
12100
12100
  },
12101
12101
  "packages/crouter-env-docker": {
12102
12102
  "name": "@north-light/env-docker",
12103
- "version": "0.3.428",
12103
+ "version": "0.3.429",
12104
12104
  "license": "UNLICENSED"
12105
12105
  },
12106
12106
  "packages/crouter-identity": {
12107
12107
  "name": "@north-light/identity",
12108
- "version": "0.3.428",
12108
+ "version": "0.3.429",
12109
12109
  "license": "UNLICENSED",
12110
12110
  "dependencies": {
12111
12111
  "jose": "^6.2.1"
@@ -12113,20 +12113,20 @@
12113
12113
  },
12114
12114
  "packages/crouter-plugin": {
12115
12115
  "name": "@north-light/plugin",
12116
- "version": "0.3.428",
12116
+ "version": "0.3.429",
12117
12117
  "license": "UNLICENSED",
12118
12118
  "dependencies": {
12119
- "@north-light/api": "0.3.428",
12120
- "@north-light/identity": "0.3.428"
12119
+ "@north-light/api": "0.3.429",
12120
+ "@north-light/identity": "0.3.429"
12121
12121
  }
12122
12122
  },
12123
12123
  "packages/crouter-sdk": {
12124
12124
  "name": "@north-light/sdk",
12125
- "version": "0.3.428",
12125
+ "version": "0.3.429",
12126
12126
  "license": "UNLICENSED",
12127
12127
  "dependencies": {
12128
- "@north-light/api": "0.3.428",
12129
- "@north-light/identity": "0.3.428",
12128
+ "@north-light/api": "0.3.429",
12129
+ "@north-light/identity": "0.3.429",
12130
12130
  "jose": "^6.2.1"
12131
12131
  },
12132
12132
  "bin": {