ai-projects 1.2.0 → 1.4.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/dist/index.d.ts +53 -35
- package/dist/index.js +156 -426
- package/package.json +8 -6
package/dist/index.d.ts
CHANGED
|
@@ -67,12 +67,18 @@ declare const commands: {
|
|
|
67
67
|
}, {
|
|
68
68
|
[x: string]: any;
|
|
69
69
|
}>>;
|
|
70
|
-
readonly
|
|
70
|
+
readonly quickstart: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
|
|
71
71
|
[x: string]: any;
|
|
72
72
|
}, {
|
|
73
73
|
[x: string]: any;
|
|
74
74
|
}>>;
|
|
75
|
-
readonly
|
|
75
|
+
readonly skill: CommandDef<zod.ZodObject<{
|
|
76
|
+
mode: zod.ZodDefault<zod.ZodEnum<["md", "claude", "hermes"]>>;
|
|
77
|
+
}, "strip", zod.ZodTypeAny, {
|
|
78
|
+
mode: "md" | "claude" | "hermes";
|
|
79
|
+
}, {
|
|
80
|
+
mode?: "md" | "claude" | "hermes" | undefined;
|
|
81
|
+
}>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
|
|
76
82
|
[x: string]: any;
|
|
77
83
|
}, {
|
|
78
84
|
[x: string]: any;
|
|
@@ -121,14 +127,17 @@ declare const commands: {
|
|
|
121
127
|
description: zod.ZodString;
|
|
122
128
|
status: zod.ZodDefault<zod.ZodString>;
|
|
123
129
|
assignee: zod.ZodOptional<zod.ZodString>;
|
|
130
|
+
summary: zod.ZodOptional<zod.ZodString>;
|
|
124
131
|
}, "strip", zod.ZodTypeAny, {
|
|
125
132
|
status: string;
|
|
126
133
|
description: string;
|
|
127
134
|
assignee?: string | undefined;
|
|
135
|
+
summary?: string | undefined;
|
|
128
136
|
}, {
|
|
129
137
|
description: string;
|
|
130
138
|
status?: string | undefined;
|
|
131
139
|
assignee?: string | undefined;
|
|
140
|
+
summary?: string | undefined;
|
|
132
141
|
}>, zod.ZodObject<{
|
|
133
142
|
name: zod.ZodString;
|
|
134
143
|
}, "strip", zod.ZodTypeAny, {
|
|
@@ -197,116 +206,125 @@ declare const commands: {
|
|
|
197
206
|
readonly task: {
|
|
198
207
|
readonly create: CommandDef<zod.ZodObject<{
|
|
199
208
|
description: zod.ZodOptional<zod.ZodString>;
|
|
200
|
-
priority: zod.ZodOptional<zod.ZodEnum<["low", "medium", "high"]>>;
|
|
201
209
|
assignee: zod.ZodOptional<zod.ZodString>;
|
|
202
|
-
status: zod.ZodDefault<zod.
|
|
210
|
+
status: zod.ZodDefault<zod.ZodString>;
|
|
211
|
+
summary: zod.ZodOptional<zod.ZodString>;
|
|
203
212
|
}, "strip", zod.ZodTypeAny, {
|
|
204
|
-
status:
|
|
213
|
+
status: string;
|
|
205
214
|
description?: string | undefined;
|
|
206
215
|
assignee?: string | undefined;
|
|
207
|
-
|
|
216
|
+
summary?: string | undefined;
|
|
208
217
|
}, {
|
|
209
|
-
status?:
|
|
218
|
+
status?: string | undefined;
|
|
210
219
|
description?: string | undefined;
|
|
211
220
|
assignee?: string | undefined;
|
|
212
|
-
|
|
221
|
+
summary?: string | undefined;
|
|
213
222
|
}>, zod.ZodObject<{
|
|
214
223
|
project: zod.ZodString;
|
|
215
224
|
name: zod.ZodString;
|
|
216
225
|
}, "strip", zod.ZodTypeAny, {
|
|
217
|
-
name: string;
|
|
218
226
|
project: string;
|
|
219
|
-
}, {
|
|
220
227
|
name: string;
|
|
228
|
+
}, {
|
|
221
229
|
project: string;
|
|
230
|
+
name: string;
|
|
222
231
|
}>>;
|
|
223
232
|
readonly current: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
|
|
224
233
|
[x: string]: any;
|
|
225
234
|
}, {
|
|
226
235
|
[x: string]: any;
|
|
227
236
|
}>>;
|
|
228
|
-
readonly ingest: CommandDef<zod.ZodObject<{
|
|
237
|
+
readonly ingest: CommandDef<zod.ZodObject<{
|
|
229
238
|
project: zod.ZodOptional<zod.ZodString>;
|
|
230
|
-
task: zod.ZodOptional<zod.ZodString>;
|
|
231
239
|
}, "strip", zod.ZodTypeAny, {
|
|
232
240
|
project?: string | undefined;
|
|
233
|
-
task?: string | undefined;
|
|
234
241
|
}, {
|
|
235
242
|
project?: string | undefined;
|
|
243
|
+
}>, zod.ZodObject<{
|
|
244
|
+
task: zod.ZodOptional<zod.ZodString>;
|
|
245
|
+
}, "strip", zod.ZodTypeAny, {
|
|
246
|
+
task?: string | undefined;
|
|
247
|
+
}, {
|
|
236
248
|
task?: string | undefined;
|
|
237
249
|
}>>;
|
|
238
250
|
readonly list: CommandDef<zod.ZodObject<{
|
|
239
251
|
project: zod.ZodOptional<zod.ZodString>;
|
|
240
|
-
|
|
252
|
+
statuses: zod.ZodDefault<zod.ZodArray<zod.ZodString, "many">>;
|
|
241
253
|
assignee: zod.ZodOptional<zod.ZodString>;
|
|
254
|
+
all: zod.ZodDefault<zod.ZodBoolean>;
|
|
255
|
+
search: zod.ZodOptional<zod.ZodString>;
|
|
242
256
|
}, "strip", zod.ZodTypeAny, {
|
|
243
|
-
|
|
257
|
+
statuses: string[];
|
|
258
|
+
all: boolean;
|
|
244
259
|
project?: string | undefined;
|
|
245
260
|
assignee?: string | undefined;
|
|
261
|
+
search?: string | undefined;
|
|
246
262
|
}, {
|
|
247
|
-
status?: string | undefined;
|
|
248
263
|
project?: string | undefined;
|
|
249
264
|
assignee?: string | undefined;
|
|
265
|
+
statuses?: string[] | undefined;
|
|
266
|
+
all?: boolean | undefined;
|
|
267
|
+
search?: string | undefined;
|
|
250
268
|
}>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
|
|
251
269
|
[x: string]: any;
|
|
252
270
|
}, {
|
|
253
271
|
[x: string]: any;
|
|
254
272
|
}>>;
|
|
255
|
-
readonly path: CommandDef<zod.ZodObject<{
|
|
256
|
-
project: zod.ZodString
|
|
273
|
+
readonly path: CommandDef<zod.ZodObject<{
|
|
274
|
+
project: zod.ZodOptional<zod.ZodString>;
|
|
275
|
+
}, "strip", zod.ZodTypeAny, {
|
|
276
|
+
project?: string | undefined;
|
|
277
|
+
}, {
|
|
278
|
+
project?: string | undefined;
|
|
279
|
+
}>, zod.ZodObject<{
|
|
257
280
|
task: zod.ZodString;
|
|
258
281
|
}, "strip", zod.ZodTypeAny, {
|
|
259
|
-
project: string;
|
|
260
282
|
task: string;
|
|
261
283
|
}, {
|
|
262
|
-
project: string;
|
|
263
284
|
task: string;
|
|
264
285
|
}>>;
|
|
265
286
|
readonly start: CommandDef<zod.ZodObject<{
|
|
287
|
+
project: zod.ZodOptional<zod.ZodString>;
|
|
266
288
|
ingest: zod.ZodDefault<zod.ZodBoolean>;
|
|
267
289
|
}, "strip", zod.ZodTypeAny, {
|
|
268
290
|
ingest: boolean;
|
|
291
|
+
project?: string | undefined;
|
|
269
292
|
}, {
|
|
293
|
+
project?: string | undefined;
|
|
270
294
|
ingest?: boolean | undefined;
|
|
271
295
|
}>, zod.ZodObject<{
|
|
272
|
-
|
|
273
|
-
task: zod.ZodString;
|
|
296
|
+
task: zod.ZodOptional<zod.ZodString>;
|
|
274
297
|
}, "strip", zod.ZodTypeAny, {
|
|
275
|
-
|
|
276
|
-
task: string;
|
|
298
|
+
task?: string | undefined;
|
|
277
299
|
}, {
|
|
278
|
-
|
|
279
|
-
task: string;
|
|
300
|
+
task?: string | undefined;
|
|
280
301
|
}>>;
|
|
281
302
|
readonly update: CommandDef<zod.ZodObject<{
|
|
282
303
|
name: zod.ZodOptional<zod.ZodString>;
|
|
283
304
|
description: zod.ZodOptional<zod.ZodString>;
|
|
284
|
-
status: zod.ZodOptional<zod.
|
|
285
|
-
priority: zod.ZodOptional<zod.ZodEnum<["low", "medium", "high"]>>;
|
|
305
|
+
status: zod.ZodOptional<zod.ZodString>;
|
|
286
306
|
assignee: zod.ZodOptional<zod.ZodString>;
|
|
307
|
+
project: zod.ZodOptional<zod.ZodString>;
|
|
287
308
|
summary: zod.ZodOptional<zod.ZodString>;
|
|
288
309
|
}, "strip", zod.ZodTypeAny, {
|
|
289
|
-
|
|
310
|
+
project?: string | undefined;
|
|
311
|
+
status?: string | undefined;
|
|
290
312
|
description?: string | undefined;
|
|
291
313
|
name?: string | undefined;
|
|
292
314
|
assignee?: string | undefined;
|
|
293
315
|
summary?: string | undefined;
|
|
294
|
-
priority?: "low" | "medium" | "high" | undefined;
|
|
295
316
|
}, {
|
|
296
|
-
|
|
317
|
+
project?: string | undefined;
|
|
318
|
+
status?: string | undefined;
|
|
297
319
|
description?: string | undefined;
|
|
298
320
|
name?: string | undefined;
|
|
299
321
|
assignee?: string | undefined;
|
|
300
322
|
summary?: string | undefined;
|
|
301
|
-
priority?: "low" | "medium" | "high" | undefined;
|
|
302
323
|
}>, zod.ZodObject<{
|
|
303
|
-
project: zod.ZodOptional<zod.ZodString>;
|
|
304
324
|
task: zod.ZodOptional<zod.ZodString>;
|
|
305
325
|
}, "strip", zod.ZodTypeAny, {
|
|
306
|
-
project?: string | undefined;
|
|
307
326
|
task?: string | undefined;
|
|
308
327
|
}, {
|
|
309
|
-
project?: string | undefined;
|
|
310
328
|
task?: string | undefined;
|
|
311
329
|
}>>;
|
|
312
330
|
};
|
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 {exec
|
|
2
|
+
import {z as z$1}from'zod';import {parser}from'zod-opts';import {spawn,exec}from'child_process';import J from'fs/promises';import T from'lodash';import B from'moment';import M from'path';import {fileURLToPath}from'url';import {inspect}from'util';import Ze from'dotenv';import Ve from'fs';import St from'yaml';var Fe=Object.defineProperty;var f=(t,e)=>()=>(t&&(e=t(t=0)),e);var He=(t,e)=>{for(var o in e)Fe(t,o,{get:e[o],enumerable:true});};var S,W=f(()=>{S={name:"ai-projects",version:"1.4.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"},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[u,l]of Object.entries(i))a[u]={type:l};let d=parser().options(a);if(r){let u=r.shape,l=Object.entries(u).map(([g,P])=>({name:g,type:P}));l.length>0&&(d=d.args(l));}return e&&(d=d.description(e)),{description:e,options:o,args:r,parser:d,handler:n,cli:u=>n(d.parse(u))}}var k=f(()=>{});var w,s,b=f(()=>{w={REPO:fileURLToPath(import.meta.url.replace(/\/(dist|src)\/.*/,"/")),join:(...t)=>M.join(...t),onRepo:(...t)=>w.join(w.REPO,...t),async ensureDir(t){await J.mkdir(t,{recursive:true});},async write(t,e){await w.ensureDir(M.dirname(t)),await J.writeFile(t,e,"utf8");},async read(t){return J.readFile(t,"utf8")},async readRepo(...t){return w.read(w.onRepo(...t))},async readMany(...t){return (await Promise.all(t.map(async o=>{if(await w.fileExists(o)){let r=await w.read(o);return `# ${o}
|
|
3
3
|
|
|
4
4
|
${r}`}return ""}))).filter(Boolean)},async logFiles(...t){let e=await w.readMany(...t);console.log(e.join(`
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
`));},dumpCommandMapLines(t,e){let o=e?
|
|
8
|
+
`));},dumpCommandMapLines(t,e){let o=e?T.pick(t,e):t,r=[];for(let[n,i]of w.entriesOf(o))r.push(`${n} {${Object.keys(i).join("|")}}`);return r},async fileExists(t){try{return await J.access(t),!0}catch{return false}},async listDir(t){try{return await J.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)=>T.isArray(t)?t.map(o=>w.omitByDeep(o,e)):T.isPlainObject(t)?T.mapValues(T.omitBy(t,e),o=>w.omitByDeep(o,e)):t,omitNilsDeep:t=>w.omitByDeep(t,T.isNil),omitUndefinedsDeep:t=>w.omitByDeep(t,T.isUndefined),cloneDeep:t=>T.cloneDeep(t),int:t=>Number.parseInt(t,10),keysOf:t=>Object.keys(t),entriesOf:t=>Object.entries(t),isKeyOf:(t,e)=>!T.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(T.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 T.extend(e,t)},isPromise:t=>T.isObject(t)&&"catch"in t,delay:t=>{let e=T.isObject(t)?w.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=>T.memoize(t,w.memoizeKey),toMS:t=>B.duration(t).asMilliseconds(),toSecs:t=>B.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(T.isObject(i)){if(r.has(i))return "[Circular]";r.add(i);}return T.isFunction(e)?e(n,i):i},o)},dump:t=>w.oneLine(w.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)=>
|
|
13
|
-
${
|
|
12
|
+
`).replace(/ {2,}/g," ").trim(),oneLine:t=>t.replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/ +/g," ").trim(),fuzzySearch:(t,e)=>T.includes(T.toLower(t||""),T.toLower(e||"")),elapsed:(t,e=Date.now())=>B.duration(B(e).diff(t||0)),iso:t=>B.utc(t).toISOString(),isoDate:t=>w.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=w;});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.md",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 Ye,bt,U,Qe,y,I=f(()=>{$();Ye=()=>{let t=fileURLToPath(import.meta.url),e=M.dirname(t),o=10;for(let r=0;r<o;r++)try{if(Ve.existsSync(M.join(e,"package.json")))return e;let n=M.dirname(e);if(n===e)break;e=n;}catch{break}return process.cwd()},bt=Ye(),U=process.env.AIP_HOME;U||(Ze.config({path:M.join(bt,".env"),quiet:true}),U=process.env.AIP_HOME);if(!U){U=process.cwd();let t=U.split(M.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(M.sep);break}}}Qe={ROOT:bt,AIP_HOME:U},y=Qe;});var xt,Z,dt,V,Et=f(()=>{b();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:St.parse(o[1]),content:o[2].trim()}:null},Z=async(t,e,o="")=>{let n=`---
|
|
13
|
+
${St.stringify(e).trim()}
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
${o}`.trim();await s.write(t,n+`
|
|
17
|
-
`);},
|
|
18
|
-
Expected at: ${o}`);console.log(e);}});});var
|
|
19
|
-
Expected at: ${o}`);let i=[r,o];await s.logFiles(...i);}});});var
|
|
20
|
-
`,r.length>0||n.length>0){let
|
|
17
|
+
`);},dt=async(t,e)=>{let o=await s.read(t),r=xt(o);if(!r)throw new Error(`No frontmatter found in ${t}`);let n={...r.frontmatter,...e};return await Z(t,n,r.content),n},V=async t=>{let e=await s.read(t),o=xt(e);if(!o)throw new Error(`No frontmatter found in ${t}`);return o.frontmatter};});var K,X,At,$t,Xe,to,m,x=f(()=>{$();I();Et();b();K=(a=>(a.BACKLOG="backlog",a.IN_PROGRESS="in-progress",a.ONGOING="ongoing",a.DONE="done",a.BLOCKED="blocked",a.TO_DO="to-do",a))(K||{}),X=Object.values(K),At=["backlog","in-progress","ongoing"],$t=[c.dirs.HOOKS,c.dirs.INPUTS,c.dirs.OUTPUTS,c.dirs.SCRIPTS],Xe=[c.dirs.TASKS,...$t],to={getProjectDir(t){return s.join(y.AIP_HOME,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(y.AIP_HOME,c.dirs.AGENTS,t)},async listProjects(){let t=s.join(y.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(y.AIP_HOME,c.dirs.AGENTS);return await s.fileExists(t)?await s.listDir(t):[]},async createProject(t,e){let o=this.getProjectDir(t);return await s.ensureDir(o),await Promise.all(Xe.map(r=>s.ensureDir(s.join(o,r)))),await Z(s.join(o,c.files.MAIN),e),await s.write(s.join(o,c.files.STATUS),""),o},async createTask(t,e,o){let r=this.getTaskDir(t,e);return await s.ensureDir(r),await Promise.all($t.map(n=>s.ensureDir(s.join(r,n)))),await Z(s.join(r,c.files.MAIN),o),await s.write(s.join(r,c.files.STATUS),""),r},async createAgent(t,e){let o=this.getAgentDir(t);return await s.ensureDir(o),await Z(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 V(e):null},async getTask(t,e){let o=s.join(this.getTaskDir(t,e),c.files.MAIN);return await s.fileExists(o)?await V(o):null},async getAgent(t){let e=s.join(this.getAgentDir(t),c.files.MAIN);return await s.fileExists(e)?await V(e):null},async updateProject(t,e){let o=s.join(this.getProjectDir(t),c.files.MAIN);return await dt(o,e)},async updateTask(t,e,o){let r=s.join(this.getTaskDir(t,e),c.files.MAIN);if((await V(r))?.status==="ongoing")throw new Error("Cannot update ongoing task. Should be done by user or update manually");return await dt(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.STATUS)];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.STATUS),...o.map(n=>s.join(this.getTaskDir(t,n),c.files.MAIN))];await s.logFiles(...r);},async ingestFiles(t){await s.logFiles(...t);}},m=to;});var vt,Ot=f(()=>{k();b();x();vt=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 m.createAgent(r,{name:t,description:e,status:o,created:new Date().toISOString()}),console.log(`Agent created: ${r}`),console.log(` Path: ${m.getAgentDir(r)}`);}});});var Dt,Ct=f(()=>{k();Dt=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,Nt=f(()=>{k();x();It=p({options:z$1.object({}),handler:async()=>{let t=await m.listAgents(),e=[];for(let o of t){let r=await m.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 Rt,Ut=f(()=>{$();k();I();b();Rt=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(y.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,Lt=f(()=>{$();k();I();b();_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(y.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 Ft,Ht,so,Mt,Kt=f(()=>{k();Ft=t=>{let e=t.shape,o=[];for(let[r,n]of Object.entries(e)){let i=n._def,a="unknown",d,u;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),u=i.defaultValue()),i.description&&(d=i.description);let l=i.typeName!=="ZodOptional"&&i.typeName!=="ZodDefault";o.push({name:r,type:a,required:l,description:d,defaultValue:u});}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"},so=(t,e,o)=>{let r=Ft(o.options),n=o.args?Ft(o.args):[],i=o.description,a=`\`${t} ${e}\``;if(i&&(a+=`: ${i}`),a+=`
|
|
20
|
+
`,r.length>0||n.length>0){let u=[];for(let l of n){let g=l.required?`<${l.name}>`:`[${l.name}]`,P=l.description||"";l.defaultValue!==void 0&&(P+=P?` (default: ${l.defaultValue})`:`(default: ${l.defaultValue})`),u.push(`\xB7 ${g}${P?": "+P:""}`);}for(let l of r){let g=l.description||"";l.defaultValue!==void 0&&(g+=g?` (default: ${l.defaultValue})`:`(default: ${l.defaultValue})`),u.push(`\xB7 --${l.name}${g?": "+g:""}`);}a+=u.join(`
|
|
21
21
|
`)+`
|
|
22
22
|
`;}return a+=`
|
|
23
|
-
`,a},
|
|
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(()=>(tt(),gt)),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 d=n[a];e+=so(r,a,d);}}console.log(e);}});});var io,Gt,zt=f(()=>{k();io=`# AIP Hooks
|
|
24
24
|
|
|
25
25
|
Automated scripts that run before/after project/task actions.
|
|
26
26
|
|
|
@@ -200,7 +200,65 @@ 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
|
-
`,
|
|
203
|
+
`,Gt=p({description:"Hook types, env vars, and patterns",options:z$1.object({}),handler:async()=>{console.log(io);}});});var D,co,Wt,Jt=f(()=>{W();k();D=Object.keys(S.bin)[0],co=`# Quick Start
|
|
204
|
+
|
|
205
|
+
## New Task/Project
|
|
206
|
+
|
|
207
|
+
\`\`\`bash
|
|
208
|
+
# 1. Create project (if needed)
|
|
209
|
+
${D} project create "my-project" --description "What I'm building"
|
|
210
|
+
|
|
211
|
+
# 2. Create task
|
|
212
|
+
${D} task create my-project "first-task" --description "Start here"
|
|
213
|
+
|
|
214
|
+
# 3. Navigate to task
|
|
215
|
+
cd $(${D} task path first-task)
|
|
216
|
+
|
|
217
|
+
# 4. Start working (implicit from PWD)
|
|
218
|
+
${D} task start
|
|
219
|
+
# \u2192 sets status to in-progress
|
|
220
|
+
|
|
221
|
+
# 5. Work session
|
|
222
|
+
# Log progress: ${D} task update --summary "API integration complete"
|
|
223
|
+
# Save: outputs/ to deliver, inputs/ for data
|
|
224
|
+
\`\`\`
|
|
225
|
+
|
|
226
|
+
## Resuming
|
|
227
|
+
|
|
228
|
+
\`\`\`bash
|
|
229
|
+
# Find your tasks (searches all projects)
|
|
230
|
+
${D} task list
|
|
231
|
+
|
|
232
|
+
# Navigate to task
|
|
233
|
+
cd $(${D} task path task-slug)
|
|
234
|
+
|
|
235
|
+
# All commands work implicitly from PWD:
|
|
236
|
+
${D} task start # Start working (sets status to in-progress)
|
|
237
|
+
\`\`\`
|
|
238
|
+
|
|
239
|
+
## Completing
|
|
240
|
+
|
|
241
|
+
\`\`\`bash
|
|
242
|
+
# Mark done (implicit from PWD)
|
|
243
|
+
${D} task update --status done --summary "What I built"
|
|
244
|
+
\`\`\`
|
|
245
|
+
|
|
246
|
+
**Note:** All task commands accept an optional task slug, but use PWD if not provided. Navigate with \`cd\` first for smoother workflow.
|
|
247
|
+
|
|
248
|
+
## Structure
|
|
249
|
+
|
|
250
|
+
\`\`\`
|
|
251
|
+
$AIP_HOME/projects/slug/
|
|
252
|
+
\u251C\u2500\u2500 main.md # Goals (read first)
|
|
253
|
+
\u251C\u2500\u2500 status.md # Log (append every session)
|
|
254
|
+
\u2514\u2500\u2500 tasks/task/
|
|
255
|
+
\u251C\u2500\u2500 main.md # Task definition
|
|
256
|
+
\u2514\u2500\u2500 status.md # Updates
|
|
257
|
+
\`\`\`
|
|
258
|
+
|
|
259
|
+
**Status format:** \`[YYYY-MM-DD HH:MM] message\`
|
|
260
|
+
**Example:** \`[2026-03-30 14:30] API integration complete\`
|
|
261
|
+
`,Wt=p({description:"Quick start guide for new users",options:z$1.object({}),handler:async()=>{console.log(co);}});});var po,lo,Zt,Vt,qt,Yt,Qt,et,ot,kt,Xt,te=f(()=>{W();$();k();x();po=Object.values(K).join("|"),{PROJECTS:lo,TASKS:Zt,HOOKS:Vt,INPUTS:qt,OUTPUTS:Yt,SCRIPTS:Qt}=c.dirs,{MAIN:et,STATUS:ot}=c.files,kt=`# AIP - Project Management Skill
|
|
204
262
|
|
|
205
263
|
Automated project and task creation with proper structure, front-matter, and file organization.
|
|
206
264
|
|
|
@@ -213,21 +271,21 @@ Streamline creation of new projects and tasks with the correct directory structu
|
|
|
213
271
|
Every project follows this structure:
|
|
214
272
|
|
|
215
273
|
\`\`\`
|
|
216
|
-
$AIP_HOME/
|
|
217
|
-
\u251C\u2500\u2500
|
|
218
|
-
\u251C\u2500\u2500
|
|
219
|
-
\u251C\u2500\u2500
|
|
220
|
-
\u251C\u2500\u2500
|
|
221
|
-
\u251C\u2500\u2500
|
|
222
|
-
\u251C\u2500\u2500
|
|
223
|
-
\u2514\u2500\u2500
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
274
|
+
$AIP_HOME/${lo}/{project-slug}/
|
|
275
|
+
\u251C\u2500\u2500 ${et} # Primary context: goals, objectives, scope, data
|
|
276
|
+
\u251C\u2500\u2500 ${ot} # Chronological log of status updates
|
|
277
|
+
\u251C\u2500\u2500 ${Vt}/ # pre|post-{create,start,update,complete}.*
|
|
278
|
+
\u251C\u2500\u2500 ${Yt}/ # Deliverables (reports, code, final files)
|
|
279
|
+
\u251C\u2500\u2500 ${qt}/ # External data (API responses, downloads)
|
|
280
|
+
\u251C\u2500\u2500 ${Qt}/ # Automation (bash/python/js)
|
|
281
|
+
\u2514\u2500\u2500 ${Zt}/
|
|
282
|
+
\u2514\u2500\u2500 {task-slug}/
|
|
283
|
+
\u251C\u2500\u2500 ${et} # Task definition with front-matter
|
|
284
|
+
\u251C\u2500\u2500 ${ot} # Single-line updates per work session
|
|
285
|
+
\u251C\u2500\u2500 ${Vt}/ # Task-level hooks
|
|
286
|
+
\u251C\u2500\u2500 ${Yt}/ # Task-specific deliverables
|
|
287
|
+
\u251C\u2500\u2500 ${qt}/ # Task-specific data files
|
|
288
|
+
\u2514\u2500\u2500 ${Qt}/ # Task-specific automation
|
|
231
289
|
\`\`\`
|
|
232
290
|
|
|
233
291
|
## File Purposes
|
|
@@ -246,7 +304,7 @@ $AIP_HOME/projects/{project-slug}/
|
|
|
246
304
|
name: Clear Title
|
|
247
305
|
description: One-line summary for search
|
|
248
306
|
assignee: agent-name
|
|
249
|
-
status:
|
|
307
|
+
status: ${po}
|
|
250
308
|
created: YYYY-MM-DD
|
|
251
309
|
---
|
|
252
310
|
\`\`\`
|
|
@@ -256,73 +314,33 @@ created: YYYY-MM-DD
|
|
|
256
314
|
**When to update:** Only when scope/goals change (rare)
|
|
257
315
|
|
|
258
316
|
### \`status.md\` - Activity Log (Append Only)
|
|
259
|
-
**What goes here:**
|
|
260
|
-
- **Tasks:** Single-line updates per work session
|
|
261
|
-
\`\`\`markdown
|
|
262
|
-
### 2026-03-17 14:30 - Started implementation
|
|
263
|
-
\u2705 Completed API integration. Next: testing.
|
|
264
|
-
\`\`\`
|
|
265
|
-
- **Projects:** Packed summary when task completes
|
|
266
|
-
\`\`\`markdown
|
|
267
|
-
### 2026-03-17 18:30 - Task: apply-optimizations \u2705
|
|
268
|
-
Implemented 7 optimizations (P0+P1). Config improved, fallbacks enabled. Details: tasks/apply-optimizations/
|
|
269
|
-
\`\`\`
|
|
317
|
+
**What goes here:** Single-line timestamped entries
|
|
270
318
|
|
|
271
|
-
**
|
|
319
|
+
**Task examples:**
|
|
320
|
+
\`\`\`markdown
|
|
321
|
+
[2026-03-17 14:30] Task created: optimize-config
|
|
322
|
+
[2026-03-17 15:45] Updated: status=in-progress
|
|
323
|
+
[2026-03-17 16:20] API integration complete
|
|
324
|
+
\`\`\`
|
|
272
325
|
|
|
273
|
-
**
|
|
326
|
+
**Project example:**
|
|
327
|
+
\`\`\`markdown
|
|
328
|
+
[2026-03-17 16:00] Task completed: gather-requirements (details: tasks/gather-requirements/)
|
|
329
|
+
\`\`\`
|
|
274
330
|
|
|
275
|
-
**When to update:**
|
|
276
|
-
- **Tasks:** Every work session (append 1 line)
|
|
277
|
-
- **Projects:** When task completes (append 1 packed line)
|
|
331
|
+
**When to update:** Every work session (tasks) or task completion (projects)
|
|
278
332
|
|
|
279
333
|
### \`outputs/\` - Deliverables
|
|
280
|
-
**What
|
|
281
|
-
|
|
282
|
-
- Generated code files
|
|
283
|
-
- Processed data
|
|
284
|
-
- Artifacts meant for use outside the project
|
|
285
|
-
|
|
286
|
-
**Examples:**
|
|
287
|
-
- \`outputs/final-report.md\`
|
|
288
|
-
- \`outputs/optimized-config.yaml\`
|
|
289
|
-
- \`outputs/website-code.zip\`
|
|
290
|
-
- \`outputs/database-migration.sql\`
|
|
291
|
-
|
|
292
|
-
**When to write:** When task produces tangible results
|
|
334
|
+
**What:** Final deliverables (reports, code, data)
|
|
335
|
+
**Examples:** \`outputs/report.md\`, \`outputs/code.zip\`
|
|
293
336
|
|
|
294
337
|
### \`inputs/\` - External Data
|
|
295
|
-
**What
|
|
296
|
-
|
|
297
|
-
- Downloaded files (web pages, datasets)
|
|
298
|
-
- Reference documents used in process
|
|
299
|
-
- Raw data before processing
|
|
300
|
-
|
|
301
|
-
**Examples:**
|
|
302
|
-
- \`inputs/api-response-2026-03-17.json\`
|
|
303
|
-
- \`inputs/downloaded-docs.zip\`
|
|
304
|
-
- \`inputs/webpage-scrape.md\`
|
|
305
|
-
|
|
306
|
-
**When to write:** When fetching external data for processing
|
|
338
|
+
**What:** External data (API responses, downloads)
|
|
339
|
+
**Examples:** \`inputs/api.json\`, \`inputs/data.csv\`
|
|
307
340
|
|
|
308
341
|
### \`scripts/\` - Automation
|
|
309
|
-
**What
|
|
310
|
-
|
|
311
|
-
- Python scripts for complex logic
|
|
312
|
-
- JavaScript/TypeScript for tooling
|
|
313
|
-
- Any code that helps complete the task
|
|
314
|
-
|
|
315
|
-
**Language Choice:**
|
|
316
|
-
- **Bash**: Simple file ops, command chaining, system commands
|
|
317
|
-
- **Python**: Data processing, API calls, complex logic
|
|
318
|
-
- **JavaScript/TypeScript**: Web scraping, Node.js tooling
|
|
319
|
-
|
|
320
|
-
**Examples:**
|
|
321
|
-
- \`scripts/deploy.sh\`
|
|
322
|
-
- \`scripts/process-data.py\`
|
|
323
|
-
- \`scripts/scrape-docs.js\`
|
|
324
|
-
|
|
325
|
-
**When to write:** When automation saves time or improves reliability
|
|
342
|
+
**What:** Automation scripts (bash, python, js)
|
|
343
|
+
**Examples:** \`scripts/deploy.sh\`, \`scripts/process.py\`
|
|
326
344
|
|
|
327
345
|
## Usage
|
|
328
346
|
|
|
@@ -332,369 +350,80 @@ created: YYYY-MM-DD
|
|
|
332
350
|
# Via AIP CLI
|
|
333
351
|
aip project create "optimize-hermes-config" \\
|
|
334
352
|
--description "Analyze and optimize Hermes Agent configuration" \\
|
|
335
|
-
--assignee basic
|
|
336
|
-
--priority high
|
|
353
|
+
--assignee basic
|
|
337
354
|
\`\`\`
|
|
338
355
|
|
|
339
356
|
### Create New Task in Existing Project
|
|
340
357
|
|
|
341
358
|
\`\`\`bash
|
|
342
359
|
aip task create "optimize-hermes-config" "apply-config-changes" \\
|
|
343
|
-
--description "Implement safe optimizations
|
|
344
|
-
--assignee basic
|
|
345
|
-
--priority high
|
|
360
|
+
--description "Implement safe optimizations" \\
|
|
361
|
+
--assignee basic
|
|
346
362
|
\`\`\`
|
|
347
363
|
|
|
348
364
|
### Navigate to Project/Task
|
|
349
365
|
|
|
350
366
|
\`\`\`bash
|
|
351
367
|
cd $(aip project path optimize-hermes-config)
|
|
352
|
-
cd $(aip task path
|
|
368
|
+
cd $(aip task path apply-config-changes)
|
|
353
369
|
\`\`\`
|
|
354
370
|
|
|
355
|
-
### Update Task Status
|
|
371
|
+
### Update Task Status (implicit from PWD)
|
|
356
372
|
|
|
357
373
|
\`\`\`bash
|
|
358
|
-
aip task update
|
|
359
|
-
aip task update
|
|
374
|
+
aip task update --status done
|
|
375
|
+
aip task update --summary "Completed implementation"
|
|
360
376
|
\`\`\`
|
|
361
377
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
**When working on a task:**
|
|
365
|
-
|
|
366
|
-
1. **Read Context**
|
|
367
|
-
\`\`\`bash
|
|
368
|
-
cat /state/projects/{project}/main.md
|
|
369
|
-
cat /state/projects/{project}/tasks/{task}/main.md
|
|
370
|
-
cat /state/projects/{project}/tasks/{task}/status.md
|
|
371
|
-
\`\`\`
|
|
372
|
-
|
|
373
|
-
2. **Do Work**
|
|
374
|
-
- Create scripts in \`scripts/\` if automation helps
|
|
375
|
-
- Save external data to \`inputs/\`
|
|
376
|
-
- Place deliverables in \`outputs/\`
|
|
378
|
+
**Note:** All task commands accept optional task slug, but use PWD if not provided. Navigate with \`cd\` first for smoother workflow.
|
|
377
379
|
|
|
378
|
-
|
|
379
|
-
\`\`\`markdown
|
|
380
|
-
### YYYY-MM-DD HH:MM - Brief description
|
|
381
|
-
\u2705 What was accomplished. Next: what's next.
|
|
382
|
-
\`\`\`
|
|
380
|
+
## Work Session
|
|
383
381
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
382
|
+
1. **Read:** \`main.md\` + \`status.md\`
|
|
383
|
+
2. **Work:** Save data to \`inputs/\`, deliverables to \`outputs/\`
|
|
384
|
+
3. **Log:** Append to \`status.md\`: \`[timestamp] message\`
|
|
385
|
+
4. **Complete:** Set status=\`done\`, summarize to project \`status.md\`
|
|
388
386
|
|
|
389
387
|
## Best Practices
|
|
390
388
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
**DO:**
|
|
394
|
-
\`\`\`markdown
|
|
395
|
-
### 2026-03-17 14:30 - API integration
|
|
396
|
-
\u2705 Completed REST API integration with error handling. Next: write tests.
|
|
397
|
-
\`\`\`
|
|
398
|
-
|
|
399
|
-
**DON'T:**
|
|
400
|
-
\`\`\`markdown
|
|
401
|
-
### 2026-03-17 14:30
|
|
402
|
-
So today I worked on the API integration and it took quite a while because there were some issues with the authentication but I managed to figure it out and now it's working properly. I think the next step should be to write some tests to make sure everything keeps working.
|
|
403
|
-
\`\`\`
|
|
389
|
+
**DO:** Concise status entries, update every session
|
|
390
|
+
**DON'T:** Long paragraphs, mix inputs/outputs
|
|
404
391
|
|
|
405
|
-
**
|
|
392
|
+
**Front-matter:** \`name\`, \`description\`, \`assignee\`, \`status\`, \`created\`
|
|
406
393
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
**DO:**
|
|
410
|
-
- Keep \`main.md\` focused on goals and context (update rarely)
|
|
411
|
-
- Append to \`status.md\` chronologically (single lines)
|
|
412
|
-
- Place final deliverables in \`outputs/\`
|
|
413
|
-
- Store external data in \`inputs/\`
|
|
414
|
-
- Create scripts only when they save time
|
|
415
|
-
|
|
416
|
-
**DON'T:**
|
|
417
|
-
- Put status updates in \`main.md\`
|
|
418
|
-
- Write long paragraphs in \`status.md\`
|
|
419
|
-
- Mix inputs and outputs
|
|
420
|
-
- Create scripts for one-time simple tasks
|
|
421
|
-
|
|
422
|
-
### Front-matter
|
|
423
|
-
|
|
424
|
-
**Always include:**
|
|
425
|
-
- \`name\`: Clear, searchable title
|
|
426
|
-
- \`description\`: One-line summary (for search and listings)
|
|
427
|
-
- \`assignee\`: Agent name who should execute
|
|
428
|
-
- \`priority\`: \`low\`, \`medium\`, or \`high\`
|
|
429
|
-
- \`status\`: \`pending\`, \`in-progress\`, \`ongoing\`, \`done\`, or \`blocked\`
|
|
430
|
-
- \`created\`: Date in YYYY-MM-DD format
|
|
431
|
-
|
|
432
|
-
## Task Lifecycle Commands
|
|
433
|
-
|
|
434
|
-
- \`task start\` - Sets status to \`in-progress\`, outputs cd command and env vars
|
|
435
|
-
- \`task update --status done\` - Marks task as complete
|
|
436
|
-
- \`task update --status ongoing\` - Marks task as ongoing/recurring (won't be auto-completed)
|
|
437
|
-
|
|
438
|
-
All status changes go through \`task update\`, which runs pre-update/post-update hooks.
|
|
439
|
-
|
|
440
|
-
## Examples
|
|
441
|
-
|
|
442
|
-
### Example Project: Website Redesign
|
|
394
|
+
## Example
|
|
443
395
|
|
|
444
396
|
\`\`\`
|
|
445
|
-
$AIP_HOME/projects/
|
|
446
|
-
\u251C\u2500\u2500
|
|
447
|
-
\
|
|
448
|
-
\
|
|
449
|
-
\
|
|
450
|
-
\
|
|
451
|
-
\
|
|
452
|
-
\u2502 status: in-progress
|
|
453
|
-
\u2502 created: 2026-03-17
|
|
454
|
-
\u2502 ---
|
|
455
|
-
\u2502 ## Objective
|
|
456
|
-
\u2502 Redesign company website with new branding guidelines...
|
|
457
|
-
\u2502
|
|
458
|
-
\u251C\u2500\u2500 status.md
|
|
459
|
-
\u2502 # Status: Website Redesign
|
|
460
|
-
\u2502 ### 2026-03-17 16:00 - Task: gather-requirements \u2705
|
|
461
|
-
\u2502 Collected stakeholder requirements, analyzed competitors. Details: tasks/gather-requirements/
|
|
462
|
-
\u2502
|
|
463
|
-
\u251C\u2500\u2500 hooks/
|
|
464
|
-
\u2502 \u2514\u2500\u2500 pre-complete.sh # Project-level validation
|
|
465
|
-
\u2502
|
|
466
|
-
\u251C\u2500\u2500 tasks/
|
|
467
|
-
\u2502 \u2514\u2500\u2500 gather-requirements/
|
|
468
|
-
\u2502 \u251C\u2500\u2500 main.md (assignee: basic, priority: high, status: done)
|
|
469
|
-
\u2502 \u251C\u2500\u2500 status.md
|
|
470
|
-
\u2502 \u2502 ### 2026-03-17 14:00 - Started research
|
|
471
|
-
\u2502 \u2502 \u{1F504} Analyzing competitor websites.
|
|
472
|
-
\u2502 \u2502 ### 2026-03-17 16:00 - Completed analysis
|
|
473
|
-
\u2502 \u2502 \u2705 Documented 15 requirements. Output: outputs/requirements.md
|
|
474
|
-
\u2502 \u251C\u2500\u2500 hooks/
|
|
475
|
-
\u2502 \u2502 \u2514\u2500\u2500 pre-complete.sh # Task-level validation
|
|
476
|
-
\u2502 \u251C\u2500\u2500 outputs/
|
|
477
|
-
\u2502 \u2502 \u2514\u2500\u2500 requirements.md
|
|
478
|
-
\u2502 \u2514\u2500\u2500 inputs/
|
|
479
|
-
\u2502 \u2514\u2500\u2500 competitor-analysis.json
|
|
397
|
+
$AIP_HOME/projects/my-project/
|
|
398
|
+
\u251C\u2500\u2500 ${et} # Goals, context
|
|
399
|
+
\u251C\u2500\u2500 ${ot} # Activity log
|
|
400
|
+
\u2514\u2500\u2500 ${Zt}/
|
|
401
|
+
\u2514\u2500\u2500 task-1/
|
|
402
|
+
\u251C\u2500\u2500 ${et} # Task definition
|
|
403
|
+
\u2514\u2500\u2500 ${ot} # Updates
|
|
480
404
|
\`\`\`
|
|
481
405
|
|
|
482
|
-
|
|
483
|
-
|
|
406
|
+
**Status log:**
|
|
484
407
|
\`\`\`markdown
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
### 2026-03-17 10:30 - API integration
|
|
489
|
-
\u2705 REST API connected. Next: error handling.
|
|
490
|
-
|
|
491
|
-
### 2026-03-17 11:15 - Error handling
|
|
492
|
-
\u2705 Added retry logic and fallbacks. Next: testing.
|
|
493
|
-
|
|
494
|
-
### 2026-03-17 12:00 - Testing complete
|
|
495
|
-
\u2705 All tests passing (23/23). Ready for review.
|
|
408
|
+
[2026-03-17 09:00] Task created: implement-api
|
|
409
|
+
[2026-03-17 10:30] Updated: status=in-progress
|
|
410
|
+
[2026-03-17 12:00] Tests passing
|
|
496
411
|
\`\`\`
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
## Directory Layout
|
|
513
|
-
|
|
514
|
-
\`\`\`
|
|
515
|
-
$AIP_HOME/
|
|
516
|
-
\u251C\u2500\u2500 projects/
|
|
517
|
-
\u2502 \u251C\u2500\u2500 {project-slug}/
|
|
518
|
-
\u2502 \u2502 \u251C\u2500\u2500 main.md # Goals, scope, context
|
|
519
|
-
\u2502 \u2502 \u251C\u2500\u2500 status.md # Chronological activity log
|
|
520
|
-
\u2502 \u2502 \u251C\u2500\u2500 hooks/ # pre|post-{create,start,update,complete}.*
|
|
521
|
-
\u2502 \u2502 \u251C\u2500\u2500 inputs/ # External data (API responses, downloads)
|
|
522
|
-
\u2502 \u2502 \u251C\u2500\u2500 outputs/ # Deliverables (reports, code, final files)
|
|
523
|
-
\u2502 \u2502 \u251C\u2500\u2500 scripts/ # Automation (bash, python, js)
|
|
524
|
-
\u2502 \u2502 \u2514\u2500\u2500 tasks/
|
|
525
|
-
\u2502 \u2502 \u2514\u2500\u2500 {task-slug}/
|
|
526
|
-
\u2502 \u2502 \u251C\u2500\u2500 main.md # Task definition
|
|
527
|
-
\u2502 \u2502 \u251C\u2500\u2500 status.md # Single-line updates
|
|
528
|
-
\u2502 \u2502 \u251C\u2500\u2500 hooks/ # Task-level hooks
|
|
529
|
-
\u2502 \u2502 \u251C\u2500\u2500 inputs/
|
|
530
|
-
\u2502 \u2502 \u251C\u2500\u2500 outputs/
|
|
531
|
-
\u2502 \u2502 \u2514\u2500\u2500 scripts/
|
|
532
|
-
\u2514\u2500\u2500 agents/
|
|
533
|
-
\u2514\u2500\u2500 {agent-slug}/
|
|
534
|
-
\u2514\u2500\u2500 main.md # Agent profile
|
|
535
|
-
\`\`\`
|
|
536
|
-
|
|
537
|
-
## File Purposes
|
|
538
|
-
|
|
539
|
-
### main.md (Context - Read First)
|
|
540
|
-
|
|
541
|
-
**Project main.md:**
|
|
542
|
-
- Objectives and success criteria
|
|
543
|
-
- Scope and constraints
|
|
544
|
-
- Background information
|
|
545
|
-
- Requirements
|
|
546
|
-
|
|
547
|
-
**Task main.md:**
|
|
548
|
-
- Specific deliverable
|
|
549
|
-
- Requirements
|
|
550
|
-
- Acceptance criteria
|
|
551
|
-
|
|
552
|
-
**Frontmatter:**
|
|
553
|
-
\`\`\`yaml
|
|
554
|
-
---
|
|
555
|
-
name: Clear Title
|
|
556
|
-
description: One-line summary
|
|
557
|
-
assignee: agent-name
|
|
558
|
-
status: pending|in-progress|ongoing|done|blocked
|
|
559
|
-
created: YYYY-MM-DD
|
|
560
|
-
---
|
|
561
|
-
\`\`\`
|
|
562
|
-
|
|
563
|
-
**Status meanings:**
|
|
564
|
-
- \`pending\` - Not started yet
|
|
565
|
-
- \`in-progress\` - Currently being worked on
|
|
566
|
-
- \`ongoing\` - Recurring or continuous task (should not be auto-completed by AI)
|
|
567
|
-
- \`done\` - Completed
|
|
568
|
-
- \`blocked\` - Waiting on external dependency
|
|
569
|
-
|
|
570
|
-
### status.md (Activity Log - Append Only)
|
|
571
|
-
|
|
572
|
-
**Task updates** (each work session):
|
|
573
|
-
\`\`\`markdown
|
|
574
|
-
### 2026-03-24 14:30 - Implemented API integration
|
|
575
|
-
\u2705 Completed REST API with error handling. Next: write tests.
|
|
576
|
-
\`\`\`
|
|
577
|
-
|
|
578
|
-
**Project updates** (when task completes):
|
|
579
|
-
\`\`\`markdown
|
|
580
|
-
### 2026-03-24 18:00 - Task: api-integration \u2705
|
|
581
|
-
Implemented 5 endpoints with validation. Details: tasks/api-integration/
|
|
582
|
-
\`\`\`
|
|
583
|
-
|
|
584
|
-
**Rules:**
|
|
585
|
-
- One line per session
|
|
586
|
-
- Include timestamp
|
|
587
|
-
- State what's done + what's next
|
|
588
|
-
- Use emojis: \u{1F504} in-progress | \u2705 done | \u26A0\uFE0F blocked | \u274C failed
|
|
589
|
-
|
|
590
|
-
**Note:** Tasks with ongoing status are meant for continuous/recurring work. AI agents should not automatically mark these as done - only users should mark them complete when the ongoing work is truly finished.
|
|
591
|
-
|
|
592
|
-
### inputs/ (External Data)
|
|
593
|
-
|
|
594
|
-
Store here:
|
|
595
|
-
- API responses (JSON, XML)
|
|
596
|
-
- Downloaded files
|
|
597
|
-
- Web scrapes
|
|
598
|
-
- Reference documents
|
|
599
|
-
|
|
600
|
-
**Naming:** \`api-response-2026-03-24.json\`, \`scraped-docs.md\`
|
|
601
|
-
|
|
602
|
-
### outputs/ (Deliverables)
|
|
603
|
-
|
|
604
|
-
Store here:
|
|
605
|
-
- Final reports
|
|
606
|
-
- Generated code
|
|
607
|
-
- Processed data
|
|
608
|
-
- Artifacts for external use
|
|
609
|
-
|
|
610
|
-
**Naming:** \`final-report.md\`, \`optimized-config.yaml\`
|
|
611
|
-
|
|
612
|
-
### scripts/ (Automation)
|
|
613
|
-
|
|
614
|
-
Create when:
|
|
615
|
-
- Work is repetitive (3+ times)
|
|
616
|
-
- Complex command sequences
|
|
617
|
-
- Validation/checking needed
|
|
618
|
-
- Data transformations
|
|
619
|
-
|
|
620
|
-
**Languages:**
|
|
621
|
-
- **Bash:** Simple ops, command chaining
|
|
622
|
-
- **Python:** Data processing, API calls
|
|
623
|
-
- **JavaScript:** Web scraping, Node.js tooling
|
|
624
|
-
|
|
625
|
-
## Workflow
|
|
626
|
-
|
|
627
|
-
### Starting Work
|
|
628
|
-
|
|
629
|
-
1. **Read context**
|
|
630
|
-
\`\`\`bash
|
|
631
|
-
cat projects/{project}/main.md
|
|
632
|
-
cat projects/{project}/tasks/{task}/main.md
|
|
633
|
-
cat projects/{project}/tasks/{task}/status.md
|
|
634
|
-
\`\`\`
|
|
635
|
-
|
|
636
|
-
2. **Check recent activity** (status.md)
|
|
637
|
-
|
|
638
|
-
3. **Review inputs/** (existing data)
|
|
639
|
-
|
|
640
|
-
### During Work
|
|
641
|
-
|
|
642
|
-
1. **Create scripts/** if automation helps
|
|
643
|
-
2. **Save external data to inputs/**
|
|
644
|
-
3. **Place deliverables in outputs/**
|
|
645
|
-
|
|
646
|
-
### Completing Work
|
|
647
|
-
|
|
648
|
-
1. **Update task status.md** (final entry)
|
|
649
|
-
2. **Update task main.md** status \u2192 \`done\`
|
|
650
|
-
3. **Append to project status.md** (packed summary)
|
|
651
|
-
4. **Ensure outputs/** has all deliverables
|
|
652
|
-
|
|
653
|
-
## Commands
|
|
654
|
-
|
|
655
|
-
\`\`\`bash
|
|
656
|
-
# Create
|
|
657
|
-
aip project create {name} --description "{desc}"
|
|
658
|
-
aip task create {project} {name} --description "{desc}"
|
|
659
|
-
|
|
660
|
-
# Navigate
|
|
661
|
-
cd $(aip project path {name})
|
|
662
|
-
cd $(aip task path {project} {task})
|
|
663
|
-
|
|
664
|
-
# Task Lifecycle
|
|
665
|
-
aip task start {project} {task} # Sets in-progress, outputs cd command
|
|
666
|
-
aip task update {project} {task} --status done
|
|
667
|
-
aip task update {project} {task} --status ongoing
|
|
668
|
-
aip task update {project} {task} --summary "Completed X"
|
|
669
|
-
|
|
670
|
-
# Context
|
|
671
|
-
aip task ingest {project} {task} # Full context for AI
|
|
672
|
-
\`\`\`
|
|
673
|
-
|
|
674
|
-
**Note:** All status changes go through \`task update\`, which runs pre-update/post-update hooks automatically.
|
|
675
|
-
|
|
676
|
-
## Best Practices
|
|
677
|
-
|
|
678
|
-
**DO:**
|
|
679
|
-
- Keep main.md focused (update rarely)
|
|
680
|
-
- Append to status.md religiously
|
|
681
|
-
- Use inputs/outputs/ separation
|
|
682
|
-
- Create scripts for repetitive work
|
|
683
|
-
- Run hooks automatically
|
|
684
|
-
|
|
685
|
-
**DON'T:**
|
|
686
|
-
- Put status updates in main.md
|
|
687
|
-
- Write paragraphs in status.md
|
|
688
|
-
- Mix inputs and outputs
|
|
689
|
-
- Create scripts for one-time tasks
|
|
690
|
-
- Ignore hook failures
|
|
691
|
-
|
|
692
|
-
---
|
|
693
|
-
|
|
694
|
-
*Structure enables autonomy. Clean files = clear context = better execution.*
|
|
695
|
-
`,Rt=p({description:"Project and task directory layout for autonomous work",options:z$1.object({}),handler:async()=>{console.log(Je);}});});var Ut,_t=g(()=>{ot();f();b();Ut=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(()=>(J(),it)),o=`${_.name} ${_.version} -`,r=s.dumpCommandMapLines(e,t);if(!t)console.log(o,"Usage: aip <noun> <verb> [options]"),console.log(r.map(n=>`-> ${n}`).join(`
|
|
696
|
-
`));else {let n=r[0]??`${t} {?}`;console.log(o,`Usage: aip ${n} [options]`);}}});});var ct,qe,T,v=g(()=>{A();D();b();ct=s.join(h.AIP_HOME,c.dirs.PROJECTS),qe={getProjectFromPwd(t=process.cwd()){let e=N.relative(ct,t);if(!e||e.startsWith(".."))return null;let o=e.split(N.sep).filter(Boolean);return o.length===0?null:o[0]},getTaskFromPwd(t=process.cwd()){let e=N.relative(ct,t);if(!e||e.startsWith(".."))return null;let o=e.split(N.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: ${ct}`);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(`
|
|
697
|
-
`)},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.join(h.AIP_HOME,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.join(h.AIP_HOME,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.join(h.AIP_HOME,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.join(h.AIP_HOME,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.")}},T=qe;});var Lt,Ht=g(()=>{f();b();v();A();Lt=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}=T.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 y;if(r==="ts")y=`#!/usr/bin/env tsx
|
|
412
|
+
`,Xt=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(kt);return}if(t.mode==="claude"){console.log(`---
|
|
413
|
+
name: ${e}
|
|
414
|
+
description: ${S.description}
|
|
415
|
+
---`),console.log(),console.log(kt);return}if(t.mode==="hermes"){console.log(`---
|
|
416
|
+
name: ${e}
|
|
417
|
+
description: ${S.description}
|
|
418
|
+
version: ${S.version}
|
|
419
|
+
author: ${S.author}
|
|
420
|
+
license: ${S.license}
|
|
421
|
+
metadata:
|
|
422
|
+
hermes:
|
|
423
|
+
tags: [${S.keywords.join(", ")}]
|
|
424
|
+
---`),console.log(),console.log(kt);return}}});});var ee,oe=f(()=>{W();k();b();ee=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(()=>(tt(),gt)),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(`
|
|
425
|
+
`)),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 yt,mo,j,v=f(()=>{$();I();b();yt=s.join(y.AIP_HOME,c.dirs.PROJECTS),mo={getProjectFromPwd(t=process.cwd()){let e=M.relative(yt,t);if(!e||e.startsWith(".."))return null;let o=e.split(M.sep).filter(Boolean);return o.length===0?null:o[0]},getTaskFromPwd(t=process.cwd()){let e=M.relative(yt,t);if(!e||e.startsWith(".."))return null;let o=e.split(M.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(`
|
|
426
|
+
`)},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.join(y.AIP_HOME,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.join(y.AIP_HOME,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.join(y.AIP_HOME,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.join(y.AIP_HOME,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=mo;});var re,se=f(()=>{k();b();v();$();re=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}=j.getTargetDir(o),d=s.join(i,c.dirs.HOOKS);await s.ensureDir(d);let u=s.join(d,`${t}${n}`);if(await s.fileExists(u))throw new Error(`Hook already exists: ${u}`);let g;if(r==="ts")g=`#!/usr/bin/env tsx
|
|
698
427
|
/** ${t} hook for ${a} */
|
|
699
428
|
|
|
700
429
|
import { env } from 'node:process'
|
|
@@ -707,7 +436,7 @@ if (env.TASK_SLUG) {
|
|
|
707
436
|
|
|
708
437
|
// Exit with non-zero to prevent action (for pre-hooks)
|
|
709
438
|
// process.exit(1)
|
|
710
|
-
`;else if(r==="js")
|
|
439
|
+
`;else if(r==="js")g=`#!/usr/bin/env node
|
|
711
440
|
/** ${t} hook for ${a} */
|
|
712
441
|
|
|
713
442
|
console.log('Running ${t} hook for ${a}')
|
|
@@ -718,7 +447,7 @@ if (process.env.TASK_SLUG) {
|
|
|
718
447
|
|
|
719
448
|
// Exit with non-zero to prevent action (for pre-hooks)
|
|
720
449
|
// process.exit(1)
|
|
721
|
-
`;else if(r==="sh")
|
|
450
|
+
`;else if(r==="sh")g=`#!/bin/bash
|
|
722
451
|
# ${t} hook for ${a}
|
|
723
452
|
|
|
724
453
|
echo "Running ${t} hook for ${a}"
|
|
@@ -729,7 +458,7 @@ fi
|
|
|
729
458
|
|
|
730
459
|
# Exit with non-zero to prevent action (for pre-hooks)
|
|
731
460
|
# exit 1
|
|
732
|
-
`;else if(r==="py")
|
|
461
|
+
`;else if(r==="py")g=`#!/usr/bin/env python3
|
|
733
462
|
"""${t} hook for ${a}"""
|
|
734
463
|
|
|
735
464
|
import os
|
|
@@ -741,12 +470,13 @@ if os.environ.get('TASK_SLUG'):
|
|
|
741
470
|
|
|
742
471
|
# Exit with non-zero to prevent action (for pre-hooks)
|
|
743
472
|
# sys.exit(1)
|
|
744
|
-
`;else throw new Error(`Unsupported language: ${r}`);await s.write(
|
|
745
|
-
`},async appendStatus(t,e,o){let r=s.join(t,c.files.STATUS),n=this.formatLogEntry(e,o);await s.write(r,n);},async appendStatusIfExists(t,e,o){let r=s.join(t,c.files.STATUS);if(!await s.fileExists(r))return false;let i=this.formatLogEntry(e,o);return await s.write(r,i),true},async readStatus(t){let e=s.join(t,c.files.STATUS);return await s.fileExists(e)?await s.read(e):""},getCurrentAgent(){return process.env.CURRENT_AGENT},async logTask(t,e){let o=
|
|
746
|
-
Expected at: ${o}`);await s.logFiles(o);}});});var
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
473
|
+
`;else throw new Error(`Unsupported language: ${r}`);await s.write(u,g);let{chmod:P}=await import('fs/promises');await P(u,493),console.log(`Hook created: ${u}`);}});});var fo,E,G=f(()=>{$();I();b();fo={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.join(y.AIP_HOME,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(d=>{let u=spawn(t,[],{stdio:"inherit",env:a,cwd:M.dirname(t),shell:false});u.on("close",(l,g)=>{l===0?d(true):(console.error(`Hook ${M.basename(t)} failed (code=${l??g})`),d(false));}),u.on("error",l=>{console.error(`Failed to execute hook ${t}: ${l.message}`),d(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))}},E=fo;});var ie,ae=f(()=>{k();G();v();$();ie=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),n={action:t,entityType:r,project:j.getProjectFromPwd()||void 0,task:j.getTaskFromPwd()||void 0};await E.runHooks(o,t,n)||(console.error(`Hook ${t} failed`),process.exit(1)),console.log(`Hook ${t} completed successfully`);}});});var go,A,z=f(()=>{$();v();I();b();go={formatLogEntry(t,e){let o=new Date().toISOString().replace("T"," ").replace(/\.\d{3}Z$/,""),r=e?` | ${e}`:"";return `[${o}${r}] ${t}
|
|
474
|
+
`},async appendStatus(t,e,o){let r=s.join(t,c.files.STATUS),n=this.formatLogEntry(e,o);await s.write(r,n);},async appendStatusIfExists(t,e,o){let r=s.join(t,c.files.STATUS);if(!await s.fileExists(r))return false;let i=this.formatLogEntry(e,o);return await s.write(r,i),true},async readStatus(t){let e=s.join(t,c.files.STATUS);return await s.fileExists(e)?await s.read(e):""},getCurrentAgent(){return process.env.CURRENT_AGENT},async logTask(t,e){let o=j.getCurrentContext();if(!o.project||!o.task)throw new Error("Not in a task directory");let r=s.join(y.AIP_HOME,c.dirs.PROJECTS,o.project,c.dirs.TASKS,o.task);await this.appendStatus(r,t,e||this.getCurrentAgent());},async logProject(t,e){let o=j.getProjectFromPwd();if(!o)throw new Error("Not in a project directory");let r=s.join(y.AIP_HOME,c.dirs.PROJECTS,o);await this.appendStatus(r,t,e||this.getCurrentAgent());},async logStatusChange(t,e,o,r){let n=e;if(o&&Object.keys(o).length>0){let i=Object.entries(o).map(([a,d])=>`${a}=${d}`).join(", ");n=`${e}: ${i}`;}await this.appendStatus(t,n,r);}},A=go;});var ce,pe=f(()=>{k();G();b();x();z();ce=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"),summary:z$1.string().optional().describe("Override the default summary line to append to status.md")}),args:z$1.object({name:z$1.string().describe("Project name")}),handler:async({name:t,description:e,status:o,assignee:r,summary:n})=>{let i=s.slugify(t),a=m.getProjectDir(i);if(!await E.runHooks(a,"pre-create",{action:"pre-create",entityType:"project"}))throw new Error("Pre-create hook failed, aborting project creation");await m.createProject(i,{name:t,description:e,status:o,assignee:r,created:new Date().toISOString()}),await A.appendStatus(a,n||`Project created: ${t} > status is ${o}`),await E.runHooks(a,"post-create",{action:"post-create",entityType:"project"}),console.log(`Project created: ${i}`),console.log(` Path: ${a}`);}});});var le,me=f(()=>{k();v();le=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 ue,fe=f(()=>{k();x();ue=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 m.listProjects(),o=[];for(let r of e){let n=await m.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 ge,ke=f(()=>{k();x();ge=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=m.getProjectDir(t);console.log(e);}});});var he,ye=f(()=>{k();x();G();z();v();he=p({description:"Update project properties: name, description, status, assignee, or append summary",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"),summary:z$1.string().optional().describe("Optional summary to append to status.md")}),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,summary:i})=>{let a=t||j.getProjectFromPwd();if(!a)throw new Error("No project specified and not in a project directory");let d=m.getProjectDir(a);if(!await E.runHooks(d,"pre-update",{action:"pre-update",entityType:"project"}))throw new Error("Pre-update hook failed, aborting update");let l={};if(e&&(l.name=e),o&&(l.description=o),r&&(l.status=r),n&&(l.assignee=n),Object.keys(l).length===0){console.log("No updates provided");return}await m.updateProject(a,l);let g=Object.entries(l).map(([P,O])=>`${P}=${O}`).join(", ");await A.appendStatus(d,`Updated: ${g}`),i&&await A.appendStatus(d,i),await E.runHooks(d,"post-update",{action:"post-update",entityType:"project"}),console.log(`Project ${a} updated`);}});});var je,Te=f(()=>{$();k();I();b();je=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(y.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}
|
|
475
|
+
Expected at: ${o}`);await s.logFiles(o);}});});var we,Pe=f(()=>{k();G();b();x();z();we=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"),summary:z$1.string().optional().describe("Override the default summary line to append to status.md")}),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,summary:i})=>{let a=s.slugify(e),d=m.getProjectDir(t),u=m.getTaskDir(t,a);if(!await E.runHooksForContext(d,u,"pre-create",{action:"pre-create",entityType:"task",project:t}))throw new Error("Pre-create hook failed, aborting task creation");await m.createTask(t,a,{name:e,description:o,assignee:r,status:n,created:new Date().toISOString()}),await A.appendStatus(u,i||`Created: ${e}`),await A.appendStatus(d,`Task created: ${a} > status is ${n}`),await E.runHooksForContext(d,u,"post-create",{action:"post-create",entityType:"task",project:t}),console.log(`Task created: ${a}`),console.log(` Project: ${t}`),console.log(` Path: ${u}`);}});});var be,Se=f(()=>{k();v();be=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 xe,Ee=f(()=>{v();k();x();xe=p({description:"Output full task context (main.md, status.md) 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:n}=await m.findTask(r,t);await m.ingestTask(n,r);}});});var Ae,$e=f(()=>{k();x();Ae=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 l of e)if(!X.includes(l))throw new Error(`Invalid status: ${l}. Valid values: ${X.join(", ")}`)}let i;e&&e.length>0?i=e:r?i=X:i=At;let a=t?[t]:await m.listProjects(),d={};for(let l of a){let g=await m.listTasks(l),P=[];for(let O of g){let h=await m.getTask(l,O);if(h&&!(i.length>0&&!i.includes(h.status||""))&&!(o&&h.assignee!==o)){if(n){let H=n.toLowerCase(),lt=O.toLowerCase().includes(H),mt=(h.name||"").toLowerCase().includes(H);if(!lt&&!mt)continue}P.push({slug:O,name:h.name||O,status:h.status,assignee:h.assignee});}}P.length>0&&(d[l]=P.sort((O,h)=>O.slug.localeCompare(h.slug)));}let u=Object.keys(d).sort();if(u.length===0){console.log("No tasks found");return}for(let l of u){console.log(`
|
|
476
|
+
${l}:`),console.log("---");for(let g of d[l])console.log(`${g.slug.padEnd(20)} ${g.name?.padEnd(30)||""} ${g.status||""} ${g.assignee||""}`);}}});});var ve,Oe=f(()=>{k();x();ve=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 m.findTask(e,t),n=m.getTaskDir(o,r);console.log(n);}});});var at,wt=f(()=>{v();k();G();x();z();at=p({description:"Update task properties: name, description, status, assignee, or append summary",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)"),summary:z$1.string().optional().describe("Override the default summary line to append to status.md")}),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,summary:a})=>{let d=j.getCurrentContext(),u=e??d.task;if(!u)throw new Error("No task specified (use --task or cd into task dir)");let{project:l}=await m.findTask(u,t),g=m.getTaskDir(l,u),P=m.getProjectDir(l);if(!await E.runHooksForContext(P,g,"pre-update",{action:"pre-update",entityType:"task",project:l,task:u}))throw new Error("Pre-update hook failed, aborting update");let h={};if(o&&(h.name=o),r&&(h.description=r),n&&(h.status=n),i&&(h.assignee=i),Object.keys(h).length===0&&!a){console.log("No updates provided");return}if(Object.keys(h).length>0){await m.updateTask(l,u,h);let lt=Object.entries(h).map(([mt,Le])=>`${mt}=${Le}`).join(", ");await A.appendStatus(g,`Updated: ${lt}`);}let H=a;!a&&(h.status||h.assignee)&&(H=`Updated: ${h.status?` status to ${h.status}`:""}${h.assignee?` assignee to ${h.assignee}`:""}`),H&&await A.appendStatus(g,H),h.status&&await A.appendStatus(P,`Task updated: ${u} > status to ${h.status}`),await E.runHooksForContext(m.getProjectDir(l),g,"post-update",{action:"post-update",entityType:"task",project:l,task:u}),console.log(`Task ${u} updated`);}});});var De,Ce=f(()=>{v();k();x();wt();De=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(),n=e??r.task;if(!n)throw new Error("No task specified (use --task or cd into task dir)");let{project:i}=await m.findTask(n,t);(await m.getTask(i,n))?.status!=="in-progress"&&await at.handler({project:i,task:n,status:"in-progress"}),o&&await m.ingestTask(i,n);}});});var Ie,Ne=f(()=>{k();x();z();Ie=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=m.getTaskDir(t,e),r=await m.getTask(t,e),i=(await A.readStatus(o)).split(`
|
|
477
|
+
`).filter(u=>u.startsWith("[")).length,a=[],d=r?.name||e;i>5&&a.push("High status update count - consider breaking into smaller tasks"),d.toLowerCase().includes("implement")&&a.push("Implementation task - check if similar patterns exist to reuse"),d.toLowerCase().includes("create")&&d.toLowerCase().includes("command")&&a.push("Command creation - check existing command patterns in src/commands/"),console.log(`
|
|
478
|
+
=== Post-Mortem Analysis ===`),console.log(`Project: ${t}`),console.log(`Task: ${e}`),console.log(`Name: ${d}`),console.log(`Status: ${r?.status||"unknown"}`),console.log(`Status updates: ${i}`),a.length>0?(console.log(`
|
|
479
|
+
Suggestions:`),a.forEach(u=>console.log(` - ${u}`))):console.log(`
|
|
750
480
|
No specific suggestions - task looks well-scoped`),console.log(`
|
|
751
481
|
=== End Post-Mortem ===
|
|
752
|
-
`);}});});var
|
|
482
|
+
`);}});});var Re,Ue=f(()=>{k();b();Re=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 gt={};He(gt,{default:()=>F});var yo,F,tt=f(()=>{Ot();Ct();Nt();Ut();Lt();Kt();zt();Jt();te();oe();se();ae();pe();me();fe();ke();ye();Te();Pe();Se();Ee();$e();Oe();Ce();wt();Ne();Ue();yo={agent:{create:vt,current:Dt,list:It,path:Rt,start:_t},help:{api:Mt,hooks:Gt,quickstart:Wt,skill:Xt,usage:ee},hook:{create:re,run:ie},project:{create:ce,current:le,list:ue,path:ge,update:he},skill:{read:je},task:{create:we,current:be,ingest:xe,list:Ae,path:ve,start:De,update:at},util:{postmortem:Ie,read:Re}},F=yo;});W();tt();b();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 _e(t){let[e,o,...r]=t;(e==="--version"||e==="-v")&&(console.log(S.version),process.exit(0));try{(!e||!s.isKeyOf(e,F))&&(await F.help.usage.handler({}),process.exit(1));let n=F[e];(!o||!s.isKeyOf(o,n))&&(await F.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 ui=_e,fi=F;s.isMain()&&_e(process.argv.slice(2));export{fi as commands,ui as default};
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-projects",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Useful CLI for AI agents to create and manage projects, tasks, skills and agents",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"bin": {
|
|
@@ -50,11 +50,13 @@
|
|
|
50
50
|
},
|
|
51
51
|
"keywords": [
|
|
52
52
|
"ai",
|
|
53
|
-
"
|
|
54
|
-
"
|
|
53
|
+
"aip",
|
|
54
|
+
"project",
|
|
55
|
+
"task",
|
|
56
|
+
"kanban",
|
|
55
57
|
"cli",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
+
"agent",
|
|
59
|
+
"automation"
|
|
58
60
|
],
|
|
59
61
|
"author": "Ariel Flesler <aflesler@gmail.com>",
|
|
60
62
|
"license": "MIT",
|