@autonomos/cli 0.0.1
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/.turbo/turbo-build.log +16 -0
- package/AGENT.md +11 -0
- package/LICENSE +11 -0
- package/README.md +72 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +63 -0
- package/eslint.config.ts +18 -0
- package/lint-staged.config.mjs +4 -0
- package/package.json +43 -0
- package/prettier.config.mjs +3 -0
- package/src/commands/agents.ts +154 -0
- package/src/commands/init.ts +128 -0
- package/src/commands/status.ts +94 -0
- package/src/commands/update.ts +111 -0
- package/src/index.ts +205 -0
- package/tsconfig.json +36 -0
- package/tsdown.config.ts +10 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
> @autonomos/cli@0.0.1 build /home/runner/work/autonomos/autonomos/packages/cli
|
|
3
|
+
> tsdown
|
|
4
|
+
|
|
5
|
+
[34mℹ[39m tsdown [2mv0.18.4[22m powered by rolldown [2mv1.0.0-beta.57[22m
|
|
6
|
+
[34mℹ[39m config file: [4m/home/runner/work/autonomos/autonomos/packages/cli/tsdown.config.ts[24m
|
|
7
|
+
[34mℹ[39m entry: [34msrc/index.ts[39m
|
|
8
|
+
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
9
|
+
[34mℹ[39m Build start
|
|
10
|
+
[34mℹ[39m Granting execute permission to [4mdist/index.mjs[24m
|
|
11
|
+
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m9.19 kB[22m [2m│ gzip: 3.35 kB[22m
|
|
12
|
+
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m0.01 kB[22m [2m│ gzip: 0.03 kB[22m
|
|
13
|
+
[34mℹ[39m 2 files, total: 9.20 kB
|
|
14
|
+
[32m✔[39m Build complete in [32m1088ms[39m
|
|
15
|
+
[32m✔[39m [2m[publint][22m No issues found [2m(342ms)[22m
|
|
16
|
+
🙏 Build succeeded!
|
package/AGENT.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# AGENT CONTEXT: @autonomos/cli
|
|
2
|
+
|
|
3
|
+
## 🧠 Context & Objectives
|
|
4
|
+
|
|
5
|
+
This package is the public-facing tool for the Agent Protocol.
|
|
6
|
+
It consumes `@autonomos/core` to perform actions like bootstrapping projects (`init`), updating docs, or parsing tasks.
|
|
7
|
+
|
|
8
|
+
## ⚙️ Workflow
|
|
9
|
+
|
|
10
|
+
- **Dependencies:** Uses `commander` for CLI args.
|
|
11
|
+
- **Linkage:** Depends on `workspace:@autonomos/core`.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hakim Saoudi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
The Software may include icons that are licensed under the Creative Commons Attribution 4.0 International License (CC BY 4.0). Commercial use is allowed, but attribution is required for the use of these icons. See LICENSE-THIRD-PARTY for more details.
|
|
10
|
+
|
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# @autonomos/cli
|
|
2
|
+
|
|
3
|
+
A command-line interface for managing the Autonomos Agent Protocol.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Locally in your project
|
|
9
|
+
pnpm add -D @autonomos/cli
|
|
10
|
+
|
|
11
|
+
# Or globally
|
|
12
|
+
pnpm add -g @autonomos/cli
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Commands
|
|
16
|
+
|
|
17
|
+
### `init`
|
|
18
|
+
|
|
19
|
+
Initialize the Agent Protocol in the current directory.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
autonomos init
|
|
23
|
+
autonomos init --dry-run
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### `update`
|
|
27
|
+
|
|
28
|
+
Update the project's Protocol to the latest version embedded in the CLI.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
autonomos update
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### `status`
|
|
35
|
+
|
|
36
|
+
Show project status and a summary of tasks from `TASKS.md`.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
autonomos status
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### `agents`
|
|
43
|
+
|
|
44
|
+
List all `AGENT.md` files in the project.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
autonomos agents # Search from current directory
|
|
48
|
+
autonomos agents --all # Search from project root
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### `version`
|
|
52
|
+
|
|
53
|
+
Show current CLI and Protocol versions.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
autonomos --version
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## How it works
|
|
60
|
+
|
|
61
|
+
The CLI manages the `.autonomos/` directory in your project, which contains:
|
|
62
|
+
|
|
63
|
+
- `manifest.json`: Protocol metadata and versioning.
|
|
64
|
+
- `PROTOCOL.md`: The immutable protocol specification.
|
|
65
|
+
- `TASKS.md`: Your project's task registry.
|
|
66
|
+
- `worklogs/`: Directory for session logs.
|
|
67
|
+
|
|
68
|
+
It also creates a root `AGENT.md` file if it doesn't exist, which serves as the primary context for AI agents.
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
|
|
72
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{Command as e}from"commander";import t from"picocolors";import{AGENT_FILE as n,AUTONOMOS_DIR as r,MANIFEST_FILE as i,PROTOCOL_FILE as a,PROTOCOL_TEMPLATE as o,PROTOCOL_VERSION as s,TASKS_FILE as c,TASKS_TEMPLATE as l,TaskParser as u,WORKLOGS_DIR as d,createManifest as f,generateAgentTemplate as p,generateManifestContent as m,parseManifest as h}from"@autonomos/core";import{existsSync as g,mkdirSync as _,readFileSync as v,readdirSync as y,statSync as b,writeFileSync as x}from"node:fs";import{basename as S,join as C,relative as w}from"node:path";function T(e){let t=e;for(;t!==`/`;){if(g(C(t,r))||g(C(t,`.git`)))return t;t=C(t,`..`)}return null}function E(e,t,r=0){let i=[],a=C(e,n);g(a)&&i.push({path:a,relativePath:w(t,a)||n,depth:r});try{let n=y(e);for(let a of n){if(a.startsWith(`.`)||a===`node_modules`||a===`dist`||a===`build`)continue;let n=C(e,a);try{b(n).isDirectory()&&i.push(...E(n,t,r+1))}catch{}}}catch{}return i}function D(e,t){if(e.length===0)return` (no AGENT.md files found)`;let n=[],r=S(t);n.push(`📁 ${r}/`);for(let t=0;t<e.length;t++){let r=e[t],i=t===e.length-1?`└── `:`├── `,a=` `.repeat(r.depth);n.push(`${a}${i}📄 ${r.relativePath}`)}return n.join(`
|
|
3
|
+
`)}function O(e={}){let t=e.cwd??process.cwd(),n;if(e.all){let e=T(t);if(!e)return{success:!1,message:`Could not find project root (.autonomos or .git directory).`};n=e}else n=t;let r=E(n,n);if(r.length===0)return{success:!0,message:`No AGENT.md files found.`,count:0};let i=D(r,n);return{success:!0,message:`Found ${r.length} AGENT.md file(s)`,tree:i,count:r.length}}function k(e={}){let t=e.cwd??process.cwd(),u=e.dryRun??!1,h=[],v=[];g(C(t,`.git`))||v.push("No Git repository detected. Consider running `git init` first.");let y=C(t,r);if(g(y))return{success:!1,message:`Project already initialized with Protocol v${s}. Use \`autonomos update\` to update.`,created:[],warnings:[],dryRun:u};if(u)return h.push(r),h.push(`${r}/${d}`),h.push(`${r}/${i}`),h.push(`${r}/${a}`),h.push(`${r}/${c}`),g(C(t,n))?v.push(`${n} already exists, would skip.`):h.push(n),{success:!0,message:`Would initialize project with Agent Protocol v${s}`,created:h,warnings:v,dryRun:!0};_(y,{recursive:!0}),h.push(r),_(C(y,d),{recursive:!0}),h.push(`${r}/${d}`);let b=f(`0.0.1`);x(C(y,i),m(b)),h.push(`${r}/${i}`),x(C(y,a),o),h.push(`${r}/${a}`),x(C(y,c),l),h.push(`${r}/${c}`);let S=C(t,n);return g(S)?v.push(`${n} already exists, skipping.`):(x(S,p(t.split(`/`).pop()??`Project`)),h.push(n)),{success:!0,message:`Project initialized with Agent Protocol v${s}`,created:h,warnings:v,dryRun:!1}}function A(e={}){let t=C(e.cwd??process.cwd(),r),n=C(t,i);if(!g(n))return{success:!1,message:"Project not initialized. Run `autonomos init` first.",initialized:!1};let a;try{a=h(v(n,`utf-8`))}catch{return{success:!1,message:`Could not read manifest.json`,initialized:!0}}let o,s=C(t,c);if(g(s))try{let e=v(s,`utf-8`),t=u.parse(e);o={total:t.length,todo:t.filter(e=>e.status===`TODO`).length,inProgress:t.filter(e=>e.status===`IN_PROGRESS`).length,done:t.filter(e=>e.status===`DONE`).length,blocked:t.filter(e=>e.status===`BLOCKED`).length}}catch{}return{success:!0,message:`Project status retrieved`,protocolVersion:a.protocolVersion,cliVersion:a.cliVersion,initialized:!0,taskSummary:o}}function j(e,t){let n=e.split(`.`).map(Number),r=t.split(`.`).map(Number);for(let e=0;e<3;e++){let t=n[e]??0,i=r[e]??0;if(t<i)return-1;if(t>i)return 1}return 0}function M(e={}){let t=C(e.cwd??process.cwd(),r),n=C(t,i);if(!g(n))return{success:!1,message:"Project not initialized. Run `autonomos init` first."};let c=h(v(n,`utf-8`)),l=c.protocolVersion,u=j(l,s);return u===0?{success:!0,message:`Already up to date (Protocol v${s})`,previousVersion:l,newVersion:s}:u>0?{success:!1,message:`This project uses Protocol v${l}, but your CLI only knows v${s}. Update your CLI with \`npm i -g @autonomos/cli\`.`,previousVersion:l,newVersion:s,cliOutdated:!0}:(x(C(t,a),o),x(n,m({...c,protocolVersion:s,cliVersion:`0.0.1`,lastUpdated:new Date().toISOString()})),{success:!0,message:`Protocol updated: v${l} → v${s}`,previousVersion:l,newVersion:s})}const N=`0.0.1`,P=new e;P.name(`autonomos`).description(t.cyan(`CLI for the Autonomos Agent Protocol
|
|
4
|
+
|
|
5
|
+
The Agent Protocol is a specification for AI agents to interact with codebases
|
|
6
|
+
in a structured, consistent way. It defines how agents should read context,
|
|
7
|
+
execute tasks, and persist knowledge.`)+`
|
|
8
|
+
|
|
9
|
+
Documentation: ${t.underline(`https://github.com/saoudi-h/autonomos`)}`).version(`${t.bold(`CLI:`)} ${t.green(N)}\n${t.bold(`Protocol:`)} ${t.green(s)}`,`-v, --version`,`Show version information`).helpOption(`-h, --help`,`Show help information`).addHelpText(`after`,`
|
|
10
|
+
${t.bold(`Examples:`)}
|
|
11
|
+
$ ${t.cyan(`autonomos init`)} Initialize the Agent Protocol in current directory
|
|
12
|
+
$ ${t.cyan(`autonomos update`)} Update Protocol to the latest version
|
|
13
|
+
$ ${t.cyan(`autonomos status`)} Show project status and task summary
|
|
14
|
+
$ ${t.cyan(`autonomos agents`)} List all AGENT.md files in the project
|
|
15
|
+
|
|
16
|
+
${t.bold(`More info:`)}
|
|
17
|
+
Run '${t.cyan(`autonomos <command> --help`)}' for detailed information about a command.
|
|
18
|
+
`),P.command(`init`).description(`Initialize the Agent Protocol in the current directory`).addHelpText(`after`,`
|
|
19
|
+
This command creates the following structure:
|
|
20
|
+
${t.blue(`.autonomos/`)}
|
|
21
|
+
├── ${t.white(`manifest.json`)} # Protocol metadata and version
|
|
22
|
+
├── ${t.white(`PROTOCOL.md`)} # Immutable protocol specification
|
|
23
|
+
├── ${t.white(`TASKS.md`)} # Task registry
|
|
24
|
+
└── ${t.blue(`worklogs/`)} # Session logs directory
|
|
25
|
+
${t.white(`AGENT.md`)} # Project context file (at root)
|
|
26
|
+
|
|
27
|
+
${t.bold(`Examples:`)}
|
|
28
|
+
$ ${t.cyan(`autonomos init`)}
|
|
29
|
+
$ ${t.cyan(`cd my-project && autonomos init`)}
|
|
30
|
+
`).option(`-n, --dry-run`,`Preview what would be created without writing files`).action(e=>{let n=k({dryRun:e.dryRun});n.success||(console.error(t.red(`\n❌ ${n.message}`)),process.exit(1)),n.dryRun?console.log(t.cyan(`\n🔍 ${n.message} (dry-run)`)):console.log(t.green(`\n✅ ${n.message}`)),n.created.length>0&&(console.log(`\n${t.bold(n.dryRun?`Would create:`:`Created:`)}`),n.created.forEach(e=>console.log(` ${t.blue(`📄`)} ${t.white(e)}`))),n.warnings.length>0&&(console.log(t.yellow(`
|
|
31
|
+
Warnings:`)),n.warnings.forEach(e=>console.log(` ${t.yellow(`⚠️`)} ${e}`)))}),P.command(`update`).description(`Update the Protocol to the latest version`).addHelpText(`after`,`
|
|
32
|
+
This command updates ${t.white(`PROTOCOL.md`)} to the latest version embedded in the CLI.
|
|
33
|
+
Only ${t.white(`PROTOCOL.md`)} is modified; your ${t.white(`TASKS.md`)} and ${t.white(`AGENT.md`)} files are preserved.
|
|
34
|
+
|
|
35
|
+
${t.bold(`Version comparison:`)}
|
|
36
|
+
- If your project has an older version: Updates to the new version
|
|
37
|
+
- If your project has a newer version: Warns you to update the CLI
|
|
38
|
+
- If versions match: No action needed
|
|
39
|
+
|
|
40
|
+
${t.bold(`Examples:`)}
|
|
41
|
+
$ ${t.cyan(`autonomos update`)}
|
|
42
|
+
`).action(()=>{let e=M();e.success||(e.cliOutdated?console.error(t.yellow(`\n⚠️ ${e.message}`)):console.error(t.red(`\n❌ ${e.message}`)),process.exit(1)),console.log(t.green(`\n✅ ${e.message}`))}),P.command(`status`).description(`Show project status and task summary`).addHelpText(`after`,`
|
|
43
|
+
Displays information about the current project:
|
|
44
|
+
- Protocol version
|
|
45
|
+
- CLI version used for initialization
|
|
46
|
+
- Task summary (todo, in-progress, done, blocked)
|
|
47
|
+
|
|
48
|
+
${t.bold(`Examples:`)}
|
|
49
|
+
$ ${t.cyan(`autonomos status`)}
|
|
50
|
+
`).action(()=>{let e=A();if(e.success||(console.error(t.red(`\n❌ ${e.message}`)),process.exit(1)),console.log(`\n${t.bold(`📦 Protocol`)} ${t.green(`v${e.protocolVersion}`)} ${t.dim(`(CLI v${e.cliVersion})`)}`),e.taskSummary){let n=e.taskSummary;console.log(`\n${t.bold(`📋 Tasks:`)} ${t.cyan(n.total)} total`),console.log(` ${t.white(`⬜ Todo:`)} ${t.white(n.todo)}`),console.log(` ${t.blue(`🔄 In Progress:`)} ${t.blue(n.inProgress)}`),console.log(` ${t.green(`✅ Done:`)} ${t.green(n.done)}`),n.blocked>0&&console.log(` ${t.red(`🚫 Blocked:`)} ${t.red(n.blocked)}`)}}),P.command(`agents`).description(`List all AGENT.md files in the project`).option(`-a, --all`,`Search from project root instead of current directory`).addHelpText(`after`,`
|
|
51
|
+
This command discovers and displays all ${t.white(`AGENT.md`)} files in a tree structure.
|
|
52
|
+
${t.white(`AGENT.md`)} files provide context to AI agents about specific directories.
|
|
53
|
+
|
|
54
|
+
${t.bold(`Modes:`)}
|
|
55
|
+
(default) Search from current directory downwards
|
|
56
|
+
--all Search from project root (finds .autonomos or .git)
|
|
57
|
+
|
|
58
|
+
${t.bold(`Examples:`)}
|
|
59
|
+
$ ${t.cyan(`autonomos agents`)} # List from current directory
|
|
60
|
+
$ ${t.cyan(`autonomos agents --all`)} # List from project root
|
|
61
|
+
$ ${t.cyan(`cd packages/core && autonomos agents`)} # List only in packages/core
|
|
62
|
+
`).action(e=>{let n=O({all:e.all});n.success||(console.error(t.red(`\n❌ ${n.message}`)),process.exit(1)),console.log(`
|
|
63
|
+
`+(n.tree??n.message)),console.log(t.dim(`\n${n.message}`))}),P.command(`version`).description(`Show the current Protocol version`).action(()=>{console.log(`${t.bold(`Agent Protocol`)} ${t.green(`v${s}`)} ${t.dim(`(CLI v${N})`)}`)}),P.parse();export{};
|
package/eslint.config.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Config } from '@repo/eslint'
|
|
2
|
+
import { base } from '@repo/eslint'
|
|
3
|
+
import { defineConfig } from 'eslint/config'
|
|
4
|
+
|
|
5
|
+
const config: Config[] = defineConfig([
|
|
6
|
+
...base,
|
|
7
|
+
{
|
|
8
|
+
ignores: [
|
|
9
|
+
'eslint.config.ts',
|
|
10
|
+
'eslint-types.d.ts',
|
|
11
|
+
'prettier.config.mjs',
|
|
12
|
+
'lint-staged.config.mjs',
|
|
13
|
+
'lowercase-script.ts',
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
])
|
|
17
|
+
|
|
18
|
+
export default config
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@autonomos/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "CLI tool for the Autonomos Agent Protocol",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"autonomos": "./dist/index.mjs"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"commander": "^14.0.2",
|
|
11
|
+
"picocolors": "1.1.1",
|
|
12
|
+
"@autonomos/core": "0.0.1"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/node": "^25.0.3",
|
|
16
|
+
"typescript": "^5.0.0",
|
|
17
|
+
"@repo/eslint": "1.0.0",
|
|
18
|
+
"@repo/prettier": "1.0.0",
|
|
19
|
+
"@repo/tsdown": "1.0.0"
|
|
20
|
+
},
|
|
21
|
+
"main": "./dist/index.mjs",
|
|
22
|
+
"module": "./dist/index.mjs",
|
|
23
|
+
"types": "./dist/index.d.mts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": "./dist/index.mjs",
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"start": "node dist/index.mjs",
|
|
30
|
+
"build": "tsdown",
|
|
31
|
+
"lint": "eslint . --max-warnings 0",
|
|
32
|
+
"lint:fix": "eslint . --max-warnings 0 --fix",
|
|
33
|
+
"format:check": "prettier \"**/*\" --ignore-unknown --list-different",
|
|
34
|
+
"format:fix": "prettier \"**/*\" --ignore-unknown --write",
|
|
35
|
+
"clean": "rimraf node_modules dist",
|
|
36
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
37
|
+
"test": "vitest",
|
|
38
|
+
"test:ui": "vitest --ui",
|
|
39
|
+
"test:run": "vitest run",
|
|
40
|
+
"test:coverage": "vitest run --coverage",
|
|
41
|
+
"pre-commit": "lint-staged"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { existsSync, readdirSync, statSync } from 'node:fs'
|
|
2
|
+
import { basename, join, relative } from 'node:path'
|
|
3
|
+
|
|
4
|
+
import { AGENT_FILE, AUTONOMOS_DIR } from '@autonomos/core'
|
|
5
|
+
|
|
6
|
+
interface AgentsOptions {
|
|
7
|
+
cwd?: string
|
|
8
|
+
all?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface AgentEntry {
|
|
12
|
+
path: string
|
|
13
|
+
relativePath: string
|
|
14
|
+
depth: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Find the project root by looking for .autonomos or .git directory
|
|
19
|
+
*/
|
|
20
|
+
function findProjectRoot(startDir: string): string | null {
|
|
21
|
+
let currentDir = startDir
|
|
22
|
+
|
|
23
|
+
while (currentDir !== '/') {
|
|
24
|
+
if (existsSync(join(currentDir, AUTONOMOS_DIR)) || existsSync(join(currentDir, '.git'))) {
|
|
25
|
+
return currentDir
|
|
26
|
+
}
|
|
27
|
+
currentDir = join(currentDir, '..')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Recursively find all AGENT.md files in a directory
|
|
35
|
+
*/
|
|
36
|
+
function findAgentFiles(dir: string, baseDir: string, depth = 0): AgentEntry[] {
|
|
37
|
+
const entries: AgentEntry[] = []
|
|
38
|
+
|
|
39
|
+
// Check if AGENT.md exists in current directory
|
|
40
|
+
const agentPath = join(dir, AGENT_FILE)
|
|
41
|
+
if (existsSync(agentPath)) {
|
|
42
|
+
entries.push({
|
|
43
|
+
path: agentPath,
|
|
44
|
+
relativePath: relative(baseDir, agentPath) || AGENT_FILE,
|
|
45
|
+
depth,
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Scan subdirectories
|
|
50
|
+
try {
|
|
51
|
+
const items = readdirSync(dir)
|
|
52
|
+
for (const item of items) {
|
|
53
|
+
// Skip hidden directories and node_modules
|
|
54
|
+
if (
|
|
55
|
+
item.startsWith('.') ||
|
|
56
|
+
item === 'node_modules' ||
|
|
57
|
+
item === 'dist' ||
|
|
58
|
+
item === 'build'
|
|
59
|
+
) {
|
|
60
|
+
continue
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const itemPath = join(dir, item)
|
|
64
|
+
try {
|
|
65
|
+
if (statSync(itemPath).isDirectory()) {
|
|
66
|
+
entries.push(...findAgentFiles(itemPath, baseDir, depth + 1))
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
// Skip inaccessible directories
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} catch {
|
|
73
|
+
// Skip inaccessible directories
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return entries
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Format agent entries as a tree structure
|
|
81
|
+
*/
|
|
82
|
+
function formatAsTree(entries: AgentEntry[], baseDir: string): string {
|
|
83
|
+
if (entries.length === 0) {
|
|
84
|
+
return ' (no AGENT.md files found)'
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const lines: string[] = []
|
|
88
|
+
const baseName = basename(baseDir)
|
|
89
|
+
|
|
90
|
+
lines.push(`📁 ${baseName}/`)
|
|
91
|
+
|
|
92
|
+
// Group entries by their parent directory
|
|
93
|
+
for (let i = 0; i < entries.length; i++) {
|
|
94
|
+
const entry = entries[i]
|
|
95
|
+
const isLast = i === entries.length - 1
|
|
96
|
+
const prefix = isLast ? '└── ' : '├── '
|
|
97
|
+
const indent = ' '.repeat(entry.depth)
|
|
98
|
+
|
|
99
|
+
lines.push(`${indent}${prefix}📄 ${entry.relativePath}`)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return lines.join('\n')
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
interface AgentsResult {
|
|
106
|
+
success: boolean
|
|
107
|
+
message: string
|
|
108
|
+
tree?: string
|
|
109
|
+
count?: number
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* List all AGENT.md files in the project
|
|
114
|
+
*/
|
|
115
|
+
export function agents(options: AgentsOptions = {}): AgentsResult {
|
|
116
|
+
const cwd = options.cwd ?? process.cwd()
|
|
117
|
+
|
|
118
|
+
// Determine search base
|
|
119
|
+
let searchBase: string
|
|
120
|
+
|
|
121
|
+
if (options.all) {
|
|
122
|
+
// Find project root
|
|
123
|
+
const projectRoot = findProjectRoot(cwd)
|
|
124
|
+
if (!projectRoot) {
|
|
125
|
+
return {
|
|
126
|
+
success: false,
|
|
127
|
+
message: 'Could not find project root (.autonomos or .git directory).',
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
searchBase = projectRoot
|
|
131
|
+
} else {
|
|
132
|
+
searchBase = cwd
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Find all AGENT.md files
|
|
136
|
+
const entries = findAgentFiles(searchBase, searchBase)
|
|
137
|
+
|
|
138
|
+
if (entries.length === 0) {
|
|
139
|
+
return {
|
|
140
|
+
success: true,
|
|
141
|
+
message: 'No AGENT.md files found.',
|
|
142
|
+
count: 0,
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const tree = formatAsTree(entries, searchBase)
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
success: true,
|
|
150
|
+
message: `Found ${entries.length} AGENT.md file(s)`,
|
|
151
|
+
tree,
|
|
152
|
+
count: entries.length,
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
AGENT_FILE,
|
|
6
|
+
AUTONOMOS_DIR,
|
|
7
|
+
createManifest,
|
|
8
|
+
generateAgentTemplate,
|
|
9
|
+
generateManifestContent,
|
|
10
|
+
MANIFEST_FILE,
|
|
11
|
+
PROTOCOL_FILE,
|
|
12
|
+
PROTOCOL_TEMPLATE,
|
|
13
|
+
PROTOCOL_VERSION,
|
|
14
|
+
TASKS_FILE,
|
|
15
|
+
TASKS_TEMPLATE,
|
|
16
|
+
WORKLOGS_DIR,
|
|
17
|
+
} from '@autonomos/core'
|
|
18
|
+
|
|
19
|
+
// Get CLI version from package.json
|
|
20
|
+
const CLI_VERSION = '0.0.1' // TODO: Import from package.json
|
|
21
|
+
|
|
22
|
+
interface InitOptions {
|
|
23
|
+
cwd?: string
|
|
24
|
+
dryRun?: boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface InitResult {
|
|
28
|
+
success: boolean
|
|
29
|
+
message: string
|
|
30
|
+
created: string[]
|
|
31
|
+
warnings: string[]
|
|
32
|
+
dryRun?: boolean
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Initialize the Autonomos Agent Protocol in a directory
|
|
37
|
+
*/
|
|
38
|
+
export function init(options: InitOptions = {}): InitResult {
|
|
39
|
+
const cwd = options.cwd ?? process.cwd()
|
|
40
|
+
const dryRun = options.dryRun ?? false
|
|
41
|
+
const created: string[] = []
|
|
42
|
+
const warnings: string[] = []
|
|
43
|
+
|
|
44
|
+
// Check for .git
|
|
45
|
+
const gitDir = join(cwd, '.git')
|
|
46
|
+
if (!existsSync(gitDir)) {
|
|
47
|
+
warnings.push('No Git repository detected. Consider running `git init` first.')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check if already initialized
|
|
51
|
+
const autonomosDir = join(cwd, AUTONOMOS_DIR)
|
|
52
|
+
if (existsSync(autonomosDir)) {
|
|
53
|
+
return {
|
|
54
|
+
success: false,
|
|
55
|
+
message: `Project already initialized with Protocol v${PROTOCOL_VERSION}. Use \`autonomos update\` to update.`,
|
|
56
|
+
created: [],
|
|
57
|
+
warnings: [],
|
|
58
|
+
dryRun,
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// In dry-run mode, just collect what would be created
|
|
63
|
+
if (dryRun) {
|
|
64
|
+
created.push(AUTONOMOS_DIR)
|
|
65
|
+
created.push(`${AUTONOMOS_DIR}/${WORKLOGS_DIR}`)
|
|
66
|
+
created.push(`${AUTONOMOS_DIR}/${MANIFEST_FILE}`)
|
|
67
|
+
created.push(`${AUTONOMOS_DIR}/${PROTOCOL_FILE}`)
|
|
68
|
+
created.push(`${AUTONOMOS_DIR}/${TASKS_FILE}`)
|
|
69
|
+
|
|
70
|
+
const agentPath = join(cwd, AGENT_FILE)
|
|
71
|
+
if (!existsSync(agentPath)) {
|
|
72
|
+
created.push(AGENT_FILE)
|
|
73
|
+
} else {
|
|
74
|
+
warnings.push(`${AGENT_FILE} already exists, would skip.`)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
success: true,
|
|
79
|
+
message: `Would initialize project with Agent Protocol v${PROTOCOL_VERSION}`,
|
|
80
|
+
created,
|
|
81
|
+
warnings,
|
|
82
|
+
dryRun: true,
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Create .autonomos directory
|
|
87
|
+
mkdirSync(autonomosDir, { recursive: true })
|
|
88
|
+
created.push(AUTONOMOS_DIR)
|
|
89
|
+
|
|
90
|
+
// Create worklogs directory
|
|
91
|
+
const worklogsDir = join(autonomosDir, WORKLOGS_DIR)
|
|
92
|
+
mkdirSync(worklogsDir, { recursive: true })
|
|
93
|
+
created.push(`${AUTONOMOS_DIR}/${WORKLOGS_DIR}`)
|
|
94
|
+
|
|
95
|
+
// Create manifest.json
|
|
96
|
+
const manifest = createManifest(CLI_VERSION)
|
|
97
|
+
const manifestPath = join(autonomosDir, MANIFEST_FILE)
|
|
98
|
+
writeFileSync(manifestPath, generateManifestContent(manifest))
|
|
99
|
+
created.push(`${AUTONOMOS_DIR}/${MANIFEST_FILE}`)
|
|
100
|
+
|
|
101
|
+
// Create PROTOCOL.md
|
|
102
|
+
const protocolPath = join(autonomosDir, PROTOCOL_FILE)
|
|
103
|
+
writeFileSync(protocolPath, PROTOCOL_TEMPLATE)
|
|
104
|
+
created.push(`${AUTONOMOS_DIR}/${PROTOCOL_FILE}`)
|
|
105
|
+
|
|
106
|
+
// Create TASKS.md
|
|
107
|
+
const tasksPath = join(autonomosDir, TASKS_FILE)
|
|
108
|
+
writeFileSync(tasksPath, TASKS_TEMPLATE)
|
|
109
|
+
created.push(`${AUTONOMOS_DIR}/${TASKS_FILE}`)
|
|
110
|
+
|
|
111
|
+
// Create AGENT.md at root (only if it doesn't exist)
|
|
112
|
+
const agentPath = join(cwd, AGENT_FILE)
|
|
113
|
+
if (!existsSync(agentPath)) {
|
|
114
|
+
const projectName = cwd.split('/').pop() ?? 'Project'
|
|
115
|
+
writeFileSync(agentPath, generateAgentTemplate(projectName))
|
|
116
|
+
created.push(AGENT_FILE)
|
|
117
|
+
} else {
|
|
118
|
+
warnings.push(`${AGENT_FILE} already exists, skipping.`)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
success: true,
|
|
123
|
+
message: `Project initialized with Agent Protocol v${PROTOCOL_VERSION}`,
|
|
124
|
+
created,
|
|
125
|
+
warnings,
|
|
126
|
+
dryRun: false,
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
AUTONOMOS_DIR,
|
|
6
|
+
MANIFEST_FILE,
|
|
7
|
+
parseManifest,
|
|
8
|
+
TaskParser,
|
|
9
|
+
TASKS_FILE,
|
|
10
|
+
type Manifest,
|
|
11
|
+
} from '@autonomos/core'
|
|
12
|
+
|
|
13
|
+
interface StatusOptions {
|
|
14
|
+
cwd?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface TaskSummary {
|
|
18
|
+
total: number
|
|
19
|
+
todo: number
|
|
20
|
+
inProgress: number
|
|
21
|
+
done: number
|
|
22
|
+
blocked: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface StatusResult {
|
|
26
|
+
success: boolean
|
|
27
|
+
message: string
|
|
28
|
+
protocolVersion?: string
|
|
29
|
+
cliVersion?: string
|
|
30
|
+
initialized: boolean
|
|
31
|
+
taskSummary?: TaskSummary
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get project status and task summary
|
|
36
|
+
*/
|
|
37
|
+
export function status(options: StatusOptions = {}): StatusResult {
|
|
38
|
+
const cwd = options.cwd ?? process.cwd()
|
|
39
|
+
|
|
40
|
+
// Check if initialized
|
|
41
|
+
const autonomosDir = join(cwd, AUTONOMOS_DIR)
|
|
42
|
+
const manifestPath = join(autonomosDir, MANIFEST_FILE)
|
|
43
|
+
|
|
44
|
+
if (!existsSync(manifestPath)) {
|
|
45
|
+
return {
|
|
46
|
+
success: false,
|
|
47
|
+
message: 'Project not initialized. Run `autonomos init` first.',
|
|
48
|
+
initialized: false,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Read manifest
|
|
53
|
+
let manifest: Manifest
|
|
54
|
+
try {
|
|
55
|
+
const manifestContent = readFileSync(manifestPath, 'utf-8')
|
|
56
|
+
manifest = parseManifest(manifestContent)
|
|
57
|
+
} catch {
|
|
58
|
+
return {
|
|
59
|
+
success: false,
|
|
60
|
+
message: 'Could not read manifest.json',
|
|
61
|
+
initialized: true,
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Parse tasks
|
|
66
|
+
let taskSummary: TaskSummary | undefined
|
|
67
|
+
const tasksPath = join(autonomosDir, TASKS_FILE)
|
|
68
|
+
|
|
69
|
+
if (existsSync(tasksPath)) {
|
|
70
|
+
try {
|
|
71
|
+
const tasksContent = readFileSync(tasksPath, 'utf-8')
|
|
72
|
+
const tasks = TaskParser.parse(tasksContent)
|
|
73
|
+
|
|
74
|
+
taskSummary = {
|
|
75
|
+
total: tasks.length,
|
|
76
|
+
todo: tasks.filter(t => t.status === 'TODO').length,
|
|
77
|
+
inProgress: tasks.filter(t => t.status === 'IN_PROGRESS').length,
|
|
78
|
+
done: tasks.filter(t => t.status === 'DONE').length,
|
|
79
|
+
blocked: tasks.filter(t => t.status === 'BLOCKED').length,
|
|
80
|
+
}
|
|
81
|
+
} catch {
|
|
82
|
+
// Tasks file exists but couldn't be parsed
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
success: true,
|
|
88
|
+
message: 'Project status retrieved',
|
|
89
|
+
protocolVersion: manifest.protocolVersion,
|
|
90
|
+
cliVersion: manifest.cliVersion,
|
|
91
|
+
initialized: true,
|
|
92
|
+
taskSummary,
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
AUTONOMOS_DIR,
|
|
6
|
+
generateManifestContent,
|
|
7
|
+
MANIFEST_FILE,
|
|
8
|
+
parseManifest,
|
|
9
|
+
PROTOCOL_FILE,
|
|
10
|
+
PROTOCOL_TEMPLATE,
|
|
11
|
+
PROTOCOL_VERSION,
|
|
12
|
+
type Manifest,
|
|
13
|
+
} from '@autonomos/core'
|
|
14
|
+
|
|
15
|
+
// Get CLI version from package.json
|
|
16
|
+
const CLI_VERSION = '0.0.1' // TODO: Import from package.json
|
|
17
|
+
|
|
18
|
+
interface UpdateOptions {
|
|
19
|
+
cwd?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface UpdateResult {
|
|
23
|
+
success: boolean
|
|
24
|
+
message: string
|
|
25
|
+
previousVersion?: string
|
|
26
|
+
newVersion?: string
|
|
27
|
+
cliOutdated?: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Compare two SemVer versions
|
|
32
|
+
* Returns: -1 if a < b, 0 if a === b, 1 if a > b
|
|
33
|
+
*/
|
|
34
|
+
function compareVersions(a: string, b: string): number {
|
|
35
|
+
const aParts = a.split('.').map(Number)
|
|
36
|
+
const bParts = b.split('.').map(Number)
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < 3; i++) {
|
|
39
|
+
const aNum = aParts[i] ?? 0
|
|
40
|
+
const bNum = bParts[i] ?? 0
|
|
41
|
+
if (aNum < bNum) return -1
|
|
42
|
+
if (aNum > bNum) return 1
|
|
43
|
+
}
|
|
44
|
+
return 0
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Update the Protocol to the latest version
|
|
49
|
+
*/
|
|
50
|
+
export function update(options: UpdateOptions = {}): UpdateResult {
|
|
51
|
+
const cwd = options.cwd ?? process.cwd()
|
|
52
|
+
|
|
53
|
+
// Check if initialized
|
|
54
|
+
const autonomosDir = join(cwd, AUTONOMOS_DIR)
|
|
55
|
+
const manifestPath = join(autonomosDir, MANIFEST_FILE)
|
|
56
|
+
|
|
57
|
+
if (!existsSync(manifestPath)) {
|
|
58
|
+
return {
|
|
59
|
+
success: false,
|
|
60
|
+
message: 'Project not initialized. Run `autonomos init` first.',
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Read current manifest
|
|
65
|
+
const manifestContent = readFileSync(manifestPath, 'utf-8')
|
|
66
|
+
const manifest: Manifest = parseManifest(manifestContent)
|
|
67
|
+
const currentVersion = manifest.protocolVersion
|
|
68
|
+
|
|
69
|
+
// Compare versions
|
|
70
|
+
const comparison = compareVersions(currentVersion, PROTOCOL_VERSION)
|
|
71
|
+
|
|
72
|
+
if (comparison === 0) {
|
|
73
|
+
return {
|
|
74
|
+
success: true,
|
|
75
|
+
message: `Already up to date (Protocol v${PROTOCOL_VERSION})`,
|
|
76
|
+
previousVersion: currentVersion,
|
|
77
|
+
newVersion: PROTOCOL_VERSION,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (comparison > 0) {
|
|
82
|
+
// Project uses a newer version than CLI knows
|
|
83
|
+
return {
|
|
84
|
+
success: false,
|
|
85
|
+
message: `This project uses Protocol v${currentVersion}, but your CLI only knows v${PROTOCOL_VERSION}. Update your CLI with \`npm i -g @autonomos/cli\`.`,
|
|
86
|
+
previousVersion: currentVersion,
|
|
87
|
+
newVersion: PROTOCOL_VERSION,
|
|
88
|
+
cliOutdated: true,
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Update Protocol (comparison < 0)
|
|
93
|
+
const protocolPath = join(autonomosDir, PROTOCOL_FILE)
|
|
94
|
+
writeFileSync(protocolPath, PROTOCOL_TEMPLATE)
|
|
95
|
+
|
|
96
|
+
// Update manifest
|
|
97
|
+
const updatedManifest: Manifest = {
|
|
98
|
+
...manifest,
|
|
99
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
100
|
+
cliVersion: CLI_VERSION,
|
|
101
|
+
lastUpdated: new Date().toISOString(),
|
|
102
|
+
}
|
|
103
|
+
writeFileSync(manifestPath, generateManifestContent(updatedManifest))
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
success: true,
|
|
107
|
+
message: `Protocol updated: v${currentVersion} → v${PROTOCOL_VERSION}`,
|
|
108
|
+
previousVersion: currentVersion,
|
|
109
|
+
newVersion: PROTOCOL_VERSION,
|
|
110
|
+
}
|
|
111
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander'
|
|
3
|
+
import pc from 'picocolors'
|
|
4
|
+
|
|
5
|
+
import { PROTOCOL_VERSION } from '@autonomos/core'
|
|
6
|
+
import { agents } from './commands/agents'
|
|
7
|
+
import { init } from './commands/init'
|
|
8
|
+
import { status } from './commands/status'
|
|
9
|
+
import { update } from './commands/update'
|
|
10
|
+
|
|
11
|
+
const CLI_VERSION = '0.0.1'
|
|
12
|
+
|
|
13
|
+
const program = new Command()
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.name('autonomos')
|
|
17
|
+
.description(
|
|
18
|
+
pc.cyan(`CLI for the Autonomos Agent Protocol
|
|
19
|
+
|
|
20
|
+
The Agent Protocol is a specification for AI agents to interact with codebases
|
|
21
|
+
in a structured, consistent way. It defines how agents should read context,
|
|
22
|
+
execute tasks, and persist knowledge.`) +
|
|
23
|
+
`
|
|
24
|
+
|
|
25
|
+
Documentation: ${pc.underline('https://github.com/saoudi-h/autonomos')}`
|
|
26
|
+
)
|
|
27
|
+
.version(
|
|
28
|
+
`${pc.bold('CLI:')} ${pc.green(CLI_VERSION)}\n${pc.bold('Protocol:')} ${pc.green(PROTOCOL_VERSION)}`,
|
|
29
|
+
'-v, --version',
|
|
30
|
+
'Show version information'
|
|
31
|
+
)
|
|
32
|
+
.helpOption('-h, --help', 'Show help information')
|
|
33
|
+
.addHelpText(
|
|
34
|
+
'after',
|
|
35
|
+
`
|
|
36
|
+
${pc.bold('Examples:')}
|
|
37
|
+
$ ${pc.cyan('autonomos init')} Initialize the Agent Protocol in current directory
|
|
38
|
+
$ ${pc.cyan('autonomos update')} Update Protocol to the latest version
|
|
39
|
+
$ ${pc.cyan('autonomos status')} Show project status and task summary
|
|
40
|
+
$ ${pc.cyan('autonomos agents')} List all AGENT.md files in the project
|
|
41
|
+
|
|
42
|
+
${pc.bold('More info:')}
|
|
43
|
+
Run '${pc.cyan('autonomos <command> --help')}' for detailed information about a command.
|
|
44
|
+
`
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
program
|
|
48
|
+
.command('init')
|
|
49
|
+
.description('Initialize the Agent Protocol in the current directory')
|
|
50
|
+
.addHelpText(
|
|
51
|
+
'after',
|
|
52
|
+
`
|
|
53
|
+
This command creates the following structure:
|
|
54
|
+
${pc.blue('.autonomos/')}
|
|
55
|
+
├── ${pc.white('manifest.json')} # Protocol metadata and version
|
|
56
|
+
├── ${pc.white('PROTOCOL.md')} # Immutable protocol specification
|
|
57
|
+
├── ${pc.white('TASKS.md')} # Task registry
|
|
58
|
+
└── ${pc.blue('worklogs/')} # Session logs directory
|
|
59
|
+
${pc.white('AGENT.md')} # Project context file (at root)
|
|
60
|
+
|
|
61
|
+
${pc.bold('Examples:')}
|
|
62
|
+
$ ${pc.cyan('autonomos init')}
|
|
63
|
+
$ ${pc.cyan('cd my-project && autonomos init')}
|
|
64
|
+
`
|
|
65
|
+
)
|
|
66
|
+
.option('-n, --dry-run', 'Preview what would be created without writing files')
|
|
67
|
+
.action(opts => {
|
|
68
|
+
const result = init({ dryRun: opts.dryRun })
|
|
69
|
+
|
|
70
|
+
if (!result.success) {
|
|
71
|
+
console.error(pc.red(`\n❌ ${result.message}`))
|
|
72
|
+
process.exit(1)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (result.dryRun) {
|
|
76
|
+
console.log(pc.cyan(`\n🔍 ${result.message} (dry-run)`))
|
|
77
|
+
} else {
|
|
78
|
+
console.log(pc.green(`\n✅ ${result.message}`))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (result.created.length > 0) {
|
|
82
|
+
console.log(`\n${pc.bold(result.dryRun ? 'Would create:' : 'Created:')}`)
|
|
83
|
+
result.created.forEach(file => console.log(` ${pc.blue('📄')} ${pc.white(file)}`))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (result.warnings.length > 0) {
|
|
87
|
+
console.log(pc.yellow('\nWarnings:'))
|
|
88
|
+
result.warnings.forEach(warn => console.log(` ${pc.yellow('⚠️')} ${warn}`))
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
program
|
|
93
|
+
.command('update')
|
|
94
|
+
.description('Update the Protocol to the latest version')
|
|
95
|
+
.addHelpText(
|
|
96
|
+
'after',
|
|
97
|
+
`
|
|
98
|
+
This command updates ${pc.white('PROTOCOL.md')} to the latest version embedded in the CLI.
|
|
99
|
+
Only ${pc.white('PROTOCOL.md')} is modified; your ${pc.white('TASKS.md')} and ${pc.white('AGENT.md')} files are preserved.
|
|
100
|
+
|
|
101
|
+
${pc.bold('Version comparison:')}
|
|
102
|
+
- If your project has an older version: Updates to the new version
|
|
103
|
+
- If your project has a newer version: Warns you to update the CLI
|
|
104
|
+
- If versions match: No action needed
|
|
105
|
+
|
|
106
|
+
${pc.bold('Examples:')}
|
|
107
|
+
$ ${pc.cyan('autonomos update')}
|
|
108
|
+
`
|
|
109
|
+
)
|
|
110
|
+
.action(() => {
|
|
111
|
+
const result = update()
|
|
112
|
+
|
|
113
|
+
if (!result.success) {
|
|
114
|
+
if (result.cliOutdated) {
|
|
115
|
+
console.error(pc.yellow(`\n⚠️ ${result.message}`))
|
|
116
|
+
} else {
|
|
117
|
+
console.error(pc.red(`\n❌ ${result.message}`))
|
|
118
|
+
}
|
|
119
|
+
process.exit(1)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log(pc.green(`\n✅ ${result.message}`))
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
program
|
|
126
|
+
.command('status')
|
|
127
|
+
.description('Show project status and task summary')
|
|
128
|
+
.addHelpText(
|
|
129
|
+
'after',
|
|
130
|
+
`
|
|
131
|
+
Displays information about the current project:
|
|
132
|
+
- Protocol version
|
|
133
|
+
- CLI version used for initialization
|
|
134
|
+
- Task summary (todo, in-progress, done, blocked)
|
|
135
|
+
|
|
136
|
+
${pc.bold('Examples:')}
|
|
137
|
+
$ ${pc.cyan('autonomos status')}
|
|
138
|
+
`
|
|
139
|
+
)
|
|
140
|
+
.action(() => {
|
|
141
|
+
const result = status()
|
|
142
|
+
|
|
143
|
+
if (!result.success) {
|
|
144
|
+
console.error(pc.red(`\n❌ ${result.message}`))
|
|
145
|
+
process.exit(1)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
console.log(
|
|
149
|
+
`\n${pc.bold('📦 Protocol')} ${pc.green(`v${result.protocolVersion}`)} ${pc.dim(`(CLI v${result.cliVersion})`)}`
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
if (result.taskSummary) {
|
|
153
|
+
const s = result.taskSummary
|
|
154
|
+
console.log(`\n${pc.bold('📋 Tasks:')} ${pc.cyan(s.total)} total`)
|
|
155
|
+
console.log(` ${pc.white('⬜ Todo:')} ${pc.white(s.todo)}`)
|
|
156
|
+
console.log(` ${pc.blue('🔄 In Progress:')} ${pc.blue(s.inProgress)}`)
|
|
157
|
+
console.log(` ${pc.green('✅ Done:')} ${pc.green(s.done)}`)
|
|
158
|
+
if (s.blocked > 0) {
|
|
159
|
+
console.log(` ${pc.red('🚫 Blocked:')} ${pc.red(s.blocked)}`)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
program
|
|
165
|
+
.command('agents')
|
|
166
|
+
.description('List all AGENT.md files in the project')
|
|
167
|
+
.option('-a, --all', 'Search from project root instead of current directory')
|
|
168
|
+
.addHelpText(
|
|
169
|
+
'after',
|
|
170
|
+
`
|
|
171
|
+
This command discovers and displays all ${pc.white('AGENT.md')} files in a tree structure.
|
|
172
|
+
${pc.white('AGENT.md')} files provide context to AI agents about specific directories.
|
|
173
|
+
|
|
174
|
+
${pc.bold('Modes:')}
|
|
175
|
+
(default) Search from current directory downwards
|
|
176
|
+
--all Search from project root (finds .autonomos or .git)
|
|
177
|
+
|
|
178
|
+
${pc.bold('Examples:')}
|
|
179
|
+
$ ${pc.cyan('autonomos agents')} # List from current directory
|
|
180
|
+
$ ${pc.cyan('autonomos agents --all')} # List from project root
|
|
181
|
+
$ ${pc.cyan('cd packages/core && autonomos agents')} # List only in packages/core
|
|
182
|
+
`
|
|
183
|
+
)
|
|
184
|
+
.action(opts => {
|
|
185
|
+
const result = agents({ all: opts.all })
|
|
186
|
+
|
|
187
|
+
if (!result.success) {
|
|
188
|
+
console.error(pc.red(`\n❌ ${result.message}`))
|
|
189
|
+
process.exit(1)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
console.log('\n' + (result.tree ?? result.message))
|
|
193
|
+
console.log(pc.dim(`\n${result.message}`))
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
program
|
|
197
|
+
.command('version')
|
|
198
|
+
.description('Show the current Protocol version')
|
|
199
|
+
.action(() => {
|
|
200
|
+
console.log(
|
|
201
|
+
`${pc.bold('Agent Protocol')} ${pc.green(`v${PROTOCOL_VERSION}`)} ${pc.dim(`(CLI v${CLI_VERSION})`)}`
|
|
202
|
+
)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
program.parse()
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "@repo/tsconfig/base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "esnext",
|
|
5
|
+
"lib": ["es2022"],
|
|
6
|
+
"moduleDetection": "force",
|
|
7
|
+
"module": "esnext",
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"types": ["node", "vitest"],
|
|
11
|
+
"strict": true,
|
|
12
|
+
"noUnusedLocals": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"verbatimModuleSyntax": true,
|
|
17
|
+
"skipLibCheck": true,
|
|
18
|
+
"baseUrl": ".",
|
|
19
|
+
"outDir": "./dist",
|
|
20
|
+
"rootDir": ".",
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["src/*"],
|
|
23
|
+
"@tests/*": ["tests/*"]
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"include": [
|
|
27
|
+
"./src/**/*",
|
|
28
|
+
"./src/**/*.json",
|
|
29
|
+
"tsdown.config.ts",
|
|
30
|
+
"vitest.config.ts",
|
|
31
|
+
"tests/**/*",
|
|
32
|
+
"lint-staged.config.mjs",
|
|
33
|
+
"prettier.config.mjs"
|
|
34
|
+
],
|
|
35
|
+
"exclude": ["dist", "build", "node_modules", ".vscode", ".turbo", "coverage"]
|
|
36
|
+
}
|
package/tsdown.config.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { base } from '@repo/tsdown'
|
|
2
|
+
import type { UserConfigFn } from 'tsdown/config'
|
|
3
|
+
import { defineConfig } from 'tsdown/config'
|
|
4
|
+
|
|
5
|
+
const configFn: UserConfigFn = defineConfig(async options => ({
|
|
6
|
+
...(await base(options, { ci: true })),
|
|
7
|
+
entry: ['./src/index.ts', './src/*/index.ts'],
|
|
8
|
+
}))
|
|
9
|
+
|
|
10
|
+
export default configFn
|