@emaxe/oa 0.1.0 → 0.3.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/CHANGELOG.md +46 -0
- package/CHANGELOG.ru.md +46 -0
- package/LICENSE +21 -0
- package/README.md +178 -19
- package/README.ru.md +193 -0
- package/dist/__tests__/inferKind.test.js +27 -0
- package/dist/__tests__/inferKind.test.js.map +1 -0
- package/dist/__tests__/org-resolution.test.js +60 -0
- package/dist/__tests__/org-resolution.test.js.map +1 -0
- package/dist/__tests__/project-config.test.js +87 -0
- package/dist/__tests__/project-config.test.js.map +1 -0
- package/dist/__tests__/scopes.test.js +14 -0
- package/dist/__tests__/scopes.test.js.map +1 -0
- package/dist/client.js +6 -2
- package/dist/client.js.map +1 -1
- package/dist/commands/artifacts.js +15 -3
- package/dist/commands/artifacts.js.map +1 -1
- package/dist/commands/login.js +15 -5
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/orgs.js +52 -0
- package/dist/commands/orgs.js.map +1 -0
- package/dist/commands/share.js +8 -3
- package/dist/commands/share.js.map +1 -1
- package/dist/config.js +6 -3
- package/dist/config.js.map +1 -1
- package/dist/index.js +18 -4
- package/dist/index.js.map +1 -1
- package/dist/org.js +31 -0
- package/dist/org.js.map +1 -0
- package/dist/project-config.js +53 -0
- package/dist/project-config.js.map +1 -0
- package/package.json +20 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the `@emaxe/oa` package will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
**[English](CHANGELOG.md)** | **[Русский](CHANGELOG.ru.md)**
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## [0.3.0] - 2026-09-11
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **Personal API Keys**: `oa login` now issues a personal key by default — valid across every team you belong to (with your real role in each), instead of one agent key per team. Use `oa login --agent` for the old behavior: a key locked to one team, for CI and narrowly-scoped use cases.
|
|
16
|
+
- **`oa orgs`**: Lists the teams your key can act in, marking the one currently selected for this project.
|
|
17
|
+
- **`oa use <team>`**: Sets the default team for the current project, saved to a `.oa.json` file next to it (no secrets — safe to commit). Pass `--global` to set it for the whole machine instead.
|
|
18
|
+
- **`--org <team>` flag**: Added to `oa list` and `oa push` to override the resolved default team for a single invocation.
|
|
19
|
+
- **Project-scoped config resolution**: `.oa.json` is found by walking up from the current directory, the same way `.git`/`.eslintrc` are — so the right team is picked up automatically no matter which subdirectory a command runs from.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- Structured handling of the new `org_required` error: when a personal key belongs to more than one team and none is selected, the CLI prints the candidate list and points at `oa use`/`--org` instead of a raw error.
|
|
23
|
+
- Credentials file permissions (`600`) are now re-applied on every login, not just when the file is first created.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## [0.2.0] - 2026-09-11
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- **OAuth Device Flow**: Added `oa login` command enabling interactive device authentication with code verification and browser activation.
|
|
31
|
+
- **Verification Command**: Added `oa whoami` command to check current credentials, active server, organization, and token expiration.
|
|
32
|
+
- **Enhanced Share Options**: Added `--password` and `--expires` flags to `oa push` and `oa share` for secure, time-limited artifact sharing.
|
|
33
|
+
- **Automatic Format Detection**: Automatic inference of artifact kind (`html`, `markdown`, `mermaid`, `svg`) based on file extension.
|
|
34
|
+
- **Artifact Management**: Added `oa rm` and `oa unshare` commands.
|
|
35
|
+
- **Bilingual Documentation**: Added English and Russian READMEs and Changelogs.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
- **Package Name**: Renamed npm package to [`@emaxe/oa`](https://www.npmjs.com/package/@emaxe/oa).
|
|
39
|
+
- **Global Flag**: Ensured all commands support `--json` for scripting and agent pipeline compatibility.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## [0.1.0] - 2026-09-10
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
- Initial CLI release supporting artifact push, list, and get operations.
|
package/CHANGELOG.ru.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# История изменений (Changelog)
|
|
2
|
+
|
|
3
|
+
Все заметные изменения пакета `@emaxe/oa` документируются в этом файле.
|
|
4
|
+
|
|
5
|
+
Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.0.0/),
|
|
6
|
+
и проект придерживается [Семантического версионирования](https://semver.org/lang/ru/).
|
|
7
|
+
|
|
8
|
+
**[English](CHANGELOG.md)** | **[Русский](CHANGELOG.ru.md)**
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## [0.3.0] - 2026-09-11
|
|
13
|
+
|
|
14
|
+
### Добавлено
|
|
15
|
+
- **Личные API-ключи**: `oa login` теперь по умолчанию выпускает личный ключ — действующий во всех ваших командах (с вашей реальной ролью в каждой) вместо отдельного ключа агента на команду. Прежнее поведение (ключ, запертый в одной команде — для CI и узких прав) доступно через `oa login --agent`.
|
|
16
|
+
- **`oa orgs`**: Список команд, доступных ключу, с отметкой текущей выбранной для этого проекта.
|
|
17
|
+
- **`oa use <team>`**: Устанавливает команду по умолчанию для текущего проекта — сохраняется в файл `.oa.json` рядом с ним (без секретов, можно коммитить). Флаг `--global` задаёт значение для всего компьютера.
|
|
18
|
+
- **Флаг `--org <team>`**: Добавлен в `oa list` и `oa push` для разового переопределения выбранной команды.
|
|
19
|
+
- **Разрешение конфигурации по проекту**: `.oa.json` ищется подъёмом вверх по дереву каталогов от текущей директории — так же, как `.git`/`.eslintrc` — поэтому нужная команда подхватывается автоматически из любой вложенной папки.
|
|
20
|
+
|
|
21
|
+
### Изменено
|
|
22
|
+
- Структурированная обработка новой ошибки `org_required`: если у личного ключа несколько команд и ни одна не выбрана, CLI печатает список кандидатов и подсказывает `oa use`/`--org` вместо сырой ошибки.
|
|
23
|
+
- Права на файл с учётными данными (`600`) теперь применяются при каждом логине, а не только при первом создании файла.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## [0.2.0] - 2026-09-11
|
|
28
|
+
|
|
29
|
+
### Добавлено
|
|
30
|
+
- **OAuth Device Flow**: Добавлена команда `oa login` для интерактивной авторизации устройства через браузер с короткими кодами активации.
|
|
31
|
+
- **Команда проверки статуса**: Добавлена команда `oa whoami` для проверки действующих ключей, адреса сервера, организации и срока действия токена.
|
|
32
|
+
- **Расширенные опции шеринга**: Поддержка параметров `--password` и `--expires` в командах `oa push` и `oa share` для создания защищенных паролем и временных ссылок.
|
|
33
|
+
- **Автоопределение типа файла**: Автоматическое определение формата артефакта (`html`, `markdown`, `mermaid`, `svg`) по расширению файла.
|
|
34
|
+
- **Управление артефактами**: Добавлены команды удаления артефакта `oa rm` и отзыва ссылки `oa unshare`.
|
|
35
|
+
- **Двуязычная документация**: Добавлены русская и английская версии README и истории изменений.
|
|
36
|
+
|
|
37
|
+
### Изменено
|
|
38
|
+
- **Имя пакета**: Пакет переименован в [`@emaxe/oa`](https://www.npmjs.com/package/@emaxe/oa) в реестре npm.
|
|
39
|
+
- **Флаг JSON**: Все команды поддерживают флаг `--json` для интеграции в скрипты и пайплайны агентов.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## [0.1.0] - 2026-09-10
|
|
44
|
+
|
|
45
|
+
### Добавлено
|
|
46
|
+
- Начальный релиз CLI с поддержкой команд `push`, `list` и `get`.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 emaxe
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,34 +1,193 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @emaxe/oa
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
<p align="left">
|
|
4
|
+
<a href="https://www.npmjs.com/package/@emaxe/oa"><img src="https://img.shields.io/npm/v/@emaxe/oa.svg?color=blue&logo=npm" alt="npm version"></a>
|
|
5
|
+
<a href="https://www.npmjs.com/package/@emaxe/oa"><img src="https://img.shields.io/npm/dm/@emaxe/oa.svg?color=blue&logo=npm" alt="npm downloads"></a>
|
|
6
|
+
<a href="https://github.com/emaxe/open-artifacts"><img src="https://img.shields.io/badge/GitHub-emaxe%2Fopen--artifacts-blue?logo=github" alt="GitHub Repository"></a>
|
|
7
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
|
|
8
|
+
<a href="https://nodejs.org/"><img src="https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg?logo=node.js" alt="Node.js"></a>
|
|
9
|
+
<a href="https://skills.sh/emaxe/open-artifacts"><img src="https://skills.sh/b/emaxe/open-artifacts" alt="skills.sh"></a>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
**[English](README.md)** | **[Русский](README.ru.md)** | **[Changelog](CHANGELOG.md)** | **[История изменений](CHANGELOG.ru.md)**
|
|
13
|
+
|
|
14
|
+
Official CLI for [Open Artifacts](https://github.com/emaxe/open-artifacts) — a self-hosted, open-source alternative to Claude Artifacts. Publish HTML applications, Markdown documents, Mermaid diagrams, or vector SVG files from your terminal, scripts, or AI agent sessions and get back an interactive, shareable preview URL.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
### Topics & Tags
|
|
19
|
+
`ai-agents` • `artifacts` • `claude-artifacts` • `claude` • `mcp` • `model-context-protocol` • `self-hosted` • `cli` • `open-artifacts` • `developer-tools`
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
6
24
|
|
|
7
25
|
```bash
|
|
26
|
+
# Global installation (recommended):
|
|
8
27
|
npm install -g @emaxe/oa
|
|
28
|
+
|
|
29
|
+
# Or run directly without installing:
|
|
30
|
+
npx @emaxe/oa --help
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
### 1. Authenticate
|
|
38
|
+
|
|
39
|
+
Connect to your Open Artifacts server using the interactive OAuth Device Flow:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
oa login --server https://artifacts.your-company.com
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The CLI outputs a short code (e.g. `ABCD-1234`) and an activation link. Open the link in your browser and approve access. This issues a **personal key** by default — it's valid across every team you belong to, not locked to one. Credentials are saved locally to `~/.config/open-artifacts/credentials.json` (`600` permissions).
|
|
46
|
+
|
|
47
|
+
Verify your session at any time:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
oa whoami
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. Pick a team
|
|
54
|
+
|
|
55
|
+
If you belong to more than one team, tell the CLI which one to use for this project:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
oa orgs # list your teams, with a * next to the current default
|
|
59
|
+
oa use <team> # set the default for this project (writes a secret-free .oa.json you can commit)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
With exactly one team, this step is optional — it's used automatically. Override it for a single command with `--org <team>` on `oa list` / `oa push`, without changing the saved default.
|
|
63
|
+
|
|
64
|
+
### 3. Publish Content
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Publish an HTML file and get a public shareable URL:
|
|
68
|
+
oa push report.html --title "Quarterly Financials" --share
|
|
69
|
+
|
|
70
|
+
# Publish a Markdown summary:
|
|
71
|
+
oa push summary.md --title "Meeting Minutes" --share
|
|
72
|
+
|
|
73
|
+
# Render a Mermaid flowchart:
|
|
74
|
+
oa push architecture.mmd --title "Service Architecture" --share
|
|
75
|
+
|
|
76
|
+
# Upload an SVG vector graphic:
|
|
77
|
+
oa push diagram.svg --title "Database Schema" --share
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Command Reference
|
|
83
|
+
|
|
84
|
+
### `oa login`
|
|
85
|
+
Authorizes the CLI with an Open Artifacts server using the OAuth device flow.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
oa login [options]
|
|
89
|
+
--server <url> Open Artifacts server URL (default: "http://localhost:3000")
|
|
90
|
+
--name <name> Name to register this device/agent as
|
|
91
|
+
--scopes <scopes> Comma-separated list of scopes (default: "artifacts:read,artifacts:write,shares:write")
|
|
92
|
+
--agent Issue an agent key locked to one team, instead of a personal key spanning all your teams
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `oa whoami`
|
|
96
|
+
Displays current credentials, server endpoint, key type, effective team, and token expiration.
|
|
97
|
+
|
|
98
|
+
### `oa orgs`
|
|
99
|
+
Lists the teams your key can act in, marking the one currently selected for this project.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
oa orgs [--json]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### `oa use <team>`
|
|
106
|
+
Sets the default team (by id or slug) for the current project, or for the whole machine.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
oa use <team> [--global]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `oa push <file>`
|
|
113
|
+
Creates a new artifact or updates an existing one from a local file.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
oa push <file> [options]
|
|
117
|
+
--title <title> Artifact title (defaults to filename)
|
|
118
|
+
--kind <kind> Content type: html | markdown | mermaid | svg (auto-detected if omitted)
|
|
119
|
+
--id <id> Update an existing artifact instead of creating a new one
|
|
120
|
+
--share Automatically generate a public share link
|
|
121
|
+
--password <pass> Protect the share link with a password (implies --share)
|
|
122
|
+
--expires <ttl> Share expiration: 1h, 1d, 7d, 30d (implies --share)
|
|
123
|
+
--message <msg> Version commit message
|
|
124
|
+
--org <team> Team id or slug to publish into (overrides the project/machine default)
|
|
125
|
+
--json Output result as JSON
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### `oa list`
|
|
129
|
+
Lists all artifacts in your active team.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
oa list [--org <team>] [--json]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### `oa get <artifact-id>`
|
|
136
|
+
Retrieves artifact metadata or downloads raw content to a file.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
oa get <artifact-id> [-o output-file] [--json]
|
|
9
140
|
```
|
|
10
141
|
|
|
11
|
-
|
|
142
|
+
### `oa rm <artifact-id>`
|
|
143
|
+
Soft-deletes an artifact.
|
|
12
144
|
|
|
13
145
|
```bash
|
|
14
|
-
oa
|
|
15
|
-
oa push report.html --title "Q3 Report" --share # publish + print a share URL
|
|
16
|
-
oa list # see what you've published
|
|
17
|
-
oa get <artifact-id> -o report.html # fetch content back
|
|
18
|
-
oa share <artifact-id> --password "..." --expires 7d # a password-protected, expiring link
|
|
146
|
+
oa rm <artifact-id> [--json]
|
|
19
147
|
```
|
|
20
148
|
|
|
21
|
-
|
|
22
|
-
|
|
149
|
+
### `oa share <artifact-id>`
|
|
150
|
+
Generates a new shareable link for an existing artifact.
|
|
23
151
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
152
|
+
```bash
|
|
153
|
+
oa share <artifact-id> [options]
|
|
154
|
+
--password <pass> Password protect the link
|
|
155
|
+
--expires <ttl> Link expiration duration (e.g. 1h, 1d, 7d, 30d)
|
|
156
|
+
--json Output share metadata as JSON
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### `oa unshare <share-id>`
|
|
160
|
+
Revokes an active share link immediately.
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
oa unshare <share-id> [--json]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Non-Interactive & CI Environments
|
|
169
|
+
|
|
170
|
+
For CI/CD pipelines, headless scripts, or background agent environments, you can bypass the device flow by setting environment variables:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
export OA_SERVER="https://artifacts.your-company.com"
|
|
174
|
+
export OA_TOKEN="oa_live_xxxxxxxxxxxxxxxxxxxxxxxx"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
For CI, an agent key (`oa login --agent`, or generated in the web dashboard under **Team > Agents**) is usually the right choice — it's locked to one team, which keeps the blast radius of a leaked CI secret small. A personal key issued from **Settings > Личные API-ключи** also works via `OA_TOKEN`, but it spans every team you belong to.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## AI Agent Integration
|
|
182
|
+
|
|
183
|
+
This CLI is designed to be invoked by LLM coding agents (Claude Code, Cursor, Windsurf, Codex, Antigravity, OpenCode). You can install the pre-configured skill via [skills.sh](https://skills.sh/emaxe/open-artifacts):
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npx skills add emaxe/open-artifacts
|
|
187
|
+
```
|
|
27
188
|
|
|
28
|
-
|
|
29
|
-
[main repository](https://github.com/emaxe/open-artifacts) for how to self-host one via Docker
|
|
30
|
-
Compose.
|
|
189
|
+
---
|
|
31
190
|
|
|
32
191
|
## License
|
|
33
192
|
|
|
34
|
-
MIT
|
|
193
|
+
MIT © [emaxe](https://github.com/emaxe)
|
package/README.ru.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# @emaxe/oa
|
|
2
|
+
|
|
3
|
+
<p align="left">
|
|
4
|
+
<a href="https://www.npmjs.com/package/@emaxe/oa"><img src="https://img.shields.io/npm/v/@emaxe/oa.svg?color=blue&logo=npm" alt="npm version"></a>
|
|
5
|
+
<a href="https://www.npmjs.com/package/@emaxe/oa"><img src="https://img.shields.io/npm/dm/@emaxe/oa.svg?color=blue&logo=npm" alt="npm downloads"></a>
|
|
6
|
+
<a href="https://github.com/emaxe/open-artifacts"><img src="https://img.shields.io/badge/GitHub-emaxe%2Fopen--artifacts-blue?logo=github" alt="GitHub Repository"></a>
|
|
7
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
|
|
8
|
+
<a href="https://nodejs.org/"><img src="https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg?logo=node.js" alt="Node.js"></a>
|
|
9
|
+
<a href="https://skills.sh/emaxe/open-artifacts"><img src="https://skills.sh/b/emaxe/open-artifacts" alt="skills.sh"></a>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
**[English](README.md)** | **[Русский](README.ru.md)** | **[Changelog](CHANGELOG.md)** | **[История изменений](CHANGELOG.ru.md)**
|
|
13
|
+
|
|
14
|
+
Официальная консольная утилита (CLI) для [Open Artifacts](https://github.com/emaxe/open-artifacts) — открытой альтернативы Claude Artifacts. Позволяет публиковать веб-приложения на HTML, документы Markdown, диаграммы Mermaid или векторную графику SVG из терминала, скриптов или диалогов с AI-агентами, получая в ответ интерактивную публичную ссылку.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
### Топики и теги
|
|
19
|
+
`ai-agents` • `artifacts` • `claude-artifacts` • `claude` • `mcp` • `model-context-protocol` • `self-hosted` • `cli` • `open-artifacts` • `developer-tools`
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Установка
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Глобальная установка (рекомендуется):
|
|
27
|
+
npm install -g @emaxe/oa
|
|
28
|
+
|
|
29
|
+
# Или запуск без установки:
|
|
30
|
+
npx @emaxe/oa --help
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Быстрый старт
|
|
36
|
+
|
|
37
|
+
### 1. Авторизация
|
|
38
|
+
|
|
39
|
+
Подключитесь к вашему серверу Open Artifacts через удобный интерактивный OAuth Device Flow:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
oa login --server https://artifacts.your-company.com
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Утилита сгенерирует короткий код подтверждения (например, `ABCD-1234`) и ссылку на страницу активации. Перейдите по ссылке и разрешите доступ. По умолчанию выпускается **личный ключ** — он действует во всех ваших командах, а не запертый в одной. Токен сохранится локально в `~/.config/open-artifacts/credentials.json` с правами `600`.
|
|
46
|
+
|
|
47
|
+
Проверить статус сессии в любой момент:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
oa whoami
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. Выбор команды
|
|
54
|
+
|
|
55
|
+
Если вы состоите в нескольких командах, укажите CLI, какую использовать для этого проекта:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
oa orgs # список ваших команд с отметкой * у текущей по умолчанию
|
|
59
|
+
oa use <team> # задать команду по умолчанию для проекта (пишет .oa.json без секретов, можно коммитить)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Если команда одна — этот шаг не нужен, она подставится автоматически. Переопределить для одного вызова можно флагом `--org <team>` у `oa list`/`oa push`, не меняя сохранённое значение по умолчанию.
|
|
63
|
+
|
|
64
|
+
### 3. Публикация файлов
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Опубликовать HTML-страницу и получить публичную ссылку:
|
|
68
|
+
oa push report.html --title "Финансовый отчет" --share
|
|
69
|
+
|
|
70
|
+
# Опубликовать документ Markdown:
|
|
71
|
+
oa push summary.md --title "Протокол встречи" --share
|
|
72
|
+
|
|
73
|
+
# Отрендерить диаграмму Mermaid:
|
|
74
|
+
oa push architecture.mmd --title "Архитектура сервиса" --share
|
|
75
|
+
|
|
76
|
+
# Загрузить векторный файл SVG:
|
|
77
|
+
oa push diagram.svg --title "Схема базы данных" --share
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Справочник команд
|
|
83
|
+
|
|
84
|
+
### `oa login`
|
|
85
|
+
Авторизация CLI на сервере Open Artifacts по протоколу OAuth Device Flow.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
oa login [options]
|
|
89
|
+
--server <url> URL сервера Open Artifacts (по умолчанию: "http://localhost:3000")
|
|
90
|
+
--name <name> Имя регистрируемого устройства/агента
|
|
91
|
+
--scopes <scopes> Список запрашиваемых прав через запятую (по умолчанию: "artifacts:read,artifacts:write,shares:write")
|
|
92
|
+
--agent Выпустить ключ агента, запертый в одной команде, вместо личного ключа на все ваши команды
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `oa whoami`
|
|
96
|
+
Показывает текущие учётные данные, адрес сервера, тип ключа, выбранную команду и статус токена.
|
|
97
|
+
|
|
98
|
+
### `oa orgs`
|
|
99
|
+
Список команд, доступных ключу, с отметкой текущей выбранной для этого проекта.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
oa orgs [--json]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### `oa use <team>`
|
|
106
|
+
Задаёт команду по умолчанию (по id или slug) для текущего проекта или для всего компьютера.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
oa use <team> [--global]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `oa push <file>`
|
|
113
|
+
Создает новый артефакт или обновляет существующий из локального файла.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
oa push <file> [options]
|
|
117
|
+
--title <title> Название артефакта (по умолчанию: имя файла)
|
|
118
|
+
--kind <kind> Тип контента: html | markdown | mermaid | svg (определяется автоматически)
|
|
119
|
+
--id <id> ID существующего артефакта для создания новой версии
|
|
120
|
+
--share Сразу сгенерировать публичную ссылку
|
|
121
|
+
--password <pass> Защитить ссылку паролем (включает --share)
|
|
122
|
+
--expires <ttl> Срок действия ссылки: 1h, 1d, 7d, 30d (включает --share)
|
|
123
|
+
--message <msg> Сообщение версии
|
|
124
|
+
--org <team> Команда для публикации (переопределяет значение по умолчанию проекта/машины)
|
|
125
|
+
--json Вывод результата в формате JSON
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### `oa list`
|
|
129
|
+
Выводит список всех артефактов в текущей команде.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
oa list [--org <team>] [--json]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### `oa get <artifact-id>`
|
|
136
|
+
Показывает информацию об артефакте или скачивает его содержимое в файл.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
oa get <artifact-id> [-o output-file] [--json]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### `oa rm <artifact-id>`
|
|
143
|
+
Удаляет артефакт в архив.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
oa rm <artifact-id> [--json]
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### `oa share <artifact-id>`
|
|
150
|
+
Создает ссылку для совместного доступа к артефакту.
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
oa share <artifact-id> [options]
|
|
154
|
+
--password <pass> Защитить ссылку паролем
|
|
155
|
+
--expires <ttl> Срок действия ссылки (например: 1h, 1d, 7d, 30d)
|
|
156
|
+
--json Вывод информации о ссылке в формате JSON
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### `oa unshare <share-id>`
|
|
160
|
+
Мгновенно отзывает выданную ссылку.
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
oa unshare <share-id> [--json]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Использование в CI/CD и неинтерактивных средах
|
|
169
|
+
|
|
170
|
+
Для автоматических пайплайнов или фоновых скриптов можно передать параметры через переменные окружения, минуя Device Flow:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
export OA_SERVER="https://artifacts.your-company.com"
|
|
174
|
+
export OA_TOKEN="oa_live_xxxxxxxxxxxxxxxxxxxxxxxx"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Для CI обычно правильный выбор — ключ агента (`oa login --agent`, либо выпущенный в панели управления в разделе **Команда > Агенты**): он заперт в одной команде, что ограничивает ущерб от утечки CI-секрета. Личный ключ из **Настройки > Личные API-ключи** тоже подходит для `OA_TOKEN`, но действует во всех ваших командах.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Интеграция с AI-агентами
|
|
182
|
+
|
|
183
|
+
Утилита оптимизирована для взаимодействия с современными AI-агентами (Claude Code, Cursor, Windsurf, Codex, Antigravity, OpenCode). Установите готовый скилл через [skills.sh](https://skills.sh/emaxe/open-artifacts):
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npx skills add emaxe/open-artifacts
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Лицензия
|
|
192
|
+
|
|
193
|
+
MIT © [emaxe](https://github.com/emaxe)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { inferKind } from "../commands/artifacts.js";
|
|
3
|
+
describe("inferKind", () => {
|
|
4
|
+
it("recognizes markdown extensions", () => {
|
|
5
|
+
expect(inferKind("report.md")).toBe("markdown");
|
|
6
|
+
expect(inferKind("report.markdown")).toBe("markdown");
|
|
7
|
+
});
|
|
8
|
+
it("recognizes svg", () => {
|
|
9
|
+
expect(inferKind("logo.svg")).toBe("svg");
|
|
10
|
+
});
|
|
11
|
+
it("recognizes mermaid extensions", () => {
|
|
12
|
+
expect(inferKind("diagram.mmd")).toBe("mermaid");
|
|
13
|
+
expect(inferKind("diagram.mermaid")).toBe("mermaid");
|
|
14
|
+
});
|
|
15
|
+
it("defaults to html for .html and unrecognized extensions", () => {
|
|
16
|
+
expect(inferKind("page.html")).toBe("html");
|
|
17
|
+
expect(inferKind("notes.txt")).toBe("html");
|
|
18
|
+
expect(inferKind("no-extension")).toBe("html");
|
|
19
|
+
});
|
|
20
|
+
it("is case-insensitive", () => {
|
|
21
|
+
expect(inferKind("REPORT.MD")).toBe("markdown");
|
|
22
|
+
});
|
|
23
|
+
it("only looks at the extension, ignoring directories in the path", () => {
|
|
24
|
+
expect(inferKind("/tmp/my.markdown.folder/report.svg")).toBe("svg");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=inferKind.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inferKind.test.js","sourceRoot":"","sources":["../../src/__tests__/inferKind.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAChD,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gBAAgB,EAAE,GAAG,EAAE;QACxB,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,CAAC,SAAS,CAAC,oCAAoC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
5
|
+
import { resolveOrg } from "../org.js";
|
|
6
|
+
let dir;
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
if (dir)
|
|
9
|
+
rmSync(dir, { recursive: true, force: true });
|
|
10
|
+
dir = undefined;
|
|
11
|
+
});
|
|
12
|
+
function makeTmpDir() {
|
|
13
|
+
dir = mkdtempSync(join(tmpdir(), "oa-org-resolution-"));
|
|
14
|
+
return dir;
|
|
15
|
+
}
|
|
16
|
+
const userCreds = { server: "https://oa.example.com", token: "oa_live_x", expiresAt: null, kind: "user", userId: "u1" };
|
|
17
|
+
const legacyAgentCreds = { server: "https://oa.example.com", token: "oa_live_x", expiresAt: null, agentId: "a1", orgId: "org-legacy" };
|
|
18
|
+
describe("resolveOrg priority", () => {
|
|
19
|
+
it("--org flag wins over everything else", () => {
|
|
20
|
+
const root = makeTmpDir();
|
|
21
|
+
writeFileSync(join(root, ".oa.json"), JSON.stringify({ orgId: "org-project" }));
|
|
22
|
+
const res = resolveOrg({ flag: "org-flag", cwd: root, env: { OA_ORG: "org-env" }, creds: userCreds });
|
|
23
|
+
expect(res).toEqual({ orgId: "org-flag", source: "flag" });
|
|
24
|
+
});
|
|
25
|
+
it("OA_ORG env wins over the project config", () => {
|
|
26
|
+
const root = makeTmpDir();
|
|
27
|
+
writeFileSync(join(root, ".oa.json"), JSON.stringify({ orgId: "org-project" }));
|
|
28
|
+
const res = resolveOrg({ cwd: root, env: { OA_ORG: "org-env" }, creds: userCreds });
|
|
29
|
+
expect(res).toEqual({ orgId: "org-env", source: "env" });
|
|
30
|
+
});
|
|
31
|
+
it("falls back to the project's .oa.json when no flag or env is given", () => {
|
|
32
|
+
const root = makeTmpDir();
|
|
33
|
+
writeFileSync(join(root, ".oa.json"), JSON.stringify({ orgId: "org-project", server: "https://oa.example.com" }));
|
|
34
|
+
const res = resolveOrg({ cwd: root, env: {}, creds: userCreds });
|
|
35
|
+
expect(res).toEqual({ orgId: "org-project", source: "project", configPath: join(root, ".oa.json") });
|
|
36
|
+
});
|
|
37
|
+
it("ignores a project config written for a different server", () => {
|
|
38
|
+
const root = makeTmpDir();
|
|
39
|
+
writeFileSync(join(root, ".oa.json"), JSON.stringify({ orgId: "org-project", server: "https://other.example.com" }));
|
|
40
|
+
const res = resolveOrg({ cwd: root, env: {}, creds: userCreds });
|
|
41
|
+
expect(res).toEqual({ source: "none" });
|
|
42
|
+
});
|
|
43
|
+
it("falls back to a legacy agent credentials file's locked org when nothing else resolves", () => {
|
|
44
|
+
const root = makeTmpDir();
|
|
45
|
+
const res = resolveOrg({ cwd: root, env: {}, creds: legacyAgentCreds });
|
|
46
|
+
expect(res).toEqual({ orgId: "org-legacy", source: "credentials" });
|
|
47
|
+
});
|
|
48
|
+
it("never falls back to credentials.orgId for a personal (kind: user) key", () => {
|
|
49
|
+
const root = makeTmpDir();
|
|
50
|
+
const personalWithOrg = { ...userCreds, orgId: "should-not-be-used" };
|
|
51
|
+
const res = resolveOrg({ cwd: root, env: {}, creds: personalWithOrg });
|
|
52
|
+
expect(res).toEqual({ source: "none" });
|
|
53
|
+
});
|
|
54
|
+
it("resolves to 'none' with no flag, env, project config, or usable credentials fallback", () => {
|
|
55
|
+
const root = makeTmpDir();
|
|
56
|
+
const res = resolveOrg({ cwd: root, env: {}, creds: userCreds });
|
|
57
|
+
expect(res).toEqual({ source: "none" });
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
//# sourceMappingURL=org-resolution.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-resolution.test.js","sourceRoot":"","sources":["../../src/__tests__/org-resolution.test.ts"],"names":[],"mappings":"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"}
|