ai-projects 1.5.0 → 1.6.0

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/README.md CHANGED
@@ -1,25 +1,153 @@
1
- # AIP - AI Project Management CLI
1
+ # AIP - AI Project Management CLI 🤖
2
2
 
3
- Command-line tool for managing AI agent projects, tasks, and agents.
3
+ **Built for AI agents. Polished by AI agents.**
4
4
 
5
- ## Installation
5
+ A command-line tool for managing AI agent projects, tasks, and agents with structured workflows, activity logging, and automation hooks.
6
6
 
7
+ ## 📚 Help System
8
+
9
+ AIP has a comprehensive built-in help system for every level:
10
+
11
+ ```bash
12
+ # 🚀 New here? Start with the quick guide
13
+ aip help quickstart
14
+
15
+ # 📋 Browse all commands by noun
16
+ aip help usage
17
+
18
+ # 🎯 Need commands for a specific noun?
19
+ aip help usage task # All task commands
20
+ aip help usage project # All project commands
21
+ aip help usage log # All logging commands
22
+
23
+ # 📖 Complete API reference (comprehensive!)
24
+ aip help api
25
+
26
+ # 🛠️ Project management skill documentation
27
+ aip help skill
28
+
29
+ # 🔗 Hook system documentation
30
+ aip help hooks
31
+ ```
32
+
33
+ ## ✨ Features
34
+
35
+ - **Structured Projects**: YAML frontmatter + markdown body
36
+ - **Activity Logging**: TSV-based status tracking (date, time, type, action, text)
37
+ - **Automation Hooks**: Pre/post hooks for create, start, update, complete
38
+ - **Multi-line Support**: Heredoc syntax for complex content
39
+ - **Agent-Ready**: Designed for autonomous AI workflows
40
+
41
+ ## 🚀 Quick Start
42
+
43
+ ```bash
44
+ # Create a project with multi-line body
45
+ aip project create "my-project" --description "..." --body "$(cat <<'EOF'
46
+ # Goals
47
+ - Build something amazing
48
+ - Solve real problems
49
+
50
+ ## Success Criteria
51
+ - Tests passing
52
+ - Documentation complete
53
+ EOF
54
+ )"
55
+
56
+ # Create a task in the project
57
+ aip task create my-project "first-task" --description "Get started"
58
+
59
+ # Navigate and work
60
+ cd $(aip task path first-task)
61
+
62
+ # Log your progress
63
+ aip log append "API integration complete"
64
+
65
+ # View activity history
66
+ aip log read
67
+ ```
68
+
69
+ ## 📁 Project Structure
70
+
71
+ ```
72
+ $AIP_HOME/projects/{project}/
73
+ ├── main.md # Goals + body (YAML frontmatter + markdown)
74
+ ├── log.tsv # Activity log (tab-separated: date, time, type, slug, action, text)
75
+ ├── hooks/ # Automation: pre|post-{create,start,update,complete}
76
+ ├── outputs/ # Deliverables go here
77
+ ├── inputs/ # External data (API responses, downloads)
78
+ ├── scripts/ # Automation scripts
79
+ └── tasks/{task}/
80
+ ├── main.md # Task definition + body
81
+ ├── log.tsv # Task activity log
82
+ └── ... # Same substructure
83
+ ```
84
+
85
+ ## 🔧 Key Commands
86
+
87
+ ### Projects
88
+ ```bash
89
+ aip project create "name" --description "..." --body "..."
90
+ aip project update --status done --body "$(cat final-report.md)"
91
+ aip project list
92
+ aip project path my-project # Get absolute path
93
+ ```
94
+
95
+ ### Tasks
96
+ ```bash
97
+ aip task create my-project "task-name" --description "..."
98
+ aip task update --status in-progress
99
+ aip task list
100
+ aip task path task-name # Get absolute path
101
+ ```
102
+
103
+ ### Logging
104
+ ```bash
105
+ aip log append "Completed the implementation"
106
+ aip log append --task my-task "Fixed the bug"
107
+ aip log read # View status history
108
+ ```
109
+
110
+ ### Utilities
7
111
  ```bash
8
- npm install -g ai-projects
112
+ aip task ingest # Output full context for AI agents
113
+ aip task start # Mark as in-progress
114
+ aip help quickstart # Get started guide
9
115
  ```
10
116
 
11
- The `aip` command is provided by the package `bin` field.
117
+ ## 🤖 For AI Agents
12
118
 
13
- ## Usage
119
+ If you're an AI agent working with AIP:
120
+
121
+ 1. **Read** `$AIP_HOME/AGENTS.md` first
122
+ 2. **Review** `main.md` for goals and context
123
+ 3. **Check** `log.tsv` for activity history
124
+ 4. **Work** and save outputs to `outputs/`
125
+ 5. **Log** progress: `aip log append "message"`
126
+ 6. **Complete**: Set status=done, summarize in project status
127
+
128
+ ## 💡 Pro Tips
14
129
 
15
130
  ```bash
16
- aip <noun> <verb> [options]
131
+ # Chain commands
132
+ cd $(aip task path my-task) && aip task start
133
+
134
+ # Use heredocs for complex body content
135
+ aip project update --body "$(cat <<'EOF'
136
+ # Updated Goals
137
+ ...
138
+ EOF
139
+ )"
140
+
141
+ # Quick status check
142
+ aip log read | tail -5
17
143
  ```
18
144
 
19
- ## For Agents
145
+ ## 🛠️ Development
146
+
147
+ This tool is **meant for AI agents** and will be **automatically polished by AI agents** based on their usage.
20
148
 
21
- Read `$AIP_HOME/AGENTS.md` first.
149
+ **Suggestions and PRs welcome!** 🎉
22
150
 
23
- ## License
151
+ ## 📄 License
24
152
 
25
153
  MIT
package/dist/index.d.ts CHANGED
@@ -155,14 +155,17 @@ declare const commands: {
155
155
  description: zod.ZodString;
156
156
  status: zod.ZodDefault<zod.ZodString>;
157
157
  assignee: zod.ZodOptional<zod.ZodString>;
158
+ body: zod.ZodOptional<zod.ZodString>;
158
159
  }, "strip", zod.ZodTypeAny, {
159
160
  status: string;
160
161
  description: string;
161
162
  assignee?: string | undefined;
163
+ body?: string | undefined;
162
164
  }, {
163
165
  description: string;
164
166
  status?: string | undefined;
165
167
  assignee?: string | undefined;
168
+ body?: string | undefined;
166
169
  }>, zod.ZodObject<{
167
170
  name: zod.ZodString;
168
171
  }, "strip", zod.ZodTypeAny, {
@@ -198,16 +201,19 @@ declare const commands: {
198
201
  description: zod.ZodOptional<zod.ZodString>;
199
202
  status: zod.ZodOptional<zod.ZodString>;
200
203
  assignee: zod.ZodOptional<zod.ZodString>;
204
+ body: zod.ZodOptional<zod.ZodString>;
201
205
  }, "strip", zod.ZodTypeAny, {
202
206
  status?: string | undefined;
203
207
  description?: string | undefined;
204
208
  name?: string | undefined;
205
209
  assignee?: string | undefined;
210
+ body?: string | undefined;
206
211
  }, {
207
212
  status?: string | undefined;
208
213
  description?: string | undefined;
209
214
  name?: string | undefined;
210
215
  assignee?: string | undefined;
216
+ body?: string | undefined;
211
217
  }>, zod.ZodObject<{
212
218
  project: zod.ZodOptional<zod.ZodString>;
213
219
  }, "strip", zod.ZodTypeAny, {
@@ -230,14 +236,17 @@ declare const commands: {
230
236
  description: zod.ZodOptional<zod.ZodString>;
231
237
  assignee: zod.ZodOptional<zod.ZodString>;
232
238
  status: zod.ZodDefault<zod.ZodString>;
239
+ body: zod.ZodOptional<zod.ZodString>;
233
240
  }, "strip", zod.ZodTypeAny, {
234
241
  status: string;
235
242
  description?: string | undefined;
236
243
  assignee?: string | undefined;
244
+ body?: string | undefined;
237
245
  }, {
238
246
  status?: string | undefined;
239
247
  description?: string | undefined;
240
248
  assignee?: string | undefined;
249
+ body?: string | undefined;
241
250
  }>, zod.ZodObject<{
242
251
  project: zod.ZodString;
243
252
  name: zod.ZodString;
@@ -324,18 +333,21 @@ declare const commands: {
324
333
  status: zod.ZodOptional<zod.ZodString>;
325
334
  assignee: zod.ZodOptional<zod.ZodString>;
326
335
  project: zod.ZodOptional<zod.ZodString>;
336
+ body: zod.ZodOptional<zod.ZodString>;
327
337
  }, "strip", zod.ZodTypeAny, {
328
338
  project?: string | undefined;
329
339
  status?: string | undefined;
330
340
  description?: string | undefined;
331
341
  name?: string | undefined;
332
342
  assignee?: string | undefined;
343
+ body?: string | undefined;
333
344
  }, {
334
345
  project?: string | undefined;
335
346
  status?: string | undefined;
336
347
  description?: string | undefined;
337
348
  name?: string | undefined;
338
349
  assignee?: string | undefined;
350
+ body?: string | undefined;
339
351
  }>, zod.ZodObject<{
340
352
  task: zod.ZodOptional<zod.ZodString>;
341
353
  }, "strip", zod.ZodTypeAny, {
package/dist/index.js CHANGED
@@ -1,26 +1,26 @@
1
1
  #!/usr/bin/env node
2
- import {z as z$1}from'zod';import {parser}from'zod-opts';import Je from'dotenv';import Be from'fs';import F from'path';import {fileURLToPath}from'url';import {spawn,exec}from'child_process';import K from'fs/promises';import y from'lodash';import W from'moment';import {inspect}from'util';import Pt from'yaml';var He=Object.defineProperty;var f=(t,e)=>()=>(t&&(e=t(t=0)),e);var Ke=(t,e)=>{for(var o in e)He(t,o,{get:e[o],enumerable:true});};var b,B=f(()=>{b={name:"ai-projects",version:"1.5.0",type:"module",description:"Useful CLI for AI agents to create and manage projects, tasks, skills and agents",main:"dist/index.js",types:"dist/index.d.ts",bin:{aip:"dist/index.js"},files:["dist/**/*","README.md","LICENSE"],scripts:{build:"npm run build:map && npm run build:code","build:map":"tsx bin/map-commands.ts","build:code":"tsup --no-dts","build:all":"npm run build:map && tsup","build:check":"tsc --noEmit","build:watch":"npm run build:code -- --watch","build:clean":"rimraf dist/*","build:incr":"tsup --no-dts",start:"dist/index.js",dev:'npm run build:watch -- --onSuccess "dist/index.js"',cli:"npm run build && npm start --",ts:"tsx",vitest:"VITE_CJS_IGNORE_WARNING=true vitest",test:"npm run test:types && npm run test:unit","test:unit":"npm run vitest -- run","test:types:test":"tsc -p tsconfig.test.json --incremental --tsBuildInfoFile dist/test.tsbuildinfo","test:types:bin":"tsc -p bin/tsconfig.json --incremental --tsBuildInfoFile dist/bin.tsbuildinfo","test:types":"npm run test:types:test && npm run test:types:bin","test:full":"npm run lint:full && npm run test",eslint:"eslint --cache",lint:"npm run eslint -- '{src,bin}/**/*.ts'","lint:fix":"npm run lint -- --fix","lint:full":"npm run build:incr && npm run test:types:bin && npm run lint:fix","lint:full:silent":"npm run -s lint:full && echo LINT OK",map:"npm run build:map",link:"npm link",unlink:"npm unlink",prepare:'[ "$CI" != "true" ] && [ -d node_modules/husky ] && husky || true',prepack:"npm run test:full && npm run build:all","publish:dry":"npm pack --dry-run","version:patch":"npm version patch","version:minor":"npm version minor","version:major":"npm version major","agent:stop":"npm run -s lint:full:silent"},keywords:["ai","aip","project","task","kanban","cli","agent","automation"],author:"Ariel Flesler <aflesler@gmail.com>",license:"MIT",repository:{type:"git",url:"git+https://github.com/flesler/ai-projects.git"},homepage:"https://github.com/flesler/ai-projects#readme",bugs:{url:"https://github.com/flesler/ai-projects/issues"},engines:{node:">=20.0.0"},dependencies:{dotenv:"^17.3.1",lodash:"^4.17.21",moment:"^2.30.1",tslib:"^2.8.1",yaml:"^2.8.0",zod:"^3.25.76","zod-opts":"^1.0.0"},devDependencies:{"@eslint/js":"^10.0.1","@stylistic/eslint-plugin":"^5.7.0","@types/dotenv":"^8.2.3","@types/eslint":"^9.6.1","@types/lodash":"^4.17.23","@types/moment":"^2.13.0","@types/node":"^25.0.9","@types/source-map-support":"^0.5.10","@typescript-eslint/eslint-plugin":"^8.53.0","@typescript-eslint/parser":"^8.53.0",eslint:"^10.0.3","eslint-plugin-import-x":"^4.16.2","eslint-plugin-unused-imports":"^4.4.1","fast-glob":"^3.3.3",husky:"^9.1.7",rimraf:"^6.0.1","source-map-support":"^0.5.21",tsup:"^8.5.1",tsx:"^4.20.3","types-package-json":"^2.0.39",typescript:"^5.8.3",vitest:"^4.0.17"}};});function p(t){let{description:e,options:o=z$1.object({}),args:r,handler:s}=t,i=o.shape,a={};for(let[m,d]of Object.entries(i))a[m]={type:d};let l=parser().options(a);if(r){let m=r.shape,d=Object.entries(m).map(([k,P])=>({name:k,type:P}));d.length>0&&(l=l.args(d));}return e&&(l=l.description(e)),{description:e,options:o,args:r,parser:l,handler:s,cli:m=>s(l.parse(m))}}var g=f(()=>{});var c,$=f(()=>{c={dirs:{PROJECTS:"projects",SKILLS:"skills",AGENTS:"agents",TASKS:"tasks",INPUTS:"inputs",OUTPUTS:"outputs",HOOKS:"hooks",SCRIPTS:"scripts"},files:{MAIN:"main.md",STATUS:"status.tsv",LOG:"audit.log",SKILL:"SKILL.md"},hookTypes:["pre-create","post-create","pre-complete","post-complete","pre-start","post-start","pre-update","post-update"],languages:["ts","js","sh","py"],targets:["project","task"]};});var Ve,bt,N,Ze,E,H=f(()=>{$();Ve=()=>{let t=fileURLToPath(import.meta.url),e=F.dirname(t),o=10;for(let r=0;r<o;r++)try{if(Be.existsSync(F.join(e,"package.json")))return e;let s=F.dirname(e);if(s===e)break;e=s;}catch{break}return process.cwd()},bt=Ve(),N=process.env.AIP_HOME;N||(Je.config({path:F.join(bt,".env"),quiet:true}),N=process.env.AIP_HOME);if(!N){N=process.cwd();let t=N.split(F.sep);for(let e of [c.dirs.PROJECTS,c.dirs.SKILLS,c.dirs.AGENTS]){let o=t.indexOf(e);if(o!==-1){N=t.slice(0,o).join(F.sep);break}}}Ze={ROOT:bt,AIP_HOME:N},E=Ze;});var h,n,T=f(()=>{H();h={REPO:fileURLToPath(import.meta.url.replace(/\/(dist|src)\/.*/,"/")),join:(...t)=>F.join(...t),onRepo:(...t)=>h.join(h.REPO,...t),joinHome:(...t)=>h.join(E.AIP_HOME,...t),async ensureDir(t){await K.mkdir(t,{recursive:true});},async write(t,e){await h.ensureDir(F.dirname(t)),await K.writeFile(t,e,"utf8");},async append(t,e){await h.ensureDir(F.dirname(t)),await K.appendFile(t,e,"utf8");},async read(t){return K.readFile(t,"utf8")},async readRepo(...t){return h.read(h.onRepo(...t))},async readMany(...t){return (await Promise.all(t.map(async o=>{if(await h.fileExists(o)){let r=await h.read(o);return `# ${o}
2
+ import {z as z$1}from'zod';import {parser}from'zod-opts';import Ve from'dotenv';import We from'fs';import G from'path';import {fileURLToPath}from'url';import {spawn,exec}from'child_process';import z from'fs/promises';import w from'lodash';import Z from'moment';import {inspect}from'util';import vt from'yaml';var Ge=Object.defineProperty;var g=(t,e)=>()=>(t&&(e=t(t=0)),e);var Me=(t,e)=>{for(var o in e)Ge(t,o,{get:e[o],enumerable:true});};var S,W=g(()=>{S={name:"ai-projects",version:"1.6.0",type:"module",description:"Useful CLI for AI agents to create and manage projects, tasks, skills and agents",main:"dist/index.js",types:"dist/index.d.ts",bin:{aip:"dist/index.js"},files:["dist/**/*","README.md","LICENSE"],scripts:{build:"npm run build:map && npm run build:code","build:map":"tsx bin/map-commands.ts","build:code":"tsup --no-dts","build:all":"npm run build:map && tsup","build:check":"tsc --noEmit","build:watch":"npm run build:code -- --watch","build:clean":"rimraf dist/*","build:incr":"tsup --no-dts",start:"dist/index.js",dev:'npm run build:watch -- --onSuccess "dist/index.js"',cli:"npm run build && npm start --",ts:"tsx",vitest:"VITE_CJS_IGNORE_WARNING=true vitest",test:"npm run test:types && npm run test:unit","test:unit":"npm run vitest -- run","test:types:test":"tsc -p tsconfig.test.json --incremental --tsBuildInfoFile dist/test.tsbuildinfo","test:types:bin":"tsc -p bin/tsconfig.json --incremental --tsBuildInfoFile dist/bin.tsbuildinfo","test:types":"npm run test:types:test && npm run test:types:bin","test:full":"npm run lint:full && npm run test",eslint:"eslint --cache",lint:"npm run eslint -- '{src,bin}/**/*.ts'","lint:fix":"npm run lint -- --fix","lint:full":"npm run build:incr && npm run test:types:bin && npm run lint:fix","lint:full:silent":"npm run -s lint:full && echo LINT OK",map:"npm run build:map",link:"npm link",unlink:"npm unlink",prepare:'[ "$CI" != "true" ] && [ -d node_modules/husky ] && husky || true',prepack:"npm run test:full && npm run build:all","publish:dry":"npm pack --dry-run","version:patch":"npm version patch","version:minor":"npm version minor","version:major":"npm version major","agent:stop":"npm run -s lint:full:silent"},keywords:["ai","aip","project","task","kanban","cli","agent","automation"],author:"Ariel Flesler <aflesler@gmail.com>",license:"MIT",repository:{type:"git",url:"git+https://github.com/flesler/ai-projects.git"},homepage:"https://github.com/flesler/ai-projects#readme",bugs:{url:"https://github.com/flesler/ai-projects/issues"},engines:{node:">=20.0.0"},dependencies:{dotenv:"^17.3.1",lodash:"^4.17.21",moment:"^2.30.1",tslib:"^2.8.1",yaml:"^2.8.0",zod:"^3.25.76","zod-opts":"^1.0.0"},devDependencies:{"@eslint/js":"^10.0.1","@stylistic/eslint-plugin":"^5.7.0","@types/dotenv":"^8.2.3","@types/eslint":"^9.6.1","@types/lodash":"^4.17.23","@types/moment":"^2.13.0","@types/node":"^25.0.9","@types/source-map-support":"^0.5.10","@typescript-eslint/eslint-plugin":"^8.53.0","@typescript-eslint/parser":"^8.53.0",eslint:"^10.0.3","eslint-plugin-import-x":"^4.16.2","eslint-plugin-unused-imports":"^4.4.1","fast-glob":"^3.3.3",husky:"^9.1.7",rimraf:"^6.0.1","source-map-support":"^0.5.21",tsup:"^8.5.1",tsx:"^4.20.3","types-package-json":"^2.0.39",typescript:"^5.8.3",vitest:"^4.0.17"}};});function p(t){let{description:e,options:o=z$1.object({}),args:r,handler:n}=t,i=o.shape,a={};for(let[m,d]of Object.entries(i))a[m]={type:d};let l=parser().options(a);if(r){let m=r.shape,d=Object.entries(m).map(([f,b])=>({name:f,type:b}));d.length>0&&(l=l.args(d));}return e&&(l=l.description(e)),{description:e,options:o,args:r,parser:l,handler:n,cli:m=>n(l.parse(m))}}var k=g(()=>{});var c,P=g(()=>{c={dirs:{PROJECTS:"projects",SKILLS:"skills",AGENTS:"agents",TASKS:"tasks",INPUTS:"inputs",OUTPUTS:"outputs",HOOKS:"hooks",SCRIPTS:"scripts"},files:{MAIN:"main.md",LOG:"log.tsv",SKILL:"SKILL.md"},hookTypes:["pre-create","post-create","pre-complete","post-complete","pre-start","post-start","pre-update","post-update"],languages:["ts","js","sh","py"],targets:["project","task"]};});var qe,$t,U,Ye,A,M=g(()=>{P();qe=()=>{let t=fileURLToPath(import.meta.url),e=G.dirname(t),o=10;for(let r=0;r<o;r++)try{if(We.existsSync(G.join(e,"package.json")))return e;let n=G.dirname(e);if(n===e)break;e=n;}catch{break}return process.cwd()},$t=qe(),U=process.env.AIP_HOME;U||(Ve.config({path:G.join($t,".env"),quiet:true}),U=process.env.AIP_HOME);if(!U){U=process.cwd();let t=U.split(G.sep);for(let e of [c.dirs.PROJECTS,c.dirs.SKILLS,c.dirs.AGENTS]){let o=t.indexOf(e);if(o!==-1){U=t.slice(0,o).join(G.sep);break}}}Ye={ROOT:$t,AIP_HOME:U},A=Ye;});var y,s,j=g(()=>{M();y={REPO:fileURLToPath(import.meta.url.replace(/\/(dist|src)\/.*/,"/")),join:(...t)=>G.join(...t),onRepo:(...t)=>y.join(y.REPO,...t),joinHome:(...t)=>y.join(A.AIP_HOME,...t),async ensureDir(t){await z.mkdir(t,{recursive:true});},async write(t,e){await y.ensureDir(G.dirname(t)),await z.writeFile(t,e,"utf8");},async append(t,e){await y.ensureDir(G.dirname(t)),await z.appendFile(t,e,"utf8");},async read(t){return z.readFile(t,"utf8")},async readRepo(...t){return y.read(y.onRepo(...t))},async readMany(...t){return (await Promise.all(t.map(async o=>{if(await y.fileExists(o)){let r=await y.read(o);return `# ${o}
3
3
 
4
- ${r}`}return ""}))).filter(Boolean)},async logFiles(...t){let e=await h.readMany(...t);console.log(e.join(`
4
+ ${r}`}return ""}))).filter(Boolean)},async logFiles(...t){let e=await y.readMany(...t);console.log(e.join(`
5
5
 
6
6
  ---
7
7
 
8
- `));},dumpCommandMapLines(t,e){let o=e?y.pick(t,e):t,r=[];for(let[s,i]of h.entriesOf(o))r.push(`${s} {${Object.keys(i).join("|")}}`);return r},async fileExists(t){try{return await K.access(t),!0}catch{return false}},async listDir(t){try{return await K.readdir(t)}catch{return []}},spawn:spawn,cd(t){process.chdir(t);},async exec(t,e){return new Promise(o=>{exec(t,{encoding:"utf8",...e},(r,s,i)=>{let a=r?.code;o({stdout:s??"",stderr:i??"",code:r?typeof a=="number"?a:1:0});});})},noop:()=>{},omitByDeep:(t,e)=>y.isArray(t)?t.map(o=>h.omitByDeep(o,e)):y.isPlainObject(t)?y.mapValues(y.omitBy(t,e),o=>h.omitByDeep(o,e)):t,omitNilsDeep:t=>h.omitByDeep(t,y.isNil),omitUndefinedsDeep:t=>h.omitByDeep(t,y.isUndefined),cloneDeep:t=>y.cloneDeep(t),int:t=>Number.parseInt(t,10),keysOf:t=>Object.keys(t),entriesOf:t=>Object.entries(t),isKeyOf:(t,e)=>!y.isNil(t)&&t in e,typeOf:t=>typeof t,never:{},undef:t=>t??void 0,toNull:t=>t??null,same:t=>t,notNil:t=>{if(y.isNil(t))throw new Error(`Received unexpected ${t} value`);return t},randomInt:(t,e)=>Math.floor(Math.random()*(e-t+1))+t,promise:()=>{let t,e=new Promise((o,r)=>{t={resolve:o,reject:r};});return y.extend(e,t)},isPromise:t=>y.isObject(t)&&"catch"in t,delay:t=>{let e=y.isObject(t)?h.toMS(t):t;return new Promise(o=>setTimeout(o,e))},promiseMap:(t,e)=>Promise.all(t.map(e)),promiseEach:(t,e)=>Promise.all(t.map(e)).then(()=>{}),memoize:t=>y.memoize(t,h.memoizeKey),toMS:t=>W.duration(t).asMilliseconds(),toSecs:t=>W.duration(t).asSeconds(),inspect:(t,e)=>inspect(t,{colors:false,showHidden:false,depth:null,compact:true,breakLength:1/0,...e}),stringify(t,e,o){let r=new WeakSet;return JSON.stringify(t,(s,i)=>{if(y.isObject(i)){if(r.has(i))return "[Circular]";r.add(i);}return y.isFunction(e)?e(s,i):i},o)},dump:t=>h.oneLine(h.stringify(t)),compactWhitespace:t=>t.replace(/\\n/g,`
8
+ `));},dumpCommandMapLines(t,e){let o=e?w.pick(t,e):t,r=[];for(let[n,i]of y.entriesOf(o))r.push(`${n} {${Object.keys(i).join("|")}}`);return r},async fileExists(t){try{return await z.access(t),!0}catch{return false}},async listDir(t){try{return await z.readdir(t)}catch{return []}},spawn:spawn,cd(t){process.chdir(t);},async exec(t,e){return new Promise(o=>{exec(t,{encoding:"utf8",...e},(r,n,i)=>{let a=r?.code;o({stdout:n??"",stderr:i??"",code:r?typeof a=="number"?a:1:0});});})},noop:()=>{},omitByDeep:(t,e)=>w.isArray(t)?t.map(o=>y.omitByDeep(o,e)):w.isPlainObject(t)?w.mapValues(w.omitBy(t,e),o=>y.omitByDeep(o,e)):t,omitNilsDeep:t=>y.omitByDeep(t,w.isNil),omitUndefinedsDeep:t=>y.omitByDeep(t,w.isUndefined),cloneDeep:t=>w.cloneDeep(t),int:t=>Number.parseInt(t,10),keysOf:t=>Object.keys(t),entriesOf:t=>Object.entries(t),isKeyOf:(t,e)=>!w.isNil(t)&&t in e,typeOf:t=>typeof t,never:{},undef:t=>t??void 0,toNull:t=>t??null,same:t=>t,notNil:t=>{if(w.isNil(t))throw new Error(`Received unexpected ${t} value`);return t},randomInt:(t,e)=>Math.floor(Math.random()*(e-t+1))+t,promise:()=>{let t,e=new Promise((o,r)=>{t={resolve:o,reject:r};});return w.extend(e,t)},isPromise:t=>w.isObject(t)&&"catch"in t,delay:t=>{let e=w.isObject(t)?y.toMS(t):t;return new Promise(o=>setTimeout(o,e))},promiseMap:(t,e)=>Promise.all(t.map(e)),promiseEach:(t,e)=>Promise.all(t.map(e)).then(()=>{}),memoize:t=>w.memoize(t,y.memoizeKey),toMS:t=>Z.duration(t).asMilliseconds(),toSecs:t=>Z.duration(t).asSeconds(),inspect:(t,e)=>inspect(t,{colors:false,showHidden:false,depth:null,compact:true,breakLength:1/0,...e}),stringify(t,e,o){let r=new WeakSet;return JSON.stringify(t,(n,i)=>{if(w.isObject(i)){if(r.has(i))return "[Circular]";r.add(i);}return w.isFunction(e)?e(n,i):i},o)},dump:t=>y.oneLine(y.stringify(t)),compactWhitespace:t=>t.replace(/\\n/g,`
9
9
  `).replace(/\r/g,"").replace(/[ \t]*\n[ \t]*/g,`
10
10
  `).replace(/\n{3,}/g,`
11
11
 
12
- `).replace(/ {2,}/g," ").trim(),oneLine:t=>t.replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/ +/g," ").trim(),fuzzySearch:(t,e)=>y.includes(y.toLower(t||""),y.toLower(e||"")),elapsed:(t,e=Date.now())=>W.duration(W(e).diff(t||0)),iso:t=>W.utc(t).toISOString(),isoDate:t=>h.iso(t).slice(0,10),memoizeKey:(...t)=>t.join(""),exit:(t=0)=>{process.exit(t);},set:(t,e,o)=>(t[e]=o,t),run:async t=>{try{await t(),process.exit(0);}catch(e){console.error(e),process.exit(1);}},isMain:()=>{let t=process.argv[1]||"";return t.includes("/index.")||t.endsWith("/bin/aip")},errorMessage:t=>t instanceof Error?t.message:String(t),slugify:t=>t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")},n=h;});var xt,V,ut,Z,$t=f(()=>{T();xt=t=>{let e=t.trim();if(!e.startsWith("---"))return null;let o=e.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);return o?{frontmatter:Pt.parse(o[1]),content:o[2].trim()}:null},V=async(t,e,o="")=>{let s=`---
13
- ${Pt.stringify(e).trim()}
12
+ `).replace(/ {2,}/g," ").trim(),oneLine:t=>t.replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/ +/g," ").trim(),fuzzySearch:(t,e)=>w.includes(w.toLower(t||""),w.toLower(e||"")),elapsed:(t,e=Date.now())=>Z.duration(Z(e).diff(t||0)),iso:t=>Z.utc(t).toISOString(),isoDate:t=>y.iso(t).slice(0,10),memoizeKey:(...t)=>t.join(""),exit:(t=0)=>{process.exit(t);},set:(t,e,o)=>(t[e]=o,t),run:async t=>{try{await t(),process.exit(0);}catch(e){console.error(e),process.exit(1);}},isMain:()=>{let t=process.argv[1]||"";return t.includes("/index.")||t.endsWith("/bin/aip")},errorMessage:t=>t instanceof Error?t.message:String(t),slugify:t=>t.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")},s=y;});var et,B,ft,q,Et=g(()=>{j();et=t=>{let e=t.trim();if(!e.startsWith("---"))return null;let o=e.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);return o?{frontmatter:vt.parse(o[1]),content:o[2].trim()}:null},B=async(t,e,o="")=>{let n=`---
13
+ ${vt.stringify(e).trim()}
14
14
  ---
15
15
 
16
- ${o}`.trim();await n.write(t,s+`
17
- `);},ut=async(t,e)=>{let o=await n.read(t),r=xt(o);if(!r)throw new Error(`No frontmatter found in ${t}`);let s={...r.frontmatter,...e};return await V(t,s,r.content),s},Z=async t=>{let e=await n.read(t),o=xt(e);if(!o)throw new Error(`No frontmatter found in ${t}`);return o.frontmatter};});var M,et,vt,Et,to,eo,u,x=f(()=>{$();H();$t();T();M=(a=>(a.BACKLOG="backlog",a.IN_PROGRESS="in-progress",a.ONGOING="ongoing",a.DONE="done",a.BLOCKED="blocked",a.TO_DO="to-do",a))(M||{}),et=Object.values(M),vt=["backlog","in-progress","ongoing"],Et=[c.dirs.HOOKS,c.dirs.INPUTS,c.dirs.OUTPUTS,c.dirs.SCRIPTS],to=[c.dirs.TASKS,...Et],eo={getProjectDir(t){return n.joinHome(c.dirs.PROJECTS,t)},getTaskDir(t,e){return n.join(this.getProjectDir(t),c.dirs.TASKS,e)},async findTask(t,e){if(e)return {project:e,task:t};let o=await this.listProjects(),r=[];if(await n.promiseEach(o,async s=>{(await this.listTasks(s)).includes(t)&&r.push(s);}),r.length===0)throw new Error(`Task '${t}' not found. Use --project to specify the project.`);if(r.length>1)throw new Error(`Task '${t}' found in multiple projects: ${r.join(", ")}. Use --project to specify which one.`);return {project:r[0],task:t}},getAgentDir(t){return n.join(E.AIP_HOME,c.dirs.AGENTS,t)},async listProjects(){let t=n.join(E.AIP_HOME,c.dirs.PROJECTS),e=await n.listDir(t);return (await n.promiseMap(e,async r=>{let s=this.getProjectDir(r);return await n.fileExists(s)&&r!==c.dirs.AGENTS?r:null})).filter(r=>r!==null).sort()},async listTasks(t){let e=n.join(this.getProjectDir(t),c.dirs.TASKS);return await n.fileExists(e)?await n.listDir(e):[]},async listAgents(){let t=n.join(E.AIP_HOME,c.dirs.AGENTS);return await n.fileExists(t)?await n.listDir(t):[]},async createProject(t,e){let o=this.getProjectDir(t);return await n.ensureDir(o),await Promise.all(to.map(r=>n.ensureDir(n.join(o,r)))),await V(n.join(o,c.files.MAIN),e),await n.write(n.join(o,c.files.STATUS),""),o},async createTask(t,e,o){let r=this.getTaskDir(t,e);return await n.ensureDir(r),await Promise.all(Et.map(s=>n.ensureDir(n.join(r,s)))),await V(n.join(r,c.files.MAIN),o),await n.write(n.join(r,c.files.STATUS),""),r},async createAgent(t,e){let o=this.getAgentDir(t);return await n.ensureDir(o),await V(n.join(o,c.files.MAIN),e),o},async getProject(t){let e=n.join(this.getProjectDir(t),c.files.MAIN);return await n.fileExists(e)?await Z(e):null},async getTask(t,e){let o=n.join(this.getTaskDir(t,e),c.files.MAIN);return await n.fileExists(o)?await Z(o):null},async getAgent(t){let e=n.join(this.getAgentDir(t),c.files.MAIN);return await n.fileExists(e)?await Z(e):null},async updateProject(t,e){let o=n.join(this.getProjectDir(t),c.files.MAIN);return await ut(o,e)},async updateTask(t,e,o){let r=n.join(this.getTaskDir(t,e),c.files.MAIN);if((await Z(r))?.status==="ongoing")throw new Error("Cannot update ongoing task. Should be done by user or update manually");return await ut(r,o)},async ingestTask(t,e){let o=this.getTaskDir(t,e),r=this.getProjectDir(t),s=[n.join(r,c.files.MAIN),n.join(o,c.files.MAIN),n.join(o,c.files.STATUS)];await n.logFiles(...s);},async ingestProject(t){let e=this.getProjectDir(t),o=await this.listTasks(t),r=[n.join(e,c.files.MAIN),n.join(e,c.files.STATUS),...o.map(s=>n.join(this.getTaskDir(t,s),c.files.MAIN))];await n.logFiles(...r);},async ingestFiles(t){await n.logFiles(...t);}},u=eo;});var At,Dt=f(()=>{g();T();x();At=p({options:z$1.object({description:z$1.string().describe("Agent description"),status:z$1.string().default("active").describe("Initial status")}),args:z$1.object({name:z$1.string().describe("Agent name")}),handler:async({name:t,description:e,status:o})=>{let r=n.slugify(t);await u.createAgent(r,{name:t,description:e,status:o,created:new Date().toISOString()}),console.log(`Agent created: ${r}`),console.log(` Path: ${u.getAgentDir(r)}`);}});});var Ot,Ct=f(()=>{g();Ot=p({options:z$1.object({}),handler:async()=>{let t=process.env.CURRENT_AGENT;t||(console.error("CURRENT_AGENT not set"),process.exit(1)),console.log(t);}});});var Rt,Nt=f(()=>{g();x();Rt=p({options:z$1.object({}),handler:async()=>{let t=await u.listAgents(),e=[];for(let o of t){let r=await u.getAgent(o);r&&e.push({slug:o,name:r.name||o,status:r.status,description:r.description});}if(e.length===0){console.log("No agents found");return}console.log("Agents:"),console.log("---");for(let o of e)console.log(`${o.slug.padEnd(20)} ${o.name?.padEnd(30)||""} ${o.status||""} ${o.description||""}`);}});});var It,Ut=f(()=>{$();g();H();T();It=p({description:"Output agent directory path (for cd)",options:z$1.object({}),args:z$1.object({name:z$1.string().describe("Agent name (directory name)")}),handler:async({name:t})=>{let e=n.join(E.AIP_HOME,c.dirs.AGENTS,t),o=n.join(e,c.files.MAIN);if(!await n.fileExists(o))throw new Error(`Agent not found: ${t}
18
- Expected at: ${o}`);console.log(e);}});});var _t,Lt=f(()=>{$();g();H();T();_t=p({description:"Start an agent: read SOUL.md and AGENTS.md content",options:z$1.object({}),args:z$1.object({name:z$1.string().describe("Agent name (directory name)")}),handler:async({name:t})=>{let e=n.join(E.AIP_HOME,c.dirs.AGENTS,t),o=n.join(e,c.files.MAIN),r=n.join(e,"SOUL.md");if(!await n.fileExists(o))throw new Error(`Agent not found: ${t}
19
- Expected at: ${o}`);let i=[r,o];await n.logFiles(...i);}});});var Ft,Ht,no,Kt,Mt=f(()=>{g();Ft=t=>{let e=t.shape,o=[];for(let[r,s]of Object.entries(e)){let i=s._def,a="unknown",l,m;i.typeName==="ZodString"?a="string":i.typeName==="ZodNumber"?a="number":i.typeName==="ZodBoolean"?a="boolean":i.typeName==="ZodEnum"?a=`enum: ${i.values.join(" | ")}`:i.typeName==="ZodOptional"?a=Ht(i.innerType):i.typeName==="ZodDefault"&&(a=Ht(i.innerType),m=i.defaultValue()),i.description&&(l=i.description);let d=i.typeName!=="ZodOptional"&&i.typeName!=="ZodDefault";o.push({name:r,type:a,required:d,description:l,defaultValue:m});}return o},Ht=t=>{let e=t._def;return e.typeName==="ZodString"?"string":e.typeName==="ZodNumber"?"number":e.typeName==="ZodBoolean"?"boolean":e.typeName==="ZodEnum"?`enum: ${e.values.join(" | ")}`:"unknown"},no=(t,e,o)=>{let r=Ft(o.options),s=o.args?Ft(o.args):[],i=o.description,a=`\`${t} ${e}\``;if(i&&(a+=`: ${i}`),a+=`
20
- `,r.length>0||s.length>0){let m=[];for(let d of s){let k=d.required?`<${d.name}>`:`[${d.name}]`,P=d.description||"";d.defaultValue!==void 0&&(P+=P?` (default: ${d.defaultValue})`:`(default: ${d.defaultValue})`),m.push(`\xB7 ${k}${P?": "+P:""}`);}for(let d of r){let k=d.description||"";d.defaultValue!==void 0&&(k+=k?` (default: ${d.defaultValue})`:`(default: ${d.defaultValue})`),m.push(`\xB7 --${d.name}${k?": "+k:""}`);}a+=m.join(`
16
+ ${o}`.trim();await s.write(t,n+`
17
+ `);},ft=async(t,e)=>{let o=await s.read(t),r=et(o);if(!r)throw new Error(`No frontmatter found in ${t}`);let n={...r.frontmatter,...e};return await B(t,n,r.content),n},q=async t=>{let e=await s.read(t),o=et(e);if(!o)throw new Error(`No frontmatter found in ${t}`);return o.frontmatter};});var J,ot,At,Ot,oo,ro,u,x=g(()=>{P();M();Et();j();J=(a=>(a.BACKLOG="backlog",a.IN_PROGRESS="in-progress",a.ONGOING="ongoing",a.DONE="done",a.BLOCKED="blocked",a.TO_DO="to-do",a))(J||{}),ot=Object.values(J),At=["backlog","in-progress","ongoing"],Ot=[c.dirs.HOOKS,c.dirs.INPUTS,c.dirs.OUTPUTS,c.dirs.SCRIPTS],oo=[c.dirs.TASKS,...Ot],ro={getProjectDir(t){return s.joinHome(c.dirs.PROJECTS,t)},getTaskDir(t,e){return s.join(this.getProjectDir(t),c.dirs.TASKS,e)},async findTask(t,e){if(e)return {project:e,task:t};let o=await this.listProjects(),r=[];if(await s.promiseEach(o,async n=>{(await this.listTasks(n)).includes(t)&&r.push(n);}),r.length===0)throw new Error(`Task '${t}' not found. Use --project to specify the project.`);if(r.length>1)throw new Error(`Task '${t}' found in multiple projects: ${r.join(", ")}. Use --project to specify which one.`);return {project:r[0],task:t}},getAgentDir(t){return s.join(A.AIP_HOME,c.dirs.AGENTS,t)},async listProjects(){let t=s.join(A.AIP_HOME,c.dirs.PROJECTS),e=await s.listDir(t);return (await s.promiseMap(e,async r=>{let n=this.getProjectDir(r);return await s.fileExists(n)&&r!==c.dirs.AGENTS?r:null})).filter(r=>r!==null).sort()},async listTasks(t){let e=s.join(this.getProjectDir(t),c.dirs.TASKS);return await s.fileExists(e)?await s.listDir(e):[]},async listAgents(){let t=s.join(A.AIP_HOME,c.dirs.AGENTS);return await s.fileExists(t)?await s.listDir(t):[]},async createProject(t,e,o){let r=this.getProjectDir(t);return await s.ensureDir(r),await Promise.all(oo.map(n=>s.ensureDir(s.join(r,n)))),await B(s.join(r,c.files.MAIN),e,o),await s.write(s.join(r,c.files.LOG),""),r},async createTask(t,e,o,r){let n=this.getTaskDir(t,e);return await s.ensureDir(n),await Promise.all(Ot.map(i=>s.ensureDir(s.join(n,i)))),await B(s.join(n,c.files.MAIN),o,r),await s.write(s.join(n,c.files.LOG),""),n},async createAgent(t,e){let o=this.getAgentDir(t);return await s.ensureDir(o),await B(s.join(o,c.files.MAIN),e),o},async getProject(t){let e=s.join(this.getProjectDir(t),c.files.MAIN);return await s.fileExists(e)?await q(e):null},async getTask(t,e){let o=s.join(this.getTaskDir(t,e),c.files.MAIN);return await s.fileExists(o)?await q(o):null},async getAgent(t){let e=s.join(this.getAgentDir(t),c.files.MAIN);return await s.fileExists(e)?await q(e):null},async updateProject(t,e){let o=s.join(this.getProjectDir(t),c.files.MAIN);return await ft(o,e)},async updateBody(t,e){let o=await s.read(t),r=et(o);if(!r)throw new Error(`No frontmatter found in ${t}`);await B(t,r.frontmatter,e);},async updateTask(t,e,o){let r=s.join(this.getTaskDir(t,e),c.files.MAIN);if((await q(r))?.status==="ongoing")throw new Error("Cannot update ongoing task. Should be done by user or update manually");return await ft(r,o)},async ingestTask(t,e){let o=this.getTaskDir(t,e),r=this.getProjectDir(t),n=[s.join(r,c.files.MAIN),s.join(o,c.files.MAIN),s.join(o,c.files.LOG)];await s.logFiles(...n);},async ingestProject(t){let e=this.getProjectDir(t),o=await this.listTasks(t),r=[s.join(e,c.files.MAIN),s.join(e,c.files.LOG),...o.map(n=>s.join(this.getTaskDir(t,n),c.files.MAIN))];await s.logFiles(...r);},async ingestFiles(t){await s.logFiles(...t);}},u=ro;});var Dt,Ct=g(()=>{k();j();x();Dt=p({options:z$1.object({description:z$1.string().describe("Agent description"),status:z$1.string().default("active").describe("Initial status")}),args:z$1.object({name:z$1.string().describe("Agent name")}),handler:async({name:t,description:e,status:o})=>{let r=s.slugify(t);await u.createAgent(r,{name:t,description:e,status:o,created:new Date().toISOString()}),console.log(`Agent created: ${r}`),console.log(` Path: ${u.getAgentDir(r)}`);}});});var Nt,Rt=g(()=>{k();Nt=p({options:z$1.object({}),handler:async()=>{let t=process.env.CURRENT_AGENT;t||(console.error("CURRENT_AGENT not set"),process.exit(1)),console.log(t);}});});var It,Lt=g(()=>{k();x();It=p({options:z$1.object({}),handler:async()=>{let t=await u.listAgents(),e=[];for(let o of t){let r=await u.getAgent(o);r&&e.push({slug:o,name:r.name||o,status:r.status,description:r.description});}if(e.length===0){console.log("No agents found");return}console.log("Agents:"),console.log("---");for(let o of e)console.log(`${o.slug.padEnd(20)} ${o.name?.padEnd(30)||""} ${o.status||""} ${o.description||""}`);}});});var Ft,Ut=g(()=>{P();k();M();j();Ft=p({description:"Output agent directory path (for cd)",options:z$1.object({}),args:z$1.object({name:z$1.string().describe("Agent name (directory name)")}),handler:async({name:t})=>{let e=s.join(A.AIP_HOME,c.dirs.AGENTS,t),o=s.join(e,c.files.MAIN);if(!await s.fileExists(o))throw new Error(`Agent not found: ${t}
18
+ Expected at: ${o}`);console.log(e);}});});var _t,Ht=g(()=>{P();k();M();j();_t=p({description:"Start an agent: read SOUL.md and AGENTS.md content",options:z$1.object({}),args:z$1.object({name:z$1.string().describe("Agent name (directory name)")}),handler:async({name:t})=>{let e=s.join(A.AIP_HOME,c.dirs.AGENTS,t),o=s.join(e,c.files.MAIN),r=s.join(e,"SOUL.md");if(!await s.fileExists(o))throw new Error(`Agent not found: ${t}
19
+ Expected at: ${o}`);let i=[r,o];await s.logFiles(...i);}});});var Kt,Gt,ao,Mt,zt=g(()=>{k();Kt=t=>{let e=t.shape,o=[];for(let[r,n]of Object.entries(e)){let i=n._def,a="unknown",l,m;i.typeName==="ZodString"?a="string":i.typeName==="ZodNumber"?a="number":i.typeName==="ZodBoolean"?a="boolean":i.typeName==="ZodEnum"?a=`enum: ${i.values.join(" | ")}`:i.typeName==="ZodOptional"?a=Gt(i.innerType):i.typeName==="ZodDefault"&&(a=Gt(i.innerType),m=i.defaultValue()),i.description&&(l=i.description);let d=i.typeName!=="ZodOptional"&&i.typeName!=="ZodDefault";o.push({name:r,type:a,required:d,description:l,defaultValue:m});}return o},Gt=t=>{let e=t._def;return e.typeName==="ZodString"?"string":e.typeName==="ZodNumber"?"number":e.typeName==="ZodBoolean"?"boolean":e.typeName==="ZodEnum"?`enum: ${e.values.join(" | ")}`:"unknown"},ao=(t,e,o)=>{let r=Kt(o.options),n=o.args?Kt(o.args):[],i=o.description,a=`\`${t} ${e}\``;if(i&&(a+=`: ${i}`),a+=`
20
+ `,r.length>0||n.length>0){let m=[];for(let d of n){let f=d.required?`<${d.name}>`:`[${d.name}]`,b=d.description||"";d.defaultValue!==void 0&&(b+=b?` (default: ${d.defaultValue})`:`(default: ${d.defaultValue})`),m.push(`\xB7 ${f}${b?": "+b:""}`);}for(let d of r){let f=d.description||"";d.defaultValue!==void 0&&(f+=f?` (default: ${d.defaultValue})`:`(default: ${d.defaultValue})`),m.push(`\xB7 --${d.name}${f?": "+f:""}`);}a+=m.join(`
21
21
  `)+`
22
22
  `;}return a+=`
23
- `,a},Kt=p({description:"Print generated CLI reference from command schemas",options:z$1.object({}),handler:async()=>{let{default:t}=await Promise.resolve().then(()=>(ot(),kt)),e="Prepend `aip` to each command\n\n",o=Object.keys(t).sort();for(let r of o){let s=t[r],i=Object.keys(s).sort();for(let a of i){let l=s[a];e+=no(r,a,l);}}console.log(e);}});});var ao,Gt,zt=f(()=>{g();ao=`# AIP Hooks
23
+ `,a},Mt=p({description:"Print generated CLI reference from command schemas",options:z$1.object({}),handler:async()=>{let{default:t}=await Promise.resolve().then(()=>(rt(),yt)),e="Prepend `aip` to each command\n\n",o=Object.keys(t).sort();for(let r of o){let n=t[r],i=Object.keys(n).sort();for(let a of i){let l=n[a];e+=ao(r,a,l);}}console.log(e);}});});var po,Bt,Jt=g(()=>{k();po=`# AIP Hooks
24
24
 
25
25
  Automated scripts that run before/after project/task actions.
26
26
 
@@ -62,7 +62,7 @@ Projects can include validation scripts and hooks to enforce folder semantics:
62
62
 
63
63
  - **\`hooks/pre-complete.sh\`** \u2013 Runs before task completion
64
64
  - Validates required files exist
65
- - Checks status.tsv has completion entry
65
+ - Checks log.tsv has completion entry
66
66
  - Runs structure validation (warning only)
67
67
  - Exit 1 blocks completion
68
68
 
@@ -112,10 +112,10 @@ if (!content.includes('description:')) {
112
112
  process.exit(1)
113
113
  }
114
114
 
115
- // Require status update
116
- const statusPath = join(taskDir, 'status.tsv')
117
- if (!existsSync(statusPath) || readFileSync(statusPath, 'utf-8').length === 0) {
118
- console.error('\u274C status.tsv is empty')
115
+ // Require log update
116
+ const logPath = join(taskDir, config.files.LOG)
117
+ if (!existsSync(logPath) || readFileSync(logPath, 'utf-8').length === 0) {
118
+ console.error('\u274C log.tsv is empty')
119
119
  process.exit(1)
120
120
  }
121
121
  \`\`\`
@@ -183,7 +183,7 @@ DEBUG=1 aip task update --status done
183
183
  - Require tests before completion
184
184
  - Check outputs exist
185
185
  - Validate frontmatter fields
186
- - Ensure status.tsv updated
186
+ - Ensure log.tsv updated
187
187
 
188
188
  ### Automation
189
189
  - Backup before changes
@@ -200,16 +200,20 @@ DEBUG=1 aip task update --status done
200
200
  ---
201
201
 
202
202
  *Hooks automate workflow enforcement. Pre-hooks guard quality, post-hooks handle cleanup.*
203
- `,Gt=p({description:"Hook types, env vars, and patterns",options:z$1.object({}),handler:async()=>{console.log(ao);}});});var O,po,Jt,Bt=f(()=>{B();g();O=Object.keys(b.bin)[0],po=`# Quick Start
203
+ `,Bt=p({description:"Hook types, env vars, and patterns",options:z$1.object({}),handler:async()=>{console.log(po);}});});var O,Vt,mo,Wt,Zt=g(()=>{P();k();W();O=Object.keys(S.bin)[0],{LOG:Vt}=c.files,mo=`# Quick Start
204
204
 
205
205
  ## New Task/Project
206
206
 
207
207
  \`\`\`bash
208
208
  # 1. Create project (if needed)
209
- ${O} project create "my-project" --description "What I'm building"
209
+ ${O} project create "my-project" --description "What I'm building" --body $'# Goals
210
+ - Build X
211
+ - Solve Y'
210
212
 
211
- # 2. Create task
212
- ${O} task create my-project "first-task" --description "Start here"
213
+ # 2. Create task (heredoc works too)
214
+ ${O} task create my-project "first-task" --description "Start here" --body "$(cat <<< '# Task Details
215
+ - Step 1
216
+ - Step 2')"
213
217
 
214
218
  # 3. Navigate to task
215
219
  cd $(${O} task path first-task)
@@ -256,16 +260,18 @@ ${O} task current
256
260
 
257
261
  \`\`\`
258
262
  $AIP_HOME/projects/slug/
259
- \u251C\u2500\u2500 main.md # Goals (read first)
260
- \u251C\u2500\u2500 status.tsv # Log (append every session)
263
+ \u251C\u2500\u2500 main.md # Definition + body
264
+ \u251C\u2500\u2500 ${Vt} # Log (auto-appended, has key task updates too)
261
265
  \u2514\u2500\u2500 tasks/task/
262
- \u251C\u2500\u2500 main.md # Task definition
263
- \u2514\u2500\u2500 status.tsv # Updates
266
+ \u251C\u2500\u2500 main.md # Task definition + body
267
+ \u2514\u2500\u2500 ${Vt} # Updates
264
268
  \`\`\`
265
269
 
266
- **Status format:** TSV with columns: date, time, entityType, slug, action, text
270
+ **Log format:** TSV with columns: date, time, entityType, slug, action, text
267
271
  **Example:** \`2026-03-30<TAB>14:30:00<TAB>task<TAB>api-integration<TAB>log<TAB>API integration complete\`
268
- `,Jt=p({description:"Quick start guide for new users",options:z$1.object({}),handler:async()=>{console.log(po);}});});var lo,mo,uo,fo,go,ko,jo,Vt,Zt,G,jt,qt,Yt=f(()=>{B();$();g();x();lo=Object.values(M).join("|"),{PROJECTS:mo,TASKS:uo,HOOKS:fo,INPUTS:go,OUTPUTS:ko,SCRIPTS:jo}=c.dirs,{MAIN:Vt,STATUS:Zt}=c.files,G=Object.keys(b.bin)[0],jt=`# AIP - Project Management Skill
272
+
273
+ Run \`${O} help usage\` for all commands.
274
+ `,Wt=p({description:"Quick start guide for new users",options:z$1.object({}),handler:async()=>{console.log(mo);}});});var uo,go,fo,ko,ho,yo,jo,Yt,jt,R,Tt,Qt,Xt=g(()=>{W();P();k();x();uo=Object.values(J).join("|"),{PROJECTS:go,TASKS:fo,HOOKS:ko,INPUTS:ho,OUTPUTS:yo,SCRIPTS:jo}=c.dirs,{MAIN:Yt,LOG:jt}=c.files,R=Object.keys(S.bin)[0],Tt=`# AIP - Project Management Skill
269
275
 
270
276
  Automated project and task creation with proper structure, front-matter, and file organization.
271
277
 
@@ -275,25 +281,25 @@ Streamline creation of new projects and tasks with the correct directory structu
275
281
 
276
282
  ## Quick Start
277
283
 
278
- - New user? Run: \`${G} help quickstart\`
279
- - All commands? Run: \`${G} help usage\`
280
- - Just for one noun? Run: \`${G} help usage <noun>\` (e.g., \`${G} help usage task\`)
281
- - Need EVERYTHING (big)? Run: \`${G} help api\` - Shows all commands with full option details
284
+ - New user? Run: \`${R} help quickstart\`
285
+ - All commands? Run: \`${R} help usage\`
286
+ - Just for one noun? Run: \`${R} help usage <noun>\` (e.g., \`${R} help usage task\`)
287
+ - Need EVERYTHING (big)? Run: \`${R} help api\` - Shows all commands with full option details
282
288
 
283
289
  ## File Structure Overview
284
290
 
285
291
  \`\`\`
286
- $AIP_HOME/${mo}/{project-slug}/
287
- \u251C\u2500\u2500 ${Vt} # Primary context: goals, scope, data
288
- \u251C\u2500\u2500 ${Zt} # Chronological log (TSV: date, time, entityType, slug, action, text)
289
- \u251C\u2500\u2500 ${fo}/ # pre|post-{create,start,update,complete}.*
290
- \u251C\u2500\u2500 ${ko}/ # Deliverables
291
- \u251C\u2500\u2500 ${go}/ # External data
292
+ $AIP_HOME/${go}/{project-slug}/
293
+ \u251C\u2500\u2500 ${Yt} # Goals + body (YAML frontmatter + markdown content)
294
+ \u251C\u2500\u2500 ${jt} # Chronological log (TSV: date, time, entityType, slug, action, text)
295
+ \u251C\u2500\u2500 ${ko}/ # pre|post-{create,start,update,complete}.*
296
+ \u251C\u2500\u2500 ${yo}/ # Deliverables
297
+ \u251C\u2500\u2500 ${ho}/ # External data
292
298
  \u251C\u2500\u2500 ${jo}/ # Automation
293
- \u2514\u2500\u2500 ${uo}/
299
+ \u2514\u2500\u2500 ${fo}/
294
300
  \u2514\u2500\u2500 {task-slug}/
295
- \u251C\u2500\u2500 ${Vt} # Task definition
296
- \u251C\u2500\u2500 ${Zt} # Activity log
301
+ \u251C\u2500\u2500 ${Yt} # Task definition + body
302
+ \u251C\u2500\u2500 ${jt} # Activity log
297
303
  \u2514\u2500\u2500 ... (same structure)
298
304
  \`\`\`
299
305
 
@@ -304,11 +310,28 @@ $AIP_HOME/${mo}/{project-slug}/
304
310
  name: Clear Title
305
311
  description: One-line summary
306
312
  assignee: agent-name
307
- status: ${lo}
313
+ status: ${uo}
308
314
  created: YYYY-MM-DD
309
315
  ---
310
316
  \`\`\`
311
317
 
318
+ ## Body/Content
319
+
320
+ Markdown after frontmatter. Add via CLI:
321
+
322
+ \`\`\`bash
323
+ # Using heredoc (multi-line)
324
+ ${R} project create "my-project" --description "..." --body "$(cat <<'EOF'
325
+ # Goals
326
+ - Build X
327
+ - Solve Y
328
+ EOF
329
+ )"
330
+
331
+ # Update/replace body
332
+ ${R} project update --body "$(cat new-content.md)"
333
+ \`\`\`
334
+
312
335
  ## Best Practices
313
336
 
314
337
  **DO:** Concise status entries, update every session, save deliverables to outputs/
@@ -318,25 +341,25 @@ created: YYYY-MM-DD
318
341
 
319
342
  When working on a task:
320
343
  1. Read \`main.md\` first (goals/context)
321
- 2. Review \`status.tsv\` (activity history)
344
+ 2. Review \`${jt}\` (activity history)
322
345
  3. Work and save outputs to \`outputs/\`
323
- 4. Log progress: \`${G} log append "message"\`
346
+ 4. Log progress: \`${R} log append "message"\`
324
347
  5. On completion: set status=\`done\`, log summary
325
- `,qt=p({description:"Project management skill for creating and managing projects/tasks",options:z$1.object({mode:z$1.enum(["md","claude","hermes"]).default("md").describe("Output format: md (no header), claude (name+description), hermes (full frontmatter)")}),handler:async t=>{let e=Object.keys(b.bin)[0];if(t.mode==="md"){console.log(jt);return}if(t.mode==="claude"){console.log(`---
348
+ `,Qt=p({description:"Project management skill for creating and managing projects/tasks",options:z$1.object({mode:z$1.enum(["md","claude","hermes"]).default("md").describe("Output format: md (no header), claude (name+description), hermes (full frontmatter)")}),handler:async t=>{let e=Object.keys(S.bin)[0];if(t.mode==="md"){console.log(Tt);return}if(t.mode==="claude"){console.log(`---
326
349
  name: ${e}
327
- description: ${b.description}
328
- ---`),console.log(),console.log(jt);return}if(t.mode==="hermes"){console.log(`---
350
+ description: ${S.description}
351
+ ---`),console.log(),console.log(Tt);return}if(t.mode==="hermes"){console.log(`---
329
352
  name: ${e}
330
- description: ${b.description}
331
- version: ${b.version}
332
- author: ${b.author}
333
- license: ${b.license}
353
+ description: ${S.description}
354
+ version: ${S.version}
355
+ author: ${S.author}
356
+ license: ${S.license}
334
357
  metadata:
335
358
  hermes:
336
- tags: [${b.keywords.join(", ")}]
337
- ---`),console.log(),console.log(jt);return}}});});var Qt,Xt=f(()=>{B();g();T();Qt=p({description:"Print compact CLI usage (all nouns, or one noun if name is given)",options:z$1.object({}),args:z$1.object({name:z$1.string().optional().describe("Noun (e.g. task) to list verbs for")}),handler:async({name:t})=>{let{default:e}=await Promise.resolve().then(()=>(ot(),kt)),o=`${b.name} ${b.version} -`,r=n.dumpCommandMapLines(e,t);if(!t)console.log(o,"Usage: aip <noun> <verb> [options]"),console.log(r.map(s=>`-> ${s}`).join(`
338
- `)),console.log(),console.log("Run `aip help quickstart` for a quick start guide"),console.log("Run `aip help skill` for a broader overview");else {let s=r[0]??`${t} {?}`;console.log(o,`Usage: aip ${s} [options]`);}}});});var yt,ho,j,A=f(()=>{$();T();yt=n.joinHome(c.dirs.PROJECTS),ho={getProjectFromPwd(t=process.cwd()){let e=F.relative(yt,t);if(!e||e.startsWith(".."))return null;let o=e.split(F.sep).filter(Boolean);return o.length===0?null:o[0]},getTaskFromPwd(t=process.cwd()){let e=F.relative(yt,t);if(!e||e.startsWith(".."))return null;let o=e.split(F.sep).filter(Boolean);return o.length<3||o[1]!==c.dirs.TASKS?null:o[2]},getCurrentContext(t=process.cwd()){return {project:this.getProjectFromPwd(t),task:this.getTaskFromPwd(t)}},requireProject(t=process.cwd()){let e=this.getProjectFromPwd(t);if(!e)throw new Error(`Not in a project directory. PWD: ${t}, projects: ${yt}`);return e},requireTask(t=process.cwd()){let e=this.getCurrentContext(t);if(!e.project||!e.task)throw new Error(`Not in a task directory. PWD: ${t}`);return {project:e.project,task:e.task}},exportContext(t=process.cwd()){let e=this.getCurrentContext(t),o=[];return e.project&&o.push(`export CURRENT_PROJECT="${e.project}"`),e.task&&o.push(`export CURRENT_TASK="${e.task}"`),process.env.CURRENT_AGENT&&o.push(`export CURRENT_AGENT="${process.env.CURRENT_AGENT}"`),o.join(`
339
- `)},getTargetDir(t,e=process.cwd()){let o=this.getCurrentContext(e);if(t==="project"){let r=this.getProjectFromPwd(e);if(!r)throw new Error("Not in a project directory. Use --project flag or cd into a project.");let s=n.joinHome(c.dirs.PROJECTS,r);return {targetDir:s,projectDir:s,entityType:"project"}}if(t==="task"){if(!o.project||!o.task)throw new Error("Not in a task directory. Use --project and --task flags or cd into a task.");let r=n.joinHome(c.dirs.PROJECTS,o.project);return {targetDir:n.join(r,c.dirs.TASKS,o.task),projectDir:r,entityType:"task"}}if(o.task&&o.project){let r=n.joinHome(c.dirs.PROJECTS,o.project);return {targetDir:n.join(r,c.dirs.TASKS,o.task),projectDir:r,entityType:"task"}}if(o.project){let r=n.joinHome(c.dirs.PROJECTS,o.project);return {targetDir:r,projectDir:r,entityType:"project"}}throw new Error("Not in a project or task directory. Specify --target flag.")}},j=ho;});var te,ee=f(()=>{g();T();A();$();te=p({options:z$1.object({lang:z$1.enum(c.languages).default("ts").describe("Language"),target:z$1.enum(c.targets).default("project").describe("Target level")}),args:z$1.object({type:z$1.enum(c.hookTypes).describe("Hook type (e.g., pre-create, post-complete)")}),handler:async({type:t,lang:e,target:o})=>{let r=e,s=`.${r}`,{targetDir:i,entityType:a}=j.getTargetDir(o),l=n.join(i,c.dirs.HOOKS);await n.ensureDir(l);let m=n.join(l,`${t}${s}`);if(await n.fileExists(m))throw new Error(`Hook already exists: ${m}`);let k;if(r==="ts")k=`#!/usr/bin/env tsx
359
+ tags: [${S.keywords.join(", ")}]
360
+ ---`),console.log(),console.log(Tt);return}}});});var te,ee=g(()=>{W();k();j();te=p({description:"Print compact CLI usage (all nouns, or one noun if name is given)",options:z$1.object({}),args:z$1.object({name:z$1.string().optional().describe("Noun (e.g. task) to list verbs for")}),handler:async({name:t})=>{let{default:e}=await Promise.resolve().then(()=>(rt(),yt)),o=`${S.name} ${S.version} -`,r=s.dumpCommandMapLines(e,t);if(!t)console.log(o,"Usage: aip <noun> <verb> [options]"),console.log(r.map(n=>`-> ${n}`).join(`
361
+ `)),console.log(),console.log("Run `aip help quickstart` for a quick start guide"),console.log("Run `aip help skill` for a broader overview");else {let n=r[0]??`${t} {?}`;console.log(o,`Usage: aip ${n} [options]`);}}});});var bt,To,h,D=g(()=>{P();j();bt=s.joinHome(c.dirs.PROJECTS),To={getProjectFromPwd(t=process.cwd()){let e=G.relative(bt,t);if(!e||e.startsWith(".."))return null;let o=e.split(G.sep).filter(Boolean);return o.length===0?null:o[0]},getTaskFromPwd(t=process.cwd()){let e=G.relative(bt,t);if(!e||e.startsWith(".."))return null;let o=e.split(G.sep).filter(Boolean);return o.length<3||o[1]!==c.dirs.TASKS?null:o[2]},getCurrentContext(t=process.cwd()){return {project:this.getProjectFromPwd(t),task:this.getTaskFromPwd(t)}},requireProject(t=process.cwd()){let e=this.getProjectFromPwd(t);if(!e)throw new Error(`Not in a project directory. PWD: ${t}, projects: ${bt}`);return e},requireTask(t=process.cwd()){let e=this.getCurrentContext(t);if(!e.project||!e.task)throw new Error(`Not in a task directory. PWD: ${t}`);return {project:e.project,task:e.task}},exportContext(t=process.cwd()){let e=this.getCurrentContext(t),o=[];return e.project&&o.push(`export CURRENT_PROJECT="${e.project}"`),e.task&&o.push(`export CURRENT_TASK="${e.task}"`),process.env.CURRENT_AGENT&&o.push(`export CURRENT_AGENT="${process.env.CURRENT_AGENT}"`),o.join(`
362
+ `)},getTargetDir(t,e=process.cwd()){let o=this.getCurrentContext(e);if(t==="project"){let r=this.getProjectFromPwd(e);if(!r)throw new Error("Not in a project directory. Use --project flag or cd into a project.");let n=s.joinHome(c.dirs.PROJECTS,r);return {targetDir:n,projectDir:n,entityType:"project"}}if(t==="task"){if(!o.project||!o.task)throw new Error("Not in a task directory. Use --project and --task flags or cd into a task.");let r=s.joinHome(c.dirs.PROJECTS,o.project);return {targetDir:s.join(r,c.dirs.TASKS,o.task),projectDir:r,entityType:"task"}}if(o.task&&o.project){let r=s.joinHome(c.dirs.PROJECTS,o.project);return {targetDir:s.join(r,c.dirs.TASKS,o.task),projectDir:r,entityType:"task"}}if(o.project){let r=s.joinHome(c.dirs.PROJECTS,o.project);return {targetDir:r,projectDir:r,entityType:"project"}}throw new Error("Not in a project or task directory. Specify --target flag.")}},h=To;});var oe,re=g(()=>{k();j();D();P();oe=p({options:z$1.object({lang:z$1.enum(c.languages).default("ts").describe("Language"),target:z$1.enum(c.targets).default("project").describe("Target level")}),args:z$1.object({type:z$1.enum(c.hookTypes).describe("Hook type (e.g., pre-create, post-complete)")}),handler:async({type:t,lang:e,target:o})=>{let r=e,n=`.${r}`,{targetDir:i,entityType:a}=h.getTargetDir(o),l=s.join(i,c.dirs.HOOKS);await s.ensureDir(l);let m=s.join(l,`${t}${n}`);if(await s.fileExists(m))throw new Error(`Hook already exists: ${m}`);let f;if(r==="ts")f=`#!/usr/bin/env tsx
340
363
  /** ${t} hook for ${a} */
341
364
 
342
365
  import { env } from 'node:process'
@@ -349,7 +372,7 @@ if (env.TASK_SLUG) {
349
372
 
350
373
  // Exit with non-zero to prevent action (for pre-hooks)
351
374
  // process.exit(1)
352
- `;else if(r==="js")k=`#!/usr/bin/env node
375
+ `;else if(r==="js")f=`#!/usr/bin/env node
353
376
  /** ${t} hook for ${a} */
354
377
 
355
378
  console.log('Running ${t} hook for ${a}')
@@ -360,7 +383,7 @@ if (process.env.TASK_SLUG) {
360
383
 
361
384
  // Exit with non-zero to prevent action (for pre-hooks)
362
385
  // process.exit(1)
363
- `;else if(r==="sh")k=`#!/bin/bash
386
+ `;else if(r==="sh")f=`#!/bin/bash
364
387
  # ${t} hook for ${a}
365
388
 
366
389
  echo "Running ${t} hook for ${a}"
@@ -371,7 +394,7 @@ fi
371
394
 
372
395
  # Exit with non-zero to prevent action (for pre-hooks)
373
396
  # exit 1
374
- `;else if(r==="py")k=`#!/usr/bin/env python3
397
+ `;else if(r==="py")f=`#!/usr/bin/env python3
375
398
  """${t} hook for ${a}"""
376
399
 
377
400
  import os
@@ -383,13 +406,13 @@ if os.environ.get('TASK_SLUG'):
383
406
 
384
407
  # Exit with non-zero to prevent action (for pre-hooks)
385
408
  # sys.exit(1)
386
- `;else throw new Error(`Unsupported language: ${r}`);await n.write(m,k);let{chmod:P}=await import('fs/promises');await P(m,493),console.log(`Hook created: ${m}`);}});});var To,v,z=f(()=>{$();T();To={async findHooks(t,e){let o=n.join(t,c.dirs.HOOKS);if(!await n.fileExists(o))return [];let s=await n.listDir(o),i=`${e}.`;return s.filter(a=>a.startsWith(i)).map(a=>n.join(o,a))},async executeHook(t,e,o){if(!await n.fileExists(t))return true;let s=e.project?n.joinHome(c.dirs.PROJECTS,e.project):o,i=e.task?n.join(s,c.dirs.TASKS,e.task):"",a={...process.env,HOOK_TYPE:e.action,ENTITY_TYPE:e.entityType,TARGET_DIR:o,PROJECT_DIR:s,...e.project?{PROJECT_SLUG:e.project}:{},...e.task?{TASK_SLUG:e.task,TASK_DIR:i}:{}};return new Promise(l=>{let m=spawn(t,[],{stdio:"inherit",env:a,cwd:F.dirname(t),shell:false});m.on("close",(d,k)=>{d===0?l(true):(console.error(`Hook ${F.basename(t)} failed (code=${d??k})`),l(false));}),m.on("error",d=>{console.error(`Failed to execute hook ${t}: ${d.message}`),l(false);});})},async runHooks(t,e,o){let r=await this.findHooks(t,e),s=e.startsWith("pre-");for(let i of r)if(!await this.executeHook(i,o,t)&&s)return false;return true},async runHooksForContext(t,e,o,r){return !(!await this.runHooks(t,o,r)||e&&!await this.runHooks(e,o,r))}},v=To;});var re,se=f(()=>{g();z();A();$();re=p({options:z$1.object({target:z$1.enum(c.targets).optional().describe("Target level")}),args:z$1.object({type:z$1.enum(c.hookTypes).describe("Hook type to run")}),handler:async({type:t,target:e})=>{let{targetDir:o,entityType:r}=j.getTargetDir(e),s={action:t,entityType:r,project:j.getProjectFromPwd()||void 0,task:j.getTaskFromPwd()||void 0};await v.runHooks(o,t,s)||(console.error(`Hook ${t} failed`),process.exit(1)),console.log(`Hook ${t} completed successfully`);}});});var wo,w,C=f(()=>{$();A();T();wo={formatEntry(t,e,o,r){let s=new Date,i=s.toISOString().split("T")[0],a=s.toLocaleTimeString("en-US",{hour12:false,hour:"2-digit",minute:"2-digit",second:"2-digit"});return `${i} ${a} ${t} ${e} ${o} ${r}
387
- `},async appendStatus(t,e,o,r,s){let i=n.join(t,c.files.STATUS),a=this.formatEntry(e,o,r,s);await n.append(i,a);},async appendStatusIfExists(t,e,o,r,s){let i=n.join(t,c.files.STATUS);if(!await n.fileExists(i))return false;let l=this.formatEntry(e,o,r,s);return await n.append(i,l),true},async readStatus(t){let e=n.join(t,c.files.STATUS);return await n.fileExists(e)?await n.read(e):""},getCurrentAgent(){return process.env.CURRENT_AGENT},async logTask(t,e,o){let r=j.getCurrentContext();if(!r.project||!r.task)throw new Error("Not in a task directory");let s=n.joinHome(c.dirs.PROJECTS,r.project,c.dirs.TASKS,r.task);await this.appendStatus(s,"task",t,"log",o?`${o}: ${e}`:e);},async logProject(t,e,o){let r=j.getProjectFromPwd();if(!r)throw new Error("Not in a project directory");let s=n.joinHome(c.dirs.PROJECTS,r);await this.appendStatus(s,"project",t,"log",o?`${o}: ${e}`:e);},async logStatusChange(t,e,o,r,s,i){let a=r;if(s&&Object.keys(s).length>0){let l=Object.entries(s).map(([m,d])=>`${m}=${d}`).join(", ");a=`${r}: ${l}`;}await this.appendStatus(t,e,o,"updated",i?`${i} | ${a}`:a);}},w=wo;});var ne,ie=f(()=>{g();A();T();C();$();ne=p({description:"Append a custom entry to status.tsv",options:z$1.object({project:z$1.string().optional().describe("Project slug (uses current project from $PWD if not provided)"),task:z$1.string().optional().describe("Task slug (uses current task from $PWD if not provided)")}),args:z$1.object({text:z$1.string().describe("Text to append")}),handler:async({project:t,task:e,text:o})=>{let r=j.getCurrentContext(),s=t||r.project;if(!s)throw new Error("No project specified. Use --project or run from a project/task directory");let i=n.joinHome(c.dirs.PROJECTS,s);if(e||r.task){let a=e||r.task;if(!a)throw new Error("No task specified");let l=n.join(i,c.dirs.TASKS,a);await w.appendStatus(l,"task",a,"log",o),console.log(`Appended to task ${a} status.tsv`);}else await w.appendStatus(i,"project",s,"log",o),console.log(`Appended to project ${s} status.tsv`);}});});var ae,ce=f(()=>{g();A();T();C();$();ae=p({description:"Read status.tsv history",options:z$1.object({project:z$1.string().optional().describe("Project slug (uses current project from $PWD if not provided)"),task:z$1.string().optional().describe("Task slug (uses current task from $PWD if not provided)")}),args:z$1.object({}),handler:async({project:t,task:e})=>{let o=j.getCurrentContext(),r=t||o.project;if(!r)throw new Error("No project specified. Use --project or run from a project/task directory");let s=n.joinHome(c.dirs.PROJECTS,r);if(e||o.task){let i=e||o.task;if(!i)throw new Error("No task specified");let a=n.join(s,c.dirs.TASKS,i),l=await w.readStatus(a);console.log(l||`No status.tsv found for task ${i}`);}else {let i=await w.readStatus(s);console.log(i||`No status.tsv found for project ${r}`);}}});});var pe,le=f(()=>{g();z();T();x();C();pe=p({description:"Create a new project with name, description, optional status and assignee",options:z$1.object({description:z$1.string().describe("Project description"),status:z$1.string().default("active").describe("Initial status"),assignee:z$1.string().optional().describe("Assignee agent slug")}),args:z$1.object({name:z$1.string().describe("Project name")}),handler:async({name:t,description:e,status:o,assignee:r})=>{let s=n.slugify(t),i=u.getProjectDir(s);if(!await v.runHooks(i,"pre-create",{action:"pre-create",entityType:"project"}))throw new Error("Pre-create hook failed, aborting project creation");await u.createProject(s,{name:t,description:e,status:o,assignee:r,created:new Date().toISOString()}),await w.appendStatus(i,"project",s,"created",`status is ${o}`),await v.runHooks(i,"post-create",{action:"post-create",entityType:"project"}),console.log(`Project created: ${s}`),console.log(` Path: ${i}`);}});});var me,de=f(()=>{g();A();me=p({options:z$1.object({}),handler:async()=>{let t=j.getProjectFromPwd();t||(console.error("Not in a project directory"),process.exit(1)),console.log(t);}});});var fe,ge=f(()=>{g();x();fe=p({description:"List all projects, optionally filtered by status",options:z$1.object({status:z$1.string().optional().describe("Filter by status")}),handler:async({status:t})=>{let e=await u.listProjects(),o=[];for(let r of e){let s=await u.getProject(r);s&&(t&&s.status!==t||o.push({slug:r,name:s.name||r,status:s.status,assignee:s.assignee}));}if(o.length===0){console.log("No projects found");return}console.log("Projects:"),console.log("---");for(let r of o)console.log(`${r.slug.padEnd(20)} ${r.name?.padEnd(30)||""} ${r.status||""} ${r.assignee||""}`);}});});var ke,je=f(()=>{g();x();ke=p({description:"Output project directory path (for cd)",options:z$1.object({}),args:z$1.object({name:z$1.string().describe("Project name (slug)")}),handler:async({name:t})=>{let e=u.getProjectDir(t);console.log(e);}});});var he,ye=f(()=>{g();x();z();C();A();he=p({description:"Update project properties: name, description, status, assignee",options:z$1.object({name:z$1.string().optional().describe("New name"),description:z$1.string().optional().describe("New description"),status:z$1.string().optional().describe("New status"),assignee:z$1.string().optional().describe("New assignee")}),args:z$1.object({project:z$1.string().optional().describe("Project slug (defaults to current project from $PWD)")}),handler:async({project:t,name:e,description:o,status:r,assignee:s})=>{let i=t||j.getProjectFromPwd();if(!i)throw new Error("No project specified and not in a project directory");let a=u.getProjectDir(i);if(!await v.runHooks(a,"pre-update",{action:"pre-update",entityType:"project"}))throw new Error("Pre-update hook failed, aborting update");let m={};if(e&&(m.name=e),o&&(m.description=o),r&&(m.status=r),s&&(m.assignee=s),Object.keys(m).length===0){console.log("No updates provided");return}await u.updateProject(i,m);let d=Object.entries(m).map(([k,P])=>`${k}=${P}`).join(", ");await w.appendStatus(a,"project",i,"updated",d),await v.runHooks(a,"post-update",{action:"post-update",entityType:"project"}),console.log(`Project ${i} updated`);}});});var Te,we=f(()=>{$();g();H();T();Te=p({description:"Read a skill's SKILL.md file into the console for agent context",options:z$1.object({}),args:z$1.object({name:z$1.string().describe("Skill name (directory name)")}),handler:async({name:t})=>{let e=n.join(E.AIP_HOME,c.dirs.SKILLS,t),o=n.join(e,c.files.SKILL);if(!await n.fileExists(o))throw new Error(`Skill not found: ${t}
388
- Expected at: ${o}`);await n.logFiles(o);}});});var Se,be=f(()=>{g();z();T();x();C();Se=p({description:"Create a new task with assignee and initial status",options:z$1.object({description:z$1.string().optional().describe("Task description"),assignee:z$1.string().optional().describe("Assignee agent slug"),status:z$1.string().default("backlog").describe("Initial status")}),args:z$1.object({project:z$1.string().describe("Project slug"),name:z$1.string().describe("Task name")}),handler:async({project:t,name:e,description:o,assignee:r,status:s})=>{let i=n.slugify(e),a=u.getProjectDir(t),l=u.getTaskDir(t,i);if(!await v.runHooksForContext(a,l,"pre-create",{action:"pre-create",entityType:"task",project:t}))throw new Error("Pre-create hook failed, aborting task creation");await u.createTask(t,i,{name:e,description:o,assignee:r,status:s,created:new Date().toISOString()}),await w.appendStatus(l,"task",i,"created",e),await w.appendStatus(a,"task",i,"created",`status is ${s}`),await v.runHooksForContext(a,l,"post-create",{action:"post-create",entityType:"task",project:t}),console.log(`Task created: ${i}`),console.log(` Project: ${t}`),console.log(` Path: ${l}`);}});});var Pe,xe=f(()=>{g();A();Pe=p({description:"Get the current task slug from PWD",options:z$1.object({}),handler:async()=>{let t=j.getTaskFromPwd();t||(console.error("Not in a task directory"),process.exit(1)),console.log(t);}});});var $e,ve=f(()=>{A();g();x();$e=p({description:"Output full task context (main.md, status.tsv) for ingestion by agents",options:z$1.object({project:z$1.string().optional().describe("Project slug (searches all projects if not provided)")}),args:z$1.object({task:z$1.string().optional().describe("Task slug (default: from $PWD)")}),handler:async({project:t,task:e})=>{let o=j.getCurrentContext(),r=e??o.task;if(!r)throw new Error("Need task slug (or cd into task dir)");let{project:s}=await u.findTask(r,t);await u.ingestTask(s,r);}});});var Ee,Ae=f(()=>{g();x();Ee=p({description:"List tasks, optionally filtered by project, status, assignee, or search query",options:z$1.object({project:z$1.string().optional().describe("Project slug (searches all projects if not provided)"),statuses:z$1.array(z$1.string()).default([]).describe("Filter by statuses (multiple allowed)"),assignee:z$1.string().optional().describe("Filter by assignee"),all:z$1.boolean().default(false).describe("Include all tasks (including done/blocked)"),search:z$1.string().optional().describe("Search query (matches task slug or name, case-insensitive)")}),handler:async({project:t,statuses:e,assignee:o,all:r,search:s})=>{if(e&&e.length>0){for(let d of e)if(!et.includes(d))throw new Error(`Invalid status: ${d}. Valid values: ${et.join(", ")}`)}let i;e&&e.length>0?i=e:r?i=et:i=vt;let a=t?[t]:await u.listProjects(),l={};for(let d of a){let k=await u.listTasks(d),P=[];for(let S of k){let D=await u.getTask(d,S);if(D&&!(i.length>0&&!i.includes(D.status||""))&&!(o&&D.assignee!==o)){if(s){let tt=s.toLowerCase(),mt=S.toLowerCase().includes(tt),Fe=(D.name||"").toLowerCase().includes(tt);if(!mt&&!Fe)continue}P.push({slug:S,name:D.name||S,status:D.status,assignee:D.assignee});}}P.length>0&&(l[d]=P.sort((S,D)=>S.slug.localeCompare(D.slug)));}let m=Object.keys(l).sort();if(m.length===0){console.log("No tasks found");return}for(let d of m){console.log(`
389
- ${d}:`),console.log("---");for(let k of l[d])console.log(`${k.slug.padEnd(20)} ${k.name?.padEnd(30)||""} ${k.status||""} ${k.assignee||""}`);}}});});var De,Oe=f(()=>{g();x();De=p({description:"Output task directory path (for cd)",options:z$1.object({project:z$1.string().optional().describe("Project slug (searches all projects if not provided)")}),args:z$1.object({task:z$1.string().describe("Task slug")}),handler:async({project:t,task:e})=>{let{project:o,task:r}=await u.findTask(e,t),s=u.getTaskDir(o,r);console.log(s);}});});var ct,St=f(()=>{A();g();z();x();C();ct=p({description:"Update task properties: name, description, status, assignee",options:z$1.object({name:z$1.string().optional().describe("New name"),description:z$1.string().optional().describe("New description"),status:z$1.string().optional().describe("New status"),assignee:z$1.string().optional().describe("New assignee"),project:z$1.string().optional().describe("Project slug (searches all projects if not provided)")}),args:z$1.object({task:z$1.string().optional().describe("Task slug (default: from $PWD)")}),handler:async({project:t,task:e,name:o,description:r,status:s,assignee:i})=>{let a=j.getCurrentContext(),l=e??a.task;if(!l)throw new Error("No task specified (use --task or cd into task dir)");let{project:m}=await u.findTask(l,t),d=u.getTaskDir(m,l),k=u.getProjectDir(m);if(!await v.runHooksForContext(k,d,"pre-update",{action:"pre-update",entityType:"task",project:m,task:l}))throw new Error("Pre-update hook failed, aborting update");let S={};if(o&&(S.name=o),r&&(S.description=r),s&&(S.status=s),i&&(S.assignee=i),Object.keys(S).length===0){console.log("No updates provided");return}if(Object.keys(S).length>0){await u.updateTask(m,l,S);let D=Object.entries(S).map(([tt,mt])=>`${tt}=${mt}`).join(", ");await w.appendStatus(d,"task",l,"updated",D);}S.status&&await w.appendStatus(k,"task",l,"updated",`status to ${S.status}`),await v.runHooksForContext(u.getProjectDir(m),d,"post-update",{action:"post-update",entityType:"task",project:m,task:l}),console.log(`Task ${l} updated`);}});});var Ce,Re=f(()=>{A();g();x();St();Ce=p({description:"Start a task: set status to in-progress, optionally print context",options:z$1.object({project:z$1.string().optional().describe("Project slug (searches all projects if not provided)"),ingest:z$1.boolean().default(false).describe("Also output context for this task")}),args:z$1.object({task:z$1.string().optional().describe("Task slug (default: from $PWD)")}),handler:async({project:t,task:e,ingest:o})=>{let r=j.getCurrentContext(),s=e??r.task;if(!s)throw new Error("No task specified (use --task or cd into task dir)");let{project:i}=await u.findTask(s,t);(await u.getTask(i,s))?.status!=="in-progress"&&await ct.handler({project:i,task:s,status:"in-progress"}),o&&await u.ingestTask(i,s);}});});var Ne,Ie=f(()=>{g();x();C();Ne=p({description:"Post-mortem analysis for a completed task",options:z$1.object({}),args:z$1.object({project:z$1.string().describe("Project slug"),task:z$1.string().describe("Task slug")}),handler:async({project:t,task:e})=>{let o=u.getTaskDir(t,e),r=await u.getTask(t,e),i=(await w.readStatus(o)).split(`
390
- `).filter(m=>m.startsWith("[")).length,a=[],l=r?.name||e;i>5&&a.push("High status update count - consider breaking into smaller tasks"),l.toLowerCase().includes("implement")&&a.push("Implementation task - check if similar patterns exist to reuse"),l.toLowerCase().includes("create")&&l.toLowerCase().includes("command")&&a.push("Command creation - check existing command patterns in src/commands/"),console.log(`
391
- === Post-Mortem Analysis ===`),console.log(`Project: ${t}`),console.log(`Task: ${e}`),console.log(`Name: ${l}`),console.log(`Status: ${r?.status||"unknown"}`),console.log(`Status updates: ${i}`),a.length>0?(console.log(`
409
+ `;else throw new Error(`Unsupported language: ${r}`);await s.write(m,f);let{chmod:b}=await import('fs/promises');await b(m,493),console.log(`Hook created: ${m}`);}});});var bo,$,V=g(()=>{P();j();bo={async findHooks(t,e){let o=s.join(t,c.dirs.HOOKS);if(!await s.fileExists(o))return [];let n=await s.listDir(o),i=`${e}.`;return n.filter(a=>a.startsWith(i)).map(a=>s.join(o,a))},async executeHook(t,e,o){if(!await s.fileExists(t))return true;let n=e.project?s.joinHome(c.dirs.PROJECTS,e.project):o,i=e.task?s.join(n,c.dirs.TASKS,e.task):"",a={...process.env,HOOK_TYPE:e.action,ENTITY_TYPE:e.entityType,TARGET_DIR:o,PROJECT_DIR:n,...e.project?{PROJECT_SLUG:e.project}:{},...e.task?{TASK_SLUG:e.task,TASK_DIR:i}:{}};return new Promise(l=>{let m=spawn(t,[],{stdio:"inherit",env:a,cwd:G.dirname(t),shell:false});m.on("close",(d,f)=>{d===0?l(true):(console.error(`Hook ${G.basename(t)} failed (code=${d??f})`),l(false));}),m.on("error",d=>{console.error(`Failed to execute hook ${t}: ${d.message}`),l(false);});})},async runHooks(t,e,o){let r=await this.findHooks(t,e),n=e.startsWith("pre-");for(let i of r)if(!await this.executeHook(i,o,t)&&n)return false;return true},async runHooksForContext(t,e,o,r){return !(!await this.runHooks(t,o,r)||e&&!await this.runHooks(e,o,r))}},$=bo;});var ne,ie=g(()=>{k();V();D();P();ne=p({options:z$1.object({target:z$1.enum(c.targets).optional().describe("Target level")}),args:z$1.object({type:z$1.enum(c.hookTypes).describe("Hook type to run")}),handler:async({type:t,target:e})=>{let{targetDir:o,entityType:r}=h.getTargetDir(e),n={action:t,entityType:r,project:h.getProjectFromPwd()||void 0,task:h.getTaskFromPwd()||void 0};await $.runHooks(o,t,n)||(console.error(`Hook ${t} failed`),process.exit(1)),console.log(`Hook ${t} completed successfully`);}});});var Po,T,I=g(()=>{P();D();j();Po={formatEntry(t,e,o,r){let n=new Date,i=n.getFullYear(),a=String(n.getMonth()+1).padStart(2,"0"),l=String(n.getDate()).padStart(2,"0"),m=n.toLocaleTimeString("en-US",{hour12:false,hour:"2-digit",minute:"2-digit",second:"2-digit"});return `${`${i}-${a}-${l}`} ${m} ${t} ${e} ${o} ${r}
410
+ `},async append(t,e,o,r,n){let i=s.join(t,c.files.LOG),a=this.formatEntry(e,o,r,n);await s.append(i,a);},async read(t){let e=s.join(t,c.files.LOG);return await s.fileExists(e)?await s.read(e):""},async task(t,e,o){let r=h.getCurrentContext();if(!r.project||!r.task)throw new Error("Not in a task directory");let n=s.joinHome(c.dirs.PROJECTS,r.project,c.dirs.TASKS,r.task);await this.append(n,"task",t,"log",o?`${o}: ${e}`:e);},async project(t,e,o){let r=h.getProjectFromPwd();if(!r)throw new Error("Not in a project directory");let n=s.joinHome(c.dirs.PROJECTS,r);await this.append(n,"project",t,"log",o?`${o}: ${e}`:e);}},T=Po;});var ae,ce=g(()=>{P();D();k();j();I();ae=p({description:"Append a custom entry to log.tsv",options:z$1.object({project:z$1.string().optional().describe("Project slug (uses current project from $PWD if not provided)"),task:z$1.string().optional().describe("Task slug (uses current task from $PWD if not provided)")}),args:z$1.object({text:z$1.string().describe("Text to append")}),handler:async({project:t,task:e,text:o})=>{let r=h.getCurrentContext(),n=t||r.project;if(!n)throw new Error("No project specified. Use --project or run from a project/task directory");let i=s.joinHome(c.dirs.PROJECTS,n);if(e||r.task){let a=e||r.task;if(!a)throw new Error("No task specified");let l=s.join(i,c.dirs.TASKS,a);await T.append(l,"task",a,"log",o),console.log(`Appended to task ${a} log.tsv`);}else await T.append(i,"project",n,"log",o),console.log(`Appended to project ${n} log.tsv`);}});});var pe,le=g(()=>{P();D();k();j();I();pe=p({description:"Read log.tsv history",options:z$1.object({project:z$1.string().optional().describe("Project slug (uses current project from $PWD if not provided)"),task:z$1.string().optional().describe("Task slug (uses current task from $PWD if not provided)")}),args:z$1.object({}),handler:async({project:t,task:e})=>{let o=h.getCurrentContext(),r=t||o.project;if(!r)throw new Error("No project specified. Use --project or run from a project/task directory");let n=s.joinHome(c.dirs.PROJECTS,r);if(e||o.task){let i=e||o.task;if(!i)throw new Error("No task specified");let a=s.join(n,c.dirs.TASKS,i),l=await T.read(a);console.log(l||`No log.tsv found for task ${i}`);}else {let i=await T.read(n);console.log(i||`No log.tsv found for project ${r}`);}}});});var me,de=g(()=>{k();V();j();x();I();me=p({description:"Create a new project with name, description, optional status, assignee and body",options:z$1.object({description:z$1.string().describe("Project description"),status:z$1.string().default("active").describe("Initial status"),assignee:z$1.string().optional().describe("Assignee agent slug"),body:z$1.string().optional().describe("Initial body/content (markdown)")}),args:z$1.object({name:z$1.string().describe("Project name")}),handler:async({name:t,description:e,status:o,assignee:r,body:n})=>{let i=s.slugify(t),a=u.getProjectDir(i);if(!await $.runHooks(a,"pre-create",{action:"pre-create",entityType:"project"}))throw new Error("Pre-create hook failed, aborting project creation");await u.createProject(i,{name:t,description:e,status:o,assignee:r,created:new Date().toISOString()},n),await T.append(a,"project",i,"created",`${t} > status is ${o}`),await $.runHooks(a,"post-create",{action:"post-create",entityType:"project"}),console.log(`Project created: ${i}`),console.log(` Path: ${a}`);}});});var ue,ge=g(()=>{k();D();ue=p({options:z$1.object({}),handler:async()=>{let t=h.getProjectFromPwd();t||(console.error("Not in a project directory"),process.exit(1)),console.log(t);}});});var ke,he=g(()=>{k();x();ke=p({description:"List all projects, optionally filtered by status",options:z$1.object({status:z$1.string().optional().describe("Filter by status")}),handler:async({status:t})=>{let e=await u.listProjects(),o=[];for(let r of e){let n=await u.getProject(r);n&&(t&&n.status!==t||o.push({slug:r,name:n.name||r,status:n.status,assignee:n.assignee}));}if(o.length===0){console.log("No projects found");return}console.log("Projects:"),console.log("---");for(let r of o)console.log(`${r.slug.padEnd(20)} ${r.name?.padEnd(30)||""} ${r.status||""} ${r.assignee||""}`);}});});var ye,je=g(()=>{k();x();ye=p({description:"Output project directory path (for cd)",options:z$1.object({}),args:z$1.object({name:z$1.string().describe("Project name (slug)")}),handler:async({name:t})=>{let e=u.getProjectDir(t);console.log(e);}});});var Te,we=g(()=>{P();D();k();V();j();x();I();Te=p({description:"Update project properties: name, description, status, assignee, or replace body",options:z$1.object({name:z$1.string().optional().describe("New name"),description:z$1.string().optional().describe("New description"),status:z$1.string().optional().describe("New status"),assignee:z$1.string().optional().describe("New assignee"),body:z$1.string().optional().describe("Replace entire body/content (markdown)")}),args:z$1.object({project:z$1.string().optional().describe("Project slug (defaults to current project from $PWD)")}),handler:async({project:t,name:e,description:o,status:r,assignee:n,body:i})=>{let a=t||h.getProjectFromPwd();if(!a)throw new Error("No project specified and not in a project directory");let l=u.getProjectDir(a),m=s.join(l,c.files.MAIN);if(!await $.runHooks(l,"pre-update",{action:"pre-update",entityType:"project"}))throw new Error("Pre-update hook failed, aborting update");let f={};if(e&&(f.name=e),o&&(f.description=o),r&&(f.status=r),n&&(f.assignee=n),Object.keys(f).length===0&&!i){console.log("No updates provided");return}if(Object.keys(f).length>0){await u.updateProject(a,f);let b=Object.entries(f).map(([C,E])=>`${C}=${E}`).join(", ");await T.append(l,"project",a,"updated",b);}i!==void 0&&(await u.updateBody(m,i),await T.append(l,"project",a,"updated",`body replaced (${i.length} chars)`)),await $.runHooks(l,"post-update",{action:"post-update",entityType:"project"}),console.log(`Project ${a} updated`);}});});var be,Pe=g(()=>{P();k();M();j();be=p({description:"Read a skill's SKILL.md file into the console for agent context",options:z$1.object({}),args:z$1.object({name:z$1.string().describe("Skill name (directory name)")}),handler:async({name:t})=>{let e=s.join(A.AIP_HOME,c.dirs.SKILLS,t),o=s.join(e,c.files.SKILL);if(!await s.fileExists(o))throw new Error(`Skill not found: ${t}
411
+ Expected at: ${o}`);await s.logFiles(o);}});});var Se,xe=g(()=>{k();V();j();x();I();Se=p({description:"Create a new task with assignee, initial status and optional body",options:z$1.object({description:z$1.string().optional().describe("Task description"),assignee:z$1.string().optional().describe("Assignee agent slug"),status:z$1.string().default("backlog").describe("Initial status"),body:z$1.string().optional().describe("Initial body/content (markdown)")}),args:z$1.object({project:z$1.string().describe("Project slug"),name:z$1.string().describe("Task name")}),handler:async({project:t,name:e,description:o,assignee:r,status:n,body:i})=>{let a=s.slugify(e),l=u.getProjectDir(t),m=u.getTaskDir(t,a);if(!await $.runHooksForContext(l,m,"pre-create",{action:"pre-create",entityType:"task",project:t}))throw new Error("Pre-create hook failed, aborting task creation");await u.createTask(t,a,{name:e,description:o,assignee:r,status:n,created:new Date().toISOString()},i),await T.append(m,"task",a,"created",e),await T.append(l,"task",a,"created",`${a} > status is ${n}`),await $.runHooksForContext(l,m,"post-create",{action:"post-create",entityType:"task",project:t}),console.log(`Task created: ${a}`),console.log(` Project: ${t}`),console.log(` Path: ${m}`);}});});var $e,ve=g(()=>{k();D();$e=p({description:"Get the current task slug from PWD",options:z$1.object({}),handler:async()=>{let t=h.getTaskFromPwd();t||(console.error("Not in a task directory"),process.exit(1)),console.log(t);}});});var Ee,Ae=g(()=>{D();k();x();Ee=p({description:"Output full task context (main.md, log.tsv) for ingestion by agents",options:z$1.object({project:z$1.string().optional().describe("Project slug (searches all projects if not provided)")}),args:z$1.object({task:z$1.string().optional().describe("Task slug (default: from $PWD)")}),handler:async({project:t,task:e})=>{let o=h.getCurrentContext(),r=e??o.task;if(!r)throw new Error("Need task slug (or cd into task dir)");let{project:n}=await u.findTask(r,t);await u.ingestTask(n,r);}});});var Oe,De=g(()=>{k();x();Oe=p({description:"List tasks, optionally filtered by project, status, assignee, or search query",options:z$1.object({project:z$1.string().optional().describe("Project slug (searches all projects if not provided)"),statuses:z$1.array(z$1.string()).default([]).describe("Filter by statuses (multiple allowed)"),assignee:z$1.string().optional().describe("Filter by assignee"),all:z$1.boolean().default(false).describe("Include all tasks (including done/blocked)"),search:z$1.string().optional().describe("Search query (matches task slug or name, case-insensitive)")}),handler:async({project:t,statuses:e,assignee:o,all:r,search:n})=>{if(e&&e.length>0){for(let d of e)if(!ot.includes(d))throw new Error(`Invalid status: ${d}. Valid values: ${ot.join(", ")}`)}let i;e&&e.length>0?i=e:r?i=ot:i=At;let a=t?[t]:await u.listProjects(),l={};for(let d of a){let f=await u.listTasks(d),b=[];for(let C of f){let E=await u.getTask(d,C);if(E&&!(i.length>0&&!i.includes(E.status||""))&&!(o&&E.assignee!==o)){if(n){let v=n.toLowerCase(),dt=C.toLowerCase().includes(v),ut=(E.name||"").toLowerCase().includes(v);if(!dt&&!ut)continue}b.push({slug:C,name:E.name||C,status:E.status,assignee:E.assignee});}}b.length>0&&(l[d]=b.sort((C,E)=>C.slug.localeCompare(E.slug)));}let m=Object.keys(l).sort();if(m.length===0){console.log("No tasks found");return}for(let d of m){console.log(`
412
+ ${d}:`),console.log("---");for(let f of l[d])console.log(`${f.slug.padEnd(20)} ${f.name?.padEnd(30)||""} ${f.status||""} ${f.assignee||""}`);}}});});var Ce,Ne=g(()=>{k();x();Ce=p({description:"Output task directory path (for cd)",options:z$1.object({project:z$1.string().optional().describe("Project slug (searches all projects if not provided)")}),args:z$1.object({task:z$1.string().describe("Task slug")}),handler:async({project:t,task:e})=>{let{project:o,task:r}=await u.findTask(e,t),n=u.getTaskDir(o,r);console.log(n);}});});var pt,xt=g(()=>{P();D();k();V();j();x();I();pt=p({description:"Update task properties: name, description, status, assignee, or replace body",options:z$1.object({name:z$1.string().optional().describe("New name"),description:z$1.string().optional().describe("New description"),status:z$1.string().optional().describe("New status"),assignee:z$1.string().optional().describe("New assignee"),project:z$1.string().optional().describe("Project slug (searches all projects if not provided)"),body:z$1.string().optional().describe("Replace entire body/content (markdown)")}),args:z$1.object({task:z$1.string().optional().describe("Task slug (default: from $PWD)")}),handler:async({project:t,task:e,name:o,description:r,status:n,assignee:i,body:a})=>{let l=h.getCurrentContext(),m=e??l.task;if(!m)throw new Error("No task specified (use --task or cd into task dir)");let{project:d}=await u.findTask(m,t),f=u.getTaskDir(d,m),b=u.getProjectDir(d),C=s.join(f,c.files.MAIN);if(!await $.runHooksForContext(b,f,"pre-update",{action:"pre-update",entityType:"task",project:d,task:m}))throw new Error("Pre-update hook failed, aborting update");let v={};if(o&&(v.name=o),r&&(v.description=r),n&&(v.status=n),i&&(v.assignee=i),Object.keys(v).length===0&&!a){console.log("No updates provided");return}if(Object.keys(v).length>0){await u.updateTask(d,m,v);let dt=Object.entries(v).map(([ut,Ke])=>`${ut}=${Ke}`).join(", ");await T.append(f,"task",m,"updated",dt);}a!==void 0&&(await u.updateBody(C,a),await T.append(f,"task",m,"updated",`body replaced (${a.length} chars)`)),v.status&&await T.append(b,"task",m,"updated",`status to ${v.status}`),await $.runHooksForContext(u.getProjectDir(d),f,"post-update",{action:"post-update",entityType:"task",project:d,task:m}),console.log(`Task ${m} updated`);}});});var Re,Ie=g(()=>{D();k();x();xt();Re=p({description:"Start a task: set status to in-progress, optionally print context",options:z$1.object({project:z$1.string().optional().describe("Project slug (searches all projects if not provided)"),ingest:z$1.boolean().default(false).describe("Also output context for this task")}),args:z$1.object({task:z$1.string().optional().describe("Task slug (default: from $PWD)")}),handler:async({project:t,task:e,ingest:o})=>{let r=h.getCurrentContext(),n=e??r.task;if(!n)throw new Error("No task specified (use --task or cd into task dir)");let{project:i}=await u.findTask(n,t);(await u.getTask(i,n))?.status!=="in-progress"&&await pt.handler({project:i,task:n,status:"in-progress"}),o&&await u.ingestTask(i,n);}});});var Le,Fe=g(()=>{k();x();I();Le=p({description:"Post-mortem analysis for a completed task",options:z$1.object({}),args:z$1.object({project:z$1.string().describe("Project slug"),task:z$1.string().describe("Task slug")}),handler:async({project:t,task:e})=>{let o=u.getTaskDir(t,e),r=await u.getTask(t,e),i=(await T.read(o)).split(`
413
+ `).filter(m=>m.trim()).length,a=[],l=r?.name||e;i>5&&a.push("High log entry count - consider breaking into smaller tasks"),l.toLowerCase().includes("implement")&&a.push("Implementation task - check if similar patterns exist to reuse"),l.toLowerCase().includes("create")&&l.toLowerCase().includes("command")&&a.push("Command creation - check existing command patterns in src/commands/"),console.log(`
414
+ === Post-Mortem Analysis ===`),console.log(`Project: ${t}`),console.log(`Task: ${e}`),console.log(`Name: ${l}`),console.log(`Status: ${r?.status||"unknown"}`),console.log(`Log entries: ${i}`),a.length>0?(console.log(`
392
415
  Suggestions:`),a.forEach(m=>console.log(` - ${m}`))):console.log(`
393
416
  No specific suggestions - task looks well-scoped`),console.log(`
394
417
  === End Post-Mortem ===
395
- `);}});});var Ue,_e=f(()=>{g();T();Ue=p({description:"Read one or more files into the console",options:z$1.object({}),args:z$1.object({paths:z$1.array(z$1.string()).describe("File paths to read")}),handler:async({paths:t})=>{await n.logFiles(...t);}});});var kt={};Ke(kt,{default:()=>L});var Po,L,ot=f(()=>{Dt();Ct();Nt();Ut();Lt();Mt();zt();Bt();Yt();Xt();ee();se();ie();ce();le();de();ge();je();ye();we();be();xe();ve();Ae();Oe();Re();St();Ie();_e();Po={agent:{create:At,current:Ot,list:Rt,path:It,start:_t},help:{api:Kt,hooks:Gt,quickstart:Jt,skill:qt,usage:Qt},hook:{create:te,run:re},log:{append:ne,read:ae},project:{create:pe,current:me,list:fe,path:ke,update:he},skill:{read:Te},task:{create:Se,current:Pe,ingest:$e,list:Ee,path:De,start:Ce,update:ct},util:{postmortem:Ne,read:Ue}},L=Po;});B();ot();T();process.on("unhandledRejection",t=>{console.error("Unhandled Rejection:",t),process.exit(1);});process.on("uncaughtException",t=>{console.error("Unhandled Exception:",t),process.exit(1);});async function Le(t){let[e,o,...r]=t;(e==="--version"||e==="-v")&&(console.log(b.version),process.exit(0));try{(!e||!n.isKeyOf(e,L))&&(await L.help.usage.handler({}),process.exit(1));let s=L[e];(!o||!n.isKeyOf(o,s))&&(await L.help.usage.handler({name:e}),process.exit(1));let i=s[o];i||(console.error(`Error: unknown command '${e} ${o}'`),console.log("Run with --help for more information"),process.exit(1)),await i.handler(i.parser.name(`${e} ${o}`).parse(r));}catch(s){console.error("Error:",n.errorMessage(s)),process.exit(1);}}var Ri=Le,Ni=L;n.isMain()&&Le(process.argv.slice(2));export{Ni as commands,Ri as default};
418
+ `);}});});var Ue,_e=g(()=>{k();j();Ue=p({description:"Read one or more files into the console",options:z$1.object({}),args:z$1.object({paths:z$1.array(z$1.string()).describe("File paths to read")}),handler:async({paths:t})=>{await s.logFiles(...t);}});});var yt={};Me(yt,{default:()=>K});var $o,K,rt=g(()=>{Ct();Rt();Lt();Ut();Ht();zt();Jt();Zt();Xt();ee();re();ie();ce();le();de();ge();he();je();we();Pe();xe();ve();Ae();De();Ne();Ie();xt();Fe();_e();$o={agent:{create:Dt,current:Nt,list:It,path:Ft,start:_t},help:{api:Mt,hooks:Bt,quickstart:Wt,skill:Qt,usage:te},hook:{create:oe,run:ne},log:{append:ae,read:pe},project:{create:me,current:ue,list:ke,path:ye,update:Te},skill:{read:be},task:{create:Se,current:$e,ingest:Ee,list:Oe,path:Ce,start:Re,update:pt},util:{postmortem:Le,read:Ue}},K=$o;});W();rt();j();process.on("unhandledRejection",t=>{console.error("Unhandled Rejection:",t),process.exit(1);});process.on("uncaughtException",t=>{console.error("Unhandled Exception:",t),process.exit(1);});async function He(t){let[e,o,...r]=t;(e==="--version"||e==="-v")&&(console.log(S.version),process.exit(0));try{(!e||!s.isKeyOf(e,K))&&(await K.help.usage.handler({}),process.exit(1));let n=K[e];(!o||!s.isKeyOf(o,n))&&(await K.help.usage.handler({name:e}),process.exit(1));let i=n[o];i||(console.error(`Error: unknown command '${e} ${o}'`),console.log("Run with --help for more information"),process.exit(1)),await i.handler(i.parser.name(`${e} ${o}`).parse(r));}catch(n){console.error("Error:",s.errorMessage(n)),process.exit(1);}}var Hi=He,Ki=K;s.isMain()&&He(process.argv.slice(2));export{Ki as commands,Hi as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-projects",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "type": "module",
5
5
  "description": "Useful CLI for AI agents to create and manage projects, tasks, skills and agents",
6
6
  "main": "dist/index.js",