@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.
@@ -0,0 +1,16 @@
1
+
2
+ > @autonomos/cli@0.0.1 build /home/runner/work/autonomos/autonomos/packages/cli
3
+ > tsdown
4
+
5
+ ℹ tsdown v0.18.4 powered by rolldown v1.0.0-beta.57
6
+ ℹ config file: /home/runner/work/autonomos/autonomos/packages/cli/tsdown.config.ts
7
+ ℹ entry: src/index.ts
8
+ ℹ tsconfig: tsconfig.json
9
+ ℹ Build start
10
+ ℹ Granting execute permission to dist/index.mjs
11
+ ℹ dist/index.mjs 9.19 kB │ gzip: 3.35 kB
12
+ ℹ dist/index.d.mts 0.01 kB │ gzip: 0.03 kB
13
+ ℹ 2 files, total: 9.20 kB
14
+ ✔ Build complete in 1088ms
15
+ ✔ [publint] No issues found (342ms)
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
@@ -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{};
@@ -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
@@ -0,0 +1,4 @@
1
+ export default {
2
+ '**/*.{ts,tsx}': ['prettier --write', 'eslint --fix --no-warn-ignored'],
3
+ '**/*.{json,md,mdx}': 'prettier --write',
4
+ }
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,3 @@
1
+ import baseConfig from '@repo/prettier'
2
+
3
+ export default baseConfig
@@ -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
+ }
@@ -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
@@ -0,0 +1,9 @@
1
+ import { base } from '@repo/vitest'
2
+ import type { ViteUserConfig } from 'vitest/config'
3
+ import { defineConfig } from 'vitest/config'
4
+
5
+ const config: ViteUserConfig = defineConfig({
6
+ ...base,
7
+ })
8
+
9
+ export default config