@clinebot/shared 0.0.10 → 0.0.12

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/db/index.js CHANGED
@@ -1,92 +1,80 @@
1
- var E=Object.defineProperty;var F=(S)=>S;function G(S,g){this[S]=F.bind(null,g)}var Z=(S,g)=>{for(var z in g)E(S,z,{get:g[z],enumerable:!0,configurable:!0,set:G.bind(g,z)})};import{mkdirSync as J}from"node:fs";import{createRequire as K}from"node:module";import{dirname as L}from"node:path";function Q(){return new Date().toISOString()}function T(S){return S?1:0}function U(S){return typeof S==="string"?S:""}function V(S){if(typeof S!=="string")return;let g=S.trim();return g.length>0?g:void 0}function W(S){return S===1||S===!0}function X(S){J(L(S),{recursive:!0});let g=K(import.meta.url);if(typeof globalThis.Bun<"u"){let{Database:j}=g("bun:sqlite"),x=new j(S,{create:!0});return{prepare:(I)=>{let w=x.query(I);return{run:(...O)=>w.run(...O),get:(...O)=>w.get(...O),all:(...O)=>w.all(...O)}},exec:(I)=>x.exec(I)}}try{let j=["node",":sqlite"].join(""),{DatabaseSync:x}=g(j),I=new x(S);return{prepare:(w)=>{let O=I.prepare(w);return{run:(...A)=>O.run(...A),get:(...A)=>O.get(...A)??null,all:(...A)=>O.all(...A)}},exec:(w)=>I.exec(w)}}catch{}let B=["better","-sqlite3"].join("");return new(g(B))(S)}function Y(S,g={}){if(S.exec("PRAGMA journal_mode = WAL;"),S.exec("PRAGMA busy_timeout = 5000;"),S.exec(`
2
- CREATE TABLE IF NOT EXISTS sessions (
3
- session_id TEXT PRIMARY KEY,
4
- source TEXT NOT NULL,
5
- pid INTEGER NOT NULL,
6
- started_at TEXT NOT NULL,
7
- ended_at TEXT,
8
- exit_code INTEGER,
9
- status TEXT NOT NULL,
10
- status_lock INTEGER NOT NULL DEFAULT 0,
11
- interactive INTEGER NOT NULL,
12
- provider TEXT NOT NULL,
13
- model TEXT NOT NULL,
14
- cwd TEXT NOT NULL,
15
- workspace_root TEXT NOT NULL,
16
- team_name TEXT,
17
- enable_tools INTEGER NOT NULL,
18
- enable_spawn INTEGER NOT NULL,
19
- enable_teams INTEGER NOT NULL,
20
- parent_session_id TEXT,
21
- parent_agent_id TEXT,
22
- agent_id TEXT,
23
- conversation_id TEXT,
24
- is_subagent INTEGER NOT NULL DEFAULT 0,
25
- prompt TEXT,
26
- metadata_json TEXT,
27
- transcript_path TEXT NOT NULL,
28
- hook_path TEXT NOT NULL,
29
- messages_path TEXT,
30
- updated_at TEXT NOT NULL
31
- );
32
- `),S.exec(`
33
- CREATE TABLE IF NOT EXISTS subagent_spawn_queue (
34
- id INTEGER PRIMARY KEY AUTOINCREMENT,
35
- root_session_id TEXT NOT NULL,
36
- parent_agent_id TEXT NOT NULL,
37
- task TEXT,
38
- system_prompt TEXT,
39
- created_at TEXT NOT NULL,
40
- consumed_at TEXT
41
- );
42
- `),S.exec(`
43
- CREATE TABLE IF NOT EXISTS schedules (
44
- schedule_id TEXT PRIMARY KEY,
45
- name TEXT NOT NULL,
46
- cron_pattern TEXT NOT NULL,
47
- prompt TEXT NOT NULL,
48
- provider TEXT NOT NULL,
49
- model TEXT NOT NULL,
50
- mode TEXT NOT NULL DEFAULT 'act',
51
- workspace_root TEXT,
52
- cwd TEXT,
53
- system_prompt TEXT,
54
- max_iterations INTEGER,
55
- timeout_seconds INTEGER,
56
- max_parallel INTEGER NOT NULL DEFAULT 1,
57
- enabled INTEGER NOT NULL DEFAULT 1,
58
- created_at TEXT NOT NULL,
59
- updated_at TEXT NOT NULL,
60
- last_run_at TEXT,
61
- next_run_at TEXT,
62
- claim_token TEXT,
63
- claim_started_at TEXT,
64
- claim_until_at TEXT,
65
- created_by TEXT,
66
- tags TEXT,
67
- metadata_json TEXT
68
- );
69
- `),S.exec(`
70
- CREATE TABLE IF NOT EXISTS schedule_executions (
71
- execution_id TEXT PRIMARY KEY,
72
- schedule_id TEXT NOT NULL,
73
- session_id TEXT,
74
- triggered_at TEXT NOT NULL,
75
- started_at TEXT,
76
- ended_at TEXT,
77
- status TEXT NOT NULL,
78
- exit_code INTEGER,
79
- error_message TEXT,
80
- iterations INTEGER,
81
- tokens_used INTEGER,
82
- cost_usd REAL,
83
- FOREIGN KEY (schedule_id) REFERENCES schedules(schedule_id) ON DELETE CASCADE,
84
- FOREIGN KEY (session_id) REFERENCES sessions(session_id) ON DELETE SET NULL
85
- );
86
- `),S.exec(`
87
- CREATE INDEX IF NOT EXISTS idx_schedule_executions_schedule
88
- ON schedule_executions(schedule_id, triggered_at DESC);
89
- `),S.exec(`
90
- CREATE INDEX IF NOT EXISTS idx_schedules_next_run
91
- ON schedules(enabled, next_run_at);
92
- `),!g.includeLegacyMigrations)return;let z=S.prepare("PRAGMA table_info(sessions);").all(),B=(x)=>z.some((I)=>I.name===x);if(!B("workspace_root"))S.exec("ALTER TABLE sessions ADD COLUMN workspace_root TEXT;"),S.exec("UPDATE sessions SET workspace_root = cwd WHERE workspace_root IS NULL OR workspace_root = '';");if(!B("parent_session_id"))S.exec("ALTER TABLE sessions ADD COLUMN parent_session_id TEXT;");if(!B("parent_agent_id"))S.exec("ALTER TABLE sessions ADD COLUMN parent_agent_id TEXT;");if(!B("agent_id"))S.exec("ALTER TABLE sessions ADD COLUMN agent_id TEXT;");if(!B("conversation_id"))S.exec("ALTER TABLE sessions ADD COLUMN conversation_id TEXT;");if(!B("is_subagent"))S.exec("ALTER TABLE sessions ADD COLUMN is_subagent INTEGER NOT NULL DEFAULT 0;");if(!B("messages_path"))S.exec("ALTER TABLE sessions ADD COLUMN messages_path TEXT;");if(!B("metadata_json"))S.exec("ALTER TABLE sessions ADD COLUMN metadata_json TEXT;");let D=S.prepare("PRAGMA table_info(schedules);").all(),j=(x)=>D.some((I)=>I.name===x);if(!j("claim_token"))S.exec("ALTER TABLE schedules ADD COLUMN claim_token TEXT;");if(!j("claim_started_at"))S.exec("ALTER TABLE schedules ADD COLUMN claim_started_at TEXT;");if(!j("claim_until_at"))S.exec("ALTER TABLE schedules ADD COLUMN claim_until_at TEXT;")}export{T as toBoolInt,Q as nowIso,X as loadSqliteDb,Y as ensureSessionSchema,U as asString,V as asOptionalString,W as asBool};
1
+ var J=Object.defineProperty;var K=(S)=>S;function Q(S,x){this[S]=K.bind(null,x)}var M=(S,x)=>{for(var B in x)J(S,B,{get:x[B],enumerable:!0,configurable:!0,set:Q.bind(x,B)})};import{mkdirSync as U}from"node:fs";import{createRequire as V}from"node:module";import{dirname as W}from"node:path";function X(){return new Date().toISOString()}function Z(S){return S?1:0}function $(S){return typeof S==="string"?S:""}function k(S){if(typeof S!=="string")return;let x=S.trim();return x.length>0?x:void 0}function y(S){return S===1||S===!0}function F(S){return{prepare:(x)=>S.query(x),exec:(x)=>S.exec(x)}}function H(S){return{prepare:(x)=>{let B=S.prepare(x);return{run:(...O)=>B.run(...O),get:(...O)=>B.get(...O)??null,all:(...O)=>B.all(...O)}},exec:(x)=>S.exec(x)}}function L(S){U(W(S),{recursive:!0});let x=V(import.meta.url);if(typeof globalThis.Bun<"u"){let{Database:O}=x("bun:sqlite");return F(new O(S,{create:!0}))}try{let O=process.emitWarning;process.emitWarning=(z,...I)=>{if((typeof z==="string"?z:z?.message??"").includes("SQLite"))return;return O.call(process,z,...I)};let{DatabaseSync:j}=x(["node",":sqlite"].join(""));return process.emitWarning=O,H(new j(S))}catch{}return new(x(["better","-sqlite3"].join("")))(S)}var Y=[`CREATE TABLE IF NOT EXISTS sessions (
2
+ session_id TEXT PRIMARY KEY,
3
+ source TEXT NOT NULL,
4
+ pid INTEGER NOT NULL,
5
+ started_at TEXT NOT NULL,
6
+ ended_at TEXT,
7
+ exit_code INTEGER,
8
+ status TEXT NOT NULL,
9
+ status_lock INTEGER NOT NULL DEFAULT 0,
10
+ interactive INTEGER NOT NULL,
11
+ provider TEXT NOT NULL,
12
+ model TEXT NOT NULL,
13
+ cwd TEXT NOT NULL,
14
+ workspace_root TEXT NOT NULL,
15
+ team_name TEXT,
16
+ enable_tools INTEGER NOT NULL,
17
+ enable_spawn INTEGER NOT NULL,
18
+ enable_teams INTEGER NOT NULL,
19
+ parent_session_id TEXT,
20
+ parent_agent_id TEXT,
21
+ agent_id TEXT,
22
+ conversation_id TEXT,
23
+ is_subagent INTEGER NOT NULL DEFAULT 0,
24
+ prompt TEXT,
25
+ metadata_json TEXT,
26
+ transcript_path TEXT NOT NULL,
27
+ hook_path TEXT NOT NULL,
28
+ messages_path TEXT,
29
+ updated_at TEXT NOT NULL
30
+ );`,`CREATE TABLE IF NOT EXISTS subagent_spawn_queue (
31
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
32
+ root_session_id TEXT NOT NULL,
33
+ parent_agent_id TEXT NOT NULL,
34
+ task TEXT,
35
+ system_prompt TEXT,
36
+ created_at TEXT NOT NULL,
37
+ consumed_at TEXT
38
+ );`,`CREATE TABLE IF NOT EXISTS schedules (
39
+ schedule_id TEXT PRIMARY KEY,
40
+ name TEXT NOT NULL,
41
+ cron_pattern TEXT NOT NULL,
42
+ prompt TEXT NOT NULL,
43
+ provider TEXT NOT NULL,
44
+ model TEXT NOT NULL,
45
+ mode TEXT NOT NULL DEFAULT 'act',
46
+ workspace_root TEXT,
47
+ cwd TEXT,
48
+ system_prompt TEXT,
49
+ max_iterations INTEGER,
50
+ timeout_seconds INTEGER,
51
+ max_parallel INTEGER NOT NULL DEFAULT 1,
52
+ enabled INTEGER NOT NULL DEFAULT 1,
53
+ created_at TEXT NOT NULL,
54
+ updated_at TEXT NOT NULL,
55
+ last_run_at TEXT,
56
+ next_run_at TEXT,
57
+ claim_token TEXT,
58
+ claim_started_at TEXT,
59
+ claim_until_at TEXT,
60
+ created_by TEXT,
61
+ tags TEXT,
62
+ metadata_json TEXT
63
+ );`,`CREATE TABLE IF NOT EXISTS schedule_executions (
64
+ execution_id TEXT PRIMARY KEY,
65
+ schedule_id TEXT NOT NULL,
66
+ session_id TEXT,
67
+ triggered_at TEXT NOT NULL,
68
+ started_at TEXT,
69
+ ended_at TEXT,
70
+ status TEXT NOT NULL,
71
+ exit_code INTEGER,
72
+ error_message TEXT,
73
+ iterations INTEGER,
74
+ tokens_used INTEGER,
75
+ cost_usd REAL,
76
+ FOREIGN KEY (schedule_id) REFERENCES schedules(schedule_id) ON DELETE CASCADE,
77
+ FOREIGN KEY (session_id) REFERENCES sessions(session_id) ON DELETE SET NULL
78
+ );`,`CREATE INDEX IF NOT EXISTS idx_schedule_executions_schedule
79
+ ON schedule_executions(schedule_id, triggered_at DESC);`,`CREATE INDEX IF NOT EXISTS idx_schedules_next_run
80
+ ON schedules(enabled, next_run_at);`],D=[{table:"sessions",column:"workspace_root",sql:"ALTER TABLE sessions ADD COLUMN workspace_root TEXT;"},{table:"sessions",column:"parent_session_id",sql:"ALTER TABLE sessions ADD COLUMN parent_session_id TEXT;"},{table:"sessions",column:"parent_agent_id",sql:"ALTER TABLE sessions ADD COLUMN parent_agent_id TEXT;"},{table:"sessions",column:"agent_id",sql:"ALTER TABLE sessions ADD COLUMN agent_id TEXT;"},{table:"sessions",column:"conversation_id",sql:"ALTER TABLE sessions ADD COLUMN conversation_id TEXT;"},{table:"sessions",column:"is_subagent",sql:"ALTER TABLE sessions ADD COLUMN is_subagent INTEGER NOT NULL DEFAULT 0;"},{table:"sessions",column:"messages_path",sql:"ALTER TABLE sessions ADD COLUMN messages_path TEXT;"},{table:"sessions",column:"metadata_json",sql:"ALTER TABLE sessions ADD COLUMN metadata_json TEXT;"},{table:"schedules",column:"claim_token",sql:"ALTER TABLE schedules ADD COLUMN claim_token TEXT;"},{table:"schedules",column:"claim_started_at",sql:"ALTER TABLE schedules ADD COLUMN claim_started_at TEXT;"},{table:"schedules",column:"claim_until_at",sql:"ALTER TABLE schedules ADD COLUMN claim_until_at TEXT;"}];function G(S,x){return new Set(S.prepare(`PRAGMA table_info(${x});`).all().map((B)=>B.name))}function R(S,x={}){S.exec("PRAGMA journal_mode = WAL;"),S.exec("PRAGMA busy_timeout = 5000;");for(let j of Y)S.exec(j);if(!x.includeLegacyMigrations)return;let B=new Map,O=(j)=>{let z=B.get(j);if(!z)z=G(S,j),B.set(j,z);return z};for(let j of D)if(!O(j.table).has(j.column)){if(S.exec(j.sql),j.column==="workspace_root")S.exec("UPDATE sessions SET workspace_root = cwd WHERE workspace_root IS NULL OR workspace_root = '';")}}export{Z as toBoolInt,X as nowIso,L as loadSqliteDb,R as ensureSessionSchema,$ as asString,k as asOptionalString,y as asBool};
@@ -60,6 +60,7 @@ export interface RpcChatRunTurnRequest {
60
60
  messages?: RpcChatMessage[];
61
61
  prompt: string;
62
62
  attachments?: RpcChatAttachments;
63
+ delivery?: "queue" | "steer";
63
64
  }
64
65
  export interface RpcChatToolCallResult {
65
66
  name: string;
@@ -1 +1 @@
1
- export { AGENT_CONFIG_DIRECTORY_NAME, CLINE_MCP_SETTINGS_FILE_NAME, ensureHookLogDir, ensureParentDir, HOOKS_CONFIG_DIRECTORY_NAME, RULES_CONFIG_DIRECTORY_NAME, resolveAgentConfigSearchPaths, resolveAgentsConfigDirPath, resolveClineDataDir, resolveClineDir, resolveDocumentsAgentConfigDirectoryPath, resolveDocumentsClineDirectoryPath, resolveDocumentsHooksDirectoryPath, resolveDocumentsRulesDirectoryPath, resolveDocumentsWorkflowsDirectoryPath, resolveHooksConfigSearchPaths, resolveMcpSettingsPath, resolvePluginConfigSearchPaths, resolveProviderSettingsPath, resolveRulesConfigSearchPaths, resolveSessionDataDir, resolveSkillsConfigSearchPaths, resolveTeamDataDir, resolveWorkflowsConfigSearchPaths, SKILLS_CONFIG_DIRECTORY_NAME, setClineDir, setClineDirIfUnset, setHomeDir, setHomeDirIfUnset, WORKFLOWS_CONFIG_DIRECTORY_NAME, } from "./paths";
1
+ export { AGENT_CONFIG_DIRECTORY_NAME, CLINE_MCP_SETTINGS_FILE_NAME, discoverPluginModulePaths, ensureHookLogDir, ensureParentDir, HOOKS_CONFIG_DIRECTORY_NAME, isPluginModulePath, RULES_CONFIG_DIRECTORY_NAME, resolveAgentConfigSearchPaths, resolveAgentsConfigDirPath, resolveClineDataDir, resolveClineDir, resolveConfiguredPluginModulePaths, resolveDocumentsAgentConfigDirectoryPath, resolveDocumentsClineDirectoryPath, resolveDocumentsHooksDirectoryPath, resolveDocumentsPluginsDirectoryPath, resolveDocumentsRulesDirectoryPath, resolveDocumentsWorkflowsDirectoryPath, resolveHooksConfigSearchPaths, resolveMcpSettingsPath, resolvePluginConfigSearchPaths, resolvePluginModuleEntries, resolveProviderSettingsPath, resolveRulesConfigSearchPaths, resolveSessionDataDir, resolveSkillsConfigSearchPaths, resolveTeamDataDir, resolveWorkflowsConfigSearchPaths, SKILLS_CONFIG_DIRECTORY_NAME, setClineDir, setClineDirIfUnset, setHomeDir, setHomeDirIfUnset, WORKFLOWS_CONFIG_DIRECTORY_NAME, } from "./paths";
@@ -1 +1 @@
1
- var j=Object.defineProperty;var q=(o)=>o;function z(o,v){this[o]=q.bind(null,v)}var i=(o,v)=>{for(var S in v)j(o,S,{get:v[S],enumerable:!0,configurable:!0,set:z.bind(v,S)})};import{existsSync as G,mkdirSync as e}from"node:fs";import{dirname as y,join as n}from"node:path";var F="agents",H="hooks",g="skills",M="rules",f="workflows",O="plugins",T="cline_mcp_settings.json",s=process?.env?.HOME||"~",_=!1;function B(o){let v=o.trim();if(!v)return;s=v,_=!0}function J(o){if(_)return;let v=o.trim();if(!v)return;s=v}var A,K=!1;function Q(o){let v=o.trim();if(!v)return;A=v,K=!0}function V(o){if(K)return;let v=o.trim();if(!v)return;A=v}function N(){if(A)return A;let o=process.env.CLINE_DIR?.trim();if(o)return o;return n(s,".cline")}function D(){return n(s,"Documents","Cline")}function R(){return n(D(),"Agents")}function U(){return n(D(),"Hooks")}function E(){return n(D(),"Rules")}function W(){return n(D(),"Workflows")}function C(){let o=process.env.CLINE_DATA_DIR?.trim();if(o)return o;return n(N(),"data")}function Z(){let o=process.env.CLINE_SESSION_DATA_DIR?.trim();if(o)return o;return n(C(),"sessions")}function $(){let o=process.env.CLINE_TEAM_DATA_DIR?.trim();if(o)return o;return n(C(),"teams")}function I(){let o=process.env.CLINE_PROVIDER_SETTINGS_PATH?.trim();if(o)return o;return n(C(),"settings","providers.json")}function X(){let o=process.env.CLINE_MCP_SETTINGS_PATH?.trim();if(o)return o;return n(C(),"settings",T)}function l(o){let v=new Set,S=[];for(let u of o){if(!u||v.has(u))continue;v.add(u),S.push(u)}return S}function L(o){if(!o)return[];return[n(o,".clinerules",g),n(o,".cline",g),n(o,".claude",g),n(o,".agents",g)]}function Y(){return n(C(),"settings",F)}function m(){return[R(),Y()]}function r(o){return l([o?n(o,".clinerules",H):"",U()])}function x(o){return l([...L(o),n(C(),"settings",g),n(N(),g),n(s,".agents",g)])}function k(o){return l([o?n(o,".clinerules"):"",n(C(),"settings",M),E()])}function h(o){return l([o?n(o,".clinerules","workflows"):"",n(C(),"settings",f),W()])}function P(o){return l([o?n(o,".clinerules",O):"",n(N(),O),n(s,".agents",O)])}function b(o){let v=y(o);if(!G(v))e(v,{recursive:!0})}function c(o){if(o?.trim())return b(o),y(o);let v=n(C(),"hooks");if(!G(v))e(v,{recursive:!0});return v}export{J as setHomeDirIfUnset,B as setHomeDir,V as setClineDirIfUnset,Q as setClineDir,h as resolveWorkflowsConfigSearchPaths,$ as resolveTeamDataDir,x as resolveSkillsConfigSearchPaths,Z as resolveSessionDataDir,k as resolveRulesConfigSearchPaths,I as resolveProviderSettingsPath,P as resolvePluginConfigSearchPaths,X as resolveMcpSettingsPath,r as resolveHooksConfigSearchPaths,W as resolveDocumentsWorkflowsDirectoryPath,E as resolveDocumentsRulesDirectoryPath,U as resolveDocumentsHooksDirectoryPath,D as resolveDocumentsClineDirectoryPath,R as resolveDocumentsAgentConfigDirectoryPath,N as resolveClineDir,C as resolveClineDataDir,Y as resolveAgentsConfigDirPath,m as resolveAgentConfigSearchPaths,b as ensureParentDir,c as ensureHookLogDir,f as WORKFLOWS_CONFIG_DIRECTORY_NAME,g as SKILLS_CONFIG_DIRECTORY_NAME,M as RULES_CONFIG_DIRECTORY_NAME,H as HOOKS_CONFIG_DIRECTORY_NAME,T as CLINE_MCP_SETTINGS_FILE_NAME,F as AGENT_CONFIG_DIRECTORY_NAME};
1
+ var s=Object.defineProperty;var n=(C)=>C;function w(C,D){this[C]=n.bind(null,D)}var EC=(C,D)=>{for(var N in D)s(C,N,{get:D[N],enumerable:!0,configurable:!0,set:w.bind(D,N)})};import{existsSync as g,mkdirSync as L,readdirSync as k,readFileSync as i,statSync as G}from"node:fs";import{dirname as U,join as S,resolve as H}from"node:path";var Y="agents",j="hooks",A="skills",q="rules",z="workflows",u="plugins",B="cline_mcp_settings.json",I=process?.env?.HOME||"~",Q=!1;function c(C){let D=C.trim();if(!D)return;I=D,Q=!0}function P(C){if(Q)return;let D=C.trim();if(!D)return;I=D}var T,V=!1;function d(C){let D=C.trim();if(!D)return;T=D,V=!0}function r(C){if(V)return;let D=C.trim();if(!D)return;T=D}function l(){if(T)return T;let C=process.env.CLINE_DIR?.trim();if(C)return C;return S(I,".cline")}function M(){return S(I,"Documents","Cline")}function Z(){return S(M(),"Agents")}function $(){return S(M(),"Hooks")}function f(){return S(M(),"Rules")}function X(){return S(M(),"Workflows")}function J(){return S(I,"Documents","Plugins")}function R(){let C=process.env.CLINE_DATA_DIR?.trim();if(C)return C;return S(l(),"data")}function h(){let C=process.env.CLINE_SESSION_DATA_DIR?.trim();if(C)return C;return S(R(),"sessions")}function p(){let C=process.env.CLINE_TEAM_DATA_DIR?.trim();if(C)return C;return S(R(),"teams")}function e(){let C=process.env.CLINE_PROVIDER_SETTINGS_PATH?.trim();if(C)return C;return S(R(),"settings","providers.json")}function t(){let C=process.env.CLINE_MCP_SETTINGS_PATH?.trim();if(C)return C;return S(R(),"settings",B)}function E(C){let D=new Set,N=[];for(let _ of C){if(!_||D.has(_))continue;D.add(_),N.push(_)}return N}function a(C){if(!C)return[];return[S(C,".clinerules",A),S(C,".cline",A),S(C,".claude",A),S(C,".agents",A)]}function x(){return S(R(),"settings",Y)}function CC(){return[Z(),x()]}function DC(C){return E([C?S(C,".clinerules",j):"",$()])}function SC(C){return E([...a(C),S(R(),"settings",A),S(l(),A),S(I,".agents",A)])}function vC(C){return E([C?S(C,".clinerules"):"",S(R(),"settings",q),f()])}function NC(C){return E([C?S(C,".clinerules","workflows"):"",S(R(),"settings",z),X()])}function OC(C){return E([C?S(C,".clinerules",u):"",S(l(),u),J()])}var b=new Set([".js",".mjs",".cjs",".ts",".mts",".cts"]),_C="package.json",RC=["index.ts","index.mts","index.cts","index.js","index.mjs","index.cjs"];function K(C){let D=C.lastIndexOf(".");if(D===-1)return!1;return b.has(C.slice(D))}function gC(C){try{let D=JSON.parse(i(C,"utf8"));if(!D.cline||typeof D.cline!=="object")return null;return D.cline}catch{return null}}function AC(C){let D=C?.plugins??C?.extensions;if(!Array.isArray(D))return[];return D.filter((N)=>typeof N==="string")}function o(C){let D=H(C);if(!g(D)||!G(D).isDirectory())return null;let N=S(D,_C);if(g(N)){let _=gC(N),O=AC(_).map((v)=>H(D,v)).filter((v)=>g(v)&&G(v).isFile()&&K(v));if(O.length>0)return O}for(let _ of RC){let O=S(D,_);if(g(O)&&G(O).isFile())return[O]}return null}function m(C){let D=H(C);if(!g(D))return[];let N=[],_=[D];while(_.length>0){let O=_.pop();if(!O)continue;for(let v of k(O,{withFileTypes:!0})){let F=S(O,v.name);if(v.isDirectory()){_.push(F);continue}if(v.name.startsWith("."))continue;if(v.isFile()&&K(F))N.push(F)}}return N.sort((O,v)=>O.localeCompare(v))}function IC(C,D){let N=[];for(let _ of C){let O=_.trim();if(!O)continue;let v=H(D,O);if(!g(v))throw Error(`Plugin path does not exist: ${v}`);if(G(v).isDirectory()){let W=o(v);if(W){N.push(...W);continue}N.push(...m(v));continue}if(!K(v))throw Error(`Plugin file must use a supported extension (${[...b].join(", ")}): ${v}`);N.push(v)}return N}function y(C){let D=U(C);if(!g(D))L(D,{recursive:!0})}function MC(C){if(C?.trim())return y(C),U(C);let D=S(R(),"hooks");if(!g(D))L(D,{recursive:!0});return D}export{P as setHomeDirIfUnset,c as setHomeDir,r as setClineDirIfUnset,d as setClineDir,NC as resolveWorkflowsConfigSearchPaths,p as resolveTeamDataDir,SC as resolveSkillsConfigSearchPaths,h as resolveSessionDataDir,vC as resolveRulesConfigSearchPaths,e as resolveProviderSettingsPath,o as resolvePluginModuleEntries,OC as resolvePluginConfigSearchPaths,t as resolveMcpSettingsPath,DC as resolveHooksConfigSearchPaths,X as resolveDocumentsWorkflowsDirectoryPath,f as resolveDocumentsRulesDirectoryPath,J as resolveDocumentsPluginsDirectoryPath,$ as resolveDocumentsHooksDirectoryPath,M as resolveDocumentsClineDirectoryPath,Z as resolveDocumentsAgentConfigDirectoryPath,IC as resolveConfiguredPluginModulePaths,l as resolveClineDir,R as resolveClineDataDir,x as resolveAgentsConfigDirPath,CC as resolveAgentConfigSearchPaths,K as isPluginModulePath,y as ensureParentDir,MC as ensureHookLogDir,m as discoverPluginModulePaths,z as WORKFLOWS_CONFIG_DIRECTORY_NAME,A as SKILLS_CONFIG_DIRECTORY_NAME,q as RULES_CONFIG_DIRECTORY_NAME,j as HOOKS_CONFIG_DIRECTORY_NAME,B as CLINE_MCP_SETTINGS_FILE_NAME,Y as AGENT_CONFIG_DIRECTORY_NAME};
@@ -15,6 +15,7 @@ export declare function resolveDocumentsAgentConfigDirectoryPath(): string;
15
15
  export declare function resolveDocumentsHooksDirectoryPath(): string;
16
16
  export declare function resolveDocumentsRulesDirectoryPath(): string;
17
17
  export declare function resolveDocumentsWorkflowsDirectoryPath(): string;
18
+ export declare function resolveDocumentsPluginsDirectoryPath(): string;
18
19
  export declare function resolveClineDataDir(): string;
19
20
  export declare function resolveSessionDataDir(): string;
20
21
  export declare function resolveTeamDataDir(): string;
@@ -27,5 +28,9 @@ export declare function resolveSkillsConfigSearchPaths(workspacePath?: string):
27
28
  export declare function resolveRulesConfigSearchPaths(workspacePath?: string): string[];
28
29
  export declare function resolveWorkflowsConfigSearchPaths(workspacePath?: string): string[];
29
30
  export declare function resolvePluginConfigSearchPaths(workspacePath?: string): string[];
31
+ export declare function isPluginModulePath(path: string): boolean;
32
+ export declare function resolvePluginModuleEntries(directoryPath: string): string[] | null;
33
+ export declare function discoverPluginModulePaths(directoryPath: string): string[];
34
+ export declare function resolveConfiguredPluginModulePaths(pluginPaths: ReadonlyArray<string>, cwd: string): string[];
30
35
  export declare function ensureParentDir(filePath: string): void;
31
36
  export declare function ensureHookLogDir(filePath?: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clinebot/shared",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "Shared utilities, types, and schemas for Cline packages",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -13,26 +13,6 @@ export type SqliteDb = {
13
13
  exec: (sql: string) => void;
14
14
  };
15
15
 
16
- type BunSqliteDb = {
17
- query: (sql: string) => {
18
- run: (...params: unknown[]) => { changes?: number };
19
- get: (...params: unknown[]) => Record<string, unknown> | null;
20
- all: (...params: unknown[]) => Record<string, unknown>[];
21
- };
22
- exec: (sql: string) => void;
23
- };
24
-
25
- type NodeSqliteStatement = {
26
- run: (...params: unknown[]) => { changes?: number };
27
- get: (...params: unknown[]) => Record<string, unknown> | undefined;
28
- all: (...params: unknown[]) => Record<string, unknown>[];
29
- };
30
-
31
- type NodeSqliteDb = {
32
- prepare: (sql: string) => NodeSqliteStatement;
33
- exec: (sql: string) => void;
34
- };
35
-
36
16
  export function nowIso(): string {
37
17
  return new Date().toISOString();
38
18
  }
@@ -46,9 +26,7 @@ export function asString(value: unknown): string {
46
26
  }
47
27
 
48
28
  export function asOptionalString(value: unknown): string | undefined {
49
- if (typeof value !== "string") {
50
- return undefined;
51
- }
29
+ if (typeof value !== "string") return undefined;
52
30
  const trimmed = value.trim();
53
31
  return trimmed.length > 0 ? trimmed : undefined;
54
32
  }
@@ -57,59 +35,83 @@ export function asBool(value: unknown): boolean {
57
35
  return value === 1 || value === true;
58
36
  }
59
37
 
38
+ function wrapBunDb(db: {
39
+ query: (sql: string) => SqliteStatement;
40
+ exec: (sql: string) => void;
41
+ }): SqliteDb {
42
+ return {
43
+ prepare: (sql) => db.query(sql),
44
+ exec: (sql) => db.exec(sql),
45
+ };
46
+ }
47
+
48
+ function wrapNodeDb(db: {
49
+ prepare: (sql: string) => {
50
+ run: (...params: unknown[]) => { changes?: number };
51
+ get: (...params: unknown[]) => Record<string, unknown> | undefined;
52
+ all: (...params: unknown[]) => Record<string, unknown>[];
53
+ };
54
+ exec: (sql: string) => void;
55
+ }): SqliteDb {
56
+ return {
57
+ prepare: (sql) => {
58
+ const stmt = db.prepare(sql);
59
+ return {
60
+ run: (...params) => stmt.run(...params),
61
+ get: (...params) => stmt.get(...params) ?? null,
62
+ all: (...params) => stmt.all(...params),
63
+ };
64
+ },
65
+ exec: (sql) => db.exec(sql),
66
+ };
67
+ }
68
+
60
69
  export function loadSqliteDb(filePath: string): SqliteDb {
61
70
  mkdirSync(dirname(filePath), { recursive: true });
62
71
  const require = createRequire(import.meta.url);
63
- const isBunRuntime =
64
- typeof (globalThis as { Bun?: unknown }).Bun !== "undefined";
65
72
 
66
- if (isBunRuntime) {
73
+ if (typeof (globalThis as { Bun?: unknown }).Bun !== "undefined") {
67
74
  const { Database } = require("bun:sqlite") as {
68
75
  Database: new (
69
76
  path: string,
70
- options?: { create?: boolean; strict?: boolean },
71
- ) => BunSqliteDb;
72
- };
73
- const db = new Database(filePath, { create: true });
74
-
75
- return {
76
- prepare: (sql: string): SqliteStatement => {
77
- const query = db.query(sql);
78
- return {
79
- run: (...params: unknown[]) => query.run(...params),
80
- get: (...params: unknown[]) => query.get(...params),
81
- all: (...params: unknown[]) => query.all(...params),
82
- };
83
- },
84
- exec: (sql: string) => db.exec(sql),
77
+ options?: { create?: boolean },
78
+ ) => {
79
+ query: (sql: string) => SqliteStatement;
80
+ exec: (sql: string) => void;
81
+ };
85
82
  };
83
+ return wrapBunDb(new Database(filePath, { create: true }));
86
84
  }
87
85
 
88
86
  try {
89
- const nodeSqliteModuleName = ["node", ":sqlite"].join("");
90
- const { DatabaseSync } = require(nodeSqliteModuleName) as {
91
- DatabaseSync: new (path: string) => NodeSqliteDb;
92
- };
93
- const db = new DatabaseSync(filePath);
94
- return {
95
- prepare: (sql: string): SqliteStatement => {
96
- const statement = db.prepare(sql);
97
- return {
98
- run: (...params: unknown[]) => statement.run(...params),
99
- get: (...params: unknown[]) => statement.get(...params) ?? null,
100
- all: (...params: unknown[]) => statement.all(...params),
87
+ // Suppress "ExperimentalWarning: SQLite is an experimental feature"
88
+ const originalEmit = process.emitWarning;
89
+ process.emitWarning = ((warning: string | Error, ...args: unknown[]) => {
90
+ const msg =
91
+ typeof warning === "string" ? warning : (warning?.message ?? "");
92
+ if (msg.includes("SQLite")) return;
93
+ return (originalEmit as Function).call(process, warning, ...args);
94
+ }) as typeof process.emitWarning;
95
+
96
+ const { DatabaseSync } = require(["node", ":sqlite"].join("")) as {
97
+ DatabaseSync: new (
98
+ path: string,
99
+ ) => {
100
+ prepare: (sql: string) => {
101
+ run: (...params: unknown[]) => { changes?: number };
102
+ get: (...params: unknown[]) => Record<string, unknown> | undefined;
103
+ all: (...params: unknown[]) => Record<string, unknown>[];
101
104
  };
102
- },
103
- exec: (sql: string) => db.exec(sql),
105
+ exec: (sql: string) => void;
106
+ };
104
107
  };
108
+ process.emitWarning = originalEmit;
109
+ return wrapNodeDb(new DatabaseSync(filePath));
105
110
  } catch {
106
- // Fall through to better-sqlite3 for older Node runtimes without node:sqlite.
111
+ // Fall through to better-sqlite3 for older Node runtimes.
107
112
  }
108
113
 
109
- // Keep the module name non-literal so browser/SSR bundlers don't try to resolve
110
- // better-sqlite3 when this Node-only path is not executed.
111
- const betterSqlite3ModuleName = ["better", "-sqlite3"].join("");
112
- const BetterSqlite3 = require(betterSqlite3ModuleName) as new (
114
+ const BetterSqlite3 = require(["better", "-sqlite3"].join("")) as new (
113
115
  path: string,
114
116
  ) => SqliteDb;
115
117
  return new BetterSqlite3(filePath);
@@ -119,156 +121,195 @@ export interface SessionSchemaOptions {
119
121
  includeLegacyMigrations?: boolean;
120
122
  }
121
123
 
124
+ const SCHEMA_STATEMENTS = [
125
+ `CREATE TABLE IF NOT EXISTS sessions (
126
+ session_id TEXT PRIMARY KEY,
127
+ source TEXT NOT NULL,
128
+ pid INTEGER NOT NULL,
129
+ started_at TEXT NOT NULL,
130
+ ended_at TEXT,
131
+ exit_code INTEGER,
132
+ status TEXT NOT NULL,
133
+ status_lock INTEGER NOT NULL DEFAULT 0,
134
+ interactive INTEGER NOT NULL,
135
+ provider TEXT NOT NULL,
136
+ model TEXT NOT NULL,
137
+ cwd TEXT NOT NULL,
138
+ workspace_root TEXT NOT NULL,
139
+ team_name TEXT,
140
+ enable_tools INTEGER NOT NULL,
141
+ enable_spawn INTEGER NOT NULL,
142
+ enable_teams INTEGER NOT NULL,
143
+ parent_session_id TEXT,
144
+ parent_agent_id TEXT,
145
+ agent_id TEXT,
146
+ conversation_id TEXT,
147
+ is_subagent INTEGER NOT NULL DEFAULT 0,
148
+ prompt TEXT,
149
+ metadata_json TEXT,
150
+ transcript_path TEXT NOT NULL,
151
+ hook_path TEXT NOT NULL,
152
+ messages_path TEXT,
153
+ updated_at TEXT NOT NULL
154
+ );`,
155
+ `CREATE TABLE IF NOT EXISTS subagent_spawn_queue (
156
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
157
+ root_session_id TEXT NOT NULL,
158
+ parent_agent_id TEXT NOT NULL,
159
+ task TEXT,
160
+ system_prompt TEXT,
161
+ created_at TEXT NOT NULL,
162
+ consumed_at TEXT
163
+ );`,
164
+ `CREATE TABLE IF NOT EXISTS schedules (
165
+ schedule_id TEXT PRIMARY KEY,
166
+ name TEXT NOT NULL,
167
+ cron_pattern TEXT NOT NULL,
168
+ prompt TEXT NOT NULL,
169
+ provider TEXT NOT NULL,
170
+ model TEXT NOT NULL,
171
+ mode TEXT NOT NULL DEFAULT 'act',
172
+ workspace_root TEXT,
173
+ cwd TEXT,
174
+ system_prompt TEXT,
175
+ max_iterations INTEGER,
176
+ timeout_seconds INTEGER,
177
+ max_parallel INTEGER NOT NULL DEFAULT 1,
178
+ enabled INTEGER NOT NULL DEFAULT 1,
179
+ created_at TEXT NOT NULL,
180
+ updated_at TEXT NOT NULL,
181
+ last_run_at TEXT,
182
+ next_run_at TEXT,
183
+ claim_token TEXT,
184
+ claim_started_at TEXT,
185
+ claim_until_at TEXT,
186
+ created_by TEXT,
187
+ tags TEXT,
188
+ metadata_json TEXT
189
+ );`,
190
+ `CREATE TABLE IF NOT EXISTS schedule_executions (
191
+ execution_id TEXT PRIMARY KEY,
192
+ schedule_id TEXT NOT NULL,
193
+ session_id TEXT,
194
+ triggered_at TEXT NOT NULL,
195
+ started_at TEXT,
196
+ ended_at TEXT,
197
+ status TEXT NOT NULL,
198
+ exit_code INTEGER,
199
+ error_message TEXT,
200
+ iterations INTEGER,
201
+ tokens_used INTEGER,
202
+ cost_usd REAL,
203
+ FOREIGN KEY (schedule_id) REFERENCES schedules(schedule_id) ON DELETE CASCADE,
204
+ FOREIGN KEY (session_id) REFERENCES sessions(session_id) ON DELETE SET NULL
205
+ );`,
206
+ `CREATE INDEX IF NOT EXISTS idx_schedule_executions_schedule
207
+ ON schedule_executions(schedule_id, triggered_at DESC);`,
208
+ `CREATE INDEX IF NOT EXISTS idx_schedules_next_run
209
+ ON schedules(enabled, next_run_at);`,
210
+ ];
211
+
212
+ const LEGACY_MIGRATIONS: Array<{
213
+ table: string;
214
+ column: string;
215
+ sql: string;
216
+ }> = [
217
+ {
218
+ table: "sessions",
219
+ column: "workspace_root",
220
+ sql: "ALTER TABLE sessions ADD COLUMN workspace_root TEXT;",
221
+ },
222
+ {
223
+ table: "sessions",
224
+ column: "parent_session_id",
225
+ sql: "ALTER TABLE sessions ADD COLUMN parent_session_id TEXT;",
226
+ },
227
+ {
228
+ table: "sessions",
229
+ column: "parent_agent_id",
230
+ sql: "ALTER TABLE sessions ADD COLUMN parent_agent_id TEXT;",
231
+ },
232
+ {
233
+ table: "sessions",
234
+ column: "agent_id",
235
+ sql: "ALTER TABLE sessions ADD COLUMN agent_id TEXT;",
236
+ },
237
+ {
238
+ table: "sessions",
239
+ column: "conversation_id",
240
+ sql: "ALTER TABLE sessions ADD COLUMN conversation_id TEXT;",
241
+ },
242
+ {
243
+ table: "sessions",
244
+ column: "is_subagent",
245
+ sql: "ALTER TABLE sessions ADD COLUMN is_subagent INTEGER NOT NULL DEFAULT 0;",
246
+ },
247
+ {
248
+ table: "sessions",
249
+ column: "messages_path",
250
+ sql: "ALTER TABLE sessions ADD COLUMN messages_path TEXT;",
251
+ },
252
+ {
253
+ table: "sessions",
254
+ column: "metadata_json",
255
+ sql: "ALTER TABLE sessions ADD COLUMN metadata_json TEXT;",
256
+ },
257
+ {
258
+ table: "schedules",
259
+ column: "claim_token",
260
+ sql: "ALTER TABLE schedules ADD COLUMN claim_token TEXT;",
261
+ },
262
+ {
263
+ table: "schedules",
264
+ column: "claim_started_at",
265
+ sql: "ALTER TABLE schedules ADD COLUMN claim_started_at TEXT;",
266
+ },
267
+ {
268
+ table: "schedules",
269
+ column: "claim_until_at",
270
+ sql: "ALTER TABLE schedules ADD COLUMN claim_until_at TEXT;",
271
+ },
272
+ ];
273
+
274
+ function getColumnNames(db: SqliteDb, table: string): Set<string> {
275
+ return new Set(
276
+ db
277
+ .prepare(`PRAGMA table_info(${table});`)
278
+ .all()
279
+ .map((c) => c.name as string),
280
+ );
281
+ }
282
+
122
283
  export function ensureSessionSchema(
123
284
  db: SqliteDb,
124
285
  options: SessionSchemaOptions = {},
125
286
  ): void {
126
287
  db.exec("PRAGMA journal_mode = WAL;");
127
288
  db.exec("PRAGMA busy_timeout = 5000;");
128
- db.exec(`
129
- CREATE TABLE IF NOT EXISTS sessions (
130
- session_id TEXT PRIMARY KEY,
131
- source TEXT NOT NULL,
132
- pid INTEGER NOT NULL,
133
- started_at TEXT NOT NULL,
134
- ended_at TEXT,
135
- exit_code INTEGER,
136
- status TEXT NOT NULL,
137
- status_lock INTEGER NOT NULL DEFAULT 0,
138
- interactive INTEGER NOT NULL,
139
- provider TEXT NOT NULL,
140
- model TEXT NOT NULL,
141
- cwd TEXT NOT NULL,
142
- workspace_root TEXT NOT NULL,
143
- team_name TEXT,
144
- enable_tools INTEGER NOT NULL,
145
- enable_spawn INTEGER NOT NULL,
146
- enable_teams INTEGER NOT NULL,
147
- parent_session_id TEXT,
148
- parent_agent_id TEXT,
149
- agent_id TEXT,
150
- conversation_id TEXT,
151
- is_subagent INTEGER NOT NULL DEFAULT 0,
152
- prompt TEXT,
153
- metadata_json TEXT,
154
- transcript_path TEXT NOT NULL,
155
- hook_path TEXT NOT NULL,
156
- messages_path TEXT,
157
- updated_at TEXT NOT NULL
158
- );
159
- `);
160
- db.exec(`
161
- CREATE TABLE IF NOT EXISTS subagent_spawn_queue (
162
- id INTEGER PRIMARY KEY AUTOINCREMENT,
163
- root_session_id TEXT NOT NULL,
164
- parent_agent_id TEXT NOT NULL,
165
- task TEXT,
166
- system_prompt TEXT,
167
- created_at TEXT NOT NULL,
168
- consumed_at TEXT
169
- );
170
- `);
171
- db.exec(`
172
- CREATE TABLE IF NOT EXISTS schedules (
173
- schedule_id TEXT PRIMARY KEY,
174
- name TEXT NOT NULL,
175
- cron_pattern TEXT NOT NULL,
176
- prompt TEXT NOT NULL,
177
- provider TEXT NOT NULL,
178
- model TEXT NOT NULL,
179
- mode TEXT NOT NULL DEFAULT 'act',
180
- workspace_root TEXT,
181
- cwd TEXT,
182
- system_prompt TEXT,
183
- max_iterations INTEGER,
184
- timeout_seconds INTEGER,
185
- max_parallel INTEGER NOT NULL DEFAULT 1,
186
- enabled INTEGER NOT NULL DEFAULT 1,
187
- created_at TEXT NOT NULL,
188
- updated_at TEXT NOT NULL,
189
- last_run_at TEXT,
190
- next_run_at TEXT,
191
- claim_token TEXT,
192
- claim_started_at TEXT,
193
- claim_until_at TEXT,
194
- created_by TEXT,
195
- tags TEXT,
196
- metadata_json TEXT
197
- );
198
- `);
199
- db.exec(`
200
- CREATE TABLE IF NOT EXISTS schedule_executions (
201
- execution_id TEXT PRIMARY KEY,
202
- schedule_id TEXT NOT NULL,
203
- session_id TEXT,
204
- triggered_at TEXT NOT NULL,
205
- started_at TEXT,
206
- ended_at TEXT,
207
- status TEXT NOT NULL,
208
- exit_code INTEGER,
209
- error_message TEXT,
210
- iterations INTEGER,
211
- tokens_used INTEGER,
212
- cost_usd REAL,
213
- FOREIGN KEY (schedule_id) REFERENCES schedules(schedule_id) ON DELETE CASCADE,
214
- FOREIGN KEY (session_id) REFERENCES sessions(session_id) ON DELETE SET NULL
215
- );
216
- `);
217
- db.exec(`
218
- CREATE INDEX IF NOT EXISTS idx_schedule_executions_schedule
219
- ON schedule_executions(schedule_id, triggered_at DESC);
220
- `);
221
- db.exec(`
222
- CREATE INDEX IF NOT EXISTS idx_schedules_next_run
223
- ON schedules(enabled, next_run_at);
224
- `);
225
-
226
- if (!options.includeLegacyMigrations) {
227
- return;
289
+ for (const stmt of SCHEMA_STATEMENTS) {
290
+ db.exec(stmt);
228
291
  }
229
292
 
230
- const columns = db.prepare("PRAGMA table_info(sessions);").all();
231
- const hasColumn = (name: string): boolean =>
232
- columns.some((column) => column.name === name);
233
- if (!hasColumn("workspace_root")) {
234
- db.exec("ALTER TABLE sessions ADD COLUMN workspace_root TEXT;");
235
- db.exec(
236
- "UPDATE sessions SET workspace_root = cwd WHERE workspace_root IS NULL OR workspace_root = '';",
237
- );
238
- }
239
- if (!hasColumn("parent_session_id")) {
240
- db.exec("ALTER TABLE sessions ADD COLUMN parent_session_id TEXT;");
241
- }
242
- if (!hasColumn("parent_agent_id")) {
243
- db.exec("ALTER TABLE sessions ADD COLUMN parent_agent_id TEXT;");
244
- }
245
- if (!hasColumn("agent_id")) {
246
- db.exec("ALTER TABLE sessions ADD COLUMN agent_id TEXT;");
247
- }
248
- if (!hasColumn("conversation_id")) {
249
- db.exec("ALTER TABLE sessions ADD COLUMN conversation_id TEXT;");
250
- }
251
- if (!hasColumn("is_subagent")) {
252
- db.exec(
253
- "ALTER TABLE sessions ADD COLUMN is_subagent INTEGER NOT NULL DEFAULT 0;",
254
- );
255
- }
256
- if (!hasColumn("messages_path")) {
257
- db.exec("ALTER TABLE sessions ADD COLUMN messages_path TEXT;");
258
- }
259
- if (!hasColumn("metadata_json")) {
260
- db.exec("ALTER TABLE sessions ADD COLUMN metadata_json TEXT;");
261
- }
262
- const scheduleColumns = db.prepare("PRAGMA table_info(schedules);").all();
263
- const scheduleHasColumn = (name: string): boolean =>
264
- scheduleColumns.some((column) => column.name === name);
265
- if (!scheduleHasColumn("claim_token")) {
266
- db.exec("ALTER TABLE schedules ADD COLUMN claim_token TEXT;");
267
- }
268
- if (!scheduleHasColumn("claim_started_at")) {
269
- db.exec("ALTER TABLE schedules ADD COLUMN claim_started_at TEXT;");
270
- }
271
- if (!scheduleHasColumn("claim_until_at")) {
272
- db.exec("ALTER TABLE schedules ADD COLUMN claim_until_at TEXT;");
293
+ if (!options.includeLegacyMigrations) return;
294
+
295
+ const columnCache = new Map<string, Set<string>>();
296
+ const getColumns = (table: string) => {
297
+ let cols = columnCache.get(table);
298
+ if (!cols) {
299
+ cols = getColumnNames(db, table);
300
+ columnCache.set(table, cols);
301
+ }
302
+ return cols;
303
+ };
304
+
305
+ for (const migration of LEGACY_MIGRATIONS) {
306
+ if (!getColumns(migration.table).has(migration.column)) {
307
+ db.exec(migration.sql);
308
+ if (migration.column === "workspace_root") {
309
+ db.exec(
310
+ "UPDATE sessions SET workspace_root = cwd WHERE workspace_root IS NULL OR workspace_root = '';",
311
+ );
312
+ }
313
+ }
273
314
  }
274
315
  }
@@ -75,6 +75,7 @@ export interface RpcChatRunTurnRequest {
75
75
  messages?: RpcChatMessage[];
76
76
  prompt: string;
77
77
  attachments?: RpcChatAttachments;
78
+ delivery?: "queue" | "steer";
78
79
  }
79
80
 
80
81
  export interface RpcChatToolCallResult {
@@ -1,22 +1,27 @@
1
1
  export {
2
2
  AGENT_CONFIG_DIRECTORY_NAME,
3
3
  CLINE_MCP_SETTINGS_FILE_NAME,
4
+ discoverPluginModulePaths,
4
5
  ensureHookLogDir,
5
6
  ensureParentDir,
6
7
  HOOKS_CONFIG_DIRECTORY_NAME,
8
+ isPluginModulePath,
7
9
  RULES_CONFIG_DIRECTORY_NAME,
8
10
  resolveAgentConfigSearchPaths,
9
11
  resolveAgentsConfigDirPath,
10
12
  resolveClineDataDir,
11
13
  resolveClineDir,
14
+ resolveConfiguredPluginModulePaths,
12
15
  resolveDocumentsAgentConfigDirectoryPath,
13
16
  resolveDocumentsClineDirectoryPath,
14
17
  resolveDocumentsHooksDirectoryPath,
18
+ resolveDocumentsPluginsDirectoryPath,
15
19
  resolveDocumentsRulesDirectoryPath,
16
20
  resolveDocumentsWorkflowsDirectoryPath,
17
21
  resolveHooksConfigSearchPaths,
18
22
  resolveMcpSettingsPath,
19
23
  resolvePluginConfigSearchPaths,
24
+ resolvePluginModuleEntries,
20
25
  resolveProviderSettingsPath,
21
26
  resolveRulesConfigSearchPaths,
22
27
  resolveSessionDataDir,
@@ -1,5 +1,11 @@
1
- import { existsSync, mkdirSync } from "node:fs";
2
- import { dirname, join } from "node:path";
1
+ import {
2
+ existsSync,
3
+ mkdirSync,
4
+ readdirSync,
5
+ readFileSync,
6
+ statSync,
7
+ } from "node:fs";
8
+ import { dirname, join, resolve } from "node:path";
3
9
 
4
10
  export const AGENT_CONFIG_DIRECTORY_NAME = "agents";
5
11
  export const HOOKS_CONFIG_DIRECTORY_NAME = "hooks";
@@ -86,6 +92,10 @@ export function resolveDocumentsWorkflowsDirectoryPath(): string {
86
92
  return join(resolveDocumentsClineDirectoryPath(), "Workflows");
87
93
  }
88
94
 
95
+ export function resolveDocumentsPluginsDirectoryPath(): string {
96
+ return join(HOME_DIR, "Documents", "Plugins");
97
+ }
98
+
89
99
  export function resolveClineDataDir(): string {
90
100
  const explicitDir = process.env.CLINE_DATA_DIR?.trim();
91
101
  if (explicitDir) {
@@ -212,10 +222,164 @@ export function resolvePluginConfigSearchPaths(
212
222
  ? join(workspacePath, ".clinerules", PLUGINS_DIRECTORY_NAME)
213
223
  : "",
214
224
  join(resolveClineDir(), PLUGINS_DIRECTORY_NAME),
215
- join(HOME_DIR, ".agents", PLUGINS_DIRECTORY_NAME),
225
+ resolveDocumentsPluginsDirectoryPath(),
216
226
  ]);
217
227
  }
218
228
 
229
+ const PLUGIN_MODULE_EXTENSIONS = new Set([
230
+ ".js",
231
+ ".mjs",
232
+ ".cjs",
233
+ ".ts",
234
+ ".mts",
235
+ ".cts",
236
+ ]);
237
+ const PLUGIN_PACKAGE_JSON_FILE_NAME = "package.json";
238
+ const PLUGIN_DIRECTORY_INDEX_CANDIDATES = [
239
+ "index.ts",
240
+ "index.mts",
241
+ "index.cts",
242
+ "index.js",
243
+ "index.mjs",
244
+ "index.cjs",
245
+ ];
246
+
247
+ interface PluginPackageManifest {
248
+ plugins?: unknown;
249
+ extensions?: unknown;
250
+ }
251
+
252
+ export function isPluginModulePath(path: string): boolean {
253
+ const dot = path.lastIndexOf(".");
254
+ if (dot === -1) {
255
+ return false;
256
+ }
257
+ return PLUGIN_MODULE_EXTENSIONS.has(path.slice(dot));
258
+ }
259
+
260
+ function readPluginPackageManifest(
261
+ packageJsonPath: string,
262
+ ): PluginPackageManifest | null {
263
+ try {
264
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")) as {
265
+ cline?: PluginPackageManifest;
266
+ };
267
+ if (!packageJson.cline || typeof packageJson.cline !== "object") {
268
+ return null;
269
+ }
270
+ return packageJson.cline;
271
+ } catch {
272
+ return null;
273
+ }
274
+ }
275
+
276
+ function getManifestPluginEntries(
277
+ manifest: PluginPackageManifest | null,
278
+ ): string[] {
279
+ const entries = manifest?.plugins ?? manifest?.extensions;
280
+ if (!Array.isArray(entries)) {
281
+ return [];
282
+ }
283
+ return entries.filter((entry): entry is string => typeof entry === "string");
284
+ }
285
+
286
+ export function resolvePluginModuleEntries(
287
+ directoryPath: string,
288
+ ): string[] | null {
289
+ const root = resolve(directoryPath);
290
+ if (!existsSync(root) || !statSync(root).isDirectory()) {
291
+ return null;
292
+ }
293
+
294
+ const packageJsonPath = join(root, PLUGIN_PACKAGE_JSON_FILE_NAME);
295
+ if (existsSync(packageJsonPath)) {
296
+ const manifest = readPluginPackageManifest(packageJsonPath);
297
+ const entries = getManifestPluginEntries(manifest)
298
+ .map((entry) => resolve(root, entry))
299
+ .filter(
300
+ (entryPath) =>
301
+ existsSync(entryPath) &&
302
+ statSync(entryPath).isFile() &&
303
+ isPluginModulePath(entryPath),
304
+ );
305
+ if (entries.length > 0) {
306
+ return entries;
307
+ }
308
+ }
309
+
310
+ for (const candidate of PLUGIN_DIRECTORY_INDEX_CANDIDATES) {
311
+ const entryPath = join(root, candidate);
312
+ if (existsSync(entryPath) && statSync(entryPath).isFile()) {
313
+ return [entryPath];
314
+ }
315
+ }
316
+
317
+ return null;
318
+ }
319
+
320
+ export function discoverPluginModulePaths(directoryPath: string): string[] {
321
+ const root = resolve(directoryPath);
322
+ if (!existsSync(root)) {
323
+ return [];
324
+ }
325
+ const discovered: string[] = [];
326
+ const stack = [root];
327
+ while (stack.length > 0) {
328
+ const current = stack.pop();
329
+ if (!current) {
330
+ continue;
331
+ }
332
+ for (const entry of readdirSync(current, { withFileTypes: true })) {
333
+ const candidate = join(current, entry.name);
334
+ if (entry.isDirectory()) {
335
+ stack.push(candidate);
336
+ continue;
337
+ }
338
+ if (entry.name.startsWith(".")) {
339
+ continue;
340
+ }
341
+ if (entry.isFile() && isPluginModulePath(candidate)) {
342
+ discovered.push(candidate);
343
+ }
344
+ }
345
+ }
346
+ return discovered.sort((a, b) => a.localeCompare(b));
347
+ }
348
+
349
+ export function resolveConfiguredPluginModulePaths(
350
+ pluginPaths: ReadonlyArray<string>,
351
+ cwd: string,
352
+ ): string[] {
353
+ const resolvedPaths: string[] = [];
354
+ for (const pluginPath of pluginPaths) {
355
+ const trimmed = pluginPath.trim();
356
+ if (!trimmed) {
357
+ continue;
358
+ }
359
+ const absolutePath = resolve(cwd, trimmed);
360
+ if (!existsSync(absolutePath)) {
361
+ throw new Error(`Plugin path does not exist: ${absolutePath}`);
362
+ }
363
+ const stats = statSync(absolutePath);
364
+ if (stats.isDirectory()) {
365
+ const entries = resolvePluginModuleEntries(absolutePath);
366
+ if (entries) {
367
+ resolvedPaths.push(...entries);
368
+ continue;
369
+ }
370
+ resolvedPaths.push(...discoverPluginModulePaths(absolutePath));
371
+ continue;
372
+ }
373
+ if (!isPluginModulePath(absolutePath)) {
374
+ throw new Error(
375
+ `Plugin file must use a supported extension (${[...PLUGIN_MODULE_EXTENSIONS].join(", ")}): ${absolutePath}`,
376
+ );
377
+ }
378
+ resolvedPaths.push(absolutePath);
379
+ }
380
+ return resolvedPaths;
381
+ }
382
+
219
383
  export function ensureParentDir(filePath: string): void {
220
384
  const parent = dirname(filePath);
221
385
  if (!existsSync(parent)) {