kodu 1.1.20 → 1.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kodu",
3
- "version": "1.1.20",
3
+ "version": "1.2.0",
4
4
  "description": "High-performance CLI to prepare codebase for LLMs, automate reviews, and draft commits.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,184 @@
1
+ ---
2
+ name: kodu-ops
3
+ description: Use when a user asks in plain language to deploy, update environment variables, add/remove domains, or inspect server/app status on dev/prod, and these intents should be translated into `kodu ops` commands.
4
+ ---
5
+
6
+ # Kodu Ops
7
+
8
+ ## Overview
9
+
10
+ Справочник для `kodu ops`: как переводить пользовательские запросы в корректные команды `sysinfo`, `env`, `routes`, `service`.
11
+
12
+ Ключевой принцип: `kodu ops` должен возвращать JSON-ответы без интерактивщины; агент выбирает подкоманды и флаги точно по контракту.
13
+
14
+ ## When To Use
15
+
16
+ Используйте этот скилл, когда нужно:
17
+
18
+ - Перевести бытовой/джуновский запрос на инфраструктуру в `kodu ops` (без ожидания, что пользователь знает CLI).
19
+ - Получить диагностику удаленного сервера (`sysinfo`).
20
+ - Прочитать или изменить `.env` проекта (`env`).
21
+ - Посмотреть или изменить маршруты Caddy (`routes`).
22
+ - Управлять lifecycle сервиса через Docker Compose (`service`).
23
+ - Выполнить несколько ops-действий в одном запросе в строгой последовательности.
24
+
25
+ Не используйте, если задача не про `kodu ops` (например, локальная сборка/линт/git без удаленных операций).
26
+
27
+ ## Core Rules
28
+
29
+ - Всегда используйте именованные флаги; positional arguments не поддерживаются.
30
+ - Не ожидайте, что пользователь назовет `kodu ops` или `--action`; извлекайте intent из обычной речи.
31
+ - Для каждого шага проверяйте обязательные флаги до запуска следующего.
32
+ - В цепочке "сначала ... потом ..." выполняйте команды последовательно.
33
+ - В ошибках ориентируйтесь на JSON-поля `status`, `code` и `error`/`stderr`.
34
+ - Если пользователь дал неполные данные, запрашивайте только отсутствующие обязательные параметры.
35
+
36
+ ## Quick Reference
37
+
38
+ | Подкоманда | Назначение | Действия | Обязательные флаги |
39
+ | --- | --- | --- | --- |
40
+ | `sysinfo` | Диагностика сервера | - | `--server` |
41
+ | `env` | Работа с `.env` проекта | `get`, `set`, `unset` | `--server --action --project` (+ `--key` для `set/unset`, + `--val` для `set`) |
42
+ | `routes` | Работа с Caddy маршрутами | `list`, `add`, `remove`, `update` | `--server --action` (+ `--domain` для `add/remove/update`, + `--upstream` для `add/update`) |
43
+ | `service` | Управление сервисом | `clone`, `pull`, `up`, `down`, `logs`, `status` | `--server --action --project` (+ `--repo` для `clone`) |
44
+
45
+ ## Command Details
46
+
47
+ ### `sysinfo`
48
+
49
+ Назначение: собрать `uptime`, загрузку диска `/` и свободную память.
50
+
51
+ Флаги:
52
+
53
+ - `-s, --server <name>` - алиас сервера из `kodu.json`.
54
+
55
+ Пример:
56
+
57
+ ```bash
58
+ kodu ops sysinfo --server dev
59
+ ```
60
+
61
+ ### `env`
62
+
63
+ Назначение: читать и изменять `.env` файла проекта в `ops.servers.<alias>.paths.apps/<project>/.env`.
64
+
65
+ Флаги:
66
+
67
+ - `-s, --server <name>`
68
+ - `-a, --action <get|set|unset>`
69
+ - `-p, --project <name>`
70
+ - `--key <key>` - обязателен для `set` и `unset`
71
+ - `--val <value>` - обязателен только для `set`
72
+
73
+ Примеры:
74
+
75
+ ```bash
76
+ kodu ops env --server dev --action get --project my-app
77
+ kodu ops env --server dev --action set --project my-app --key PORT --val 3123
78
+ kodu ops env --server dev --action unset --project my-app --key PORT
79
+ ```
80
+
81
+ Ограничения:
82
+
83
+ - Ключ проходит валидацию: `[A-Za-z_][A-Za-z0-9_]*`.
84
+
85
+ ### `routes`
86
+
87
+ Назначение: читать и редактировать блоки доменов в `Caddyfile` (reverse proxy).
88
+
89
+ Флаги:
90
+
91
+ - `-s, --server <name>`
92
+ - `-a, --action <list|add|remove|update>`
93
+ - `--domain <domain>` - обязателен для `add`, `remove`, `update`
94
+ - `--upstream <host:port>` - обязателен для `add`, `update`
95
+
96
+ Примеры:
97
+
98
+ ```bash
99
+ kodu ops routes --server dev --action list
100
+ kodu ops routes --server dev --action add --domain api.example.com --upstream 127.0.0.1:3000
101
+ kodu ops routes --server dev --action update --domain api.example.com --upstream 127.0.0.1:4000
102
+ kodu ops routes --server dev --action remove --domain api.example.com
103
+ ```
104
+
105
+ Поведение:
106
+
107
+ - После `add/remove/update` автоматически применяется `./caddy.sh`.
108
+ - Если маршрут не найден при `remove/update`, ожидайте ошибку с кодом `NOT_FOUND`.
109
+
110
+ ### `service`
111
+
112
+ Назначение: управлять проектом в директории apps через `git` и `docker compose`.
113
+
114
+ Флаги:
115
+
116
+ - `-s, --server <name>`
117
+ - `-a, --action <clone|pull|up|down|logs|status>`
118
+ - `-p, --project <name>`
119
+ - `--repo <url>` - обязателен только для `clone`
120
+
121
+ Примеры:
122
+
123
+ ```bash
124
+ kodu ops service --server dev --action clone --project temp --repo https://github.com/org/repo.git
125
+ kodu ops service --server dev --action up --project temp
126
+ kodu ops service --server dev --action status --project temp
127
+ kodu ops service --server dev --action logs --project temp
128
+ kodu ops service --server dev --action pull --project temp
129
+ kodu ops service --server dev --action down --project temp
130
+ ```
131
+
132
+ Фактические действия:
133
+
134
+ - `clone` -> `git clone <repo> <projectPath>` (ошибка, если директория уже существует)
135
+ - `pull` -> `git pull`
136
+ - `up` -> `docker compose up -d`
137
+ - `down` -> `docker compose down`
138
+ - `logs` -> `docker compose logs --no-color --tail=200`
139
+ - `status` -> `docker compose ps --format json` (fallback на обычный `docker compose ps`)
140
+
141
+ ## JSON Output Contract
142
+
143
+ Успех:
144
+
145
+ - Всегда есть `status: "ok"`.
146
+ - Полезная нагрузка приходит в `data` или `message` в зависимости от подкоманды.
147
+
148
+ Ошибка:
149
+
150
+ - Всегда есть `status: "error"`.
151
+ - Поле `code` может быть строкой (например, `VALIDATION_ERROR`, `NOT_FOUND`) или числовым exit-code SSH.
152
+ - Текст ошибки приходит как `error` (CLI-валидация) или `stderr` (SSH/remote ошибки).
153
+
154
+ ## Multi-Step Intent Mapping
155
+
156
+ Если пользователь описывает цепочку действий, раскладывайте ее на команды в указанном порядке.
157
+
158
+ Частые разговорные формулировки:
159
+
160
+ - "залей на прод/дев" -> обычно `service pull` + `service up` (или `service clone` + `service up`, если проекта еще нет).
161
+ - "добавь домен" -> `routes --action add --domain ... --upstream ...`.
162
+ - "поменяй домен на новый порт" -> `routes --action update --domain ... --upstream ...`.
163
+ - "посмотри что с сервисом" -> `service --action status` (+ при необходимости `service --action logs`).
164
+ - "поставь переменную" -> `env --action set --key ... --val ...`.
165
+
166
+ Пример:
167
+
168
+ ```text
169
+ "Покажи sysinfo на dev, поставь PORT=3123 в temp и добавь маршрут api.example.com -> 127.0.0.1:3000"
170
+ ```
171
+
172
+ Порядок команд:
173
+
174
+ 1. `kodu ops sysinfo --server dev`
175
+ 2. `kodu ops env --server dev --action set --project temp --key PORT --val 3123`
176
+ 3. `kodu ops routes --server dev --action add --domain api.example.com --upstream 127.0.0.1:3000`
177
+
178
+ ## Common Mistakes
179
+
180
+ - Пропуск `--project` для `service`/`env` (он обязателен даже для `clone`).
181
+ - Использование `pull` как обновления docker-образов: здесь `pull` делает `git pull` в проекте.
182
+ - Ожидание единого формата ошибки `error` во всех случаях: для SSH-ошибок обычно поле `stderr`.
183
+ - Передача key в неверном формате (например, `my.key`), что ломает валидацию.
184
+ - Попытка передать positional args вместо `--flags`.
@@ -200,8 +200,8 @@ export class OpsRoutesCommand extends CommandRunner {
200
200
  ' if not domain_re.search(text):',
201
201
  ' sys.stderr.write("Route not found")',
202
202
  ' sys.exit(4)',
203
- ' text = domain_re.sub("\n", text, count=1)',
204
- ' text = re.sub(r"\\n{3,}", "\n\n", text)',
203
+ ' text = domain_re.sub("\\n", text, count=1)',
204
+ ' text = re.sub(r"\\n{3,}", "\\n\\n", text)',
205
205
  ' text = re.sub(r"^\\n+", "", text)',
206
206
  'elif action == "update":',
207
207
  ' match = domain_re.search(text)',
@@ -12,6 +12,7 @@ type PackOptions = {
12
12
  copy?: boolean;
13
13
  template?: string;
14
14
  out?: string;
15
+ path?: string[];
15
16
  };
16
17
 
17
18
  type TemplateContext = {
@@ -57,6 +58,14 @@ export class PackCommand extends CommandRunner {
57
58
  return value;
58
59
  }
59
60
 
61
+ @Option({
62
+ flags: '-p, --path <path>',
63
+ description: 'Directory or glob to include (repeatable)',
64
+ })
65
+ parsePath(value: string, previous: string[] = []): string[] {
66
+ return [...previous, value];
67
+ }
68
+
60
69
  async run(_inputs: string[], options: PackOptions): Promise<void> {
61
70
  const spinner = this.ui
62
71
  .createSpinner({ text: 'Collecting files...' })
@@ -69,6 +78,7 @@ export class PackCommand extends CommandRunner {
69
78
  useGitignore: packer.useGitignore,
70
79
  ignore: packer.ignore,
71
80
  contentBasedBinaryDetection: packer.contentBasedBinaryDetection,
81
+ rootPaths: options.path,
72
82
  });
73
83
 
74
84
  if (files.length === 0) {
@@ -20,6 +20,7 @@ type FindProjectFilesOptions = {
20
20
  excludeBinary?: boolean;
21
21
  contentBasedBinaryDetection?: boolean;
22
22
  maxFileSizeBytes?: number;
23
+ rootPaths?: string[];
23
24
  };
24
25
 
25
26
  @Injectable()
@@ -53,7 +54,12 @@ export class FsService {
53
54
  }
54
55
 
55
56
  const globIgnore = this.buildGlobIgnorePatterns(combinedIgnore);
56
- const entries = await glob(['**/*'], {
57
+
58
+ const patterns = options.rootPaths?.length
59
+ ? options.rootPaths.map((p) => `${p}/**`)
60
+ : ['**/*'];
61
+
62
+ const entries = await glob(patterns, {
57
63
  onlyFiles: true,
58
64
  absolute: true,
59
65
  dot: true,