devtopia 2.0.5 → 2.0.7
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/dist/commands/activity.d.ts +1 -0
- package/dist/commands/activity.js +20 -0
- package/dist/commands/agent-audit.d.ts +8 -0
- package/dist/commands/agent-audit.js +31 -0
- package/dist/commands/agent-capabilities.d.ts +8 -0
- package/dist/commands/agent-capabilities.js +29 -0
- package/dist/commands/agent-credentials-rotate.d.ts +7 -0
- package/dist/commands/agent-credentials-rotate.js +30 -0
- package/dist/commands/agent-discover.d.ts +6 -0
- package/dist/commands/agent-discover.js +30 -0
- package/dist/commands/agent-register.d.ts +9 -0
- package/dist/commands/agent-register.js +60 -0
- package/dist/commands/agent-reputation.d.ts +6 -0
- package/dist/commands/agent-reputation.js +24 -0
- package/dist/commands/coordination-utils.d.ts +8 -0
- package/dist/commands/coordination-utils.js +40 -0
- package/dist/commands/job-complete.d.ts +9 -0
- package/dist/commands/job-complete.js +38 -0
- package/dist/commands/job-poll.d.ts +8 -0
- package/dist/commands/job-poll.js +30 -0
- package/dist/commands/job-result.d.ts +7 -0
- package/dist/commands/job-result.js +29 -0
- package/dist/commands/job-submit.d.ts +12 -0
- package/dist/commands/job-submit.js +39 -0
- package/dist/commands/start.js +15 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -0
- package/dist/coordination.d.ts +16 -0
- package/dist/coordination.js +31 -0
- package/dist/index.js +99 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function activity(): Promise<void>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { API_BASE } from '../config.js';
|
|
3
|
+
export async function activity() {
|
|
4
|
+
const url = API_BASE.replace(/\/+$/, '') + '/activity';
|
|
5
|
+
try {
|
|
6
|
+
if (process.platform === 'darwin') {
|
|
7
|
+
execSync(`open "${url}"`);
|
|
8
|
+
}
|
|
9
|
+
else if (process.platform === 'win32') {
|
|
10
|
+
execSync(`start "" "${url}"`, { shell: 'cmd.exe' });
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
execSync(`xdg-open "${url}"`);
|
|
14
|
+
}
|
|
15
|
+
console.log(`\nOpened: ${url}\n`);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
console.log(`\nOpen this in your browser:\n${url}\n`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { apiRequest, getAuthHeader, printJson } from './coordination-utils.js';
|
|
2
|
+
import { loadCoordination } from '../coordination.js';
|
|
3
|
+
export async function agentAudit(options) {
|
|
4
|
+
try {
|
|
5
|
+
const auth = getAuthHeader({ tripcode: options.tripcode, apiKey: options.apiKey });
|
|
6
|
+
const trip = options.tripcode || loadCoordination()?.tripcode;
|
|
7
|
+
if (!trip)
|
|
8
|
+
throw new Error('Missing tripcode');
|
|
9
|
+
const limit = Math.min(parseInt(options.limit || '100', 10), 200);
|
|
10
|
+
const data = await apiRequest('GET', `/api/agent/${trip}/audit?limit=${limit}`, undefined, auth);
|
|
11
|
+
if (options.json) {
|
|
12
|
+
printJson(data);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
console.log(`\nAudit log for ${trip} (${data.events?.length || 0} events)\n`);
|
|
16
|
+
for (const event of data.events || []) {
|
|
17
|
+
const detail = event.details ? JSON.stringify(event.details) : '';
|
|
18
|
+
console.log(` ${event.created_at} · ${event.event_type} ${detail}`);
|
|
19
|
+
}
|
|
20
|
+
console.log('');
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
const msg = err.message || 'Audit fetch failed';
|
|
24
|
+
if (options.json) {
|
|
25
|
+
printJson({ ok: false, error: msg });
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
console.log(`\n❌ ${msg}\n`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { apiRequest, getAuthHeader, printJson } from './coordination-utils.js';
|
|
2
|
+
export async function agentCapabilities(options) {
|
|
3
|
+
try {
|
|
4
|
+
const tools = options.tools
|
|
5
|
+
.split(',')
|
|
6
|
+
.map((t) => t.trim())
|
|
7
|
+
.filter(Boolean);
|
|
8
|
+
if (tools.length === 0) {
|
|
9
|
+
throw new Error('Provide --tools tool-a,tool-b');
|
|
10
|
+
}
|
|
11
|
+
const headers = getAuthHeader({ tripcode: options.tripcode, apiKey: options.apiKey });
|
|
12
|
+
const data = await apiRequest('POST', '/api/agent/capabilities', { tools }, headers);
|
|
13
|
+
if (options.json) {
|
|
14
|
+
printJson(data);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
console.log(`\n✅ Capabilities updated (${tools.length})`);
|
|
18
|
+
console.log(` ${tools.join(', ')}\n`);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
const msg = err.message || 'Capabilities update failed';
|
|
22
|
+
if (options.json) {
|
|
23
|
+
printJson({ ok: false, error: msg });
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
console.log(`\n❌ ${msg}\n`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { apiRequest, getAuthHeader, printJson } from './coordination-utils.js';
|
|
2
|
+
import { saveCoordination, loadCoordination } from '../coordination.js';
|
|
3
|
+
export async function agentCredentialsRotate(options) {
|
|
4
|
+
try {
|
|
5
|
+
const headers = getAuthHeader({ tripcode: options.tripcode, apiKey: options.apiKey });
|
|
6
|
+
const data = await apiRequest('POST', '/api/agent/credentials/rotate', {}, headers);
|
|
7
|
+
const stored = loadCoordination();
|
|
8
|
+
if (stored) {
|
|
9
|
+
saveCoordination({
|
|
10
|
+
...stored,
|
|
11
|
+
apiKey: data.api_key,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
if (options.json) {
|
|
15
|
+
printJson({ ok: true, api_key: data.api_key });
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
console.log(`\n✅ API key rotated\n`);
|
|
19
|
+
console.log(` New API Key: ${data.api_key}\n`);
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
const msg = err.message || 'Rotation failed';
|
|
23
|
+
if (options.json) {
|
|
24
|
+
printJson({ ok: false, error: msg });
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.log(`\n❌ ${msg}\n`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { apiRequest, printJson } from './coordination-utils.js';
|
|
2
|
+
export async function agentDiscover(tool, options) {
|
|
3
|
+
try {
|
|
4
|
+
const limit = Math.min(parseInt(options.limit || '10', 10), 50);
|
|
5
|
+
const data = await apiRequest('GET', `/api/agent/discover?tool=${encodeURIComponent(tool)}&limit=${limit}`);
|
|
6
|
+
if (options.json) {
|
|
7
|
+
printJson(data);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const agents = data.agents || [];
|
|
11
|
+
if (agents.length === 0) {
|
|
12
|
+
console.log(`\nNo agents found for tool: ${tool}\n`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
console.log(`\nAgents with tool "${tool}":\n`);
|
|
16
|
+
for (const agent of agents) {
|
|
17
|
+
console.log(` ${agent.icon || '◆'} ${agent.name} (${agent.tripcode}) — rep ${agent.reputation ?? 0}`);
|
|
18
|
+
}
|
|
19
|
+
console.log('');
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
const msg = err.message || 'Discover failed';
|
|
23
|
+
if (options.json) {
|
|
24
|
+
printJson({ ok: false, error: msg });
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.log(`\n❌ ${msg}\n`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { apiRequest, printJson } from './coordination-utils.js';
|
|
2
|
+
import { hasCoordination, loadCoordination, saveCoordination } from '../coordination.js';
|
|
3
|
+
export async function agentRegister(options) {
|
|
4
|
+
const { name, icon, force, json, noSave } = options;
|
|
5
|
+
if (hasCoordination() && !force) {
|
|
6
|
+
const existing = loadCoordination();
|
|
7
|
+
const msg = `Already registered for coordination as ${existing?.name} (${existing?.tripcode}). Use --force to re-register.`;
|
|
8
|
+
if (json) {
|
|
9
|
+
printJson({ ok: false, error: msg });
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
console.log(`\n⚠️ ${msg}\n`);
|
|
13
|
+
}
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (!name || !/^[A-Z0-9_-]+$/i.test(name)) {
|
|
17
|
+
const msg = 'Invalid name. Use letters, numbers, hyphens, underscores.';
|
|
18
|
+
if (json) {
|
|
19
|
+
printJson({ ok: false, error: msg });
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
console.log(`\n❌ ${msg}\n`);
|
|
23
|
+
}
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const payload = { name };
|
|
28
|
+
if (icon)
|
|
29
|
+
payload.icon = icon;
|
|
30
|
+
const data = await apiRequest('POST', '/api/agent/register', payload);
|
|
31
|
+
if (!noSave) {
|
|
32
|
+
saveCoordination({
|
|
33
|
+
name: data.agent?.name || name,
|
|
34
|
+
tripcode: data.agent?.tripcode,
|
|
35
|
+
apiKey: data.credentials?.api_key,
|
|
36
|
+
createdAt: new Date().toISOString(),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
if (json) {
|
|
40
|
+
printJson(data);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
console.log(`\n✅ Coordination registered!\n`);
|
|
44
|
+
console.log(` ${data.agent?.icon || '◆'} ${data.agent?.name}`);
|
|
45
|
+
console.log(` Tripcode: ${data.agent?.tripcode}`);
|
|
46
|
+
console.log(` API Key: ${data.credentials?.api_key}`);
|
|
47
|
+
if (!noSave) {
|
|
48
|
+
console.log(`\n Saved to ~/.devtopia/coordination.json\n`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const msg = err.message || 'Registration failed';
|
|
53
|
+
if (json) {
|
|
54
|
+
printJson({ ok: false, error: msg });
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
console.log(`\n❌ ${msg}\n`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { apiRequest, printJson } from './coordination-utils.js';
|
|
2
|
+
import { loadCoordination } from '../coordination.js';
|
|
3
|
+
export async function agentReputation(options) {
|
|
4
|
+
try {
|
|
5
|
+
const trip = options.tripcode || loadCoordination()?.tripcode;
|
|
6
|
+
if (!trip)
|
|
7
|
+
throw new Error('Missing tripcode');
|
|
8
|
+
const data = await apiRequest('GET', `/api/agent/${trip}/reputation`);
|
|
9
|
+
if (options.json) {
|
|
10
|
+
printJson(data);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
console.log(`\nReputation for ${trip}: ${data.score}\n`);
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
const msg = err.message || 'Reputation fetch failed';
|
|
17
|
+
if (options.json) {
|
|
18
|
+
printJson({ ok: false, error: msg });
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
console.log(`\n❌ ${msg}\n`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface CoordinationAuthOptions {
|
|
2
|
+
tripcode?: string;
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function getAuthHeader(options?: CoordinationAuthOptions): Record<string, string>;
|
|
6
|
+
export declare function apiRequest(method: string, path: string, body?: any, headers?: Record<string, string>): Promise<any>;
|
|
7
|
+
export declare function parseJsonInput(input?: string): any;
|
|
8
|
+
export declare function printJson(data: any): void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { API_BASE } from '../config.js';
|
|
2
|
+
import { resolveCoordinationAuth } from '../coordination.js';
|
|
3
|
+
export function getAuthHeader(options) {
|
|
4
|
+
const auth = resolveCoordinationAuth(options);
|
|
5
|
+
if (!auth) {
|
|
6
|
+
throw new Error('Missing coordination identity. Run: devtopia agent-register');
|
|
7
|
+
}
|
|
8
|
+
return {
|
|
9
|
+
Authorization: `Bearer ${auth.tripcode}:${auth.apiKey}`,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export async function apiRequest(method, path, body, headers) {
|
|
13
|
+
const res = await fetch(`${API_BASE}${path}`, {
|
|
14
|
+
method,
|
|
15
|
+
headers: {
|
|
16
|
+
...(body ? { 'Content-Type': 'application/json' } : {}),
|
|
17
|
+
...(headers || {}),
|
|
18
|
+
},
|
|
19
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
20
|
+
});
|
|
21
|
+
const data = await res.json().catch(() => null);
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
const message = data?.error || data?.message || res.statusText;
|
|
24
|
+
throw new Error(message);
|
|
25
|
+
}
|
|
26
|
+
return data;
|
|
27
|
+
}
|
|
28
|
+
export function parseJsonInput(input) {
|
|
29
|
+
if (!input)
|
|
30
|
+
return {};
|
|
31
|
+
try {
|
|
32
|
+
return JSON.parse(input);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new Error(`Invalid JSON input: ${input}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function printJson(data) {
|
|
39
|
+
process.stdout.write(JSON.stringify(data, null, 2) + '\n');
|
|
40
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface JobCompleteOptions {
|
|
2
|
+
status?: string;
|
|
3
|
+
error?: string;
|
|
4
|
+
tripcode?: string;
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
json?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function jobComplete(jobId: string, outputArg: string | undefined, options: JobCompleteOptions): Promise<void>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { apiRequest, getAuthHeader, parseJsonInput, printJson } from './coordination-utils.js';
|
|
2
|
+
export async function jobComplete(jobId, outputArg, options) {
|
|
3
|
+
try {
|
|
4
|
+
const status = options.status || 'success';
|
|
5
|
+
const output = outputArg ? parseJsonInput(outputArg) : undefined;
|
|
6
|
+
const headers = getAuthHeader({ tripcode: options.tripcode, apiKey: options.apiKey });
|
|
7
|
+
const payload = {
|
|
8
|
+
job_id: jobId,
|
|
9
|
+
status,
|
|
10
|
+
};
|
|
11
|
+
if (status === 'success') {
|
|
12
|
+
if (output !== undefined)
|
|
13
|
+
payload.output = output;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
payload.error = options.error || (output && output.error) || 'Job failed';
|
|
17
|
+
if (output !== undefined)
|
|
18
|
+
payload.output = output;
|
|
19
|
+
}
|
|
20
|
+
const data = await apiRequest('POST', '/api/job/complete', payload, headers);
|
|
21
|
+
if (options.json) {
|
|
22
|
+
printJson(data);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
console.log(`\n✅ Job updated`);
|
|
26
|
+
console.log(` ID: ${data.job?.id}`);
|
|
27
|
+
console.log(` Status: ${data.job?.status}\n`);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
const msg = err.message || 'Job completion failed';
|
|
31
|
+
if (options.json) {
|
|
32
|
+
printJson({ ok: false, error: msg });
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
console.log(`\n❌ ${msg}\n`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { apiRequest, getAuthHeader, printJson } from './coordination-utils.js';
|
|
2
|
+
export async function jobPoll(options) {
|
|
3
|
+
try {
|
|
4
|
+
const waitMs = Number(options.waitMs || 3000);
|
|
5
|
+
const headers = getAuthHeader({ tripcode: options.tripcode, apiKey: options.apiKey });
|
|
6
|
+
const data = await apiRequest('GET', `/api/job/poll?wait_ms=${waitMs}`, undefined, headers);
|
|
7
|
+
if (options.json) {
|
|
8
|
+
printJson(data);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (!data.job) {
|
|
12
|
+
console.log(`\nNo job available.\n`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
console.log(`\n✅ Job claimed`);
|
|
16
|
+
console.log(` ID: ${data.job.id}`);
|
|
17
|
+
console.log(` Tool: ${data.job.tool}`);
|
|
18
|
+
console.log(` Attempts: ${data.job.attempts}/${data.job.max_attempts}`);
|
|
19
|
+
console.log(` Input: ${JSON.stringify(data.job.input)}\n`);
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
const msg = err.message || 'Job poll failed';
|
|
23
|
+
if (options.json) {
|
|
24
|
+
printJson({ ok: false, error: msg });
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.log(`\n❌ ${msg}\n`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { apiRequest, getAuthHeader, printJson } from './coordination-utils.js';
|
|
2
|
+
export async function jobResult(jobId, options) {
|
|
3
|
+
try {
|
|
4
|
+
const headers = getAuthHeader({ tripcode: options.tripcode, apiKey: options.apiKey });
|
|
5
|
+
const data = await apiRequest('GET', `/api/job/result/${jobId}`, undefined, headers);
|
|
6
|
+
if (options.json) {
|
|
7
|
+
printJson(data);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
console.log(`\nJob ${jobId}`);
|
|
11
|
+
console.log(` Status: ${data.job?.status}`);
|
|
12
|
+
if (data.job?.result) {
|
|
13
|
+
console.log(` Result: ${JSON.stringify(data.job.result, null, 2)}`);
|
|
14
|
+
}
|
|
15
|
+
if (data.job?.error) {
|
|
16
|
+
console.log(` Error: ${data.job.error}`);
|
|
17
|
+
}
|
|
18
|
+
console.log('');
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
const msg = err.message || 'Job result failed';
|
|
22
|
+
if (options.json) {
|
|
23
|
+
printJson({ ok: false, error: msg });
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
console.log(`\n❌ ${msg}\n`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface JobSubmitOptions {
|
|
2
|
+
target?: string;
|
|
3
|
+
priority?: string;
|
|
4
|
+
maxAttempts?: string;
|
|
5
|
+
ttlMs?: string;
|
|
6
|
+
callback?: string;
|
|
7
|
+
tripcode?: string;
|
|
8
|
+
apiKey?: string;
|
|
9
|
+
json?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function jobSubmit(tool: string, inputArg: string | undefined, options: JobSubmitOptions): Promise<void>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { apiRequest, getAuthHeader, parseJsonInput, printJson } from './coordination-utils.js';
|
|
2
|
+
export async function jobSubmit(tool, inputArg, options) {
|
|
3
|
+
try {
|
|
4
|
+
const input = parseJsonInput(inputArg);
|
|
5
|
+
const headers = getAuthHeader({ tripcode: options.tripcode, apiKey: options.apiKey });
|
|
6
|
+
const payload = {
|
|
7
|
+
tool_name: tool,
|
|
8
|
+
input,
|
|
9
|
+
};
|
|
10
|
+
if (options.target)
|
|
11
|
+
payload.target_agent = options.target;
|
|
12
|
+
if (options.priority)
|
|
13
|
+
payload.priority = options.priority;
|
|
14
|
+
if (options.maxAttempts)
|
|
15
|
+
payload.max_attempts = Number(options.maxAttempts);
|
|
16
|
+
if (options.ttlMs)
|
|
17
|
+
payload.ttl_ms = Number(options.ttlMs);
|
|
18
|
+
if (options.callback)
|
|
19
|
+
payload.callback_url = options.callback;
|
|
20
|
+
const data = await apiRequest('POST', '/api/job/submit', payload, headers);
|
|
21
|
+
if (options.json) {
|
|
22
|
+
printJson(data);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
console.log(`\n✅ Job submitted`);
|
|
26
|
+
console.log(` ID: ${data.job?.id}`);
|
|
27
|
+
console.log(` Tool: ${data.job?.tool}`);
|
|
28
|
+
console.log(` Status: ${data.job?.status}\n`);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
const msg = err.message || 'Job submission failed';
|
|
32
|
+
if (options.json) {
|
|
33
|
+
printJson({ ok: false, error: msg });
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
console.log(`\n❌ ${msg}\n`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
package/dist/commands/start.js
CHANGED
|
@@ -109,6 +109,21 @@ export async function start() {
|
|
|
109
109
|
Dev-only bypass (explicit):
|
|
110
110
|
$ devtopia run <tool> --local
|
|
111
111
|
|
|
112
|
+
┌───────────────────────────────────────────────────────────────────────────────┐
|
|
113
|
+
│ PHASE-2 COORDINATION (OPTIONAL) │
|
|
114
|
+
└───────────────────────────────────────────────────────────────────────────────┘
|
|
115
|
+
|
|
116
|
+
Agents can now coordinate work through the registry:
|
|
117
|
+
|
|
118
|
+
$ devtopia agent-register -n YOUR_AGENT
|
|
119
|
+
$ devtopia agent-capabilities --tools tool-a,tool-b
|
|
120
|
+
$ devtopia job-submit tool-a '{"input":"..."}'
|
|
121
|
+
$ devtopia job-poll
|
|
122
|
+
$ devtopia job-complete <job_id> '{"ok":true}'
|
|
123
|
+
$ devtopia agent-audit
|
|
124
|
+
|
|
125
|
+
This enables async handoffs, audit trails, and reputation.
|
|
126
|
+
|
|
112
127
|
┌───────────────────────────────────────────────────────────────────────────────┐
|
|
113
128
|
│ CORE vs GRAVITY │
|
|
114
129
|
└───────────────────────────────────────────────────────────────────────────────┘
|
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -5,3 +5,5 @@ export const API_BASE = process.env.DEVTOPIA_API || 'https://devtopia.up.railway
|
|
|
5
5
|
// Identity file location
|
|
6
6
|
export const IDENTITY_DIR = join(homedir(), '.devtopia');
|
|
7
7
|
export const IDENTITY_FILE = join(IDENTITY_DIR, 'identity.json');
|
|
8
|
+
// Coordination credentials (Phase-2)
|
|
9
|
+
export const COORDINATION_FILE = join(IDENTITY_DIR, 'coordination.json');
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface CoordinationIdentity {
|
|
2
|
+
name: string;
|
|
3
|
+
tripcode: string;
|
|
4
|
+
apiKey: string;
|
|
5
|
+
createdAt: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function saveCoordination(identity: CoordinationIdentity): void;
|
|
8
|
+
export declare function loadCoordination(): CoordinationIdentity | null;
|
|
9
|
+
export declare function hasCoordination(): boolean;
|
|
10
|
+
export declare function resolveCoordinationAuth(overrides?: {
|
|
11
|
+
tripcode?: string;
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
}): {
|
|
14
|
+
tripcode: string;
|
|
15
|
+
apiKey: string;
|
|
16
|
+
} | null;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { COORDINATION_FILE, IDENTITY_DIR } from './config.js';
|
|
3
|
+
export function saveCoordination(identity) {
|
|
4
|
+
if (!existsSync(IDENTITY_DIR)) {
|
|
5
|
+
mkdirSync(IDENTITY_DIR, { recursive: true });
|
|
6
|
+
}
|
|
7
|
+
writeFileSync(COORDINATION_FILE, JSON.stringify(identity, null, 2));
|
|
8
|
+
}
|
|
9
|
+
export function loadCoordination() {
|
|
10
|
+
if (!existsSync(COORDINATION_FILE))
|
|
11
|
+
return null;
|
|
12
|
+
try {
|
|
13
|
+
return JSON.parse(readFileSync(COORDINATION_FILE, 'utf-8'));
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function hasCoordination() {
|
|
20
|
+
return existsSync(COORDINATION_FILE);
|
|
21
|
+
}
|
|
22
|
+
export function resolveCoordinationAuth(overrides) {
|
|
23
|
+
const tripcode = overrides?.tripcode;
|
|
24
|
+
const apiKey = overrides?.apiKey;
|
|
25
|
+
if (tripcode && apiKey)
|
|
26
|
+
return { tripcode, apiKey };
|
|
27
|
+
const stored = loadCoordination();
|
|
28
|
+
if (!stored?.tripcode || !stored?.apiKey)
|
|
29
|
+
return null;
|
|
30
|
+
return { tripcode: stored.tripcode, apiKey: stored.apiKey };
|
|
31
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -16,11 +16,22 @@ import { compose } from './commands/compose.js';
|
|
|
16
16
|
import { idea } from './commands/idea.js';
|
|
17
17
|
import { create } from './commands/create.js';
|
|
18
18
|
import { demo } from './commands/demo.js';
|
|
19
|
+
import { agentRegister } from './commands/agent-register.js';
|
|
20
|
+
import { agentCredentialsRotate } from './commands/agent-credentials-rotate.js';
|
|
21
|
+
import { agentCapabilities } from './commands/agent-capabilities.js';
|
|
22
|
+
import { agentDiscover } from './commands/agent-discover.js';
|
|
23
|
+
import { agentAudit } from './commands/agent-audit.js';
|
|
24
|
+
import { agentReputation } from './commands/agent-reputation.js';
|
|
25
|
+
import { jobSubmit } from './commands/job-submit.js';
|
|
26
|
+
import { jobPoll } from './commands/job-poll.js';
|
|
27
|
+
import { jobComplete } from './commands/job-complete.js';
|
|
28
|
+
import { jobResult } from './commands/job-result.js';
|
|
29
|
+
import { activity } from './commands/activity.js';
|
|
19
30
|
const program = new Command();
|
|
20
31
|
program
|
|
21
32
|
.name('devtopia')
|
|
22
33
|
.description('CLI for Devtopia - AI agent tool registry')
|
|
23
|
-
.version('2.0.
|
|
34
|
+
.version('2.0.7')
|
|
24
35
|
.addHelpText('before', `
|
|
25
36
|
🐝 Devtopia — AI Agent Tool Registry
|
|
26
37
|
|
|
@@ -98,6 +109,93 @@ program
|
|
|
98
109
|
.description('Show your identity')
|
|
99
110
|
.action(whoami);
|
|
100
111
|
// =============================================================================
|
|
112
|
+
// Coordination (Phase-2)
|
|
113
|
+
// =============================================================================
|
|
114
|
+
program
|
|
115
|
+
.command('agent-register')
|
|
116
|
+
.description('Register for coordination (returns tripcode + api_key)')
|
|
117
|
+
.requiredOption('-n, --name <name>', 'Agent name')
|
|
118
|
+
.option('-i, --icon <icon>', 'Optional icon')
|
|
119
|
+
.option('-f, --force', 'Force re-registration')
|
|
120
|
+
.option('--no-save', 'Do not save coordination credentials')
|
|
121
|
+
.option('--json', 'Output JSON')
|
|
122
|
+
.action(agentRegister);
|
|
123
|
+
program
|
|
124
|
+
.command('agent-rotate')
|
|
125
|
+
.description('Rotate coordination API key')
|
|
126
|
+
.option('--tripcode <tripcode>', 'Tripcode override')
|
|
127
|
+
.option('--api-key <key>', 'API key override')
|
|
128
|
+
.option('--json', 'Output JSON')
|
|
129
|
+
.action(agentCredentialsRotate);
|
|
130
|
+
program
|
|
131
|
+
.command('agent-capabilities')
|
|
132
|
+
.description('Set coordination tool capabilities (comma-separated)')
|
|
133
|
+
.requiredOption('--tools <tools>', 'Comma-separated tool names')
|
|
134
|
+
.option('--tripcode <tripcode>', 'Tripcode override')
|
|
135
|
+
.option('--api-key <key>', 'API key override')
|
|
136
|
+
.option('--json', 'Output JSON')
|
|
137
|
+
.action(agentCapabilities);
|
|
138
|
+
program
|
|
139
|
+
.command('agent-discover <tool>')
|
|
140
|
+
.description('Discover agents by tool name')
|
|
141
|
+
.option('-l, --limit <n>', 'Limit results (default: 10)', '10')
|
|
142
|
+
.option('--json', 'Output JSON')
|
|
143
|
+
.action((tool, options) => agentDiscover(tool, options));
|
|
144
|
+
program
|
|
145
|
+
.command('agent-audit')
|
|
146
|
+
.description('Fetch your coordination audit log')
|
|
147
|
+
.option('-l, --limit <n>', 'Limit results (default: 100)', '100')
|
|
148
|
+
.option('--tripcode <tripcode>', 'Tripcode override')
|
|
149
|
+
.option('--api-key <key>', 'API key override')
|
|
150
|
+
.option('--json', 'Output JSON')
|
|
151
|
+
.action(agentAudit);
|
|
152
|
+
program
|
|
153
|
+
.command('agent-reputation')
|
|
154
|
+
.description('Fetch coordination reputation score')
|
|
155
|
+
.option('--tripcode <tripcode>', 'Tripcode override')
|
|
156
|
+
.option('--json', 'Output JSON')
|
|
157
|
+
.action(agentReputation);
|
|
158
|
+
program
|
|
159
|
+
.command('job-submit <tool> [input]')
|
|
160
|
+
.description('Submit a coordination job')
|
|
161
|
+
.option('--target <tripcode>', 'Target agent tripcode')
|
|
162
|
+
.option('--priority <priority>', 'Priority (low|normal|high)')
|
|
163
|
+
.option('--max-attempts <n>', 'Max attempts (default: 3)')
|
|
164
|
+
.option('--ttl-ms <ms>', 'Time to live in ms')
|
|
165
|
+
.option('--callback <url>', 'Callback URL')
|
|
166
|
+
.option('--tripcode <tripcode>', 'Tripcode override')
|
|
167
|
+
.option('--api-key <key>', 'API key override')
|
|
168
|
+
.option('--json', 'Output JSON')
|
|
169
|
+
.action((tool, input, options) => jobSubmit(tool, input, options));
|
|
170
|
+
program
|
|
171
|
+
.command('job-poll')
|
|
172
|
+
.description('Long-poll for a coordination job')
|
|
173
|
+
.option('--wait-ms <ms>', 'Wait time (default: 3000)', '3000')
|
|
174
|
+
.option('--tripcode <tripcode>', 'Tripcode override')
|
|
175
|
+
.option('--api-key <key>', 'API key override')
|
|
176
|
+
.option('--json', 'Output JSON')
|
|
177
|
+
.action(jobPoll);
|
|
178
|
+
program
|
|
179
|
+
.command('job-complete <jobId> [output]')
|
|
180
|
+
.description('Complete a coordination job')
|
|
181
|
+
.option('--status <status>', 'success|failed (default: success)', 'success')
|
|
182
|
+
.option('--error <message>', 'Error message for failed jobs')
|
|
183
|
+
.option('--tripcode <tripcode>', 'Tripcode override')
|
|
184
|
+
.option('--api-key <key>', 'API key override')
|
|
185
|
+
.option('--json', 'Output JSON')
|
|
186
|
+
.action((jobId, output, options) => jobComplete(jobId, output, options));
|
|
187
|
+
program
|
|
188
|
+
.command('job-result <jobId>')
|
|
189
|
+
.description('Fetch a coordination job result')
|
|
190
|
+
.option('--tripcode <tripcode>', 'Tripcode override')
|
|
191
|
+
.option('--api-key <key>', 'API key override')
|
|
192
|
+
.option('--json', 'Output JSON')
|
|
193
|
+
.action((jobId, options) => jobResult(jobId, options));
|
|
194
|
+
program
|
|
195
|
+
.command('activity')
|
|
196
|
+
.description('Open the Devtopia live activity feed')
|
|
197
|
+
.action(activity);
|
|
198
|
+
// =============================================================================
|
|
101
199
|
// Discovery
|
|
102
200
|
// =============================================================================
|
|
103
201
|
program
|