cubelife 0.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/LICENSE +21 -0
- package/README.md +81 -0
- package/SPRITE-LICENSE +14 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +39 -0
- package/dist/commands/agents.d.ts +2 -0
- package/dist/commands/agents.js +303 -0
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.js +233 -0
- package/dist/commands/billing.d.ts +2 -0
- package/dist/commands/billing.js +362 -0
- package/dist/commands/creature.d.ts +2 -0
- package/dist/commands/creature.js +166 -0
- package/dist/commands/default.d.ts +2 -0
- package/dist/commands/default.js +87 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +48 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +200 -0
- package/dist/commands/mcp.d.ts +2 -0
- package/dist/commands/mcp.js +9 -0
- package/dist/commands/projects.d.ts +2 -0
- package/dist/commands/projects.js +122 -0
- package/dist/commands/setup.d.ts +2 -0
- package/dist/commands/setup.js +453 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +89 -0
- package/dist/commands/tutorial.d.ts +2 -0
- package/dist/commands/tutorial.js +9 -0
- package/dist/commands/view.d.ts +2 -0
- package/dist/commands/view.js +262 -0
- package/dist/data/sprite-data.d.ts +32 -0
- package/dist/data/sprite-data.js +865 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +6 -0
- package/dist/lib/api.d.ts +162 -0
- package/dist/lib/api.js +160 -0
- package/dist/lib/auth.d.ts +12 -0
- package/dist/lib/auth.js +113 -0
- package/dist/lib/browser.d.ts +1 -0
- package/dist/lib/browser.js +21 -0
- package/dist/lib/command-helpers.d.ts +26 -0
- package/dist/lib/command-helpers.js +60 -0
- package/dist/lib/compositor.d.ts +34 -0
- package/dist/lib/compositor.js +232 -0
- package/dist/lib/config.d.ts +39 -0
- package/dist/lib/config.js +89 -0
- package/dist/lib/constants.d.ts +12 -0
- package/dist/lib/constants.js +39 -0
- package/dist/lib/detect.d.ts +17 -0
- package/dist/lib/detect.js +99 -0
- package/dist/lib/doctor.d.ts +18 -0
- package/dist/lib/doctor.js +321 -0
- package/dist/lib/index.d.ts +11 -0
- package/dist/lib/index.js +6 -0
- package/dist/lib/integration.d.ts +66 -0
- package/dist/lib/integration.js +337 -0
- package/dist/lib/poll.d.ts +11 -0
- package/dist/lib/poll.js +31 -0
- package/dist/lib/resolve.d.ts +1 -0
- package/dist/lib/resolve.js +10 -0
- package/dist/lib/services/account-service.d.ts +17 -0
- package/dist/lib/services/account-service.js +30 -0
- package/dist/lib/services/agent-service.d.ts +17 -0
- package/dist/lib/services/agent-service.js +62 -0
- package/dist/lib/services/creature-service.d.ts +12 -0
- package/dist/lib/services/creature-service.js +35 -0
- package/dist/lib/services/project-service.d.ts +9 -0
- package/dist/lib/services/project-service.js +22 -0
- package/dist/lib/tutorial.d.ts +12 -0
- package/dist/lib/tutorial.js +358 -0
- package/dist/mcp/server.d.ts +8 -0
- package/dist/mcp/server.js +116 -0
- package/dist/ui/banner.d.ts +3 -0
- package/dist/ui/banner.js +27 -0
- package/dist/ui/half-block.d.ts +6 -0
- package/dist/ui/half-block.js +45 -0
- package/dist/ui/helpers.d.ts +3 -0
- package/dist/ui/helpers.js +11 -0
- package/dist/ui/index.d.ts +5 -0
- package/dist/ui/index.js +5 -0
- package/dist/ui/panel.d.ts +7 -0
- package/dist/ui/panel.js +21 -0
- package/dist/ui/preview.d.ts +7 -0
- package/dist/ui/preview.js +21 -0
- package/dist/ui/table.d.ts +8 -0
- package/dist/ui/table.js +20 -0
- package/dist/ui/theme.d.ts +24 -0
- package/dist/ui/theme.js +32 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ivy Innovation
|
|
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
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# cubelife
|
|
2
|
+
|
|
3
|
+
CLI for CubeLife. Give your AI agent a living pixel-art companion.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g cubelife
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or run directly:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx cubelife
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cubelife register # Create an account
|
|
21
|
+
cubelife tutorial # Guided setup (6 steps)
|
|
22
|
+
cubelife status coding "Working on auth" # Report agent state
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Commands
|
|
26
|
+
|
|
27
|
+
| Command | Description |
|
|
28
|
+
|---------|-------------|
|
|
29
|
+
| `register` | Create a new CubeLife account |
|
|
30
|
+
| `login` | Log in to your account |
|
|
31
|
+
| `logout` | Log out and clear credentials |
|
|
32
|
+
| `whoami` | Show account, tier, and linked agent |
|
|
33
|
+
| `projects` | Manage CubeLife projects |
|
|
34
|
+
| `agents` | Manage agents within a project |
|
|
35
|
+
| `creature` | Manage creature companions |
|
|
36
|
+
| `init` | Link a project and agent to the current directory |
|
|
37
|
+
| `setup <tool>` | Configure integration for an AI tool |
|
|
38
|
+
| `tutorial` | Interactive setup walkthrough |
|
|
39
|
+
| `doctor` | Run diagnostic checks |
|
|
40
|
+
| `status [state] [detail]` | Report agent state |
|
|
41
|
+
| `mcp` | Start the MCP server (stdio transport) |
|
|
42
|
+
|
|
43
|
+
## MCP server
|
|
44
|
+
|
|
45
|
+
The CLI includes an MCP server for AI tool integration:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
cubelife mcp # Start server (stdio)
|
|
49
|
+
cubelife setup claude-code # Auto-configure Claude Code
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The MCP server exposes four tools: `cubelife_report`, `cubelife_complete`, `cubelife_error`, and `cubelife_status`.
|
|
53
|
+
|
|
54
|
+
## Global flags
|
|
55
|
+
|
|
56
|
+
- `--json` Output as machine-readable JSON
|
|
57
|
+
- `--yes` Skip confirmation prompts
|
|
58
|
+
- `--agent <id>` Override the default linked agent
|
|
59
|
+
|
|
60
|
+
## Node SDK
|
|
61
|
+
|
|
62
|
+
For programmatic access, use the SDK:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm install @cubelife/sdk
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { CubeLifeClient } from '@cubelife/sdk';
|
|
70
|
+
|
|
71
|
+
const client = new CubeLifeClient({ apiKey: 'your-agent-key' });
|
|
72
|
+
await client.report('coding', { detail: 'Building the auth flow' });
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Requirements
|
|
76
|
+
|
|
77
|
+
- Node.js 18+
|
|
78
|
+
|
|
79
|
+
## Licence
|
|
80
|
+
|
|
81
|
+
MIT (source code). Pixel art sprite assets are proprietary (see SPRITE-LICENSE).
|
package/SPRITE-LICENSE
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Sprite Asset Licence
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ivy Innovation. All rights reserved.
|
|
4
|
+
|
|
5
|
+
The pixel art sprite data contained in dist/data/sprite-data.js was generated
|
|
6
|
+
using PixelLab (https://pixellab.ai) and is the property of Ivy Innovation.
|
|
7
|
+
|
|
8
|
+
These sprite assets are provided as part of the CubeLife CLI for the sole
|
|
9
|
+
purpose of rendering CubeLife agent characters in the terminal. They may not
|
|
10
|
+
be extracted, modified, redistributed, or used independently of the CubeLife
|
|
11
|
+
CLI without prior written permission from Ivy Innovation.
|
|
12
|
+
|
|
13
|
+
This licence applies only to the sprite data. The CubeLife CLI source code
|
|
14
|
+
is licensed separately under the MIT License (see LICENSE file).
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { logo, version as versionTag } from './ui/index.js';
|
|
4
|
+
import { CLI_VERSION } from './version.js';
|
|
5
|
+
import { registerAuthCommands } from './commands/auth.js';
|
|
6
|
+
import { registerProjectCommands } from './commands/projects.js';
|
|
7
|
+
import { registerAgentCommands } from './commands/agents.js';
|
|
8
|
+
import { registerCreatureCommands } from './commands/creature.js';
|
|
9
|
+
import { registerInitCommand } from './commands/init.js';
|
|
10
|
+
import { registerSetupCommands } from './commands/setup.js';
|
|
11
|
+
import { registerTutorialCommand } from './commands/tutorial.js';
|
|
12
|
+
import { registerDoctorCommand } from './commands/doctor.js';
|
|
13
|
+
import { registerStatusCommand } from './commands/status.js';
|
|
14
|
+
import { registerMcpCommand } from './commands/mcp.js';
|
|
15
|
+
import { registerBillingCommands } from './commands/billing.js';
|
|
16
|
+
import { registerViewCommand } from './commands/view.js';
|
|
17
|
+
import { defaultAction } from './commands/default.js';
|
|
18
|
+
const program = new Command()
|
|
19
|
+
.name('cubelife')
|
|
20
|
+
.description('Give your AI agent a living pixel-art companion')
|
|
21
|
+
.version(CLI_VERSION, '-v, --version')
|
|
22
|
+
.option('--json', 'Output as machine-readable JSON')
|
|
23
|
+
.option('--yes', 'Skip confirmation prompts')
|
|
24
|
+
.option('--agent <id>', 'Override the default linked agent')
|
|
25
|
+
.addHelpText('beforeAll', `\n${logo()}\n${versionTag(CLI_VERSION)}\n`)
|
|
26
|
+
.action(() => defaultAction(program));
|
|
27
|
+
registerAuthCommands(program);
|
|
28
|
+
registerProjectCommands(program);
|
|
29
|
+
registerAgentCommands(program);
|
|
30
|
+
registerCreatureCommands(program);
|
|
31
|
+
registerInitCommand(program);
|
|
32
|
+
registerSetupCommands(program);
|
|
33
|
+
registerTutorialCommand(program);
|
|
34
|
+
registerDoctorCommand(program);
|
|
35
|
+
registerStatusCommand(program);
|
|
36
|
+
registerMcpCommand(program);
|
|
37
|
+
registerBillingCommands(program);
|
|
38
|
+
registerViewCommand(program);
|
|
39
|
+
program.parse();
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import { createAdminClient, ApiError } from '../lib/api.js';
|
|
3
|
+
import { readAgents } from '../lib/config.js';
|
|
4
|
+
import { brand, dot } from '../ui/theme.js';
|
|
5
|
+
import { table } from '../ui/table.js';
|
|
6
|
+
import { panel } from '../ui/panel.js';
|
|
7
|
+
import { CREATURE_TYPES, ID_DISPLAY_LENGTH } from '../lib/constants.js';
|
|
8
|
+
import { isCancel } from '../ui/helpers.js';
|
|
9
|
+
import { rootOpts, requireProject, handleCommandError, } from '../lib/command-helpers.js';
|
|
10
|
+
import * as agentService from '../lib/services/agent-service.js';
|
|
11
|
+
function maskKey(key) {
|
|
12
|
+
if (key.length <= 12)
|
|
13
|
+
return key;
|
|
14
|
+
return `${key.slice(0, ID_DISPLAY_LENGTH)}${'*'.repeat(ID_DISPLAY_LENGTH)}${key.slice(-4)}`;
|
|
15
|
+
}
|
|
16
|
+
function formatForm(agent) {
|
|
17
|
+
if (agent.form === 'creature' && agent.creature?.type) {
|
|
18
|
+
return `creature:${agent.creature.type}`;
|
|
19
|
+
}
|
|
20
|
+
return agent.form;
|
|
21
|
+
}
|
|
22
|
+
export function registerAgentCommands(program) {
|
|
23
|
+
const agents = program
|
|
24
|
+
.command('agents')
|
|
25
|
+
.description('Manage agents within a project')
|
|
26
|
+
.option('--project <id>', 'Override the project to operate on');
|
|
27
|
+
agents
|
|
28
|
+
.command('list')
|
|
29
|
+
.description('List agents in the current project')
|
|
30
|
+
.action(async function () {
|
|
31
|
+
const { json } = rootOpts(this);
|
|
32
|
+
const { projectId } = await requireProject(this, json);
|
|
33
|
+
const spin = p.spinner();
|
|
34
|
+
if (!json)
|
|
35
|
+
spin.start('Fetching agents');
|
|
36
|
+
try {
|
|
37
|
+
const client = await createAdminClient();
|
|
38
|
+
const { agents: items, linkedAgentId } = await agentService.listAgents(client, projectId);
|
|
39
|
+
if (json) {
|
|
40
|
+
console.log(JSON.stringify({ agents: items }));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
spin.stop('Agents loaded');
|
|
44
|
+
if (items.length === 0) {
|
|
45
|
+
p.log.info(`No agents yet. Create one with ${brand.accent('cubelife agents create <name>')}`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const rows = items.map((a) => ({
|
|
49
|
+
linked: a.id === linkedAgentId ? dot.working : ' ',
|
|
50
|
+
name: a.name,
|
|
51
|
+
id: a.id.slice(0, ID_DISPLAY_LENGTH),
|
|
52
|
+
form: formatForm(a),
|
|
53
|
+
visibility: a.isPublic ? 'public' : 'private',
|
|
54
|
+
created: new Date(a.createdAt).toLocaleDateString(),
|
|
55
|
+
}));
|
|
56
|
+
console.log(table([
|
|
57
|
+
{ label: '', key: 'linked', width: 2 },
|
|
58
|
+
{ label: 'Name', key: 'name' },
|
|
59
|
+
{ label: 'ID', key: 'id', width: 10 },
|
|
60
|
+
{ label: 'Form', key: 'form', width: 16 },
|
|
61
|
+
{ label: 'Visibility', key: 'visibility', width: 10 },
|
|
62
|
+
{ label: 'Created', key: 'created', width: 12 },
|
|
63
|
+
], rows));
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
handleCommandError({ error: err, json, spinner: spin });
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
agents
|
|
70
|
+
.command('create <name>')
|
|
71
|
+
.description('Create a new agent')
|
|
72
|
+
.action(async function (name) {
|
|
73
|
+
const { json, yes } = rootOpts(this);
|
|
74
|
+
const { projectId } = await requireProject(this, json);
|
|
75
|
+
let form = 'human';
|
|
76
|
+
let creatureType;
|
|
77
|
+
if (!json) {
|
|
78
|
+
p.intro(brand.primary('Create a new agent'));
|
|
79
|
+
const formResult = await p.select({
|
|
80
|
+
message: 'Character form',
|
|
81
|
+
options: [
|
|
82
|
+
{ value: 'human', label: 'Human character' },
|
|
83
|
+
{ value: 'creature', label: 'Creature companion' },
|
|
84
|
+
],
|
|
85
|
+
});
|
|
86
|
+
if (isCancel(formResult)) {
|
|
87
|
+
p.cancel('Cancelled.');
|
|
88
|
+
process.exit(0);
|
|
89
|
+
}
|
|
90
|
+
form = formResult;
|
|
91
|
+
if (form === 'creature') {
|
|
92
|
+
const typeResult = await p.select({
|
|
93
|
+
message: 'Creature type',
|
|
94
|
+
options: CREATURE_TYPES.map((t) => ({ value: t, label: t })),
|
|
95
|
+
});
|
|
96
|
+
if (isCancel(typeResult)) {
|
|
97
|
+
p.cancel('Cancelled.');
|
|
98
|
+
process.exit(0);
|
|
99
|
+
}
|
|
100
|
+
creatureType = typeResult;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const spin = p.spinner();
|
|
104
|
+
if (!json)
|
|
105
|
+
spin.start('Creating agent');
|
|
106
|
+
try {
|
|
107
|
+
const client = await createAdminClient();
|
|
108
|
+
const body = {
|
|
109
|
+
name,
|
|
110
|
+
form,
|
|
111
|
+
...(creatureType ? { creature: { type: creatureType } } : {}),
|
|
112
|
+
};
|
|
113
|
+
const result = await agentService.createAgent(client, projectId, body);
|
|
114
|
+
if (json) {
|
|
115
|
+
console.log(JSON.stringify(result));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
spin.stop('Agent created');
|
|
119
|
+
console.log(panel([
|
|
120
|
+
`${brand.label('Name'.padEnd(10))}${brand.primary(result.name)}`,
|
|
121
|
+
`${brand.label('ID'.padEnd(10))}${result.id}`,
|
|
122
|
+
`${brand.label('API Key'.padEnd(10))}${maskKey(result.apiKey)}`,
|
|
123
|
+
], { title: 'New Agent', width: 56 }));
|
|
124
|
+
if (!yes) {
|
|
125
|
+
const link = await p.confirm({
|
|
126
|
+
message: 'Link this agent to the current directory?',
|
|
127
|
+
});
|
|
128
|
+
if (!isCancel(link) && link) {
|
|
129
|
+
await agentService.linkAgent(projectId, result.id);
|
|
130
|
+
p.log.info('Linked. Run ' + brand.accent(`cubelife status coding "test"`) + ' to try it.');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
handleCommandError({ error: err, json, spinner: spin });
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
agents
|
|
139
|
+
.command('edit <id>')
|
|
140
|
+
.description('Edit an agent')
|
|
141
|
+
.action(async function (agentId) {
|
|
142
|
+
const { projectId } = await requireProject(this);
|
|
143
|
+
const spin = p.spinner();
|
|
144
|
+
spin.start('Fetching agent');
|
|
145
|
+
try {
|
|
146
|
+
const client = await createAdminClient();
|
|
147
|
+
const agent = await agentService.getAgent(client, projectId, agentId);
|
|
148
|
+
spin.stop('Agent loaded');
|
|
149
|
+
console.log(panel([
|
|
150
|
+
`${brand.label('Name'.padEnd(12))}${agent.name}`,
|
|
151
|
+
`${brand.label('Form'.padEnd(12))}${agent.form}`,
|
|
152
|
+
`${brand.label('Visibility'.padEnd(12))}${agent.isPublic ? 'public' : 'private'}`,
|
|
153
|
+
], { title: 'Current Settings', width: 50 }));
|
|
154
|
+
const fields = await p.multiselect({
|
|
155
|
+
message: 'Select fields to edit',
|
|
156
|
+
options: [
|
|
157
|
+
{ value: 'name', label: 'Name' },
|
|
158
|
+
{ value: 'isPublic', label: 'Visibility' },
|
|
159
|
+
],
|
|
160
|
+
required: false,
|
|
161
|
+
});
|
|
162
|
+
if (isCancel(fields) || fields.length === 0) {
|
|
163
|
+
p.cancel('No changes.');
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const updates = {};
|
|
167
|
+
const selected = fields;
|
|
168
|
+
if (selected.includes('name')) {
|
|
169
|
+
const newName = await p.text({
|
|
170
|
+
message: 'New name',
|
|
171
|
+
initialValue: agent.name,
|
|
172
|
+
validate: (v) => { if (!v.trim())
|
|
173
|
+
return 'Name cannot be empty.'; },
|
|
174
|
+
});
|
|
175
|
+
if (isCancel(newName)) {
|
|
176
|
+
p.cancel('Cancelled.');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
updates.name = newName;
|
|
180
|
+
}
|
|
181
|
+
if (selected.includes('isPublic')) {
|
|
182
|
+
const pub = await p.confirm({
|
|
183
|
+
message: 'Make agent public?',
|
|
184
|
+
initialValue: agent.isPublic,
|
|
185
|
+
});
|
|
186
|
+
if (isCancel(pub)) {
|
|
187
|
+
p.cancel('Cancelled.');
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
updates.isPublic = pub;
|
|
191
|
+
}
|
|
192
|
+
const updateSpin = p.spinner();
|
|
193
|
+
updateSpin.start('Updating agent');
|
|
194
|
+
await agentService.updateAgent(client, projectId, agentId, updates);
|
|
195
|
+
updateSpin.stop('Agent updated');
|
|
196
|
+
p.log.success('Changes saved.');
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
handleCommandError({ error: err });
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
agents
|
|
203
|
+
.command('delete <id>')
|
|
204
|
+
.description('Delete an agent')
|
|
205
|
+
.action(async function (agentId) {
|
|
206
|
+
const { json, yes } = rootOpts(this);
|
|
207
|
+
const { projectId } = await requireProject(this, json);
|
|
208
|
+
try {
|
|
209
|
+
if (!yes && !json) {
|
|
210
|
+
const confirmed = await p.confirm({
|
|
211
|
+
message: `Delete agent ${brand.primary(agentId.slice(0, ID_DISPLAY_LENGTH))}? This cannot be undone.`,
|
|
212
|
+
});
|
|
213
|
+
if (isCancel(confirmed) || !confirmed) {
|
|
214
|
+
p.cancel('Cancelled.');
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const spin = p.spinner();
|
|
219
|
+
if (!json)
|
|
220
|
+
spin.start('Deleting agent');
|
|
221
|
+
const client = await createAdminClient();
|
|
222
|
+
const { wasLinked } = await agentService.deleteAgent(client, projectId, agentId);
|
|
223
|
+
if (json) {
|
|
224
|
+
console.log(JSON.stringify({ deleted: true, id: agentId }));
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
spin.stop('Agent deleted');
|
|
228
|
+
if (wasLinked)
|
|
229
|
+
p.log.info('Unlinked from current directory.');
|
|
230
|
+
p.log.success('Agent deleted.');
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
if (err instanceof ApiError && err.status === 403) {
|
|
235
|
+
const friendly = 'Agent deletion requires admin access. Use the dashboard or contact support.';
|
|
236
|
+
if (json)
|
|
237
|
+
console.log(JSON.stringify({ error: friendly }));
|
|
238
|
+
else
|
|
239
|
+
p.log.error(friendly);
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
handleCommandError({ error: err, json });
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
agents
|
|
246
|
+
.command('key <id>')
|
|
247
|
+
.description('Reveal or regenerate an agent API key')
|
|
248
|
+
.option('--reveal', 'Show the full API key')
|
|
249
|
+
.option('--regenerate', 'Generate a new API key')
|
|
250
|
+
.action(async function (agentId, opts) {
|
|
251
|
+
const { json, yes } = rootOpts(this);
|
|
252
|
+
if (opts.regenerate) {
|
|
253
|
+
const { projectId } = await requireProject(this, json);
|
|
254
|
+
if (!yes && !json) {
|
|
255
|
+
const confirmed = await p.confirm({
|
|
256
|
+
message: 'Regenerate API key? Existing integrations using the old key will stop working.',
|
|
257
|
+
});
|
|
258
|
+
if (isCancel(confirmed) || !confirmed) {
|
|
259
|
+
p.cancel('Cancelled.');
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
const spin = p.spinner();
|
|
264
|
+
if (!json)
|
|
265
|
+
spin.start('Regenerating key');
|
|
266
|
+
try {
|
|
267
|
+
const client = await createAdminClient();
|
|
268
|
+
const apiKey = await agentService.regenerateKey(client, projectId, agentId);
|
|
269
|
+
if (json) {
|
|
270
|
+
console.log(JSON.stringify({ apiKey }));
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
spin.stop('Key regenerated');
|
|
274
|
+
p.log.success(`New key: ${brand.primary(apiKey)}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
handleCommandError({ error: err, json, spinner: spin });
|
|
279
|
+
}
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const store = await readAgents();
|
|
283
|
+
const key = agentService.getStoredKey(agentId, store);
|
|
284
|
+
if (!key) {
|
|
285
|
+
const msg = `No key stored locally for ${agentId.slice(0, ID_DISPLAY_LENGTH)}. Use ${brand.accent('--regenerate')} to create a new one, or ${brand.accent('cubelife init')} to link this agent.`;
|
|
286
|
+
if (json)
|
|
287
|
+
console.log(JSON.stringify({ error: 'no_key_stored' }));
|
|
288
|
+
else
|
|
289
|
+
p.log.warn(msg);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (json) {
|
|
293
|
+
console.log(JSON.stringify({ apiKey: key }));
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
const display = opts.reveal ? key : maskKey(key);
|
|
297
|
+
p.log.info(`API key: ${brand.primary(display)}`);
|
|
298
|
+
if (!opts.reveal) {
|
|
299
|
+
p.log.message(brand.muted(`Use ${brand.accent('--reveal')} to show the full key.`));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|