@openadapter/koda-agent-core 1.0.0-beta.3

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.
Files changed (52) hide show
  1. package/README.md +488 -0
  2. package/dist/agent-loop.d.ts +23 -0
  3. package/dist/agent-loop.js +1 -0
  4. package/dist/agent.d.ts +117 -0
  5. package/dist/agent.js +1 -0
  6. package/dist/harness/agent-harness.d.ts +94 -0
  7. package/dist/harness/agent-harness.js +1 -0
  8. package/dist/harness/compaction/branch-summarization.d.ts +52 -0
  9. package/dist/harness/compaction/branch-summarization.js +38 -0
  10. package/dist/harness/compaction/compaction.d.ts +94 -0
  11. package/dist/harness/compaction/compaction.js +106 -0
  12. package/dist/harness/compaction/utils.d.ts +24 -0
  13. package/dist/harness/compaction/utils.js +17 -0
  14. package/dist/harness/env/nodejs.d.ts +50 -0
  15. package/dist/harness/env/nodejs.js +1 -0
  16. package/dist/harness/messages.d.ts +50 -0
  17. package/dist/harness/messages.js +17 -0
  18. package/dist/harness/prompt-templates.d.ts +47 -0
  19. package/dist/harness/prompt-templates.js +5 -0
  20. package/dist/harness/session/jsonl-repo.d.ts +25 -0
  21. package/dist/harness/session/jsonl-repo.js +1 -0
  22. package/dist/harness/session/jsonl-storage.d.ts +32 -0
  23. package/dist/harness/session/jsonl-storage.js +5 -0
  24. package/dist/harness/session/memory-repo.d.ts +17 -0
  25. package/dist/harness/session/memory-repo.js +1 -0
  26. package/dist/harness/session/memory-storage.d.ts +24 -0
  27. package/dist/harness/session/memory-storage.js +1 -0
  28. package/dist/harness/session/repo-utils.d.ts +10 -0
  29. package/dist/harness/session/repo-utils.js +1 -0
  30. package/dist/harness/session/session.d.ts +32 -0
  31. package/dist/harness/session/session.js +1 -0
  32. package/dist/harness/session/uuid.d.ts +1 -0
  33. package/dist/harness/session/uuid.js +1 -0
  34. package/dist/harness/skills.d.ts +43 -0
  35. package/dist/harness/skills.js +10 -0
  36. package/dist/harness/system-prompt.d.ts +2 -0
  37. package/dist/harness/system-prompt.js +2 -0
  38. package/dist/harness/types.d.ts +614 -0
  39. package/dist/harness/types.js +1 -0
  40. package/dist/harness/utils/shell-output.d.ts +13 -0
  41. package/dist/harness/utils/shell-output.js +1 -0
  42. package/dist/harness/utils/truncate.d.ts +69 -0
  43. package/dist/harness/utils/truncate.js +5 -0
  44. package/dist/index.d.ts +19 -0
  45. package/dist/index.js +1 -0
  46. package/dist/node.d.ts +2 -0
  47. package/dist/node.js +1 -0
  48. package/dist/proxy.d.ts +68 -0
  49. package/dist/proxy.js +2 -0
  50. package/dist/types.d.ts +392 -0
  51. package/dist/types.js +0 -0
  52. package/package.json +68 -0
@@ -0,0 +1,17 @@
1
+ var u=Object.defineProperty;var o=(e,t)=>u(e,"name",{value:t,configurable:!0});const c=`The conversation history before this point was compacted into the following summary:
2
+
3
+ <summary>
4
+ `,i=`
5
+ </summary>`,s=`The following is a summary of a branch that this conversation came back from:
6
+
7
+ <summary>
8
+ `,m="</summary>";function p(e){let t=`Ran \`${e.command}\`
9
+ `;return e.output?t+=`\`\`\`
10
+ ${e.output}
11
+ \`\`\``:t+="(no output)",e.cancelled?t+=`
12
+
13
+ (command cancelled)`:e.exitCode!==null&&e.exitCode!==void 0&&e.exitCode!==0&&(t+=`
14
+
15
+ Command exited with code ${e.exitCode}`),e.truncated&&e.fullOutputPath&&(t+=`
16
+
17
+ [Output truncated. Full output: ${e.fullOutputPath}]`),t}o(p,"bashExecutionToText");function x(e,t,n){return{role:"branchSummary",summary:e,fromId:t,timestamp:new Date(n).getTime()}}o(x,"createBranchSummaryMessage");function d(e,t,n){return{role:"compactionSummary",summary:e,tokensBefore:t,timestamp:new Date(n).getTime()}}o(d,"createCompactionSummaryMessage");function f(e,t,n,r,a){return{role:"custom",customType:e,content:t,display:n,details:r,timestamp:new Date(a).getTime()}}o(f,"createCustomMessage");function y(e){return e.map(t=>{switch(t.role){case"bashExecution":return t.excludeFromContext?void 0:{role:"user",content:[{type:"text",text:p(t)}],timestamp:t.timestamp};case"custom":return{role:"user",content:typeof t.content=="string"?[{type:"text",text:t.content}]:t.content,timestamp:t.timestamp};case"branchSummary":return{role:"user",content:[{type:"text",text:s+t.summary+m}],timestamp:t.timestamp};case"compactionSummary":return{role:"user",content:[{type:"text",text:c+t.summary+i}],timestamp:t.timestamp};case"user":case"assistant":case"toolResult":return t;default:return}}).filter(t=>t!==void 0)}o(y,"convertToLlm");export{s as BRANCH_SUMMARY_PREFIX,m as BRANCH_SUMMARY_SUFFIX,c as COMPACTION_SUMMARY_PREFIX,i as COMPACTION_SUMMARY_SUFFIX,p as bashExecutionToText,y as convertToLlm,x as createBranchSummaryMessage,d as createCompactionSummaryMessage,f as createCustomMessage};
@@ -0,0 +1,47 @@
1
+ import { type ExecutionEnv, type PromptTemplate } from "./types.ts";
2
+ export type PromptTemplateDiagnosticCode = "file_info_failed" | "list_failed" | "read_failed" | "parse_failed";
3
+ /** Warning produced while loading prompt templates. */
4
+ export interface PromptTemplateDiagnostic {
5
+ /** Diagnostic severity. Currently only warnings are emitted. */
6
+ type: "warning";
7
+ /** Stable diagnostic code. */
8
+ code: PromptTemplateDiagnosticCode;
9
+ /** Human-readable diagnostic message. */
10
+ message: string;
11
+ /** Path associated with the diagnostic. */
12
+ path: string;
13
+ }
14
+ /**
15
+ * Load prompt templates from one or more paths.
16
+ *
17
+ * Directory inputs load direct `.md` children non-recursively. File inputs load explicit `.md` files. Missing paths and
18
+ * non-markdown files are skipped. Read and parse failures are returned as diagnostics.
19
+ */
20
+ export declare function loadPromptTemplates(env: ExecutionEnv, paths: string | string[]): Promise<{
21
+ promptTemplates: PromptTemplate[];
22
+ diagnostics: PromptTemplateDiagnostic[];
23
+ }>;
24
+ /**
25
+ * Load prompt templates from source-tagged paths.
26
+ *
27
+ * Source values are preserved exactly and attached to every loaded prompt template and diagnostic. The agent package does
28
+ * not interpret source values; applications define their own provenance shape.
29
+ */
30
+ export declare function loadSourcedPromptTemplates<TSource, TPromptTemplate extends PromptTemplate = PromptTemplate>(env: ExecutionEnv, inputs: Array<{
31
+ path: string;
32
+ source: TSource;
33
+ }>, mapPromptTemplate?: (promptTemplate: PromptTemplate, source: TSource) => TPromptTemplate): Promise<{
34
+ promptTemplates: Array<{
35
+ promptTemplate: TPromptTemplate;
36
+ source: TSource;
37
+ }>;
38
+ diagnostics: Array<PromptTemplateDiagnostic & {
39
+ source: TSource;
40
+ }>;
41
+ }>;
42
+ /** Parse an argument string using simple shell-style single and double quotes. */
43
+ export declare function parseCommandArgs(argsString: string): string[];
44
+ /** Substitute prompt template placeholders (`$1`, `$@`, `$ARGUMENTS`, `${@:N}`, `${@:N:L}`) with command arguments. */
45
+ export declare function substituteArgs(content: string, args: string[]): string;
46
+ /** Format a prompt template invocation with positional arguments. */
47
+ export declare function formatPromptTemplateInvocation(template: PromptTemplate, args?: string[]): string;
@@ -0,0 +1,5 @@
1
+ var d=Object.defineProperty;var c=(n,e)=>d(n,"name",{value:e,configurable:!0});import{parse as m}from"yaml";import{toError as g}from"./types.js";async function h(n,e){const t=[],r=[];for(const o of Array.isArray(e)?e:[e]){const s=await n.fileInfo(o);if(!s.ok){s.error.code!=="not_found"&&r.push({type:"warning",code:"file_info_failed",message:s.error.message,path:o});continue}const i=s.value,a=await u(n,i,r);if(a==="directory"){const p=await y(n,i.path);t.push(...p.promptTemplates),r.push(...p.diagnostics)}else if(a==="file"&&i.name.endsWith(".md")){const p=await l(n,i.path);p.promptTemplate&&t.push(p.promptTemplate),r.push(...p.diagnostics)}}return{promptTemplates:t,diagnostics:r}}c(h,"loadPromptTemplates");async function v(n,e,t){const r=[],o=[];for(const s of e){const i=await h(n,s.path);for(const a of i.promptTemplates)r.push({promptTemplate:t?t(a,s.source):a,source:s.source});for(const a of i.diagnostics)o.push({...a,source:s.source})}return{promptTemplates:r,diagnostics:o}}c(v,"loadSourcedPromptTemplates");async function y(n,e){const t=[],r=[],o=await n.listDir(e);if(!o.ok)return r.push({type:"warning",code:"list_failed",message:o.error.message,path:e}),{promptTemplates:t,diagnostics:r};const s=o.value;for(const i of s.sort((a,p)=>a.name.localeCompare(p.name))){if(await u(n,i,r)!=="file"||!i.name.endsWith(".md"))continue;const p=await l(n,i.path);p.promptTemplate&&t.push(p.promptTemplate),r.push(...p.diagnostics)}return{promptTemplates:t,diagnostics:r}}c(y,"loadTemplatesFromDir");async function l(n,e){const t=[],r=await n.readTextFile(e);if(!r.ok)return t.push({type:"warning",code:"read_failed",message:r.error.message,path:e}),{promptTemplate:null,diagnostics:t};const o=T(r.value);if(!o.ok)return t.push({type:"warning",code:"parse_failed",message:o.error.message,path:e}),{promptTemplate:null,diagnostics:t};const{frontmatter:s,body:i}=o.value,a=i.split(`
2
+ `).find(f=>f.trim());let p=typeof s.description=="string"?s.description:"";return!p&&a&&(p=a.slice(0,60),a.length>60&&(p+="...")),{promptTemplate:{name:k(e).replace(/\.md$/i,""),description:p,content:i},diagnostics:t}}c(l,"loadTemplateFromFile");async function u(n,e,t){if(e.kind==="file"||e.kind==="directory")return e.kind;const r=await n.canonicalPath(e.path);if(!r.ok){r.error.code!=="not_found"&&t.push({type:"warning",code:"file_info_failed",message:r.error.message,path:e.path});return}const o=await n.fileInfo(r.value);if(!o.ok){o.error.code!=="not_found"&&t.push({type:"warning",code:"file_info_failed",message:o.error.message,path:e.path});return}return o.value.kind==="file"||o.value.kind==="directory"?o.value.kind:void 0}c(u,"resolveKind");function T(n){try{const e=n.replace(/\r\n/g,`
3
+ `).replace(/\r/g,`
4
+ `);if(!e.startsWith("---"))return{ok:!0,value:{frontmatter:{},body:e}};const t=e.indexOf(`
5
+ ---`,3);if(t===-1)return{ok:!0,value:{frontmatter:{},body:e}};const r=e.slice(4,t),o=e.slice(t+4).trim();return{ok:!0,value:{frontmatter:m(r)??{},body:o}}}catch(e){return{ok:!1,error:g(e)}}}c(T,"parseFrontmatter");function k(n){const e=n.replace(/\/+$/,""),t=e.lastIndexOf("/");return t===-1?e:e.slice(t+1)}c(k,"basenameEnvPath");function b(n){const e=[];let t="",r=null;for(let o=0;o<n.length;o++){const s=n[o];r?s===r?r=null:t+=s:s==='"'||s==="'"?r=s:s===" "||s===" "?t&&(e.push(t),t=""):t+=s}return t&&e.push(t),e}c(b,"parseCommandArgs");function w(n,e){let t=n;t=t.replace(/\$(\d+)/g,(o,s)=>e[parseInt(s,10)-1]??""),t=t.replace(/\$\{@:(\d+)(?::(\d+))?\}/g,(o,s,i)=>{let a=parseInt(s,10)-1;return a<0&&(a=0),i?e.slice(a,a+parseInt(i,10)).join(" "):e.slice(a).join(" ")});const r=e.join(" ");return t=t.replace(/\$ARGUMENTS/g,r),t=t.replace(/\$@/g,r),t}c(w,"substituteArgs");function A(n,e=[]){return w(n.content,e)}c(A,"formatPromptTemplateInvocation");export{A as formatPromptTemplateInvocation,h as loadPromptTemplates,v as loadSourcedPromptTemplates,b as parseCommandArgs,w as substituteArgs};
@@ -0,0 +1,25 @@
1
+ import type { FileSystem, JsonlSessionCreateOptions, JsonlSessionListOptions, JsonlSessionMetadata, JsonlSessionRepoApi, Session } from "../types.ts";
2
+ type JsonlSessionRepoFileSystem = Pick<FileSystem, "cwd" | "absolutePath" | "joinPath" | "readTextFile" | "readTextLines" | "writeFile" | "appendFile" | "listDir" | "exists" | "createDir" | "remove">;
3
+ export declare class JsonlSessionRepo implements JsonlSessionRepoApi {
4
+ private readonly fs;
5
+ private readonly sessionsRootInput;
6
+ private sessionsRoot;
7
+ constructor(options: {
8
+ fs: JsonlSessionRepoFileSystem;
9
+ sessionsRoot: string;
10
+ });
11
+ private getSessionsRoot;
12
+ private getSessionDir;
13
+ private createSessionFilePath;
14
+ create(options: JsonlSessionCreateOptions): Promise<Session<JsonlSessionMetadata>>;
15
+ open(metadata: JsonlSessionMetadata): Promise<Session<JsonlSessionMetadata>>;
16
+ list(options?: JsonlSessionListOptions): Promise<JsonlSessionMetadata[]>;
17
+ delete(metadata: JsonlSessionMetadata): Promise<void>;
18
+ fork(sourceMetadata: JsonlSessionMetadata, options: JsonlSessionCreateOptions & {
19
+ entryId?: string;
20
+ position?: "before" | "at";
21
+ id?: string;
22
+ }): Promise<Session<JsonlSessionMetadata>>;
23
+ private listSessionDirs;
24
+ }
25
+ export {};
@@ -0,0 +1 @@
1
+ var g=Object.defineProperty;var d=(c,s)=>g(c,"name",{value:s,configurable:!0});import{SessionError as w,toError as y}from"../types.js";import{JsonlSessionStorage as f,loadJsonlSessionMetadata as F}from"./jsonl-storage.js";import{createSessionId as u,createTimestamp as S,getEntriesToFork as D,getFileSystemResultOrThrow as o,toSession as l}from"./repo-utils.js";function R(c){return`--${c.replace(/^[/\\]/,"").replace(/[/\\:]/g,"-")}--`}d(R,"encodeCwd");class v{static{d(this,"JsonlSessionRepo")}fs;sessionsRootInput;sessionsRoot;constructor(s){this.fs=s.fs,this.sessionsRootInput=s.sessionsRoot}async getSessionsRoot(){return this.sessionsRoot||(this.sessionsRoot=o(await this.fs.absolutePath(this.sessionsRootInput),`Failed to resolve sessions root ${this.sessionsRootInput}`)),this.sessionsRoot}async getSessionDir(s){return o(await this.fs.joinPath([await this.getSessionsRoot(),R(s)]),`Failed to resolve session directory for ${s}`)}async createSessionFilePath(s,t,e){return o(await this.fs.joinPath([await this.getSessionDir(s),`${e.replace(/[:.]/g,"-")}_${t}.jsonl`]),`Failed to resolve session file path for ${t}`)}async create(s){const t=s.id??u(),e=S(),i=await this.getSessionDir(s.cwd);o(await this.fs.createDir(i,{recursive:!0}),`Failed to create session directory ${i}`);const r=await this.createSessionFilePath(s.cwd,t,e),n=await f.create(this.fs,r,{cwd:s.cwd,sessionId:t,parentSessionPath:s.parentSessionPath});return l(n)}async open(s){if(!o(await this.fs.exists(s.path),`Failed to check session ${s.path}`))throw new w("not_found",`Session not found: ${s.path}`);const t=await f.open(this.fs,s.path);return l(t)}async list(s={}){const t=s.cwd?[await this.getSessionDir(s.cwd)]:await this.listSessionDirs(),e=[];for(const i of t){if(!o(await this.fs.exists(i),`Failed to check session directory ${i}`))continue;const r=o(await this.fs.listDir(i),`Failed to list sessions in ${i}`).filter(n=>n.kind!=="directory"&&n.name.endsWith(".jsonl"));for(const n of r)try{e.push(await F(this.fs,n.path))}catch(h){const a=y(h);if(!(a instanceof w)||a.code!=="invalid_session")throw a}}return e.sort((i,r)=>new Date(r.createdAt).getTime()-new Date(i.createdAt).getTime()),e}async delete(s){o(await this.fs.remove(s.path,{force:!0}),`Failed to delete session ${s.path}`)}async fork(s,t){const e=await this.open(s),i=await D(e.getStorage(),t),r=t.id??u(),n=S(),h=await this.getSessionDir(t.cwd);o(await this.fs.createDir(h,{recursive:!0}),`Failed to create session directory ${h}`);const a=await f.create(this.fs,await this.createSessionFilePath(t.cwd,r,n),{cwd:t.cwd,sessionId:r,parentSessionPath:t.parentSessionPath??s.path});for(const p of i)await a.appendEntry(p);return l(a)}async listSessionDirs(){const s=await this.getSessionsRoot();return o(await this.fs.exists(s),`Failed to check sessions root ${s}`)?o(await this.fs.listDir(s),`Failed to list sessions root ${s}`).filter(e=>e.kind==="directory").map(e=>e.path):[]}}export{v as JsonlSessionRepo};
@@ -0,0 +1,32 @@
1
+ import type { FileSystem, JsonlSessionMetadata, SessionStorage, SessionTreeEntry } from "../types.ts";
2
+ type JsonlSessionStorageFileSystem = Pick<FileSystem, "readTextFile" | "readTextLines" | "writeFile" | "appendFile">;
3
+ export declare function loadJsonlSessionMetadata(fs: JsonlSessionStorageFileSystem, filePath: string): Promise<JsonlSessionMetadata>;
4
+ export declare class JsonlSessionStorage implements SessionStorage<JsonlSessionMetadata> {
5
+ private readonly fs;
6
+ private readonly filePath;
7
+ private readonly metadata;
8
+ private entries;
9
+ private byId;
10
+ private labelsById;
11
+ private currentLeafId;
12
+ private constructor();
13
+ static open(fs: JsonlSessionStorageFileSystem, filePath: string): Promise<JsonlSessionStorage>;
14
+ static create(fs: JsonlSessionStorageFileSystem, filePath: string, options: {
15
+ cwd: string;
16
+ sessionId: string;
17
+ parentSessionPath?: string;
18
+ }): Promise<JsonlSessionStorage>;
19
+ getMetadata(): Promise<JsonlSessionMetadata>;
20
+ getLeafId(): Promise<string | null>;
21
+ setLeafId(leafId: string | null): Promise<void>;
22
+ createEntryId(): Promise<string>;
23
+ appendEntry(entry: SessionTreeEntry): Promise<void>;
24
+ getEntry(id: string): Promise<SessionTreeEntry | undefined>;
25
+ findEntries<TType extends SessionTreeEntry["type"]>(type: TType): Promise<Array<Extract<SessionTreeEntry, {
26
+ type: TType;
27
+ }>>>;
28
+ getLabel(id: string): Promise<string | undefined>;
29
+ getPathToRoot(leafId: string | null): Promise<SessionTreeEntry[]>;
30
+ getEntries(): Promise<SessionTreeEntry[]>;
31
+ }
32
+ export {};
@@ -0,0 +1,5 @@
1
+ var v=Object.defineProperty;var i=(n,t)=>v(n,"name",{value:t,configurable:!0});import{SessionError as c,toError as y}from"../types.js";import{getFileSystemResultOrThrow as f}from"./repo-utils.js";import{uuidv7 as w}from"./uuid.js";function I(n,t){if(t.type!=="label")return;const e=t.label?.trim();e?n.set(t.targetId,e):n.delete(t.targetId)}i(I,"updateLabelCache");function $(n){const t=new Map;for(const e of n)I(t,e);return t}i($,"buildLabelsById");function g(n){for(let t=0;t<100;t++){const e=w().slice(0,8);if(!n.has(e))return e}return w()}i(g,"generateEntryId");function m(n){return typeof n=="object"&&n!==null}i(m,"isRecord");function a(n,t,e){return new c("invalid_session",`Invalid JSONL session file ${n}: ${t}`,e)}i(a,"invalidSession");function o(n,t,e,s){return new c("invalid_entry",`Invalid JSONL session file ${n}: line ${t} ${e}`,s)}i(o,"invalidEntry");function S(n,t){let e;try{e=JSON.parse(n)}catch(s){throw a(t,"first line is not a valid session header",y(s))}if(!m(e)||e.type!=="session")throw a(t,"first line is not a valid session header");if(e.version!==3)throw a(t,"unsupported session version");if(typeof e.id!="string"||!e.id)throw a(t,"session header is missing id");if(typeof e.timestamp!="string"||!e.timestamp)throw a(t,"session header is missing timestamp");if(typeof e.cwd!="string"||!e.cwd)throw a(t,"session header is missing cwd");if(e.parentSession!==void 0&&typeof e.parentSession!="string")throw a(t,"session header parentSession must be a string");return{type:"session",version:3,id:e.id,timestamp:e.timestamp,cwd:e.cwd,parentSession:e.parentSession}}i(S,"parseHeaderLine");function E(n,t,e){let s;try{s=JSON.parse(n)}catch(r){throw o(t,e,"is not valid JSON",y(r))}if(!m(s))throw o(t,e,"is not a valid session entry");if(typeof s.type!="string")throw o(t,e,"is missing entry type");if(typeof s.id!="string"||!s.id)throw o(t,e,"is missing entry id");if(s.parentId!==null&&typeof s.parentId!="string")throw o(t,e,"has invalid parentId");if(typeof s.timestamp!="string"||!s.timestamp)throw o(t,e,"is missing timestamp");if(s.type==="leaf"&&s.targetId!==null&&typeof s.targetId!="string")throw o(t,e,"has invalid targetId");return s}i(E,"parseEntryLine");function L(n){return n.type==="leaf"?n.targetId:n.id}i(L,"leafIdAfterEntry");function b(n,t){return{id:n.id,createdAt:n.timestamp,cwd:n.cwd,path:t,parentSessionPath:n.parentSession}}i(b,"headerToSessionMetadata");async function M(n,t){const s=f(await n.readTextLines(t,{maxLines:1}),`Failed to read session header ${t}`)[0];if(s?.trim())return b(S(s,t),t);throw a(t,"missing session header")}i(M,"loadJsonlSessionMetadata");async function O(n,t){const s=f(await n.readTextFile(t),`Failed to read session ${t}`).split(`
2
+ `).filter(d=>d.trim());if(s.length===0)throw a(t,"missing session header");const r=S(s[0],t),h=[];let p=null;for(let d=1;d<s.length;d++){const l=E(s[d],t,d+1);h.push(l),p=L(l)}return{header:r,entries:h,leafId:p}}i(O,"loadJsonlStorage");class u{static{i(this,"JsonlSessionStorage")}fs;filePath;metadata;entries;byId;labelsById;currentLeafId;constructor(t,e,s,r,h){this.fs=t,this.filePath=e,this.metadata=b(s,this.filePath),this.entries=r,this.byId=new Map(r.map(p=>[p.id,p])),this.labelsById=$(r),this.currentLeafId=h}static async open(t,e){const s=await O(t,e);return new u(t,e,s.header,s.entries,s.leafId)}static async create(t,e,s){const r={type:"session",version:3,id:s.sessionId,timestamp:new Date().toISOString(),cwd:s.cwd,parentSession:s.parentSessionPath};return f(await t.writeFile(e,`${JSON.stringify(r)}
3
+ `),`Failed to create session ${e}`),new u(t,e,r,[],null)}async getMetadata(){return this.metadata}async getLeafId(){if(this.currentLeafId!==null&&!this.byId.has(this.currentLeafId))throw new c("invalid_session",`Entry ${this.currentLeafId} not found`);return this.currentLeafId}async setLeafId(t){if(t!==null&&!this.byId.has(t))throw new c("not_found",`Entry ${t} not found`);const e={type:"leaf",id:g(this.byId),parentId:this.currentLeafId,timestamp:new Date().toISOString(),targetId:t};f(await this.fs.appendFile(this.filePath,`${JSON.stringify(e)}
4
+ `),`Failed to append session leaf ${e.id}`),this.entries.push(e),this.byId.set(e.id,e),this.currentLeafId=t}async createEntryId(){return g(this.byId)}async appendEntry(t){f(await this.fs.appendFile(this.filePath,`${JSON.stringify(t)}
5
+ `),`Failed to append session entry ${t.id}`),this.entries.push(t),this.byId.set(t.id,t),I(this.labelsById,t),this.currentLeafId=L(t)}async getEntry(t){return this.byId.get(t)}async findEntries(t){return this.entries.filter(e=>e.type===t)}async getLabel(t){return this.labelsById.get(t)}async getPathToRoot(t){if(t===null)return[];const e=[];let s=this.byId.get(t);if(!s)throw new c("not_found",`Entry ${t} not found`);for(;s&&(e.unshift(s),!!s.parentId);){const r=this.byId.get(s.parentId);if(!r)throw new c("invalid_session",`Entry ${s.parentId} not found`);s=r}return e}async getEntries(){return[...this.entries]}}export{u as JsonlSessionStorage,M as loadJsonlSessionMetadata};
@@ -0,0 +1,17 @@
1
+ import { type Session, type SessionMetadata, type SessionRepo } from "../types.ts";
2
+ export declare class InMemorySessionRepo implements SessionRepo<SessionMetadata, {
3
+ id?: string;
4
+ }, void> {
5
+ private sessions;
6
+ create(options?: {
7
+ id?: string;
8
+ }): Promise<Session<SessionMetadata>>;
9
+ open(metadata: SessionMetadata): Promise<Session<SessionMetadata>>;
10
+ list(): Promise<SessionMetadata[]>;
11
+ delete(metadata: SessionMetadata): Promise<void>;
12
+ fork(sourceMetadata: SessionMetadata, options: {
13
+ entryId?: string;
14
+ position?: "before" | "at";
15
+ id?: string;
16
+ }): Promise<Session<SessionMetadata>>;
17
+ }
@@ -0,0 +1 @@
1
+ var g=Object.defineProperty;var a=(n,s)=>g(n,"name",{value:s,configurable:!0});import{SessionError as u}from"../types.js";import{InMemorySessionStorage as c}from"./memory-storage.js";import{createSessionId as d,createTimestamp as m,getEntriesToFork as S,toSession as p}from"./repo-utils.js";class M{static{a(this,"InMemorySessionRepo")}sessions=new Map;async create(s={}){const e={id:s.id??d(),createdAt:m()},o=new c({metadata:e}),t=p(o);return this.sessions.set(e.id,t),t}async open(s){const e=this.sessions.get(s.id);if(!e)throw new u("not_found",`Session not found: ${s.id}`);return e}async list(){return Promise.all([...this.sessions.values()].map(s=>s.getMetadata()))}async delete(s){this.sessions.delete(s.id)}async fork(s,e){const o=await this.open(s),t=await S(o.getStorage(),e),i={id:e.id??d(),createdAt:m()},f=new c({metadata:i,entries:t}),r=p(f);return this.sessions.set(i.id,r),r}}export{M as InMemorySessionRepo};
@@ -0,0 +1,24 @@
1
+ import { type SessionMetadata, type SessionStorage, type SessionTreeEntry } from "../types.ts";
2
+ export declare class InMemorySessionStorage<TMetadata extends SessionMetadata = SessionMetadata> implements SessionStorage<TMetadata> {
3
+ private readonly metadata;
4
+ private entries;
5
+ private byId;
6
+ private labelsById;
7
+ private leafId;
8
+ constructor(options?: {
9
+ entries?: SessionTreeEntry[];
10
+ metadata?: TMetadata;
11
+ });
12
+ getMetadata(): Promise<TMetadata>;
13
+ getLeafId(): Promise<string | null>;
14
+ setLeafId(leafId: string | null): Promise<void>;
15
+ createEntryId(): Promise<string>;
16
+ appendEntry(entry: SessionTreeEntry): Promise<void>;
17
+ getEntry(id: string): Promise<SessionTreeEntry | undefined>;
18
+ findEntries<TType extends SessionTreeEntry["type"]>(type: TType): Promise<Array<Extract<SessionTreeEntry, {
19
+ type: TType;
20
+ }>>>;
21
+ getLabel(id: string): Promise<string | undefined>;
22
+ getPathToRoot(leafId: string | null): Promise<SessionTreeEntry[]>;
23
+ getEntries(): Promise<SessionTreeEntry[]>;
24
+ }
@@ -0,0 +1 @@
1
+ var f=Object.defineProperty;var i=(n,t)=>f(n,"name",{value:t,configurable:!0});import{SessionError as r}from"../types.js";import{uuidv7 as a}from"./uuid.js";function h(n,t){if(t.type!=="label")return;const e=t.label?.trim();e?n.set(t.targetId,e):n.delete(t.targetId)}i(h,"updateLabelCache");function I(n){const t=new Map;for(const e of n)h(t,e);return t}i(I,"buildLabelsById");function o(n){for(let t=0;t<100;t++){const e=a().slice(0,8);if(!n.has(e))return e}return a()}i(o,"generateEntryId");function l(n){return n.type==="leaf"?n.targetId:n.id}i(l,"leafIdAfterEntry");class b{static{i(this,"InMemorySessionStorage")}metadata;entries;byId;labelsById;leafId;constructor(t){this.entries=t?.entries?[...t.entries]:[],this.byId=new Map(this.entries.map(e=>[e.id,e])),this.labelsById=I(this.entries),this.leafId=null;for(const e of this.entries)this.leafId=l(e);if(this.leafId!==null&&!this.byId.has(this.leafId))throw new r("invalid_session",`Entry ${this.leafId} not found`);this.metadata=t?.metadata??{id:a(),createdAt:new Date().toISOString()}}async getMetadata(){return this.metadata}async getLeafId(){if(this.leafId!==null&&!this.byId.has(this.leafId))throw new r("invalid_session",`Entry ${this.leafId} not found`);return this.leafId}async setLeafId(t){if(t!==null&&!this.byId.has(t))throw new r("not_found",`Entry ${t} not found`);const e={type:"leaf",id:o(this.byId),parentId:this.leafId,timestamp:new Date().toISOString(),targetId:t};this.entries.push(e),this.byId.set(e.id,e),this.leafId=t}async createEntryId(){return o(this.byId)}async appendEntry(t){this.entries.push(t),this.byId.set(t.id,t),h(this.labelsById,t),this.leafId=l(t)}async getEntry(t){return this.byId.get(t)}async findEntries(t){return this.entries.filter(e=>e.type===t)}async getLabel(t){return this.labelsById.get(t)}async getPathToRoot(t){if(t===null)return[];const e=[];let s=this.byId.get(t);if(!s)throw new r("not_found",`Entry ${t} not found`);for(;s&&(e.unshift(s),!!s.parentId);){const d=this.byId.get(s.parentId);if(!d)throw new r("invalid_session",`Entry ${s.parentId} not found`);s=d}return e}async getEntries(){return[...this.entries]}}export{b as InMemorySessionStorage};
@@ -0,0 +1,10 @@
1
+ import { type FileError, type Result, type SessionMetadata, type SessionStorage, type SessionTreeEntry } from "../types.ts";
2
+ import { Session } from "./session.ts";
3
+ export declare function createSessionId(): string;
4
+ export declare function createTimestamp(): string;
5
+ export declare function toSession<TMetadata extends SessionMetadata>(storage: SessionStorage<TMetadata>): Session<TMetadata>;
6
+ export declare function getFileSystemResultOrThrow<TValue>(result: Result<TValue, FileError>, message: string): TValue;
7
+ export declare function getEntriesToFork(storage: SessionStorage, options: {
8
+ entryId?: string;
9
+ position?: "before" | "at";
10
+ }): Promise<SessionTreeEntry[]>;
@@ -0,0 +1 @@
1
+ var f=Object.defineProperty;var n=(e,r)=>f(e,"name",{value:r,configurable:!0});import{SessionError as i}from"../types.js";import{Session as a}from"./session.js";import{uuidv7 as s}from"./uuid.js";function g(){return s()}n(g,"createSessionId");function w(){return new Date().toISOString()}n(w,"createTimestamp");function y(e){return new a(e)}n(y,"toSession");function p(e,r){if(!e.ok){const t=e.error.code==="not_found"?"not_found":"storage";throw new i(t,`${r}: ${e.error.message}`,e.error)}return e.value}n(p,"getFileSystemResultOrThrow");async function I(e,r){if(!r.entryId)return e.getEntries();const t=await e.getEntry(r.entryId);if(!t)throw new i("invalid_fork_target",`Entry ${r.entryId} not found`);let o;if((r.position??"before")==="at")o=t.id;else{if(t.type!=="message"||t.message.role!=="user")throw new i("invalid_fork_target",`Entry ${r.entryId} is not a user message`);o=t.parentId}return e.getPathToRoot(o)}n(I,"getEntriesToFork");export{g as createSessionId,w as createTimestamp,I as getEntriesToFork,p as getFileSystemResultOrThrow,y as toSession};
@@ -0,0 +1,32 @@
1
+ import type { ImageContent, TextContent } from "@openadapter/koda-ai";
2
+ import type { AgentMessage } from "../../types.ts";
3
+ import type { SessionContext, SessionMetadata, SessionStorage, SessionTreeEntry } from "../types.ts";
4
+ export declare function buildSessionContext(pathEntries: SessionTreeEntry[]): SessionContext;
5
+ export declare class Session<TMetadata extends SessionMetadata = SessionMetadata> {
6
+ private storage;
7
+ constructor(storage: SessionStorage<TMetadata>);
8
+ getMetadata(): Promise<TMetadata>;
9
+ getStorage(): SessionStorage<TMetadata>;
10
+ getLeafId(): Promise<string | null>;
11
+ getEntry(id: string): Promise<SessionTreeEntry | undefined>;
12
+ getEntries(): Promise<SessionTreeEntry[]>;
13
+ getBranch(fromId?: string): Promise<SessionTreeEntry[]>;
14
+ buildContext(): Promise<SessionContext>;
15
+ getLabel(id: string): Promise<string | undefined>;
16
+ getSessionName(): Promise<string | undefined>;
17
+ private appendTypedEntry;
18
+ appendMessage(message: AgentMessage): Promise<string>;
19
+ appendThinkingLevelChange(thinkingLevel: string): Promise<string>;
20
+ appendModelChange(provider: string, modelId: string): Promise<string>;
21
+ appendActiveToolsChange(activeToolNames: string[]): Promise<string>;
22
+ appendCompaction<T = unknown>(summary: string, firstKeptEntryId: string, tokensBefore: number, details?: T, fromHook?: boolean): Promise<string>;
23
+ appendCustomEntry(customType: string, data?: unknown): Promise<string>;
24
+ appendCustomMessageEntry<T = unknown>(customType: string, content: string | (TextContent | ImageContent)[], display: boolean, details?: T): Promise<string>;
25
+ appendLabel(targetId: string, label: string | undefined): Promise<string>;
26
+ appendSessionName(name: string): Promise<string>;
27
+ moveTo(entryId: string | null, summary?: {
28
+ summary: string;
29
+ details?: unknown;
30
+ fromHook?: boolean;
31
+ }): Promise<string | undefined>;
32
+ }
@@ -0,0 +1 @@
1
+ var y=Object.defineProperty;var p=(i,t)=>y(i,"name",{value:t,configurable:!0});import{createBranchSummaryMessage as h,createCompactionSummaryMessage as l,createCustomMessage as f}from"../messages.js";import{SessionError as c}from"../types.js";function u(i){let t="off",a=null,o=null,s=null;for(const e of i)e.type==="thinking_level_change"?t=e.thinkingLevel:e.type==="model_change"?a={provider:e.provider,modelId:e.modelId}:e.type==="message"&&e.message.role==="assistant"?a={provider:e.message.provider,modelId:e.message.model}:e.type==="active_tools_change"?o=[...e.activeToolNames]:e.type==="compaction"&&(s=e);const r=[],d=p(e=>{e.type==="message"?r.push(e.message):e.type==="custom_message"?r.push(f(e.customType,e.content,e.display,e.details,e.timestamp)):e.type==="branch_summary"&&e.summary&&r.push(h(e.summary,e.fromId,e.timestamp))},"appendMessage");if(s){r.push(l(s.summary,s.tokensBefore,s.timestamp));const e=i.findIndex(n=>n.type==="compaction"&&n.id===s.id);let g=!1;for(let n=0;n<e;n++){const m=i[n];m.id===s.firstKeptEntryId&&(g=!0),g&&d(m)}for(let n=e+1;n<i.length;n++)d(i[n])}else for(const e of i)d(e);return{messages:r,thinkingLevel:t,model:a,activeToolNames:o}}p(u,"buildSessionContext");class S{static{p(this,"Session")}storage;constructor(t){this.storage=t}getMetadata(){return this.storage.getMetadata()}getStorage(){return this.storage}getLeafId(){return this.storage.getLeafId()}getEntry(t){return this.storage.getEntry(t)}getEntries(){return this.storage.getEntries()}async getBranch(t){const a=t??await this.storage.getLeafId();return this.storage.getPathToRoot(a)}async buildContext(){return u(await this.getBranch())}getLabel(t){return this.storage.getLabel(t)}async getSessionName(){const t=await this.storage.findEntries("session_info");return t[t.length-1]?.name?.trim()||void 0}async appendTypedEntry(t){return await this.storage.appendEntry(t),t.id}async appendMessage(t){return this.appendTypedEntry({type:"message",id:await this.storage.createEntryId(),parentId:await this.storage.getLeafId(),timestamp:new Date().toISOString(),message:t})}async appendThinkingLevelChange(t){return this.appendTypedEntry({type:"thinking_level_change",id:await this.storage.createEntryId(),parentId:await this.storage.getLeafId(),timestamp:new Date().toISOString(),thinkingLevel:t})}async appendModelChange(t,a){return this.appendTypedEntry({type:"model_change",id:await this.storage.createEntryId(),parentId:await this.storage.getLeafId(),timestamp:new Date().toISOString(),provider:t,modelId:a})}async appendActiveToolsChange(t){return this.appendTypedEntry({type:"active_tools_change",id:await this.storage.createEntryId(),parentId:await this.storage.getLeafId(),timestamp:new Date().toISOString(),activeToolNames:[...t]})}async appendCompaction(t,a,o,s,r){return this.appendTypedEntry({type:"compaction",id:await this.storage.createEntryId(),parentId:await this.storage.getLeafId(),timestamp:new Date().toISOString(),summary:t,firstKeptEntryId:a,tokensBefore:o,details:s,fromHook:r})}async appendCustomEntry(t,a){return this.appendTypedEntry({type:"custom",id:await this.storage.createEntryId(),parentId:await this.storage.getLeafId(),timestamp:new Date().toISOString(),customType:t,data:a})}async appendCustomMessageEntry(t,a,o,s){return this.appendTypedEntry({type:"custom_message",id:await this.storage.createEntryId(),parentId:await this.storage.getLeafId(),timestamp:new Date().toISOString(),customType:t,content:a,display:o,details:s})}async appendLabel(t,a){if(!await this.storage.getEntry(t))throw new c("not_found",`Entry ${t} not found`);return this.appendTypedEntry({type:"label",id:await this.storage.createEntryId(),parentId:await this.storage.getLeafId(),timestamp:new Date().toISOString(),targetId:t,label:a})}async appendSessionName(t){return this.appendTypedEntry({type:"session_info",id:await this.storage.createEntryId(),parentId:await this.storage.getLeafId(),timestamp:new Date().toISOString(),name:t.trim()})}async moveTo(t,a){if(t!==null&&!await this.storage.getEntry(t))throw new c("not_found",`Entry ${t} not found`);if(await this.storage.setLeafId(t),!!a)return this.appendTypedEntry({type:"branch_summary",id:await this.storage.createEntryId(),parentId:t,timestamp:new Date().toISOString(),fromId:t??"root",summary:a.summary,details:a.details,fromHook:a.fromHook})}}export{S as Session,u as buildSessionContext};
@@ -0,0 +1 @@
1
+ export declare function uuidv7(): string;
@@ -0,0 +1 @@
1
+ var x=Object.defineProperty;var i=(n,f)=>x(n,"name",{value:f,configurable:!0});let o=-1/0,e=0;function r(n){const f=globalThis.crypto;if(f?.getRandomValues){f.getRandomValues(n);return}for(let t=0;t<n.length;t++)n[t]=Math.floor(Math.random()*256)}i(r,"fillRandomBytes");function s(){const n=new Uint8Array(16);r(n);const f=Date.now();f>o?(e=n[6]*16777216+n[7]*65536+n[8]*256+n[9],o=f):(e=e+1>>>0,e===0&&o++);const t=new Uint8Array(16);return t[0]=o/1099511627776&255,t[1]=o/4294967296&255,t[2]=o/16777216&255,t[3]=o/65536&255,t[4]=o/256&255,t[5]=o&255,t[6]=112|e>>>28&15,t[7]=e>>>20&255,t[8]=128|e>>>14&63,t[9]=e>>>6&255,t[10]=(e&63)<<2|n[10]&3,t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],a(t)}i(s,"uuidv7");function a(n){const f=Array.from(n,t=>t.toString(16).padStart(2,"0"));return`${f.slice(0,4).join("")}-${f.slice(4,6).join("")}-${f.slice(6,8).join("")}-${f.slice(8,10).join("")}-${f.slice(10,16).join("")}`}i(a,"formatUuid");export{s as uuidv7};
@@ -0,0 +1,43 @@
1
+ import { type ExecutionEnv, type Skill } from "./types.ts";
2
+ export type SkillDiagnosticCode = "file_info_failed" | "list_failed" | "read_failed" | "parse_failed" | "invalid_metadata";
3
+ /** Warning produced while loading skills. */
4
+ export interface SkillDiagnostic {
5
+ /** Diagnostic severity. Currently only warnings are emitted. */
6
+ type: "warning";
7
+ /** Stable diagnostic code. */
8
+ code: SkillDiagnosticCode;
9
+ /** Human-readable diagnostic message. */
10
+ message: string;
11
+ /** Path associated with the diagnostic. */
12
+ path: string;
13
+ }
14
+ /** Format a skill invocation prompt, optionally appending additional user instructions. */
15
+ export declare function formatSkillInvocation(skill: Skill, additionalInstructions?: string): string;
16
+ /**
17
+ * Load skills from one or more directories.
18
+ *
19
+ * Traverses directories recursively, loads `SKILL.md` files, loads direct root `.md` files as skills, honors ignore files,
20
+ * and returns diagnostics for invalid skill files. Missing input directories are skipped.
21
+ */
22
+ export declare function loadSkills(env: ExecutionEnv, dirs: string | string[]): Promise<{
23
+ skills: Skill[];
24
+ diagnostics: SkillDiagnostic[];
25
+ }>;
26
+ /**
27
+ * Load skills from source-tagged directories.
28
+ *
29
+ * Source values are preserved exactly and attached to every loaded skill and diagnostic. The agent package does not
30
+ * interpret source values; applications define their own provenance shape.
31
+ */
32
+ export declare function loadSourcedSkills<TSource, TSkill extends Skill = Skill>(env: ExecutionEnv, inputs: Array<{
33
+ path: string;
34
+ source: TSource;
35
+ }>, mapSkill?: (skill: Skill, source: TSource) => TSkill): Promise<{
36
+ skills: Array<{
37
+ skill: TSkill;
38
+ source: TSource;
39
+ }>;
40
+ diagnostics: Array<SkillDiagnostic & {
41
+ source: TSource;
42
+ }>;
43
+ }>;
@@ -0,0 +1,10 @@
1
+ var P=Object.defineProperty;var l=(t,e)=>P(t,"name",{value:e,configurable:!0});import W from"ignore";import{parse as N}from"yaml";import{toError as S}from"./types.js";const $=64,I=1024,b=[".gitignore",".ignore",".fdignore"];function K(t,e){const n=`<skill name="${t.name}" location="${t.filePath}">
2
+ References are relative to ${E(t.filePath)}.
3
+
4
+ ${t.content}
5
+ </skill>`;return e?`${n}
6
+
7
+ ${e}`:n}l(K,"formatSkillInvocation");async function R(t,e){const n=[],r=[];for(const s of Array.isArray(e)?e:[e]){const o=await t.fileInfo(s);if(!o.ok){o.error.code!=="not_found"&&r.push({type:"warning",code:"file_info_failed",message:o.error.message,path:s});continue}const i=o.value;if(await k(t,i,r)!=="directory")continue;const a=await v(t,i.path,!0,W(),i.path);n.push(...a.skills),r.push(...a.diagnostics)}return{skills:n,diagnostics:r}}l(R,"loadSkills");async function M(t,e,n){const r=[],s=[];for(const o of e){const i=await R(t,o.path);for(const a of i.skills)r.push({skill:n?n(a,o.source):a,source:o.source});for(const a of i.diagnostics)s.push({...a,source:o.source})}return{skills:r,diagnostics:s}}l(M,"loadSourcedSkills");async function v(t,e,n,r,s){const o=[],i=[],a=await t.fileInfo(e);if(!a.ok)return a.error.code!=="not_found"&&i.push({type:"warning",code:"file_info_failed",message:a.error.message,path:e}),{skills:o,diagnostics:i};const d=a.value;if(await k(t,d,i)!=="directory")return{skills:o,diagnostics:i};await z(t,r,e,s,i);const f=await t.listDir(e);if(!f.ok)return i.push({type:"warning",code:"list_failed",message:f.error.message,path:e}),{skills:o,diagnostics:i};const p=f.value;for(const u of p){if(u.name!=="SKILL.md")continue;const c=u.path;if(await k(t,u,i)!=="file")continue;const g=w(s,c);if(r.ignores(g))continue;const m=await x(t,c);return m.skill&&o.push(m.skill),i.push(...m.diagnostics),{skills:o,diagnostics:i}}for(const u of p.sort((c,h)=>c.name.localeCompare(h.name))){if(u.name.startsWith(".")||u.name==="node_modules")continue;const c=u.path,h=await k(t,u,i);if(!h)continue;const g=w(s,c),m=h==="directory"?`${g}/`:g;if(r.ignores(m))continue;if(h==="directory"){const _=await v(t,c,!1,r,s);o.push(..._.skills),i.push(..._.diagnostics);continue}if(h!=="file"||!n||!u.name.endsWith(".md"))continue;const y=await x(t,c);y.skill&&o.push(y.skill),i.push(...y.diagnostics)}return{skills:o,diagnostics:i}}l(v,"loadSkillsFromDirInternal");async function z(t,e,n,r,s){const o=w(r,n),i=o?`${o}/`:"";for(const a of b){const d=T(n,a),f=await t.fileInfo(d);if(!f.ok){f.error.code!=="not_found"&&s.push({type:"warning",code:"file_info_failed",message:f.error.message,path:d});continue}if(f.value.kind!=="file")continue;const p=await t.readTextFile(d);if(!p.ok){s.push({type:"warning",code:"read_failed",message:p.error.message,path:d});continue}const u=p.value.split(/\r?\n/).map(c=>F(c,i)).filter(c=>!!c);u.length>0&&e.add(u)}}l(z,"addIgnoreRules");function F(t,e){const n=t.trim();if(!n||n.startsWith("#")&&!n.startsWith("\\#"))return null;let r=t,s=!1;r.startsWith("!")?(s=!0,r=r.slice(1)):r.startsWith("\\!")&&(r=r.slice(1)),r.startsWith("/")&&(r=r.slice(1));const o=e?`${e}${r}`:r;return s?`!${o}`:o}l(F,"prefixIgnorePattern");async function x(t,e){const n=[],r=await t.readTextFile(e);if(!r.ok)return n.push({type:"warning",code:"read_failed",message:r.error.message,path:e}),{skill:null,diagnostics:n};const s=O(r.value);if(!s.ok)return n.push({type:"warning",code:"parse_failed",message:s.error.message,path:e}),{skill:null,diagnostics:n};const{frontmatter:o,body:i}=s.value,a=E(e),d=C(a),f=typeof o.description=="string"?o.description:void 0;for(const c of L(f))n.push({type:"warning",code:"invalid_metadata",message:c,path:e});const u=(typeof o.name=="string"?o.name:void 0)||d;for(const c of A(u,d))n.push({type:"warning",code:"invalid_metadata",message:c,path:e});return!f||f.trim()===""?{skill:null,diagnostics:n}:{skill:{name:u,description:f,content:i,filePath:e,disableModelInvocation:o["disable-model-invocation"]===!0},diagnostics:n}}l(x,"loadSkillFromFile");function A(t,e){const n=[];return t!==e&&n.push(`name "${t}" does not match parent directory "${e}"`),t.length>$&&n.push(`name exceeds ${$} characters (${t.length})`),/^[a-z0-9-]+$/.test(t)||n.push("name contains invalid characters (must be lowercase a-z, 0-9, hyphens only)"),(t.startsWith("-")||t.endsWith("-"))&&n.push("name must not start or end with a hyphen"),t.includes("--")&&n.push("name must not contain consecutive hyphens"),n}l(A,"validateName");function L(t){const e=[];return!t||t.trim()===""?e.push("description is required"):t.length>I&&e.push(`description exceeds ${I} characters (${t.length})`),e}l(L,"validateDescription");function O(t){try{const e=t.replace(/\r\n/g,`
8
+ `).replace(/\r/g,`
9
+ `);if(!e.startsWith("---"))return{ok:!0,value:{frontmatter:{},body:e}};const n=e.indexOf(`
10
+ ---`,3);if(n===-1)return{ok:!0,value:{frontmatter:{},body:e}};const r=e.slice(4,n),s=e.slice(n+4).trim();return{ok:!0,value:{frontmatter:N(r)??{},body:s}}}catch(e){return{ok:!1,error:S(e)}}}l(O,"parseFrontmatter");async function k(t,e,n){if(e.kind==="file"||e.kind==="directory")return e.kind;const r=await t.canonicalPath(e.path);if(!r.ok){r.error.code!=="not_found"&&n.push({type:"warning",code:"file_info_failed",message:r.error.message,path:e.path});return}const s=await t.fileInfo(r.value);if(!s.ok){s.error.code!=="not_found"&&n.push({type:"warning",code:"file_info_failed",message:s.error.message,path:e.path});return}return s.value.kind==="file"||s.value.kind==="directory"?s.value.kind:void 0}l(k,"resolveKind");function T(t,e){return`${t.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}l(T,"joinEnvPath");function E(t){const e=t.replace(/\/+$/,""),n=e.lastIndexOf("/");return n<=0?"/":e.slice(0,n)}l(E,"dirnameEnvPath");function C(t){const e=t.replace(/\/+$/,""),n=e.lastIndexOf("/");return n===-1?e:e.slice(n+1)}l(C,"basenameEnvPath");function w(t,e){const n=t.replace(/\/+$/,""),r=e.replace(/\/+$/,"");return r===n?"":r.startsWith(`${n}/`)?r.slice(n.length+1):r.replace(/^\/+/,"")}l(w,"relativeEnvPath");export{K as formatSkillInvocation,R as loadSkills,M as loadSourcedSkills};
@@ -0,0 +1,2 @@
1
+ import type { Skill } from "./types.ts";
2
+ export declare function formatSkillsForSystemPrompt(skills: Skill[]): string;
@@ -0,0 +1,2 @@
1
+ var o=Object.defineProperty;var t=(l,s)=>o(l,"name",{value:s,configurable:!0});function r(l){const s=l.filter(i=>!i.disableModelInvocation);if(s.length===0)return"";const e=["The following skills provide specialized instructions for specific tasks.","Read the full skill file when the task matches its description.","When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.","","<available_skills>"];for(const i of s)e.push(" <skill>"),e.push(` <name>${a(i.name)}</name>`),e.push(` <description>${a(i.description)}</description>`),e.push(` <location>${a(i.filePath)}</location>`),e.push(" </skill>");return e.push("</available_skills>"),e.join(`
2
+ `)}t(r,"formatSkillsForSystemPrompt");function a(l){return l.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}t(a,"escapeXml");export{r as formatSkillsForSystemPrompt};