ai-projects 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ariel Flesler
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # AIP - AI Project Management CLI
2
+
3
+ Command-line tool for managing AI agent projects, tasks, and agents.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g ai-projects
9
+ ```
10
+
11
+ The `aip` command is provided by the package `bin` field.
12
+
13
+ ## Usage
14
+
15
+ ```bash
16
+ aip <noun> <verb> [options]
17
+ ```
18
+
19
+ ## For Agents
20
+
21
+ Read `tmp/hermes/AGENTS.md` first.
22
+
23
+ ## License
24
+
25
+ MIT
@@ -0,0 +1,329 @@
1
+ import * as zod from 'zod';
2
+ import { ZodObject, z } from 'zod';
3
+ import { Parser } from 'zod-opts';
4
+
5
+ interface CommandDef<T extends ZodObject<any> = ZodObject<any>, U extends ZodObject<any> = ZodObject<any>> {
6
+ description?: string;
7
+ options: T;
8
+ args?: U;
9
+ parser: Parser;
10
+ handler: (params: z.infer<T> & z.infer<U>) => Promise<void>;
11
+ cli: (args: string[]) => Promise<void>;
12
+ }
13
+
14
+ declare function cli(args: string[]): Promise<void>;
15
+
16
+ declare const commands: {
17
+ readonly agent: {
18
+ readonly create: CommandDef<zod.ZodObject<{
19
+ description: zod.ZodString;
20
+ status: zod.ZodDefault<zod.ZodString>;
21
+ }, "strip", zod.ZodTypeAny, {
22
+ status: string;
23
+ description: string;
24
+ }, {
25
+ description: string;
26
+ status?: string | undefined;
27
+ }>, zod.ZodObject<{
28
+ name: zod.ZodString;
29
+ }, "strip", zod.ZodTypeAny, {
30
+ name: string;
31
+ }, {
32
+ name: string;
33
+ }>>;
34
+ readonly current: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
35
+ [x: string]: any;
36
+ }, {
37
+ [x: string]: any;
38
+ }>>;
39
+ readonly list: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
40
+ [x: string]: any;
41
+ }, {
42
+ [x: string]: any;
43
+ }>>;
44
+ readonly path: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<{
45
+ name: zod.ZodString;
46
+ }, "strip", zod.ZodTypeAny, {
47
+ name: string;
48
+ }, {
49
+ name: string;
50
+ }>>;
51
+ readonly start: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<{
52
+ name: zod.ZodString;
53
+ }, "strip", zod.ZodTypeAny, {
54
+ name: string;
55
+ }, {
56
+ name: string;
57
+ }>>;
58
+ };
59
+ readonly help: {
60
+ readonly api: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
61
+ [x: string]: any;
62
+ }, {
63
+ [x: string]: any;
64
+ }>>;
65
+ readonly hooks: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
66
+ [x: string]: any;
67
+ }, {
68
+ [x: string]: any;
69
+ }>>;
70
+ readonly structure: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
71
+ [x: string]: any;
72
+ }, {
73
+ [x: string]: any;
74
+ }>>;
75
+ readonly usage: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<{
76
+ name: zod.ZodOptional<zod.ZodString>;
77
+ }, "strip", zod.ZodTypeAny, {
78
+ name?: string | undefined;
79
+ }, {
80
+ name?: string | undefined;
81
+ }>>;
82
+ };
83
+ readonly hook: {
84
+ readonly create: CommandDef<zod.ZodObject<{
85
+ lang: zod.ZodDefault<zod.ZodEnum<["ts", "js", "sh", "py"]>>;
86
+ target: zod.ZodDefault<zod.ZodEnum<["project", "task"]>>;
87
+ }, "strip", zod.ZodTypeAny, {
88
+ lang: "ts" | "js" | "sh" | "py";
89
+ target: "project" | "task";
90
+ }, {
91
+ lang?: "ts" | "js" | "sh" | "py" | undefined;
92
+ target?: "project" | "task" | undefined;
93
+ }>, zod.ZodObject<{
94
+ type: zod.ZodEnum<["pre-create", "post-create", "pre-complete", "post-complete", "pre-start", "post-start", "pre-update", "post-update"]>;
95
+ }, "strip", zod.ZodTypeAny, {
96
+ type: "pre-create" | "post-create" | "pre-complete" | "post-complete" | "pre-start" | "post-start" | "pre-update" | "post-update";
97
+ }, {
98
+ type: "pre-create" | "post-create" | "pre-complete" | "post-complete" | "pre-start" | "post-start" | "pre-update" | "post-update";
99
+ }>>;
100
+ readonly run: CommandDef<zod.ZodObject<{
101
+ target: zod.ZodOptional<zod.ZodEnum<["project", "task"]>>;
102
+ }, "strip", zod.ZodTypeAny, {
103
+ target?: "project" | "task" | undefined;
104
+ }, {
105
+ target?: "project" | "task" | undefined;
106
+ }>, zod.ZodObject<{
107
+ type: zod.ZodEnum<["pre-create", "post-create", "pre-complete", "post-complete", "pre-start", "post-start", "pre-update", "post-update"]>;
108
+ }, "strip", zod.ZodTypeAny, {
109
+ type: "pre-create" | "post-create" | "pre-complete" | "post-complete" | "pre-start" | "post-start" | "pre-update" | "post-update";
110
+ }, {
111
+ type: "pre-create" | "post-create" | "pre-complete" | "post-complete" | "pre-start" | "post-start" | "pre-update" | "post-update";
112
+ }>>;
113
+ };
114
+ readonly project: {
115
+ readonly create: CommandDef<zod.ZodObject<{
116
+ description: zod.ZodString;
117
+ status: zod.ZodDefault<zod.ZodString>;
118
+ assignee: zod.ZodOptional<zod.ZodString>;
119
+ }, "strip", zod.ZodTypeAny, {
120
+ status: string;
121
+ description: string;
122
+ assignee?: string | undefined;
123
+ }, {
124
+ description: string;
125
+ status?: string | undefined;
126
+ assignee?: string | undefined;
127
+ }>, zod.ZodObject<{
128
+ name: zod.ZodString;
129
+ }, "strip", zod.ZodTypeAny, {
130
+ name: string;
131
+ }, {
132
+ name: string;
133
+ }>>;
134
+ readonly current: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
135
+ [x: string]: any;
136
+ }, {
137
+ [x: string]: any;
138
+ }>>;
139
+ readonly list: CommandDef<zod.ZodObject<{
140
+ status: zod.ZodOptional<zod.ZodString>;
141
+ }, "strip", zod.ZodTypeAny, {
142
+ status?: string | undefined;
143
+ }, {
144
+ status?: string | undefined;
145
+ }>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
146
+ [x: string]: any;
147
+ }, {
148
+ [x: string]: any;
149
+ }>>;
150
+ readonly path: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<{
151
+ name: zod.ZodString;
152
+ }, "strip", zod.ZodTypeAny, {
153
+ name: string;
154
+ }, {
155
+ name: string;
156
+ }>>;
157
+ readonly update: CommandDef<zod.ZodObject<{
158
+ name: zod.ZodOptional<zod.ZodString>;
159
+ description: zod.ZodOptional<zod.ZodString>;
160
+ status: zod.ZodOptional<zod.ZodString>;
161
+ assignee: zod.ZodOptional<zod.ZodString>;
162
+ summary: zod.ZodOptional<zod.ZodString>;
163
+ }, "strip", zod.ZodTypeAny, {
164
+ status?: string | undefined;
165
+ description?: string | undefined;
166
+ name?: string | undefined;
167
+ assignee?: string | undefined;
168
+ summary?: string | undefined;
169
+ }, {
170
+ status?: string | undefined;
171
+ description?: string | undefined;
172
+ name?: string | undefined;
173
+ assignee?: string | undefined;
174
+ summary?: string | undefined;
175
+ }>, zod.ZodObject<{
176
+ project: zod.ZodOptional<zod.ZodString>;
177
+ }, "strip", zod.ZodTypeAny, {
178
+ project?: string | undefined;
179
+ }, {
180
+ project?: string | undefined;
181
+ }>>;
182
+ };
183
+ readonly skill: {
184
+ readonly read: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<{
185
+ name: zod.ZodString;
186
+ }, "strip", zod.ZodTypeAny, {
187
+ name: string;
188
+ }, {
189
+ name: string;
190
+ }>>;
191
+ };
192
+ readonly task: {
193
+ readonly create: CommandDef<zod.ZodObject<{
194
+ description: zod.ZodOptional<zod.ZodString>;
195
+ priority: zod.ZodOptional<zod.ZodEnum<["low", "medium", "high"]>>;
196
+ assignee: zod.ZodOptional<zod.ZodString>;
197
+ status: zod.ZodDefault<zod.ZodEnum<["pending", "in-progress", "ongoing", "done"]>>;
198
+ }, "strip", zod.ZodTypeAny, {
199
+ status: "pending" | "in-progress" | "ongoing" | "done";
200
+ description?: string | undefined;
201
+ assignee?: string | undefined;
202
+ priority?: "low" | "medium" | "high" | undefined;
203
+ }, {
204
+ status?: "pending" | "in-progress" | "ongoing" | "done" | undefined;
205
+ description?: string | undefined;
206
+ assignee?: string | undefined;
207
+ priority?: "low" | "medium" | "high" | undefined;
208
+ }>, zod.ZodObject<{
209
+ project: zod.ZodString;
210
+ name: zod.ZodString;
211
+ }, "strip", zod.ZodTypeAny, {
212
+ name: string;
213
+ project: string;
214
+ }, {
215
+ name: string;
216
+ project: string;
217
+ }>>;
218
+ readonly current: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
219
+ [x: string]: any;
220
+ }, {
221
+ [x: string]: any;
222
+ }>>;
223
+ readonly ingest: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<{
224
+ project: zod.ZodOptional<zod.ZodString>;
225
+ task: zod.ZodOptional<zod.ZodString>;
226
+ }, "strip", zod.ZodTypeAny, {
227
+ project?: string | undefined;
228
+ task?: string | undefined;
229
+ }, {
230
+ project?: string | undefined;
231
+ task?: string | undefined;
232
+ }>>;
233
+ readonly list: CommandDef<zod.ZodObject<{
234
+ project: zod.ZodOptional<zod.ZodString>;
235
+ status: zod.ZodOptional<zod.ZodString>;
236
+ assignee: zod.ZodOptional<zod.ZodString>;
237
+ }, "strip", zod.ZodTypeAny, {
238
+ status?: string | undefined;
239
+ project?: string | undefined;
240
+ assignee?: string | undefined;
241
+ }, {
242
+ status?: string | undefined;
243
+ project?: string | undefined;
244
+ assignee?: string | undefined;
245
+ }>, zod.ZodObject<any, zod.UnknownKeysParam, zod.ZodTypeAny, {
246
+ [x: string]: any;
247
+ }, {
248
+ [x: string]: any;
249
+ }>>;
250
+ readonly path: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<{
251
+ project: zod.ZodString;
252
+ task: zod.ZodString;
253
+ }, "strip", zod.ZodTypeAny, {
254
+ project: string;
255
+ task: string;
256
+ }, {
257
+ project: string;
258
+ task: string;
259
+ }>>;
260
+ readonly start: CommandDef<zod.ZodObject<{
261
+ ingest: zod.ZodDefault<zod.ZodBoolean>;
262
+ }, "strip", zod.ZodTypeAny, {
263
+ ingest: boolean;
264
+ }, {
265
+ ingest?: boolean | undefined;
266
+ }>, zod.ZodObject<{
267
+ project: zod.ZodString;
268
+ task: zod.ZodString;
269
+ }, "strip", zod.ZodTypeAny, {
270
+ project: string;
271
+ task: string;
272
+ }, {
273
+ project: string;
274
+ task: string;
275
+ }>>;
276
+ readonly update: CommandDef<zod.ZodObject<{
277
+ name: zod.ZodOptional<zod.ZodString>;
278
+ description: zod.ZodOptional<zod.ZodString>;
279
+ status: zod.ZodOptional<zod.ZodEnum<["pending", "in-progress", "ongoing", "done", "blocked"]>>;
280
+ priority: zod.ZodOptional<zod.ZodEnum<["low", "medium", "high"]>>;
281
+ assignee: zod.ZodOptional<zod.ZodString>;
282
+ summary: zod.ZodOptional<zod.ZodString>;
283
+ }, "strip", zod.ZodTypeAny, {
284
+ status?: "pending" | "in-progress" | "ongoing" | "done" | "blocked" | undefined;
285
+ description?: string | undefined;
286
+ name?: string | undefined;
287
+ assignee?: string | undefined;
288
+ summary?: string | undefined;
289
+ priority?: "low" | "medium" | "high" | undefined;
290
+ }, {
291
+ status?: "pending" | "in-progress" | "ongoing" | "done" | "blocked" | undefined;
292
+ description?: string | undefined;
293
+ name?: string | undefined;
294
+ assignee?: string | undefined;
295
+ summary?: string | undefined;
296
+ priority?: "low" | "medium" | "high" | undefined;
297
+ }>, zod.ZodObject<{
298
+ project: zod.ZodOptional<zod.ZodString>;
299
+ task: zod.ZodOptional<zod.ZodString>;
300
+ }, "strip", zod.ZodTypeAny, {
301
+ project?: string | undefined;
302
+ task?: string | undefined;
303
+ }, {
304
+ project?: string | undefined;
305
+ task?: string | undefined;
306
+ }>>;
307
+ };
308
+ readonly util: {
309
+ readonly postmortem: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<{
310
+ project: zod.ZodString;
311
+ task: zod.ZodString;
312
+ }, "strip", zod.ZodTypeAny, {
313
+ project: string;
314
+ task: string;
315
+ }, {
316
+ project: string;
317
+ task: string;
318
+ }>>;
319
+ readonly read: CommandDef<zod.ZodObject<{}, "strip", zod.ZodTypeAny, {}, {}>, zod.ZodObject<{
320
+ paths: zod.ZodArray<zod.ZodString, "many">;
321
+ }, "strip", zod.ZodTypeAny, {
322
+ paths: string[];
323
+ }, {
324
+ paths: string[];
325
+ }>>;
326
+ };
327
+ };
328
+
329
+ export { commands, cli as default };
package/dist/index.js ADDED
@@ -0,0 +1,419 @@
1
+ #!/usr/bin/env node
2
+ import {z}from'zod';import {parser}from'zod-opts';import {exec,spawn}from'child_process';import _ from'fs/promises';import j from'lodash';import H from'moment';import R from'path';import {fileURLToPath}from'url';import {inspect}from'util';import De from'dotenv';import ve from'fs';import Oe from'os';import ut from'yaml';var Te=Object.defineProperty;var g=(t,e)=>()=>(t&&(e=t(t=0)),e);var we=(t,e)=>{for(var o in e)Te(t,o,{get:e[o],enumerable:true});};function p(t){let{description:e,options:o=z.object({}),args:r,handler:n}=t,i=o.shape,a={};for(let[l,u]of Object.entries(i))a[l]={type:u};let m=parser().options(a);if(r){let l=r.shape,u=Object.entries(l).map(([h,k])=>({name:h,type:k}));u.length>0&&(m=m.args(u));}return e&&(m=m.description(e)),{description:e,options:o,args:r,parser:m,handler:n,cli:l=>n(m.parse(l))}}var f=g(()=>{});var T,s,b=g(()=>{T={REPO:fileURLToPath(import.meta.url.replace(/\/(dist|src)\/.*/,"/")),join:(...t)=>R.join(...t),onRepo:(...t)=>T.join(T.REPO,...t),async ensureDir(t){await _.mkdir(t,{recursive:true});},async write(t,e){await T.ensureDir(R.dirname(t)),await _.writeFile(t,e,"utf8");},async read(t){return _.readFile(t,"utf8")},async readRepo(...t){return T.read(T.onRepo(...t))},async readMany(...t){return (await Promise.all(t.map(async o=>{if(await T.fileExists(o)){let r=await T.read(o);return `# ${o}
3
+
4
+ ${r}`}return ""}))).filter(Boolean)},async logFiles(...t){let e=await T.readMany(...t);console.log(e.join(`
5
+
6
+ ---
7
+
8
+ `));},dumpCommandMapLines(t,e){let o=e?j.pick(t,e):t,r=[];for(let[n,i]of T.entriesOf(o))r.push(`${n} {${Object.keys(i).join("|")}}`);return r},async fileExists(t){try{return await _.access(t),!0}catch{return false}},async listDir(t){try{return await _.readdir(t)}catch{return []}},async spawn(t,e=[],o){return new Promise((r,n)=>{let i=spawn(t,e,{stdio:["ignore","pipe","pipe"],...o}),a="",m="";i.stdout?.on("data",l=>{a+=l;}),i.stderr?.on("data",l=>{m+=l;}),i.on("close",l=>r({stdout:a,stderr:m,code:l})),i.on("error",n);})},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)=>j.isArray(t)?t.map(o=>T.omitByDeep(o,e)):j.isPlainObject(t)?j.mapValues(j.omitBy(t,e),o=>T.omitByDeep(o,e)):t,omitNilsDeep:t=>T.omitByDeep(t,j.isNil),omitUndefinedsDeep:t=>T.omitByDeep(t,j.isUndefined),cloneDeep:t=>j.cloneDeep(t),int:t=>Number.parseInt(t,10),keysOf:t=>Object.keys(t),entriesOf:t=>Object.entries(t),isKeyOf:(t,e)=>!j.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(j.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 j.extend(e,t)},isPromise:t=>j.isObject(t)&&"catch"in t,delay:t=>{let e=j.isObject(t)?T.toMS(t):t;return new Promise(o=>setTimeout(o,e))},promiseMap:(t,e)=>Promise.all(t.map(e)),memoize:t=>j.memoize(t,T.memoizeKey),toMS:t=>H.duration(t).asMilliseconds(),toSecs:t=>H.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(j.isObject(i)){if(r.has(i))return "[Circular]";r.add(i);}return j.isFunction(e)?e(n,i):i},o)},dump:t=>T.oneLine(T.stringify(t)),compactWhitespace:t=>t.replace(/\\n/g,`
9
+ `).replace(/\r/g,"").replace(/[ \t]*\n[ \t]*/g,`
10
+ `).replace(/\n{3,}/g,`
11
+
12
+ `).replace(/ {2,}/g," ").trim(),oneLine:t=>t.replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/ +/g," ").trim(),fuzzySearch:(t,e)=>j.includes(j.toLower(t||""),j.toLower(e||"")),elapsed:(t,e=Date.now())=>H.duration(H(e).diff(t||0)),iso:t=>H.utc(t).toISOString(),isoDate:t=>T.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=T;});var c,E=g(()=>{c={dirs:{PROJECTS:"projects",SKILLS:"skills",AGENTS:"agents",TASKS:"tasks",INPUTS:"inputs",OUTPUTS:"outputs",HOOKS:"hooks"},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"]};});function Ne(t,e){return process.env[t]??e}var Ce,dt,D,Re,y,O=g(()=>{Ce=()=>{let t=fileURLToPath(import.meta.url),e=R.dirname(t),o=10;for(let r=0;r<o;r++)try{if(ve.existsSync(R.join(e,"package.json")))return e;let n=R.dirname(e);if(n===e)break;e=n;}catch{break}return process.cwd()};dt=Ce(),D=process.env.AIP_HOME;D||(De.config({path:R.join(dt,".env"),quiet:true}),D=process.env.AIP_HOME,console.log("envHome",D));D?.startsWith("~")&&(D=R.join(Oe.homedir(),D.slice(1)));if(!D||!R.isAbsolute(D))throw new Error("AIP_HOME must be set and be an absolute path");Re={ROOT:dt,AIP_HOME:D,NODE_ENV:Ne("NODE_ENV","development")},y=Re;});var gt,L,et,M,ft=g(()=>{b();gt=t=>{let e=t.trim();if(!e.startsWith("---"))return null;let o=e.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);return o?{frontmatter:ut.parse(o[1]),content:o[2].trim()}:null},L=async(t,e,o="")=>{let n=`---
13
+ ${ut.stringify(e).trim()}
14
+ ---
15
+
16
+ ${o}`.trim();await s.write(t,n+`
17
+ `);},et=async(t,e)=>{let o=await s.read(t),r=gt(o);if(!r)throw new Error(`No frontmatter found in ${t}`);let n={...r.frontmatter,...e};return await L(t,n,r.content),n},M=async t=>{let e=await s.read(t),o=gt(e);if(!o)throw new Error(`No frontmatter found in ${t}`);return o.frontmatter};});var Ie,d,P=g(()=>{E();O();ft();b();Ie={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)},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),o=[];for(let r of e){let n=this.getProjectDir(r);await s.fileExists(n)&&r!==c.dirs.AGENTS&&o.push(r);}return o},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 s.ensureDir(s.join(o,c.dirs.TASKS)),await s.ensureDir(s.join(o,c.dirs.HOOKS)),await L(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 s.ensureDir(s.join(r,c.dirs.HOOKS)),await L(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 L(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 M(e):null},async getTask(t,e){let o=s.join(this.getTaskDir(t,e),c.files.MAIN);return await s.fileExists(o)?await M(o):null},async getAgent(t){let e=s.join(this.getAgentDir(t),c.files.MAIN);return await s.fileExists(e)?await M(e):null},async updateProject(t,e){let o=s.join(this.getProjectDir(t),c.files.MAIN);return await et(o,e)},async updateTask(t,e,o){let r=s.join(this.getTaskDir(t,e),c.files.MAIN);if((await M(r))?.status==="ongoing")throw new Error("Cannot update ongoing task. Should be done by user or update manually");return await et(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=[s.join(e,c.files.MAIN),s.join(e,c.files.STATUS)],r=await this.listTasks(t);for(let n of r)o.push(s.join(this.getTaskDir(t,n),c.files.MAIN));await s.logFiles(...o);},async ingestFiles(t){await s.logFiles(...t);}},d=Ie;});var yt,kt=g(()=>{f();b();P();yt=p({options:z.object({description:z.string().describe("Agent description"),status:z.string().default("active").describe("Initial status")}),args:z.object({name:z.string().describe("Agent name")}),handler:async({name:t,description:e,status:o})=>{let r=s.slugify(t);await d.createAgent(r,{name:t,description:e,status:o,created:new Date().toISOString()}),console.log(`Agent created: ${r}`),console.log(` Path: ${d.getAgentDir(r)}`);}});});var ht,jt=g(()=>{f();ht=p({options:z.object({}),handler:async()=>{let t=process.env.CURRENT_AGENT;t||(console.error("CURRENT_AGENT not set"),process.exit(1)),console.log(t);}});});var Tt,wt=g(()=>{f();P();Tt=p({options:z.object({}),handler:async()=>{let t=await d.listAgents(),e=[];for(let o of t){let r=await d.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 bt,Pt=g(()=>{E();f();O();b();bt=p({description:"Output agent directory path (for cd)",options:z.object({}),args:z.object({name:z.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 xt,St=g(()=>{E();f();O();b();xt=p({description:"Start an agent: read SOUL.md and AGENTS.md content",options:z.object({}),args:z.object({name:z.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 Et,At,He,Dt,vt=g(()=>{f();Et=t=>{let e=t.shape,o=[];for(let[r,n]of Object.entries(e)){let i=n._def,a="unknown",m,l;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=At(i.innerType):i.typeName==="ZodDefault"&&(a=At(i.innerType),l=i.defaultValue()),i.description&&(m=i.description);let u=i.typeName!=="ZodOptional"&&i.typeName!=="ZodDefault";o.push({name:r,type:a,required:u,description:m,defaultValue:l});}return o},At=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"},He=(t,e,o)=>{let r=Et(o.options),n=o.args?Et(o.args):[],i=o.description,a=`\`${t} ${e}\``;if(i&&(a+=`: ${i}`),a+=`
20
+ `,r.length>0||n.length>0){let l=[];for(let u of n){let h=u.required?`<${u.name}>`:`[${u.name}]`,k=u.description||"";u.defaultValue!==void 0&&(k+=k?` (default: ${u.defaultValue})`:`(default: ${u.defaultValue})`),l.push(`\xB7 ${h}${k?": "+k:""}`);}for(let u of r){let h=u.description||"";u.defaultValue!==void 0&&(h+=h?` (default: ${u.defaultValue})`:`(default: ${u.defaultValue})`),l.push(`\xB7 --${u.name}${h?": "+h:""}`);}a+=l.join(`
21
+ `)+`
22
+ `;}return a+=`
23
+ `,a},Dt=p({description:"Print generated CLI reference from command schemas",options:z.object({}),handler:async()=>{let{default:t}=await Promise.resolve().then(()=>(J(),st)),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 m=n[a];e+=He(r,a,m);}}console.log(e);}});});var Me,Ot,$t=g(()=>{f();Me=`# AIP Hooks
24
+
25
+ Automated scripts that run before/after project/task actions.
26
+
27
+ ## Hook Types
28
+
29
+ **Pre-hooks** (block action if they fail):
30
+ - \`pre-create\` - Before project/task creation
31
+ - \`pre-start\` - Before task start
32
+ - \`pre-update\` - Before task/project update
33
+ - \`pre-complete\` - Before task completion (quality gates)
34
+
35
+ **Post-hooks** (failures logged but don't block):
36
+ - \`post-create\` - After creation
37
+ - \`post-start\` - After task start
38
+ - \`post-update\` - After update
39
+ - \`post-complete\` - After completion (cleanup, notifications)
40
+
41
+ ## File Location
42
+
43
+ \`\`\`
44
+ tmp/hermes/projects/{project}/hooks/
45
+ \u251C\u2500\u2500 pre-complete.ts # Project-level hook
46
+ \u2514\u2500\u2500 post-create.sh
47
+
48
+ tmp/hermes/projects/{project}/tasks/{task}/hooks/
49
+ \u2514\u2500\u2500 pre-update.py # Task-level hook
50
+ \`\`\`
51
+
52
+ **Execution order:** Project hooks first, then task hooks.
53
+
54
+ ## Environment Variables
55
+
56
+ Hooks receive these automatic:
57
+
58
+ | Variable | Always | Description |
59
+ |----------|--------|-------------|
60
+ | \`HOOK_TYPE\` | \u2705 | e.g. \`pre-complete\` |
61
+ | \`ENTITY_TYPE\` | \u2705 | \`project\` or \`task\` |
62
+ | \`TARGET_DIR\` | \u2705 | Directory being acted on |
63
+ | \`PROJECT_DIR\` | \u2705 | Project root path |
64
+ | \`PROJECT_SLUG\` | \u2705 | Project name |
65
+ | \`TASK_DIR\` | Task only | Task directory path |
66
+ | \`TASK_SLUG\` | Task only | Task name |
67
+
68
+ ## Creating Hooks
69
+
70
+ \`\`\`bash
71
+ # TypeScript/JavaScript
72
+ aip hook create pre-complete --lang ts
73
+
74
+ # Shell
75
+ aip hook create post-create --lang sh
76
+
77
+ # Python
78
+ aip hook create pre-update --lang py
79
+ \`\`\`
80
+
81
+ ## Examples
82
+
83
+ ### Pre-complete validation (TypeScript)
84
+
85
+ \`\`\`typescript
86
+ #!/usr/bin/env tsx
87
+ import { readFileSync } from 'fs'
88
+ import { join } from 'path'
89
+
90
+ const taskDir = process.env.TASK_DIR!
91
+ const mainPath = join(taskDir, 'main.md')
92
+ const content = readFileSync(mainPath, 'utf-8')
93
+
94
+ // Require description
95
+ if (!content.includes('description:')) {
96
+ console.error('\u274C Task must have description')
97
+ process.exit(1)
98
+ }
99
+
100
+ // Require status update
101
+ const statusPath = join(taskDir, 'status.md')
102
+ if (!existsSync(statusPath) || readFileSync(statusPath, 'utf-8').length === 0) {
103
+ console.error('\u274C status.md is empty')
104
+ process.exit(1)
105
+ }
106
+ \`\`\`
107
+
108
+ ### Post-complete archive (Shell)
109
+
110
+ \`\`\`bash
111
+ #!/bin/bash
112
+ # Archive outputs after task completion
113
+
114
+ archive_dir="$PROJECT_DIR/archive/$TASK_SLUG"
115
+ mkdir -p "$archive_dir"
116
+ cp -r "$TASK_DIR/outputs/"* "$archive_dir/" 2>/dev/null || true
117
+ echo "\u2705 Archived to $archive_dir"
118
+ \`\`\`
119
+
120
+ ### Pre-update lock check (Python)
121
+
122
+ \`\`\`python
123
+ #!/usr/bin/env python3
124
+ import os
125
+ from pathlib import Path
126
+
127
+ task_dir = Path(os.environ['TASK_DIR'])
128
+ lock_file = task_dir / '.locked'
129
+
130
+ if lock_file.exists():
131
+ print("\u274C Task is locked")
132
+ print(" Remove .locked file to allow updates")
133
+ sys.exit(1)
134
+ \`\`\`
135
+
136
+ ## Rules
137
+
138
+ **DO:**
139
+ - Exit \`0\` for success, \`1\` for failure
140
+ - Use environment variables (don't hardcode paths)
141
+ - Log clear error messages
142
+ - Keep hooks fast (<5s ideal)
143
+ - Make pre-hooks idempotent (safe to run multiple times)
144
+
145
+ **DON'T:**
146
+ - Modify files in pre-hooks (only validate)
147
+ - Block in post-hooks (they're for cleanup/logging)
148
+ - Assume TASK_* vars exist (check for project-level hooks)
149
+ - Run long operations (use delegation instead)
150
+
151
+ ## Debugging
152
+
153
+ \`\`\`bash
154
+ # Test hook manually
155
+ cd tmp/hermes/projects/my-project
156
+ ./hooks/pre-complete.ts
157
+
158
+ # Check environment
159
+ echo $HOOK_TYPE $PROJECT_SLUG $TASK_SLUG
160
+
161
+ # Run with verbose logging
162
+ DEBUG=1 aip task update --status done
163
+ \`\`\`
164
+
165
+ ## Common Patterns
166
+
167
+ ### Validation gates
168
+ - Require tests before completion
169
+ - Check outputs exist
170
+ - Validate frontmatter fields
171
+ - Ensure status.md updated
172
+
173
+ ### Automation
174
+ - Backup before changes
175
+ - Archive outputs on completion
176
+ - Sync to external systems
177
+ - Send notifications (Slack, email)
178
+
179
+ ### Quality control
180
+ - Lint check before commit
181
+ - Run tests automatically
182
+ - Check for TODOs/comments
183
+ - Validate output format
184
+
185
+ ---
186
+
187
+ *Hooks automate workflow enforcement. Pre-hooks guard quality, post-hooks handle cleanup.*
188
+ `,Ot=p({description:"Hook types, env vars, and patterns",options:z.object({}),handler:async()=>{console.log(Me);}});});var ze,Ct,Nt=g(()=>{f();ze=`# AIP Project Structure
189
+
190
+ File organization for autonomous AI work.
191
+
192
+ ## Directory Layout
193
+
194
+ \`\`\`
195
+ $ROOT/
196
+ \u251C\u2500\u2500 projects/
197
+ \u2502 \u251C\u2500\u2500 {project-slug}/
198
+ \u2502 \u2502 \u251C\u2500\u2500 main.md # Goals, scope, context
199
+ \u2502 \u2502 \u251C\u2500\u2500 status.md # Chronological activity log
200
+ \u2502 \u2502 \u251C\u2500\u2500 hooks/ # pre|post-{create,start,update,complete}.*
201
+ \u2502 \u2502 \u251C\u2500\u2500 inputs/ # External data (API responses, downloads)
202
+ \u2502 \u2502 \u251C\u2500\u2500 outputs/ # Deliverables (reports, code, final files)
203
+ \u2502 \u2502 \u251C\u2500\u2500 scripts/ # Automation (bash, python, js)
204
+ \u2502 \u2502 \u2514\u2500\u2500 tasks/
205
+ \u2502 \u2502 \u2514\u2500\u2500 {task-slug}/
206
+ \u2502 \u2502 \u251C\u2500\u2500 main.md # Task definition
207
+ \u2502 \u2502 \u251C\u2500\u2500 status.md # Single-line updates
208
+ \u2502 \u2502 \u251C\u2500\u2500 hooks/ # Task-level hooks
209
+ \u2502 \u2502 \u251C\u2500\u2500 inputs/
210
+ \u2502 \u2502 \u251C\u2500\u2500 outputs/
211
+ \u2502 \u2502 \u2514\u2500\u2500 scripts/
212
+ \u2514\u2500\u2500 agents/
213
+ \u2514\u2500\u2500 {agent-slug}/
214
+ \u2514\u2500\u2500 main.md # Agent profile
215
+ \`\`\`
216
+
217
+ ## File Purposes
218
+
219
+ ### main.md (Context - Read First)
220
+
221
+ **Project main.md:**
222
+ - Objectives and success criteria
223
+ - Scope and constraints
224
+ - Background information
225
+ - Requirements
226
+
227
+ **Task main.md:**
228
+ - Specific deliverable
229
+ - Requirements
230
+ - Acceptance criteria
231
+
232
+ **Frontmatter:**
233
+ \`\`\`yaml
234
+ ---
235
+ name: Clear Title
236
+ description: One-line summary
237
+ assignee: agent-name
238
+ status: pending|in-progress|ongoing|done|blocked
239
+ created: YYYY-MM-DD
240
+ ---
241
+ \`\`\`
242
+
243
+ ### status.md (Activity Log - Append Only)
244
+
245
+ **Task updates** (each work session):
246
+ \`\`\`markdown
247
+ ### 2026-03-24 14:30 - Implemented API integration
248
+ \u2705 Completed REST API with error handling. Next: write tests.
249
+ \`\`\`
250
+
251
+ **Project updates** (when task completes):
252
+ \`\`\`markdown
253
+ ### 2026-03-24 18:00 - Task: api-integration \u2705
254
+ Implemented 5 endpoints with validation. Details: tasks/api-integration/
255
+ \`\`\`
256
+
257
+ **Rules:**
258
+ - One line per session
259
+ - Include timestamp
260
+ - State what's done + what's next
261
+ - Use emojis: \u{1F504} in-progress | \u2705 done | \u26A0\uFE0F blocked | \u274C failed
262
+
263
+ ### inputs/ (External Data)
264
+
265
+ Store here:
266
+ - API responses (JSON, XML)
267
+ - Downloaded files
268
+ - Web scrapes
269
+ - Reference documents
270
+
271
+ **Naming:** \`api-response-2026-03-24.json\`, \`scraped-docs.md\`
272
+
273
+ ### outputs/ (Deliverables)
274
+
275
+ Store here:
276
+ - Final reports
277
+ - Generated code
278
+ - Processed data
279
+ - Artifacts for external use
280
+
281
+ **Naming:** \`final-report.md\`, \`optimized-config.yaml\`
282
+
283
+ ### scripts/ (Automation)
284
+
285
+ Create when:
286
+ - Work is repetitive (3+ times)
287
+ - Complex command sequences
288
+ - Validation/checking needed
289
+ - Data transformations
290
+
291
+ **Languages:**
292
+ - **Bash:** Simple ops, command chaining
293
+ - **Python:** Data processing, API calls
294
+ - **JavaScript:** Web scraping, Node.js tooling
295
+
296
+ ## Workflow
297
+
298
+ ### Starting Work
299
+
300
+ 1. **Read context**
301
+ \`\`\`bash
302
+ cat projects/{project}/main.md
303
+ cat projects/{project}/tasks/{task}/main.md
304
+ cat projects/{project}/tasks/{task}/status.md
305
+ \`\`\`
306
+
307
+ 2. **Check recent activity** (status.md)
308
+
309
+ 3. **Review inputs/** (existing data)
310
+
311
+ ### During Work
312
+
313
+ 1. **Create scripts/** if automation helps
314
+ 2. **Save external data to inputs/**
315
+ 3. **Place deliverables in outputs/**
316
+
317
+ ### Completing Work
318
+
319
+ 1. **Update task status.md** (final entry)
320
+ 2. **Update task main.md** status \u2192 \`done\`
321
+ 3. **Append to project status.md** (packed summary)
322
+ 4. **Ensure outputs/** has all deliverables
323
+
324
+ ## Commands
325
+
326
+ \`\`\`bash
327
+ # Create
328
+ aip project create {name} --description "{desc}"
329
+ aip task create {project} {name} --description "{desc}"
330
+
331
+ # Navigate
332
+ cd $(aip project path {name})
333
+ cd $(aip task path {project} {task})
334
+
335
+ # Update
336
+ aip task update {project} {task} --status done
337
+ aip task update {project} {task} --summary "Completed X"
338
+
339
+ # Context
340
+ aip task ingest {project} {task} # Full context for AI
341
+ \`\`\`
342
+
343
+ ## Best Practices
344
+
345
+ **DO:**
346
+ - Keep main.md focused (update rarely)
347
+ - Append to status.md religiously
348
+ - Use inputs/outputs/ separation
349
+ - Create scripts for repetitive work
350
+ - Run hooks automatically
351
+
352
+ **DON'T:**
353
+ - Put status updates in main.md
354
+ - Write paragraphs in status.md
355
+ - Mix inputs and outputs
356
+ - Create scripts for one-time tasks
357
+ - Ignore hook failures
358
+
359
+ ---
360
+
361
+ *Structure enables autonomy. Clean files = clear context = better execution.*
362
+ `,Ct=p({description:"Project and task directory layout for autonomous work",options:z.object({}),handler:async()=>{console.log(ze);}});});var nt,Rt=g(()=>{nt={name:"ai-projects",version:"1.0.0",type:"module",description:"AI project management CLI - create and manage projects, tasks, 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",publish:"npm publish","version:patch":"npm version patch","version:minor":"npm version minor","version:major":"npm version major"},keywords:["ai","project-management","task-management","cli","hermes-agent","autonomous-agents"],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"}};});var It,Ft=g(()=>{Rt();f();b();It=p({description:"Print compact CLI usage (all nouns, or one noun if name is given)",options:z.object({}),args:z.object({name:z.string().optional().describe("Noun (e.g. task) to list verbs for")}),handler:async({name:t})=>{let{default:e}=await Promise.resolve().then(()=>(J(),st)),o=`${nt.name} ${nt.version} -`,r=s.dumpCommandMapLines(e,t);if(!t)console.log(o,"Usage: aip <noun> <verb> [options]"),console.log(r.map(n=>`-> ${n}`).join(`
363
+ `));else {let n=r[0]??`${t} {?}`;console.log(o,`Usage: aip ${n} [options]`);}}});});var at,Je,w,v=g(()=>{E();O();b();at=s.join(y.AIP_HOME,c.dirs.PROJECTS),Je={getProjectFromPwd(t=process.cwd()){let e=R.relative(at,t);if(!e||e.startsWith(".."))return null;let o=e.split(R.sep).filter(Boolean);return o.length===0?null:o[0]},getTaskFromPwd(t=process.cwd()){let e=R.relative(at,t);if(!e||e.startsWith(".."))return null;let o=e.split(R.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: ${at}`);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(`
364
+ `)},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.")}},w=Je;});var Ut,_t=g(()=>{f();b();v();E();Ut=p({options:z.object({lang:z.enum(c.languages).default("ts").describe("Language"),target:z.enum(c.targets).default("project").describe("Target level")}),args:z.object({type:z.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}=w.getTargetDir(o),m=s.join(i,c.dirs.HOOKS);await s.ensureDir(m);let l=s.join(m,`${t}${n}`);if(await s.fileExists(l))throw new Error(`Hook already exists: ${l}`);let h;if(r==="ts")h=`#!/usr/bin/env tsx
365
+ /** ${t} hook for ${a} */
366
+
367
+ import { env } from 'node:process'
368
+
369
+ console.log('Running ${t} hook for ${a}')
370
+ console.log('PROJECT_SLUG:', env.PROJECT_SLUG)
371
+ if (env.TASK_SLUG) {
372
+ console.log('TASK_SLUG:', env.TASK_SLUG)
373
+ }
374
+
375
+ // Exit with non-zero to prevent action (for pre-hooks)
376
+ // process.exit(1)
377
+ `;else if(r==="js")h=`#!/usr/bin/env node
378
+ /** ${t} hook for ${a} */
379
+
380
+ console.log('Running ${t} hook for ${a}')
381
+ console.log('PROJECT_SLUG:', process.env.PROJECT_SLUG)
382
+ if (process.env.TASK_SLUG) {
383
+ console.log('TASK_SLUG:', process.env.TASK_SLUG)
384
+ }
385
+
386
+ // Exit with non-zero to prevent action (for pre-hooks)
387
+ // process.exit(1)
388
+ `;else if(r==="sh")h=`#!/bin/bash
389
+ # ${t} hook for ${a}
390
+
391
+ echo "Running ${t} hook for ${a}"
392
+ echo "PROJECT_SLUG: $PROJECT_SLUG"
393
+ if [ -n "$TASK_SLUG" ]; then
394
+ echo "TASK_SLUG: $TASK_SLUG"
395
+ fi
396
+
397
+ # Exit with non-zero to prevent action (for pre-hooks)
398
+ # exit 1
399
+ `;else if(r==="py")h=`#!/usr/bin/env python3
400
+ """${t} hook for ${a}"""
401
+
402
+ import os
403
+
404
+ print(f"Running ${t} hook for ${a}")
405
+ print(f"PROJECT_SLUG: {os.environ.get('PROJECT_SLUG')}")
406
+ if os.environ.get('TASK_SLUG'):
407
+ print(f"TASK_SLUG: {os.environ.get('TASK_SLUG')}")
408
+
409
+ # Exit with non-zero to prevent action (for pre-hooks)
410
+ # sys.exit(1)
411
+ `;else throw new Error(`Unsupported language: ${r}`);await s.write(l,h);let{chmod:k}=await import('fs/promises');await k(l,493),console.log(`Hook created: ${l}`);}});});var Ze,x,I=g(()=>{E();O();b();Ze={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(m=>{let l=spawn(t,[],{stdio:"inherit",env:a,cwd:R.dirname(t),shell:false});l.on("close",(u,h)=>{u===0?m(true):(console.error(`Hook ${R.basename(t)} failed (code=${u??h})`),m(false));}),l.on("error",u=>{console.error(`Failed to execute hook ${t}: ${u.message}`),m(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))}},x=Ze;});var Lt,Mt=g(()=>{f();I();v();E();Lt=p({options:z.object({target:z.enum(c.targets).optional().describe("Target level")}),args:z.object({type:z.enum(c.hookTypes).describe("Hook type to run")}),handler:async({type:t,target:e})=>{let{targetDir:o,entityType:r}=w.getTargetDir(e),n={action:t,entityType:r,project:w.getProjectFromPwd()||void 0,task:w.getTaskFromPwd()||void 0};await x.runHooks(o,t,n)||(console.error(`Hook ${t} failed`),process.exit(1)),console.log(`Hook ${t} completed successfully`);}});});var Be,S,F=g(()=>{E();v();O();b();Be={formatLogEntry(t,e){let o=new Date().toISOString().replace("T"," ").replace(/\.\d{3}Z$/,""),r=e?` | ${e}`:"";return `[${o}${r}] ${t}
412
+ `},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=w.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=w.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,m])=>`${a}=${m}`).join(", ");n=`${e}: ${i}`;}await this.appendStatus(t,n,r);}},S=Be;});var Kt,zt=g(()=>{f();b();P();I();F();Kt=p({description:"Create a new project with name, description, optional status and assignee",options:z.object({description:z.string().describe("Project description"),status:z.string().default("active").describe("Initial status"),assignee:z.string().optional().describe("Assignee agent slug")}),args:z.object({name:z.string().describe("Project name")}),handler:async({name:t,description:e,status:o,assignee:r})=>{let n=s.slugify(t),i=d.getProjectDir(n);if(!await x.runHooks(i,"pre-create",{action:"pre-create",entityType:"project"}))throw new Error("Pre-create hook failed, aborting project creation");await d.createProject(n,{name:t,description:e,status:o,assignee:r,created:new Date().toISOString()}),await S.appendStatus(i,`Project created: ${t}`),await x.runHooks(i,"post-create",{action:"post-create",entityType:"project"}),console.log(`Project created: ${n}`),console.log(` Path: ${i}`);}});});var Gt,Jt=g(()=>{f();v();Gt=p({options:z.object({}),handler:async()=>{let t=w.getProjectFromPwd();t||(console.error("Not in a project directory"),process.exit(1)),console.log(t);}});});var Zt,Bt=g(()=>{f();P();Zt=p({description:"List all projects, optionally filtered by status",options:z.object({status:z.string().optional().describe("Filter by status")}),handler:async({status:t})=>{let e=await d.listProjects(),o=[];for(let r of e){let n=await d.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 Vt,qt=g(()=>{f();P();Vt=p({description:"Output project directory path (for cd)",options:z.object({}),args:z.object({name:z.string().describe("Project name (slug)")}),handler:async({name:t})=>{let e=d.getProjectDir(t);console.log(e);}});});var Yt,Xt=g(()=>{f();P();I();F();v();Yt=p({description:"Update project properties: name, description, status, assignee, or append summary",options:z.object({name:z.string().optional().describe("New name"),description:z.string().optional().describe("New description"),status:z.string().optional().describe("New status"),assignee:z.string().optional().describe("New assignee"),summary:z.string().optional().describe("Optional summary to append to status.md")}),args:z.object({project:z.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||w.getProjectFromPwd();if(!a)throw new Error("No project specified and not in a project directory");let m=d.getProjectDir(a);if(!await x.runHooks(m,"pre-update",{action:"pre-update",entityType:"project"}))throw new Error("Pre-update hook failed, aborting update");let u={};if(e&&(u.name=e),o&&(u.description=o),r&&(u.status=r),n&&(u.assignee=n),Object.keys(u).length===0){console.log("No updates provided");return}await d.updateProject(a,u);let h=Object.entries(u).map(([k,tt])=>`${k}=${tt}`).join(", ");await S.appendStatus(m,`Updated: ${h}`),i&&await S.appendStatus(m,i),await x.runHooks(m,"post-update",{action:"post-update",entityType:"project"}),console.log(`Project ${a} updated`);}});});var Qt,te=g(()=>{E();f();O();b();Qt=p({description:"Read a skill's SKILL.md file into the console for agent context",options:z.object({}),args:z.object({name:z.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}
413
+ Expected at: ${o}`);await s.logFiles(o);}});});var ee,oe=g(()=>{f();I();b();P();F();ee=p({description:"Create a new task with optional priority, assignee, and initial status",options:z.object({description:z.string().optional().describe("Task description"),priority:z.enum(["low","medium","high"]).optional().describe("Task priority"),assignee:z.string().optional().describe("Assignee agent slug"),status:z.enum(["pending","in-progress","ongoing","done"]).default("pending").describe("Initial status")}),args:z.object({project:z.string().describe("Project slug"),name:z.string().describe("Task name")}),handler:async({project:t,name:e,description:o,priority:r,assignee:n,status:i})=>{let a=s.slugify(e),m=d.getTaskDir(t,a);if(!await x.runHooksForContext(d.getProjectDir(t),m,"pre-create",{action:"pre-create",entityType:"task",project:t}))throw new Error("Pre-create hook failed, aborting task creation");await d.createTask(t,a,{name:e,description:o,priority:r,assignee:n,status:i,created:new Date().toISOString()}),await S.appendStatus(m,`Task created: ${e}`),await x.runHooksForContext(d.getProjectDir(t),m,"post-create",{action:"post-create",entityType:"task",project:t}),console.log(`Task created: ${a}`),console.log(` Project: ${t}`),console.log(` Path: ${m}`);}});});var re,se=g(()=>{f();v();re=p({description:"Get the current task slug from PWD",options:z.object({}),handler:async()=>{let t=w.getTaskFromPwd();t||(console.error("Not in a task directory"),process.exit(1)),console.log(t);}});});var ne,ie=g(()=>{v();f();P();ne=p({description:"Output full task context (main.md, status.md) for ingestion by agents",options:z.object({}),args:z.object({project:z.string().optional().describe("Project slug (default: from $PWD)"),task:z.string().optional().describe("Task slug (default: from $PWD)")}),handler:async({project:t,task:e})=>{let o=w.getCurrentContext(),r=t??o.project,n=e??o.task;if(!r||!n)throw new Error("Need project and task (or cd into task dir)");await d.ingestTask(r,n);}});});var ae,ce=g(()=>{f();P();v();ae=p({description:"List tasks in a project, optionally filtered by status or assignee",options:z.object({project:z.string().optional().describe("Project slug (defaults to current project from $PWD)"),status:z.string().optional().describe("Filter by status"),assignee:z.string().optional().describe("Filter by assignee")}),handler:async({project:t,status:e,assignee:o})=>{let r=t||w.getProjectFromPwd();if(!r)throw new Error("No project specified and not in a project directory");let n=await d.listTasks(r),i=[];for(let a of n){let m=await d.getTask(r,a);m&&(e&&m.status!==e||o&&m.assignee!==o||i.push({slug:a,name:m.name||a,status:m.status,assignee:m.assignee,priority:m.priority}));}if(i.length===0){console.log("No tasks found");return}console.log(`Tasks in ${r}:`),console.log("---");for(let a of i)console.log(`${a.slug.padEnd(20)} ${a.name?.padEnd(30)||""} ${a.status||""} ${a.assignee||""} ${a.priority||""}`);}});});var pe,me=g(()=>{f();P();pe=p({description:"Output task directory path (for cd)",options:z.object({}),args:z.object({project:z.string().describe("Project slug"),task:z.string().describe("Task slug")}),handler:async({project:t,task:e})=>{let o=d.getTaskDir(t,e);console.log(o);}});});var Y,mt=g(()=>{f();I();P();F();Y=p({description:"Update task properties: name, description, status, priority, assignee, or append summary",options:z.object({name:z.string().optional().describe("New name"),description:z.string().optional().describe("New description"),status:z.enum(["pending","in-progress","ongoing","done","blocked"]).optional().describe("New status"),priority:z.enum(["low","medium","high"]).optional().describe("New priority"),assignee:z.string().optional().describe("New assignee"),summary:z.string().optional().describe("Optional summary to append to status.md")}),args:z.object({project:z.string().optional().describe("Project slug (defaults to current project from $PWD)"),task:z.string().optional().describe("Task slug (defaults to current task from $PWD)")}),handler:async({project:t,task:e,name:o,description:r,status:n,priority:i,assignee:a,summary:m})=>{let l={project:t,task:e};if(!l.project||!l.task)throw new Error("No task specified and not in a task directory. Use --project and --task flags.");let u=d.getTaskDir(l.project,l.task);if(!await x.runHooksForContext(d.getProjectDir(l.project),u,"pre-update",{action:"pre-update",entityType:"task",project:l.project,task:l.task}))throw new Error("Pre-update hook failed, aborting update");let k={};if(o&&(k.name=o),r&&(k.description=r),n&&(k.status=n),i&&(k.priority=i),a&&(k.assignee=a),Object.keys(k).length===0&&!m){console.log("No updates provided");return}if(Object.keys(k).length>0){await d.updateTask(l.project,l.task,k);let tt=Object.entries(k).map(([he,je])=>`${he}=${je}`).join(", ");await S.appendStatus(u,`Updated: ${tt}`);}m&&await S.appendStatus(u,m),await x.runHooksForContext(d.getProjectDir(l.project),u,"post-update",{action:"post-update",entityType:"task",project:l.project,task:l.task}),console.log(`Task ${l.task} updated`);}});});var le,de=g(()=>{f();P();mt();le=p({description:"Start a task: set status to in-progress, optionally print context",options:z.object({ingest:z.boolean().default(false).describe("Also output context for this task")}),args:z.object({project:z.string().describe("Project slug"),task:z.string().describe("Task slug")}),handler:async({project:t,task:e,ingest:o})=>{(await d.getTask(t,e))?.status!=="in-progress"&&await Y.handler({project:t,task:e,status:"in-progress"}),o&&await d.ingestTask(t,e);}});});var ue,ge=g(()=>{f();P();F();ue=p({description:"Post-mortem analysis for a completed task",options:z.object({}),args:z.object({project:z.string().describe("Project slug"),task:z.string().describe("Task slug")}),handler:async({project:t,task:e})=>{let o=d.getTaskDir(t,e),r=await d.getTask(t,e),i=(await S.readStatus(o)).split(`
414
+ `).filter(l=>l.startsWith("[")).length,a=[],m=r?.name||e;i>5&&a.push("High status update count - consider breaking into smaller tasks"),m.toLowerCase().includes("implement")&&a.push("Implementation task - check if similar patterns exist to reuse"),m.toLowerCase().includes("create")&&m.toLowerCase().includes("command")&&a.push("Command creation - check existing command patterns in src/commands/"),console.log(`
415
+ === Post-Mortem Analysis ===`),console.log(`Project: ${t}`),console.log(`Task: ${e}`),console.log(`Name: ${m}`),console.log(`Status: ${r?.status||"unknown"}`),console.log(`Priority: ${r?.priority||"none"}`),console.log(`Status updates: ${i}`),a.length>0?(console.log(`
416
+ Suggestions:`),a.forEach(l=>console.log(` - ${l}`))):console.log(`
417
+ No specific suggestions - task looks well-scoped`),console.log(`
418
+ === End Post-Mortem ===
419
+ `);}});});var fe,ye=g(()=>{f();b();fe=p({description:"Read one or more files into the console",options:z.object({}),args:z.object({paths:z.array(z.string()).describe("File paths to read")}),handler:async({paths:t})=>{await s.logFiles(...t);}});});var st={};we(st,{default:()=>N});var Ye,N,J=g(()=>{kt();jt();wt();Pt();St();vt();$t();Nt();Ft();_t();Mt();zt();Jt();Bt();qt();Xt();te();oe();se();ie();ce();me();de();mt();ge();ye();Ye={agent:{create:yt,current:ht,list:Tt,path:bt,start:xt},help:{api:Dt,hooks:Ot,structure:Ct,usage:It},hook:{create:Ut,run:Lt},project:{create:Kt,current:Gt,list:Zt,path:Vt,update:Yt},skill:{read:Qt},task:{create:ee,current:re,ingest:ne,list:ae,path:pe,start:le,update:Y},util:{postmortem:ue,read:fe}},N=Ye;});J();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 ke(t){let[e,o,...r]=t;try{(!e||!s.isKeyOf(e,N))&&(await N.help.usage.handler({}),process.exit(1));let n=N[e];(!o||!s.isKeyOf(o,n))&&(await N.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 Un=ke,_n=N;s.isMain()&&ke(process.argv.slice(2));export{_n as commands,Un as default};
package/package.json ADDED
@@ -0,0 +1,106 @@
1
+ {
2
+ "name": "ai-projects",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "AI project management CLI - create and manage projects, tasks, and agents",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "aip": "dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist/**/*",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "scripts": {
17
+ "build": "npm run build:map && npm run build:code",
18
+ "build:map": "tsx bin/map-commands.ts",
19
+ "build:code": "tsup --no-dts",
20
+ "build:all": "npm run build:map && tsup",
21
+ "build:check": "tsc --noEmit",
22
+ "build:watch": "npm run build:code -- --watch",
23
+ "build:clean": "rimraf dist/*",
24
+ "build:incr": "tsup --no-dts",
25
+ "start": "dist/index.js",
26
+ "dev": "npm run build:watch -- --onSuccess \"dist/index.js\"",
27
+ "cli": "npm run build && npm start --",
28
+ "ts": "tsx",
29
+ "vitest": "VITE_CJS_IGNORE_WARNING=true vitest",
30
+ "test": "npm run test:types && npm run test:unit",
31
+ "test:unit": "npm run vitest -- run",
32
+ "test:types:test": "tsc -p tsconfig.test.json --incremental --tsBuildInfoFile dist/test.tsbuildinfo",
33
+ "test:types:bin": "tsc -p bin/tsconfig.json --incremental --tsBuildInfoFile dist/bin.tsbuildinfo",
34
+ "test:types": "npm run test:types:test && npm run test:types:bin",
35
+ "test:full": "npm run lint:full && npm run test",
36
+ "eslint": "eslint --cache",
37
+ "lint": "npm run eslint -- '{src,bin}/**/*.ts'",
38
+ "lint:fix": "npm run lint -- --fix",
39
+ "lint:full": "npm run build:incr && npm run test:types:bin && npm run lint:fix",
40
+ "lint:full:silent": "npm run -s lint:full && echo LINT OK",
41
+ "map": "npm run build:map",
42
+ "link": "npm link",
43
+ "unlink": "npm unlink",
44
+ "prepare": "[ \"$CI\" != \"true\" ] && [ -d node_modules/husky ] && husky || true",
45
+ "prepack": "npm run test:full && npm run build:all",
46
+ "publish:dry": "npm pack --dry-run",
47
+ "publish": "npm publish",
48
+ "version:patch": "npm version patch",
49
+ "version:minor": "npm version minor",
50
+ "version:major": "npm version major"
51
+ },
52
+ "keywords": [
53
+ "ai",
54
+ "project-management",
55
+ "task-management",
56
+ "cli",
57
+ "hermes-agent",
58
+ "autonomous-agents"
59
+ ],
60
+ "author": "Ariel Flesler <aflesler@gmail.com>",
61
+ "license": "MIT",
62
+ "repository": {
63
+ "type": "git",
64
+ "url": "git+https://github.com/flesler/ai-projects.git"
65
+ },
66
+ "homepage": "https://github.com/flesler/ai-projects#readme",
67
+ "bugs": {
68
+ "url": "https://github.com/flesler/ai-projects/issues"
69
+ },
70
+ "engines": {
71
+ "node": ">=20.0.0"
72
+ },
73
+ "dependencies": {
74
+ "dotenv": "^17.3.1",
75
+ "lodash": "^4.17.21",
76
+ "moment": "^2.30.1",
77
+ "tslib": "^2.8.1",
78
+ "yaml": "^2.8.0",
79
+ "zod": "^3.25.76",
80
+ "zod-opts": "^1.0.0"
81
+ },
82
+ "devDependencies": {
83
+ "@eslint/js": "^10.0.1",
84
+ "@stylistic/eslint-plugin": "^5.7.0",
85
+ "@types/dotenv": "^8.2.3",
86
+ "@types/eslint": "^9.6.1",
87
+ "@types/lodash": "^4.17.23",
88
+ "@types/moment": "^2.13.0",
89
+ "@types/node": "^25.0.9",
90
+ "@types/source-map-support": "^0.5.10",
91
+ "@typescript-eslint/eslint-plugin": "^8.53.0",
92
+ "@typescript-eslint/parser": "^8.53.0",
93
+ "eslint": "^10.0.3",
94
+ "eslint-plugin-import-x": "^4.16.2",
95
+ "eslint-plugin-unused-imports": "^4.4.1",
96
+ "fast-glob": "^3.3.3",
97
+ "husky": "^9.1.7",
98
+ "rimraf": "^6.0.1",
99
+ "source-map-support": "^0.5.21",
100
+ "tsup": "^8.5.1",
101
+ "tsx": "^4.20.3",
102
+ "types-package-json": "^2.0.39",
103
+ "typescript": "^5.8.3",
104
+ "vitest": "^4.0.17"
105
+ }
106
+ }