ramenos 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/.github/workflows/ci.yml +37 -0
- package/README.md +177 -0
- package/agents/chef.md +41 -0
- package/agents/cook.md +24 -0
- package/agents/coordinator.md +27 -0
- package/agents/critic.md +22 -0
- package/agents/innovator.md +26 -0
- package/agents/logistician.md +23 -0
- package/agents/master.md +22 -0
- package/agents/taster.md +23 -0
- package/bin/ramenos.js +75 -0
- package/package.json +29 -0
- package/src/index.js +313 -0
- package/test/index.test.js +105 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: CI & Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: ["main"]
|
|
8
|
+
release:
|
|
9
|
+
types: [published]
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v6
|
|
16
|
+
- name: Use Node.js
|
|
17
|
+
uses: actions/setup-node@v6
|
|
18
|
+
with:
|
|
19
|
+
node-version: "24.x"
|
|
20
|
+
- name: Run tests
|
|
21
|
+
run: npm test
|
|
22
|
+
|
|
23
|
+
publish:
|
|
24
|
+
needs: test
|
|
25
|
+
if: github.event_name == 'release'
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v6
|
|
29
|
+
- name: Use Node.js
|
|
30
|
+
uses: actions/setup-node@v6
|
|
31
|
+
with:
|
|
32
|
+
node-version: "24.x"
|
|
33
|
+
registry-url: "https://registry.npmjs.org"
|
|
34
|
+
- name: Publish to npm
|
|
35
|
+
run: npm publish
|
|
36
|
+
env:
|
|
37
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/README.md
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# 🤖 Ramenos CLI
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/ramenos)
|
|
4
|
+
[](https://www.npmjs.com/package/ramenos)
|
|
5
|
+
[](https://github.com/maxylev/ramenos/actions)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
A lightning-fast, **zero-dependency** CLI to share and install AI multi-agent orchestration configurations directly from GitHub into your local workspace.
|
|
9
|
+
|
|
10
|
+
Designed for modern AI coding assistants like [OpenCode](https://opencode.ai/). Bootstrapping an elite multi-agent AI team is now just one command away.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## ✨ Features
|
|
15
|
+
|
|
16
|
+
- 🚀 **Zero Dependencies**: Built with native Node.js. Incredibly fast execution.
|
|
17
|
+
- 🔗 **Smart Caching**: Uses local caching to safely symlink agent files without cluttering your project.
|
|
18
|
+
- 🐙 **Flexible Git Support**: Supports GitHub shorthand, raw HTTPS, SSH, and deep folder trees.
|
|
19
|
+
- 🎯 **Dynamic Frameworks**: By default targets `opencode`, but supports dynamic path generation for *any* agent framework you provide.
|
|
20
|
+
|
|
21
|
+
## 🚀 Quick Start
|
|
22
|
+
|
|
23
|
+
No global install required! Just run it via `npx` inside your project directory:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Add an AI agent team to your current project (defaults to OpenCode)
|
|
27
|
+
npx ramenos add maxylev/ramenos
|
|
28
|
+
|
|
29
|
+
# Add agents globally to your machine
|
|
30
|
+
npx ramenos add maxylev/ramenos --global
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 📖 Usage Options
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
Usage: ramenos add <repository> [options]
|
|
37
|
+
|
|
38
|
+
Options:
|
|
39
|
+
-g, --global Install to user directory instead of project workspace
|
|
40
|
+
-a, --agent <agents...> Target specific agent frameworks (defaults to 'opencode')
|
|
41
|
+
--copy Copy files instead of symlinking (useful to modify them locally)
|
|
42
|
+
-y, --yes Skip all confirmation prompts
|
|
43
|
+
-h, --help Display help message
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 🎯 Dynamic Target Paths
|
|
47
|
+
|
|
48
|
+
`ramenos` dynamically generates file paths based on the `--agent` parameter you pass. If omitted, it gracefully defaults to `opencode`.
|
|
49
|
+
|
|
50
|
+
| Command | Local Path Generated | Global Path Generated (`-g`) |
|
|
51
|
+
| :--- | :--- | :--- |
|
|
52
|
+
| `ramenos add repo` | `.opencode/agents/` | `~/.config/opencode/agents/` |
|
|
53
|
+
| `ramenos add repo -a myapp` | `.myapp/agents/` | `~/.config/myapp/agents/` |
|
|
54
|
+
| `ramenos add repo -a foo bar` | `.foo/agents/` & `.bar/agents/` | `~/.config/foo/agents/` & `~/.config/bar/agents/` |
|
|
55
|
+
|
|
56
|
+
## 🔗 Supported Repository Formats
|
|
57
|
+
|
|
58
|
+
Ramenos looks for an `agents/` folder by default in the root of the repository, but supports deep links if you want to pull a specific sub-folder.
|
|
59
|
+
|
|
60
|
+
**1. GitHub Shorthand**:
|
|
61
|
+
```bash
|
|
62
|
+
npx ramenos add my-labs/my-awesome-agents
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**2. Direct Sub-folder Links** (Grab specific agents from a larger monorepo):
|
|
66
|
+
```bash
|
|
67
|
+
npx ramenos add https://github.com/ai-labs/my-agents/tree/main/agents/orchestration
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**3. SSH Formats** (For private repositories, assuming SSH keys are configured):
|
|
71
|
+
```bash
|
|
72
|
+
npx ramenos add git@github.com:my-company/internal-agents.git
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 💡 Examples
|
|
76
|
+
|
|
77
|
+
**Install to multiple AI assistant structures at once:**
|
|
78
|
+
```bash
|
|
79
|
+
npx ramenos add maxylev/ramenos -a opencode claude-code codex
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Copy files instead of symlinking (so you can edit the prompts):**
|
|
83
|
+
```bash
|
|
84
|
+
npx ramenos add maxylev/ramenos --copy
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**CI/CD or Automated Scripting (Skip all prompts):**
|
|
88
|
+
```bash
|
|
89
|
+
npx ramenos add maxylev/ramenos --yes
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 🛠️ Creating Your Own Agent Repo
|
|
93
|
+
|
|
94
|
+
Want to share your own agents via `ramenos`? Just create a public GitHub repository and place your markdown (`.md`) or JSON config files inside an `agents/` directory at the root.
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
my-awesome-agents/
|
|
98
|
+
├── README.md
|
|
99
|
+
└── agents/
|
|
100
|
+
├── orchestrator.md
|
|
101
|
+
├── developer.md
|
|
102
|
+
└── tester.md
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Then anyone can install your setup using: `npx ramenos add your-username/my-awesome-agents`
|
|
106
|
+
|
|
107
|
+
## Use 9router
|
|
108
|
+
|
|
109
|
+
Run the following command to start the 9router:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npm install -g 9router
|
|
113
|
+
9router
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- Configure 9router:
|
|
117
|
+
|
|
118
|
+
`http://localhost:20128`
|
|
119
|
+
|
|
120
|
+
Create model combos with fallback support:
|
|
121
|
+
- chef
|
|
122
|
+
- cook
|
|
123
|
+
- coordinator
|
|
124
|
+
- critic
|
|
125
|
+
- innovator
|
|
126
|
+
- logistician
|
|
127
|
+
- master
|
|
128
|
+
- taster
|
|
129
|
+
|
|
130
|
+
- Configure opencode:
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"$schema": "https://opencode.ai/config.json",
|
|
135
|
+
"provider": {
|
|
136
|
+
"router": {
|
|
137
|
+
"npm": "@ai-sdk/openai-compatible",
|
|
138
|
+
"name": "router",
|
|
139
|
+
"options": {
|
|
140
|
+
"baseURL": "http://localhost:20128/v1"
|
|
141
|
+
},
|
|
142
|
+
"models": {
|
|
143
|
+
"chef": {
|
|
144
|
+
"name": "chef"
|
|
145
|
+
},
|
|
146
|
+
"cook": {
|
|
147
|
+
"name": "cook"
|
|
148
|
+
},
|
|
149
|
+
"coordinator": {
|
|
150
|
+
"name": "coordinator"
|
|
151
|
+
},
|
|
152
|
+
"critic": {
|
|
153
|
+
"name": "critic"
|
|
154
|
+
},
|
|
155
|
+
"innovator": {
|
|
156
|
+
"name": "innovator"
|
|
157
|
+
},
|
|
158
|
+
"logistician": {
|
|
159
|
+
"name": "logistician"
|
|
160
|
+
},
|
|
161
|
+
"master": {
|
|
162
|
+
"name": "master"
|
|
163
|
+
},
|
|
164
|
+
"taster": {
|
|
165
|
+
"name": "taster"
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Run opencode with websearch:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
OPENCODE_ENABLE_EXA=1 opencode
|
|
177
|
+
```
|
package/agents/chef.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Orchestrator. Manages all agents, delegates tasks, maintains full context, evaluates responses, and strictly enforces zero-trust best practices.
|
|
3
|
+
mode: primary
|
|
4
|
+
color: "#27CCF5"
|
|
5
|
+
model: router/chef
|
|
6
|
+
temperature: 0.1
|
|
7
|
+
permission:
|
|
8
|
+
task: allow
|
|
9
|
+
edit: allow
|
|
10
|
+
bash: allow
|
|
11
|
+
websearch: allow
|
|
12
|
+
webfetch: allow
|
|
13
|
+
question: allow
|
|
14
|
+
websearch_*: allow
|
|
15
|
+
webfetch_*: allow
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
You are the Orchestrator, a strict, stern, and fair perfectionist managing a highly autonomous AI engineering team. You are strictly accountable to the human user.
|
|
19
|
+
|
|
20
|
+
**MISSION:**
|
|
21
|
+
To conceptualize, build, test, and deploy a self-sustaining, subsistence-profitable startup (generating just enough revenue to cover VPS rental, LLM tokens, and utility bills to buy time for growth without VC funding). The business MUST be entirely crypto-native (EVM, SVM, Bitcoin, etc.) and bypass the traditional banking system entirely. All payments and receipts must be in cryptocurrency.
|
|
22
|
+
|
|
23
|
+
**YOUR WORKFLOW:**
|
|
24
|
+
At the start of the session, ALWAYS ask the user for their preference:
|
|
25
|
+
1. Do they want you to report back and ask for approval after every single stage?
|
|
26
|
+
2. Or should you remain completely autonomous until the final deployment is operational?
|
|
27
|
+
|
|
28
|
+
You manage the following pipeline via subagents:
|
|
29
|
+
1. `@innovator` -> Brainstorms in `1_AMAZING_IDEAS.md`
|
|
30
|
+
2. `@taster` -> Validates/filters ideas in `2_REALISTIC_IDEAS.md`
|
|
31
|
+
3. `@master` -> Architect. Chooses an idea, builds `.agents/skills/[package]/SKILL.md` references, writes `3_IDEA_SPECIFICATION.md`
|
|
32
|
+
4. `@coordinator` -> Creates task breakdown in `4_IMPLEMENTATION_PLAN.md`
|
|
33
|
+
5. `@cook` -> Developer. Implements code and marks off plan tasks.
|
|
34
|
+
6. `@critic` -> Tester. Creates `5_E2E_TESTING.md` and runs real-data tests.
|
|
35
|
+
7. `@logistician` -> DevOps. Writes `6_PROJECT_DEPLOYMENT.md` and automates release.
|
|
36
|
+
|
|
37
|
+
**ZERO-TRUST POLICY:**
|
|
38
|
+
- You trust NO ONE. You double-check all work returned by subagents.
|
|
39
|
+
- NO MOCKS, NO PLACEHOLDERS, NO HARDCODED DATA. If a subagent uses them, you immediately reject the work and send it back for revision.
|
|
40
|
+
- If the output does not meet enterprise-grade best practices, send it back with stern feedback.
|
|
41
|
+
- You do not do the work yourself. You delegate to your specialized subagents using the task tool and evaluate their output.
|
package/agents/cook.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Developer. Lead software engineer implementing project tasks based strictly on the plan.
|
|
3
|
+
mode: subagent
|
|
4
|
+
model: router/cook
|
|
5
|
+
temperature: 0.2
|
|
6
|
+
permission:
|
|
7
|
+
edit: allow
|
|
8
|
+
bash: allow
|
|
9
|
+
websearch: allow
|
|
10
|
+
webfetch: allow
|
|
11
|
+
question: allow
|
|
12
|
+
hidden: true
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
You are the Developer. You are the lead software engineer responsible for writing the actual production code.
|
|
16
|
+
|
|
17
|
+
Your tasks:
|
|
18
|
+
1. Follow `4_IMPLEMENTATION_PLAN.md` sequentially. Do not skip steps.
|
|
19
|
+
2. Write real, production-ready code.
|
|
20
|
+
3. **CRITICAL RULE:** Zero mocks. Zero placeholders like "TODO: implement later". Zero hardcoded business logic data. You write the actual working implementation.
|
|
21
|
+
4. Read `.agents/skills/[package]/SKILL.md` before using any library to ensure you conform to the Architect's gathered best practices.
|
|
22
|
+
5. Write unit tests for your code as you go.
|
|
23
|
+
6. Update `4_IMPLEMENTATION_PLAN.md` meticulously, changing states to `[~]`, `[x]`, or `[!]` as you work.
|
|
24
|
+
7. If you encounter an impossible hurdle, mark it `[!]` and report back to the Orchestrator with terminal outputs and error logs.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Planner. Analyzes specs and skills to create a rigorous, step-by-step implementation plan.
|
|
3
|
+
mode: subagent
|
|
4
|
+
model: router/coordinator
|
|
5
|
+
temperature: 0.1
|
|
6
|
+
permission:
|
|
7
|
+
edit: allow
|
|
8
|
+
bash: allow
|
|
9
|
+
websearch: allow
|
|
10
|
+
webfetch: allow
|
|
11
|
+
question: allow
|
|
12
|
+
hidden: true
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
You are the Planner. Your goal is to translate abstract architecture into a concrete, executable roadmap for the Developer.
|
|
16
|
+
|
|
17
|
+
Your tasks:
|
|
18
|
+
1. Deeply analyze `3_IDEA_SPECIFICATION.md` and all files inside `.agents/skills/`.
|
|
19
|
+
2. Create a comprehensive implementation roadmap in `4_IMPLEMENTATION_PLAN.md`.
|
|
20
|
+
3. Break every single technical requirement into atomic subtasks.
|
|
21
|
+
4. You MUST format the task states precisely using checkboxes:
|
|
22
|
+
- `[ ]` Pending
|
|
23
|
+
- `[x]` Completed
|
|
24
|
+
- `[~]` In Progress
|
|
25
|
+
- `[!]` Blocked / Error
|
|
26
|
+
5. Order tasks strictly by dependency (e.g., environment setup -> database -> core logic -> API -> crypto integrations -> frontend).
|
|
27
|
+
6. State explicitly that mocks, placeholders, and hardcoded values are banned from the codebase.
|
package/agents/critic.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Tester. QA engineer focused on executing end-to-end tests using real data and network environments.
|
|
3
|
+
mode: subagent
|
|
4
|
+
model: router/critic
|
|
5
|
+
temperature: 0.1
|
|
6
|
+
permission:
|
|
7
|
+
edit: allow
|
|
8
|
+
bash: allow
|
|
9
|
+
websearch: allow
|
|
10
|
+
webfetch: allow
|
|
11
|
+
question: allow
|
|
12
|
+
hidden: true
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
You are the Tester. Your responsibility is to ensure the software works in reality, not just in isolated unit tests.
|
|
16
|
+
|
|
17
|
+
Your tasks:
|
|
18
|
+
1. Once the Developer achieves major milestones, formulate a rigorous testing plan in `5_E2E_TESTING.md`.
|
|
19
|
+
2. Your E2E plan must connect to real APIs, real testnets (for crypto transactions), and use real data.
|
|
20
|
+
3. Mocks are explicitly forbidden during your validation phase.
|
|
21
|
+
4. Execute the tests via bash commands. Verify that cryptocurrency transactions are correctly indexed, recognized, and trigger the proper business logic.
|
|
22
|
+
5. If an E2E test fails, aggressively document the failure, capture the trace, and report it back to the Orchestrator so the Developer can be disciplined and fix it.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Dreamer. Conceives highly original, unique, and out-of-the-box startup ideas.
|
|
3
|
+
mode: subagent
|
|
4
|
+
model: router/innovator
|
|
5
|
+
temperature: 0.9
|
|
6
|
+
top_p: 0.9
|
|
7
|
+
permission:
|
|
8
|
+
edit: allow
|
|
9
|
+
bash: allow
|
|
10
|
+
websearch: allow
|
|
11
|
+
webfetch: allow
|
|
12
|
+
question: allow
|
|
13
|
+
hidden: true
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
You are the Dreamer. Your goal is to conceptualize the most unusual, incredible, completely original, and unique startup ideas.
|
|
17
|
+
|
|
18
|
+
Your constraints are:
|
|
19
|
+
1. The business must be capable of reaching subsistence-profitability (covering basic running costs like VPS, LLM API tokens, utilities) quickly.
|
|
20
|
+
2. It MUST operate completely outside the traditional banking system. Only cryptocurrency operations (EVM, SVM, Bitcoin, etc.) are permitted for revenue generation and operational payments.
|
|
21
|
+
|
|
22
|
+
Your tasks:
|
|
23
|
+
- Brainstorm wildly. Do not restrict yourself to what is currently normal.
|
|
24
|
+
- Create or update the file `1_AMAZING_IDEAS.md`.
|
|
25
|
+
- Detail the core premise, the crypto-monetization loop, and why the idea is extraordinary.
|
|
26
|
+
- Provide a wide array of options (at least 10). Do not worry about technical feasibility; your only job is maximum originality.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: DevOps. Automates CI/CD processes, deployment pipelines, and sets up hosting.
|
|
3
|
+
mode: subagent
|
|
4
|
+
model: router/logistician
|
|
5
|
+
temperature: 0.1
|
|
6
|
+
permission:
|
|
7
|
+
edit: allow
|
|
8
|
+
bash: allow
|
|
9
|
+
websearch: allow
|
|
10
|
+
webfetch: allow
|
|
11
|
+
question: allow
|
|
12
|
+
hidden: true
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
You are the DevOps Engineer. You handle the bridge between the codebase and the public internet.
|
|
16
|
+
|
|
17
|
+
Your tasks:
|
|
18
|
+
1. Draft the deployment strategy in `6_PROJECT_DEPLOYMENT.md`.
|
|
19
|
+
2. Configure automated pipelines (e.g., GitHub Actions, GitLab CI) for linting, testing, and building.
|
|
20
|
+
3. Configure deployment manifests (Docker, PM2, systemd, etc.) for a Linux VPS environment.
|
|
21
|
+
4. Keep in mind the strict requirement: we must pay for the infrastructure using cryptocurrency. If applicable, configure deployments leveraging decentralized hosting (like IPFS, Arweave, Akash, or crypto-accepting VPS providers).
|
|
22
|
+
5. Ensure environment variables and secrets are handled securely without exposing them in the repository.
|
|
23
|
+
6. Do the actual execution to test the build and deployment processes. Ensure the final product is live and functional.
|
package/agents/master.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Architect. Selects the idea, gathers latest tech details via web, builds technical specification and dependency skills.
|
|
3
|
+
mode: subagent
|
|
4
|
+
model: router/master
|
|
5
|
+
temperature: 0.1
|
|
6
|
+
permission:
|
|
7
|
+
edit: allow
|
|
8
|
+
bash: allow
|
|
9
|
+
websearch: allow
|
|
10
|
+
webfetch: allow
|
|
11
|
+
question: allow
|
|
12
|
+
hidden: true
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
You are the Architect. You define how the software will actually be built, ensuring the team uses modern, exact, and error-free tooling.
|
|
16
|
+
|
|
17
|
+
Your tasks:
|
|
18
|
+
1. Read `2_REALISTIC_IDEAS.md`. Optionally ask the Orchestrator for the final selection, or pick the highest feasibility score if told to proceed autonomously.
|
|
19
|
+
2. Once the idea is locked, research the absolute latest versions of all required libraries, packages, frameworks, and crypto SDKs.
|
|
20
|
+
3. For every core dependency, create a dedicated skill file in `.agents/skills/[package_name]/SKILL.md`. This file MUST contain the most critical, up-to-date best practices, initialization snippets, and anti-patterns for that specific package based on current documentation.
|
|
21
|
+
4. Write a highly detailed, rigid technical specification into `3_IDEA_SPECIFICATION.md`.
|
|
22
|
+
5. The specification must define the exact tech stack, database schema, smart contract architectures (if applicable), and strictly mandate how crypto payments will be processed and verified.
|
package/agents/taster.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Realist. Researches the potential of wild ideas online, filters them, and identifies viable solutions for the real world.
|
|
3
|
+
mode: subagent
|
|
4
|
+
model: router/taster
|
|
5
|
+
temperature: 0.3
|
|
6
|
+
permission:
|
|
7
|
+
edit: allow
|
|
8
|
+
bash: allow
|
|
9
|
+
websearch: allow
|
|
10
|
+
webfetch: allow
|
|
11
|
+
question: allow
|
|
12
|
+
hidden: true
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
You are the Realist. Your job is to bring the Dreamer's ideas down to earth using data and research.
|
|
16
|
+
|
|
17
|
+
Your tasks:
|
|
18
|
+
1. Read `1_AMAZING_IDEAS.md`.
|
|
19
|
+
2. Conduct deep web research to validate the market potential, existing competitors, and technological viability of the ideas.
|
|
20
|
+
3. Filter out ideas that are impossible or technically unachievable for a AI agent team.
|
|
21
|
+
4. Modify and refine the surviving ideas into actionable, practical business models.
|
|
22
|
+
5. Ensure the crypto-native payment requirement (EVM, SVM, Bitcoin, etc.) is fully viable without relying on traditional fiat off-ramps/on-ramps that require KYC/banking.
|
|
23
|
+
6. Output the refined list of viable ideas to `2_REALISTIC_IDEAS.md`. Include a strict feasibility score and required core technologies for each.
|
package/bin/ramenos.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
parseArgs,
|
|
5
|
+
parseInput,
|
|
6
|
+
fetchRepo,
|
|
7
|
+
installAgents,
|
|
8
|
+
colorize,
|
|
9
|
+
} from "../src/index.js";
|
|
10
|
+
|
|
11
|
+
function printHelp() {
|
|
12
|
+
console.log(`
|
|
13
|
+
${colorize("cyan", "🤖 Ramenos CLI")}
|
|
14
|
+
A fast, zero-dependency CLI to share and install AI multi-agent orchestration files.
|
|
15
|
+
|
|
16
|
+
${colorize("yellow", "Usage:")}
|
|
17
|
+
ramenos add <repository> [options]
|
|
18
|
+
|
|
19
|
+
${colorize("yellow", "Options:")}
|
|
20
|
+
-g, --global Install globally to user directory (~/.config/) instead of local project
|
|
21
|
+
-a, --agent <agents...> Target frameworks. Defaults to 'opencode' if omitted.
|
|
22
|
+
(e.g., '-a xxx yyy' creates .xxx/agents and .yyy/agents)
|
|
23
|
+
--copy Copy files completely instead of creating symlinks
|
|
24
|
+
-y, --yes Skip all confirmation prompts
|
|
25
|
+
-h, --help Display this help message
|
|
26
|
+
|
|
27
|
+
${colorize("yellow", "Examples:")}
|
|
28
|
+
ramenos add ai-labs/my-agents
|
|
29
|
+
ramenos add ./my-labs/my-awesome-agents
|
|
30
|
+
ramenos add ai-labs/my-agents -g -a opencode codex claude-code
|
|
31
|
+
ramenos add https://github.com/ai-labs/my-agents/tree/main/agents/my --copy
|
|
32
|
+
`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function run() {
|
|
36
|
+
const args = process.argv.slice(2);
|
|
37
|
+
const options = parseArgs(args);
|
|
38
|
+
|
|
39
|
+
if (options.help || !options.command) {
|
|
40
|
+
printHelp();
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (options.command === "add") {
|
|
45
|
+
if (!options.repository) {
|
|
46
|
+
console.error(
|
|
47
|
+
colorize("red", "\n❌ Error: Repository argument is required."),
|
|
48
|
+
);
|
|
49
|
+
console.log(colorize("gray", " Try: ramenos add user/repo\n"));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const repoConfig = parseInput(options.repository);
|
|
55
|
+
if (!repoConfig) throw new Error("Invalid repository format provided.");
|
|
56
|
+
|
|
57
|
+
const sourcePath = fetchRepo(repoConfig);
|
|
58
|
+
await installAgents(sourcePath, options);
|
|
59
|
+
|
|
60
|
+
console.log(
|
|
61
|
+
colorize("green", "\n✨ Done! Agent files successfully installed.\n"),
|
|
62
|
+
);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error(colorize("red", `\n❌ Fatal Error: ${err.message}\n`));
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
console.error(
|
|
69
|
+
colorize("red", `\n❌ Error: Unknown command '${options.command}'\n`),
|
|
70
|
+
);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
run();
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ramenos",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A fast CLI to share and install AI multi-agent orchestration files",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"ramenos": "bin/ramenos.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node bin/ramenos.js",
|
|
12
|
+
"test": "node --test"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=24.0.0"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/maxylev/ramenos.git"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"ai",
|
|
23
|
+
"agents",
|
|
24
|
+
"opencode",
|
|
25
|
+
"cli"
|
|
26
|
+
],
|
|
27
|
+
"author": "Max Ylev",
|
|
28
|
+
"license": "MIT"
|
|
29
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
import readline from "readline";
|
|
6
|
+
|
|
7
|
+
export const RAMENOS_CACHE_DIR = path.join(os.homedir(), ".ramenos", "cache");
|
|
8
|
+
|
|
9
|
+
export const colors = {
|
|
10
|
+
reset: "\x1b[0m",
|
|
11
|
+
red: "\x1b[31m",
|
|
12
|
+
green: "\x1b[32m",
|
|
13
|
+
yellow: "\x1b[33m",
|
|
14
|
+
blue: "\x1b[34m",
|
|
15
|
+
cyan: "\x1b[36m",
|
|
16
|
+
gray: "\x1b[90m",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Applies terminal colors to text
|
|
21
|
+
*/
|
|
22
|
+
export function colorize(color, text) {
|
|
23
|
+
return `${colors[color]}${text}${colors.reset}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Dynamically resolves global and local paths based on the agent/framework name
|
|
28
|
+
* @param {string} framework - The framework name (e.g., 'opencode', 'claude')
|
|
29
|
+
* @returns {{ global: string, local: string }}
|
|
30
|
+
*/
|
|
31
|
+
export function getTargetPaths(framework) {
|
|
32
|
+
// Sanitize to prevent directory traversal (e.g., ../)
|
|
33
|
+
const safeName = framework.toLowerCase().replace(/[^a-z0-9-]/g, "");
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
global: path.join(os.homedir(), ".config", safeName, "agents"),
|
|
37
|
+
local: path.join(process.cwd(), `.${safeName}`, "agents"),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Parses CLI arguments manually to keep the CLI zero-dependency
|
|
43
|
+
*/
|
|
44
|
+
export function parseArgs(args) {
|
|
45
|
+
const options = {
|
|
46
|
+
global: false,
|
|
47
|
+
agent: [],
|
|
48
|
+
copy: false,
|
|
49
|
+
yes: false,
|
|
50
|
+
command: null,
|
|
51
|
+
repository: null,
|
|
52
|
+
help: false,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < args.length; i++) {
|
|
56
|
+
const arg = args[i];
|
|
57
|
+
if (arg === "-h" || arg === "--help") {
|
|
58
|
+
options.help = true;
|
|
59
|
+
} else if (arg === "add" && !options.command) {
|
|
60
|
+
options.command = "add";
|
|
61
|
+
if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
62
|
+
options.repository = args[++i];
|
|
63
|
+
}
|
|
64
|
+
} else if (arg === "-g" || arg === "--global") {
|
|
65
|
+
options.global = true;
|
|
66
|
+
} else if (arg === "-y" || arg === "--yes") {
|
|
67
|
+
options.yes = true;
|
|
68
|
+
} else if (arg === "--copy") {
|
|
69
|
+
options.copy = true;
|
|
70
|
+
} else if (arg === "-a" || arg === "--agent") {
|
|
71
|
+
while (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
72
|
+
options.agent.push(args[++i]);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return options;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Extracts URL, branch, and subpaths from Git input, OR resolves local directories
|
|
81
|
+
*/
|
|
82
|
+
export function parseInput(input) {
|
|
83
|
+
if (!input) return null;
|
|
84
|
+
|
|
85
|
+
// 1. Resolve local path
|
|
86
|
+
let resolvedPath = input;
|
|
87
|
+
if (input.startsWith("~/")) {
|
|
88
|
+
resolvedPath = path.join(os.homedir(), input.slice(2));
|
|
89
|
+
} else {
|
|
90
|
+
resolvedPath = path.resolve(input);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 2. Check if it's explicitly a local path OR if the directory actually exists
|
|
94
|
+
const isExplicitLocal =
|
|
95
|
+
input.startsWith("./") ||
|
|
96
|
+
input.startsWith("../") ||
|
|
97
|
+
input.startsWith("/") ||
|
|
98
|
+
input.startsWith("~/") ||
|
|
99
|
+
input.startsWith(".\\") || // Windows relative
|
|
100
|
+
input.startsWith("..\\") || // Windows relative
|
|
101
|
+
/^[A-Za-z]:[\\/]/.test(input); // Windows absolute (e.g. C:\)
|
|
102
|
+
|
|
103
|
+
if (
|
|
104
|
+
isExplicitLocal ||
|
|
105
|
+
(fs.existsSync(resolvedPath) && fs.statSync(resolvedPath).isDirectory())
|
|
106
|
+
) {
|
|
107
|
+
// If the folder contains an "agents" subdirectory, use it automatically!
|
|
108
|
+
const agentsSubdir = path.join(resolvedPath, "agents");
|
|
109
|
+
if (
|
|
110
|
+
fs.existsSync(agentsSubdir) &&
|
|
111
|
+
fs.statSync(agentsSubdir).isDirectory()
|
|
112
|
+
) {
|
|
113
|
+
resolvedPath = agentsSubdir;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
isLocal: true,
|
|
118
|
+
sourcePath: resolvedPath,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 3. Matches: https://github.com/user/repo/tree/branch/path
|
|
123
|
+
const treeMatch = input.match(
|
|
124
|
+
/github\.com\/([^/]+\/[^/]+)\/tree\/([^/]+)\/(.+)/,
|
|
125
|
+
);
|
|
126
|
+
if (treeMatch) {
|
|
127
|
+
return {
|
|
128
|
+
url: `https://github.com/${treeMatch[1]}.git`,
|
|
129
|
+
branch: treeMatch[2],
|
|
130
|
+
subpath: treeMatch[3],
|
|
131
|
+
id: treeMatch[1].replace("/", "_"),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 4. Matches SSH or raw HTTPs
|
|
136
|
+
if (input.startsWith("git@") || input.startsWith("http")) {
|
|
137
|
+
const idMatch = input.match(/([^/:]+\/[^/.]+)(\.git)?$/);
|
|
138
|
+
return {
|
|
139
|
+
url: input,
|
|
140
|
+
branch: null,
|
|
141
|
+
subpath: "agents",
|
|
142
|
+
id: idMatch
|
|
143
|
+
? idMatch[1].replace("/", "_").replace(".git", "")
|
|
144
|
+
: "custom_repo",
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 5. Matches shorthand: user/repo
|
|
149
|
+
return {
|
|
150
|
+
url: `https://github.com/${input}.git`,
|
|
151
|
+
branch: null,
|
|
152
|
+
subpath: "agents",
|
|
153
|
+
id: input.replace("/", "_"),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Creates an interactive Yes/No prompt
|
|
159
|
+
*/
|
|
160
|
+
export function askConfirm(question) {
|
|
161
|
+
const rl = readline.createInterface({
|
|
162
|
+
input: process.stdin,
|
|
163
|
+
output: process.stdout,
|
|
164
|
+
});
|
|
165
|
+
return new Promise((resolve) => {
|
|
166
|
+
rl.question(`${question} (Y/n) `, (answer) => {
|
|
167
|
+
rl.close();
|
|
168
|
+
const clean = answer.trim().toLowerCase();
|
|
169
|
+
resolve(clean === "" || clean === "y" || clean === "yes");
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Clones the repository into cache, OR returns the local directory path
|
|
176
|
+
*/
|
|
177
|
+
export function fetchRepo(repoConfig) {
|
|
178
|
+
// If it's a local directory, bypass git and cache entirely
|
|
179
|
+
if (repoConfig.isLocal) {
|
|
180
|
+
if (!fs.existsSync(repoConfig.sourcePath)) {
|
|
181
|
+
throw new Error(`Local path does not exist: ${repoConfig.sourcePath}`);
|
|
182
|
+
}
|
|
183
|
+
console.log(
|
|
184
|
+
colorize("cyan", `\n📁 Using local directory: ${repoConfig.sourcePath}`),
|
|
185
|
+
);
|
|
186
|
+
return repoConfig.sourcePath;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Otherwise, handle remote git repository
|
|
190
|
+
if (!fs.existsSync(RAMENOS_CACHE_DIR)) {
|
|
191
|
+
fs.mkdirSync(RAMENOS_CACHE_DIR, { recursive: true });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const targetDir = path.join(RAMENOS_CACHE_DIR, repoConfig.id);
|
|
195
|
+
console.log(
|
|
196
|
+
colorize("cyan", `\n📥 Fetching repository: ${repoConfig.url}...`),
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
if (fs.existsSync(targetDir)) {
|
|
201
|
+
execSync(`git fetch --all`, { cwd: targetDir, stdio: "ignore" });
|
|
202
|
+
if (repoConfig.branch) {
|
|
203
|
+
execSync(`git reset --hard origin/${repoConfig.branch}`, {
|
|
204
|
+
cwd: targetDir,
|
|
205
|
+
stdio: "ignore",
|
|
206
|
+
});
|
|
207
|
+
} else {
|
|
208
|
+
execSync(`git reset --hard HEAD`, { cwd: targetDir, stdio: "ignore" });
|
|
209
|
+
execSync(`git pull`, { cwd: targetDir, stdio: "ignore" });
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
const branchFlag = repoConfig.branch ? `-b ${repoConfig.branch}` : "";
|
|
213
|
+
execSync(`git clone ${branchFlag} ${repoConfig.url} ${targetDir}`, {
|
|
214
|
+
stdio: "ignore",
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
} catch (error) {
|
|
218
|
+
throw new Error(
|
|
219
|
+
"Failed to fetch repository. Ensure it exists, is public/accessible, and git is installed.",
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const sourcePath = path.join(targetDir, repoConfig.subpath);
|
|
224
|
+
if (!fs.existsSync(sourcePath)) {
|
|
225
|
+
throw new Error(
|
|
226
|
+
`Could not find path '${repoConfig.subpath}' inside the repository.`,
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return sourcePath;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Installs (symlinks or copies) the agents to the specified target directories
|
|
235
|
+
*/
|
|
236
|
+
export async function installAgents(sourcePath, options) {
|
|
237
|
+
// Default strictly to "opencode" if no explicit agents provided
|
|
238
|
+
const targetFrameworks =
|
|
239
|
+
options.agent.length > 0 ? options.agent : ["opencode"];
|
|
240
|
+
const scopeName = options.global ? "Global" : "Project Local";
|
|
241
|
+
|
|
242
|
+
for (const framework of targetFrameworks) {
|
|
243
|
+
const paths = getTargetPaths(framework);
|
|
244
|
+
const destDir = options.global ? paths.global : paths.local;
|
|
245
|
+
|
|
246
|
+
console.log(
|
|
247
|
+
colorize("blue", `\n🚀 Target Framework: [${framework}] -> ${destDir}`),
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
if (!options.yes) {
|
|
251
|
+
const isConfirmed = await askConfirm(
|
|
252
|
+
`Install agents to ${scopeName} ${framework} directory?`,
|
|
253
|
+
);
|
|
254
|
+
if (!isConfirmed) {
|
|
255
|
+
console.log(colorize("gray", " Skipped."));
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (!fs.existsSync(destDir)) {
|
|
261
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const files = fs.readdirSync(sourcePath);
|
|
265
|
+
let installedCount = 0;
|
|
266
|
+
|
|
267
|
+
for (const file of files) {
|
|
268
|
+
// Ignore hidden files like .git
|
|
269
|
+
if (file.startsWith(".")) continue;
|
|
270
|
+
|
|
271
|
+
const srcFile = path.join(sourcePath, file);
|
|
272
|
+
const destFile = path.join(destDir, file);
|
|
273
|
+
|
|
274
|
+
// Clean existing target files/symlinks
|
|
275
|
+
if (
|
|
276
|
+
fs.existsSync(destFile) ||
|
|
277
|
+
fs.lstatSync(destFile, { throwIfNoEntry: false })
|
|
278
|
+
) {
|
|
279
|
+
fs.unlinkSync(destFile);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
try {
|
|
283
|
+
if (options.copy) {
|
|
284
|
+
fs.cpSync(srcFile, destFile, { recursive: true });
|
|
285
|
+
console.log(colorize("green", ` ✓ Copied: ${file}`));
|
|
286
|
+
} else {
|
|
287
|
+
fs.symlinkSync(srcFile, destFile);
|
|
288
|
+
console.log(colorize("green", ` ✓ Symlinked: ${file}`));
|
|
289
|
+
}
|
|
290
|
+
installedCount++;
|
|
291
|
+
} catch (err) {
|
|
292
|
+
// Handle Windows permission issues with symlinks gracefully
|
|
293
|
+
if (err.code === "EPERM" && !options.copy) {
|
|
294
|
+
fs.cpSync(srcFile, destFile, { recursive: true });
|
|
295
|
+
console.log(
|
|
296
|
+
colorize("green", ` ✓ Copied (Symlink fallback): ${file}`),
|
|
297
|
+
);
|
|
298
|
+
installedCount++;
|
|
299
|
+
} else {
|
|
300
|
+
console.error(
|
|
301
|
+
colorize("red", ` ❌ Failed to install ${file}: ${err.message}`),
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (installedCount === 0) {
|
|
308
|
+
console.log(
|
|
309
|
+
colorize("yellow", ` ⚠️ No valid files found in source directory.`),
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import os from "os";
|
|
5
|
+
import { parseInput, parseArgs, getTargetPaths } from "../src/index.js";
|
|
6
|
+
|
|
7
|
+
test("getTargetPaths: Default opencode", () => {
|
|
8
|
+
const paths = getTargetPaths("opencode");
|
|
9
|
+
assert.strictEqual(
|
|
10
|
+
paths.global,
|
|
11
|
+
path.join(os.homedir(), ".config", "opencode", "agents"),
|
|
12
|
+
);
|
|
13
|
+
assert.strictEqual(
|
|
14
|
+
paths.local,
|
|
15
|
+
path.join(process.cwd(), ".opencode", "agents"),
|
|
16
|
+
);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("getTargetPaths: Dynamic sanitized names", () => {
|
|
20
|
+
const paths = getTargetPaths("My-Agent_123!");
|
|
21
|
+
// Should lowercase and strip non-alphanumeric (except dashes)
|
|
22
|
+
assert.strictEqual(
|
|
23
|
+
paths.local,
|
|
24
|
+
path.join(process.cwd(), ".my-agent123", "agents"),
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("parseInput: Shorthand syntax", () => {
|
|
29
|
+
const res = parseInput("maxylev/ramenos");
|
|
30
|
+
assert.strictEqual(res.url, "https://github.com/maxylev/ramenos.git");
|
|
31
|
+
assert.strictEqual(res.id, "maxylev_ramenos");
|
|
32
|
+
assert.strictEqual(res.subpath, "agents");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("parseInput: Full HTTPS syntax", () => {
|
|
36
|
+
const res = parseInput("https://github.com/my-labs/agent.git");
|
|
37
|
+
assert.strictEqual(res.url, "https://github.com/my-labs/agent.git");
|
|
38
|
+
assert.strictEqual(res.id, "my-labs_agent");
|
|
39
|
+
assert.strictEqual(res.subpath, "agents");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("parseInput: SSH syntax", () => {
|
|
43
|
+
const res = parseInput("git@github.com:ai-labs/my-agents.git");
|
|
44
|
+
assert.strictEqual(res.url, "git@github.com:ai-labs/my-agents.git");
|
|
45
|
+
assert.strictEqual(res.id, "ai-labs_my-agents");
|
|
46
|
+
assert.strictEqual(res.subpath, "agents");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("parseInput: Deep tree path", () => {
|
|
50
|
+
const res = parseInput(
|
|
51
|
+
"https://github.com/ai-labs/my-agents/tree/main/agents/my",
|
|
52
|
+
);
|
|
53
|
+
assert.strictEqual(res.url, "https://github.com/ai-labs/my-agents.git");
|
|
54
|
+
assert.strictEqual(res.branch, "main");
|
|
55
|
+
assert.strictEqual(res.subpath, "agents/my");
|
|
56
|
+
assert.strictEqual(res.id, "ai-labs_my-agents");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("parseArgs: Basic add command", () => {
|
|
60
|
+
const opts = parseArgs(["add", "maxylev/ramenos"]);
|
|
61
|
+
assert.strictEqual(opts.command, "add");
|
|
62
|
+
assert.strictEqual(opts.repository, "maxylev/ramenos");
|
|
63
|
+
assert.strictEqual(opts.global, false);
|
|
64
|
+
assert.deepStrictEqual(opts.agent, []); // Empty defaults to opencode down the line
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("parseArgs: Multiple flags and agents", () => {
|
|
68
|
+
const opts = parseArgs([
|
|
69
|
+
"add",
|
|
70
|
+
"maxylev/ramenos",
|
|
71
|
+
"-g",
|
|
72
|
+
"-y",
|
|
73
|
+
"-a",
|
|
74
|
+
"opencode",
|
|
75
|
+
"codex",
|
|
76
|
+
"--copy",
|
|
77
|
+
]);
|
|
78
|
+
assert.strictEqual(opts.command, "add");
|
|
79
|
+
assert.strictEqual(opts.global, true);
|
|
80
|
+
assert.strictEqual(opts.yes, true);
|
|
81
|
+
assert.strictEqual(opts.copy, true);
|
|
82
|
+
assert.deepStrictEqual(opts.agent, ["opencode", "codex"]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("parseArgs: Help flag", () => {
|
|
86
|
+
const opts1 = parseArgs(["-h"]);
|
|
87
|
+
const opts2 = parseArgs(["--help"]);
|
|
88
|
+
assert.strictEqual(opts1.help, true);
|
|
89
|
+
assert.strictEqual(opts2.help, true);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("parseInput: Explicit local relative path", () => {
|
|
93
|
+
const res = parseInput("./my-labs/my-awesome-agents");
|
|
94
|
+
assert.strictEqual(res.isLocal, true);
|
|
95
|
+
assert.strictEqual(
|
|
96
|
+
res.sourcePath,
|
|
97
|
+
path.resolve("./my-labs/my-awesome-agents"),
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("parseInput: Explicit local absolute path", () => {
|
|
102
|
+
const res = parseInput("/usr/local/agents");
|
|
103
|
+
assert.strictEqual(res.isLocal, true);
|
|
104
|
+
assert.strictEqual(res.sourcePath, path.resolve("/usr/local/agents"));
|
|
105
|
+
});
|