@orchagent/cli 0.2.26 → 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/dist/adapters/agents-md.js +51 -0
- package/dist/adapters/claude-code.js +104 -0
- package/dist/adapters/cursor.js +67 -0
- package/dist/adapters/index.js +38 -0
- package/dist/adapters/registry.js +51 -0
- package/dist/adapters/types.js +2 -0
- package/dist/commands/config.js +74 -0
- package/dist/commands/formats.js +44 -0
- package/dist/commands/index.js +8 -0
- package/dist/commands/install.js +172 -0
- package/dist/commands/skill.js +24 -3
- package/dist/commands/update.js +146 -0
- package/dist/lib/config.js +23 -0
- package/dist/lib/installed.js +94 -0
- package/package.json +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.agentsMdAdapter = void 0;
|
|
4
|
+
exports.agentsMdAdapter = {
|
|
5
|
+
id: 'agents-md',
|
|
6
|
+
name: 'AGENTS.md (Universal)',
|
|
7
|
+
version: '1.0.0',
|
|
8
|
+
formatVersion: '1.0',
|
|
9
|
+
supportsAgentTypes: ['prompt', 'skill'],
|
|
10
|
+
installPaths: [
|
|
11
|
+
{
|
|
12
|
+
scope: 'project',
|
|
13
|
+
path: './',
|
|
14
|
+
description: 'Project root (AGENTS.md)',
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
canConvert(agent) {
|
|
18
|
+
const warnings = [];
|
|
19
|
+
const errors = [];
|
|
20
|
+
if (agent.type === 'code') {
|
|
21
|
+
errors.push('Code agents cannot be converted to AGENTS.md');
|
|
22
|
+
return { canConvert: false, warnings, errors };
|
|
23
|
+
}
|
|
24
|
+
if (!agent.prompt) {
|
|
25
|
+
errors.push('Agent has no prompt content');
|
|
26
|
+
return { canConvert: false, warnings, errors };
|
|
27
|
+
}
|
|
28
|
+
warnings.push('AGENTS.md content should be appended to existing file, not replaced');
|
|
29
|
+
return { canConvert: true, warnings, errors };
|
|
30
|
+
},
|
|
31
|
+
convert(agent) {
|
|
32
|
+
const agentRef = `${agent.org_slug}/${agent.name}`;
|
|
33
|
+
const description = agent.description || '';
|
|
34
|
+
// Use orchagent markers for managed section
|
|
35
|
+
const content = `<!-- orchagent:${agentRef} -->
|
|
36
|
+
## ${agent.name}
|
|
37
|
+
|
|
38
|
+
${description}
|
|
39
|
+
|
|
40
|
+
${agent.prompt || ''}
|
|
41
|
+
<!-- /orchagent:${agentRef} -->
|
|
42
|
+
`;
|
|
43
|
+
return [
|
|
44
|
+
{
|
|
45
|
+
filename: 'AGENTS.md',
|
|
46
|
+
content,
|
|
47
|
+
installPath: './',
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
},
|
|
51
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.claudeCodeAdapter = void 0;
|
|
7
|
+
const yaml_1 = __importDefault(require("yaml"));
|
|
8
|
+
// Map Anthropic model names to Claude Code aliases
|
|
9
|
+
function mapModelToAlias(model) {
|
|
10
|
+
if (!model)
|
|
11
|
+
return 'inherit';
|
|
12
|
+
const lower = model.toLowerCase();
|
|
13
|
+
if (lower.includes('opus'))
|
|
14
|
+
return 'opus';
|
|
15
|
+
if (lower.includes('haiku'))
|
|
16
|
+
return 'haiku';
|
|
17
|
+
// Default to sonnet for any Claude model
|
|
18
|
+
if (lower.includes('claude') || lower.includes('sonnet'))
|
|
19
|
+
return 'sonnet';
|
|
20
|
+
return 'inherit';
|
|
21
|
+
}
|
|
22
|
+
// Convert agent name to valid Claude Code name (lowercase + hyphens)
|
|
23
|
+
function normalizeAgentName(name) {
|
|
24
|
+
return name
|
|
25
|
+
.toLowerCase()
|
|
26
|
+
.replace(/[^a-z0-9-]/g, '-')
|
|
27
|
+
.replace(/-+/g, '-')
|
|
28
|
+
.replace(/^-|-$/g, '');
|
|
29
|
+
}
|
|
30
|
+
exports.claudeCodeAdapter = {
|
|
31
|
+
id: 'claude-code',
|
|
32
|
+
name: 'Claude Code Sub-Agent',
|
|
33
|
+
version: '1.0.0',
|
|
34
|
+
formatVersion: '2026-01',
|
|
35
|
+
supportsAgentTypes: ['prompt', 'skill'],
|
|
36
|
+
installPaths: [
|
|
37
|
+
{
|
|
38
|
+
scope: 'user',
|
|
39
|
+
path: '~/.claude/agents/',
|
|
40
|
+
description: 'User-level (available in all projects)',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
scope: 'project',
|
|
44
|
+
path: '.claude/agents/',
|
|
45
|
+
description: 'Project-level (current directory)',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
canConvert(agent) {
|
|
49
|
+
const warnings = [];
|
|
50
|
+
const errors = [];
|
|
51
|
+
// Code agents cannot be converted
|
|
52
|
+
if (agent.type === 'code') {
|
|
53
|
+
errors.push('Code agents cannot be converted to Claude Code sub-agents (they require execution)');
|
|
54
|
+
return { canConvert: false, warnings, errors };
|
|
55
|
+
}
|
|
56
|
+
// Check for prompt
|
|
57
|
+
if (!agent.prompt) {
|
|
58
|
+
errors.push('Agent has no prompt content');
|
|
59
|
+
return { canConvert: false, warnings, errors };
|
|
60
|
+
}
|
|
61
|
+
// Warnings for fields that can't be fully mapped
|
|
62
|
+
if (agent.input_schema) {
|
|
63
|
+
warnings.push('input_schema will be described in the prompt body, not enforced');
|
|
64
|
+
}
|
|
65
|
+
if (agent.output_schema) {
|
|
66
|
+
warnings.push('output_schema will be described in the prompt body, not enforced');
|
|
67
|
+
}
|
|
68
|
+
return { canConvert: true, warnings, errors };
|
|
69
|
+
},
|
|
70
|
+
convert(agent) {
|
|
71
|
+
const normalizedName = normalizeAgentName(agent.name);
|
|
72
|
+
// Build frontmatter
|
|
73
|
+
const frontmatter = {
|
|
74
|
+
name: normalizedName,
|
|
75
|
+
description: agent.description || `Delegatable agent: ${agent.name}`,
|
|
76
|
+
tools: 'Read, Glob, Grep', // Safe defaults - read-only
|
|
77
|
+
};
|
|
78
|
+
// Map model if specified
|
|
79
|
+
if (agent.default_models?.anthropic) {
|
|
80
|
+
const modelAlias = mapModelToAlias(agent.default_models.anthropic);
|
|
81
|
+
if (modelAlias !== 'inherit') {
|
|
82
|
+
frontmatter.model = modelAlias;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Build body
|
|
86
|
+
let body = agent.prompt || '';
|
|
87
|
+
// Add schema descriptions if present
|
|
88
|
+
if (agent.input_schema) {
|
|
89
|
+
body += `\n\n## Input Schema\n\nThis agent expects input matching:\n\`\`\`json\n${JSON.stringify(agent.input_schema, null, 2)}\n\`\`\``;
|
|
90
|
+
}
|
|
91
|
+
if (agent.output_schema) {
|
|
92
|
+
body += `\n\n## Output Schema\n\nThis agent should return output matching:\n\`\`\`json\n${JSON.stringify(agent.output_schema, null, 2)}\n\`\`\``;
|
|
93
|
+
}
|
|
94
|
+
// Combine frontmatter + body
|
|
95
|
+
const content = `---\n${yaml_1.default.stringify(frontmatter).trim()}\n---\n\n${body.trim()}\n`;
|
|
96
|
+
return [
|
|
97
|
+
{
|
|
98
|
+
filename: `${normalizedName}.md`,
|
|
99
|
+
content,
|
|
100
|
+
installPath: '.claude/agents/',
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
},
|
|
104
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cursorAdapter = void 0;
|
|
4
|
+
// Convert agent name to valid filename (lowercase + hyphens)
|
|
5
|
+
function normalizeAgentName(name) {
|
|
6
|
+
return name
|
|
7
|
+
.toLowerCase()
|
|
8
|
+
.replace(/[^a-z0-9-]/g, '-')
|
|
9
|
+
.replace(/-+/g, '-')
|
|
10
|
+
.replace(/^-|-$/g, '');
|
|
11
|
+
}
|
|
12
|
+
exports.cursorAdapter = {
|
|
13
|
+
id: 'cursor',
|
|
14
|
+
name: 'Cursor Rules',
|
|
15
|
+
version: '1.0.0',
|
|
16
|
+
formatVersion: '2026-01',
|
|
17
|
+
supportsAgentTypes: ['prompt', 'skill'],
|
|
18
|
+
installPaths: [
|
|
19
|
+
{
|
|
20
|
+
scope: 'project',
|
|
21
|
+
path: '.cursor/rules/',
|
|
22
|
+
description: 'Project-level Cursor rules',
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
canConvert(agent) {
|
|
26
|
+
const warnings = [];
|
|
27
|
+
const errors = [];
|
|
28
|
+
if (agent.type === 'code') {
|
|
29
|
+
errors.push('Code agents cannot be converted to Cursor rules');
|
|
30
|
+
return { canConvert: false, warnings, errors };
|
|
31
|
+
}
|
|
32
|
+
if (!agent.prompt) {
|
|
33
|
+
errors.push('Agent has no prompt content');
|
|
34
|
+
return { canConvert: false, warnings, errors };
|
|
35
|
+
}
|
|
36
|
+
// Cursor doesn't support input/output schemas
|
|
37
|
+
if (agent.input_schema) {
|
|
38
|
+
warnings.push('input_schema is not supported in Cursor rules');
|
|
39
|
+
}
|
|
40
|
+
if (agent.output_schema) {
|
|
41
|
+
warnings.push('output_schema is not supported in Cursor rules');
|
|
42
|
+
}
|
|
43
|
+
return { canConvert: true, warnings, errors };
|
|
44
|
+
},
|
|
45
|
+
convert(agent) {
|
|
46
|
+
const normalizedName = normalizeAgentName(agent.name);
|
|
47
|
+
const description = agent.description || `Rules from ${agent.name}`;
|
|
48
|
+
// Cursor .mdc format
|
|
49
|
+
const content = `---
|
|
50
|
+
description: ${description}
|
|
51
|
+
globs:
|
|
52
|
+
alwaysApply: false
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
# ${agent.name}
|
|
56
|
+
|
|
57
|
+
${agent.prompt || ''}
|
|
58
|
+
`;
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
filename: `${normalizedName}.mdc`,
|
|
62
|
+
content,
|
|
63
|
+
installPath: '.cursor/rules/',
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
},
|
|
67
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.agentsMdAdapter = exports.cursorAdapter = exports.claudeCodeAdapter = exports.adapterRegistry = exports.AdapterRegistry = void 0;
|
|
18
|
+
// Export types
|
|
19
|
+
__exportStar(require("./types"), exports);
|
|
20
|
+
// Export registry
|
|
21
|
+
const registry_1 = require("./registry");
|
|
22
|
+
var registry_2 = require("./registry");
|
|
23
|
+
Object.defineProperty(exports, "AdapterRegistry", { enumerable: true, get: function () { return registry_2.AdapterRegistry; } });
|
|
24
|
+
Object.defineProperty(exports, "adapterRegistry", { enumerable: true, get: function () { return registry_2.adapterRegistry; } });
|
|
25
|
+
// Import and register adapters
|
|
26
|
+
const claude_code_1 = require("./claude-code");
|
|
27
|
+
var claude_code_2 = require("./claude-code");
|
|
28
|
+
Object.defineProperty(exports, "claudeCodeAdapter", { enumerable: true, get: function () { return claude_code_2.claudeCodeAdapter; } });
|
|
29
|
+
const cursor_1 = require("./cursor");
|
|
30
|
+
var cursor_2 = require("./cursor");
|
|
31
|
+
Object.defineProperty(exports, "cursorAdapter", { enumerable: true, get: function () { return cursor_2.cursorAdapter; } });
|
|
32
|
+
const agents_md_1 = require("./agents-md");
|
|
33
|
+
var agents_md_2 = require("./agents-md");
|
|
34
|
+
Object.defineProperty(exports, "agentsMdAdapter", { enumerable: true, get: function () { return agents_md_2.agentsMdAdapter; } });
|
|
35
|
+
// Register built-in adapters
|
|
36
|
+
registry_1.adapterRegistry.register(claude_code_1.claudeCodeAdapter);
|
|
37
|
+
registry_1.adapterRegistry.register(cursor_1.cursorAdapter);
|
|
38
|
+
registry_1.adapterRegistry.register(agents_md_1.agentsMdAdapter);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.adapterRegistry = exports.AdapterRegistry = void 0;
|
|
4
|
+
class AdapterRegistry {
|
|
5
|
+
adapters = new Map();
|
|
6
|
+
/**
|
|
7
|
+
* Register an adapter
|
|
8
|
+
*/
|
|
9
|
+
register(adapter) {
|
|
10
|
+
if (this.adapters.has(adapter.id)) {
|
|
11
|
+
throw new Error(`Adapter '${adapter.id}' is already registered`);
|
|
12
|
+
}
|
|
13
|
+
this.adapters.set(adapter.id, adapter);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get adapter by ID
|
|
17
|
+
*/
|
|
18
|
+
get(id) {
|
|
19
|
+
return this.adapters.get(id);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* List all registered adapters
|
|
23
|
+
*/
|
|
24
|
+
list() {
|
|
25
|
+
return Array.from(this.adapters.values());
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Find adapters compatible with an agent
|
|
29
|
+
*/
|
|
30
|
+
findCompatible(agent) {
|
|
31
|
+
return this.list().filter(adapter => {
|
|
32
|
+
const result = adapter.canConvert(agent);
|
|
33
|
+
return result.canConvert;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check if an adapter ID is valid
|
|
38
|
+
*/
|
|
39
|
+
has(id) {
|
|
40
|
+
return this.adapters.has(id);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get all adapter IDs
|
|
44
|
+
*/
|
|
45
|
+
getIds() {
|
|
46
|
+
return Array.from(this.adapters.keys());
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.AdapterRegistry = AdapterRegistry;
|
|
50
|
+
// Global registry instance
|
|
51
|
+
exports.adapterRegistry = new AdapterRegistry();
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerConfigCommand = registerConfigCommand;
|
|
4
|
+
const config_1 = require("../lib/config");
|
|
5
|
+
const errors_1 = require("../lib/errors");
|
|
6
|
+
const SUPPORTED_KEYS = ['default-format'];
|
|
7
|
+
function isValidKey(key) {
|
|
8
|
+
return SUPPORTED_KEYS.includes(key);
|
|
9
|
+
}
|
|
10
|
+
async function setConfigValue(key, value) {
|
|
11
|
+
if (!isValidKey(key)) {
|
|
12
|
+
throw new errors_1.CliError(`Unknown config key: ${key}. Supported keys: ${SUPPORTED_KEYS.join(', ')}`);
|
|
13
|
+
}
|
|
14
|
+
if (key === 'default-format') {
|
|
15
|
+
const formats = value.split(',').map((f) => f.trim()).filter(Boolean);
|
|
16
|
+
// Validate all format IDs
|
|
17
|
+
const invalidFormats = formats.filter((f) => !config_1.VALID_FORMAT_IDS.includes(f));
|
|
18
|
+
if (invalidFormats.length > 0) {
|
|
19
|
+
throw new errors_1.CliError(`Invalid format ID(s): ${invalidFormats.join(', ')}. Valid formats: ${config_1.VALID_FORMAT_IDS.join(', ')}`);
|
|
20
|
+
}
|
|
21
|
+
await (0, config_1.setDefaultFormats)(formats);
|
|
22
|
+
process.stdout.write(`Set default-format to: ${formats.join(',')}\n`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async function getConfigValue(key) {
|
|
26
|
+
if (!isValidKey(key)) {
|
|
27
|
+
throw new errors_1.CliError(`Unknown config key: ${key}. Supported keys: ${SUPPORTED_KEYS.join(', ')}`);
|
|
28
|
+
}
|
|
29
|
+
if (key === 'default-format') {
|
|
30
|
+
const formats = await (0, config_1.getDefaultFormats)();
|
|
31
|
+
if (formats.length === 0) {
|
|
32
|
+
process.stdout.write('(not set)\n');
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
process.stdout.write(`${formats.join(',')}\n`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function listConfigValues() {
|
|
40
|
+
const config = await (0, config_1.loadConfig)();
|
|
41
|
+
process.stdout.write('CLI Configuration:\n\n');
|
|
42
|
+
// default-format
|
|
43
|
+
const formats = config.default_formats ?? [];
|
|
44
|
+
if (formats.length > 0) {
|
|
45
|
+
process.stdout.write(` default-format: ${formats.join(',')}\n`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
process.stdout.write(' default-format: (not set)\n');
|
|
49
|
+
}
|
|
50
|
+
process.stdout.write('\n');
|
|
51
|
+
}
|
|
52
|
+
function registerConfigCommand(program) {
|
|
53
|
+
const config = program
|
|
54
|
+
.command('config')
|
|
55
|
+
.description('Manage CLI configuration');
|
|
56
|
+
config
|
|
57
|
+
.command('set <key> <value>')
|
|
58
|
+
.description('Set a configuration value')
|
|
59
|
+
.action(async (key, value) => {
|
|
60
|
+
await setConfigValue(key, value);
|
|
61
|
+
});
|
|
62
|
+
config
|
|
63
|
+
.command('get <key>')
|
|
64
|
+
.description('Get a configuration value')
|
|
65
|
+
.action(async (key) => {
|
|
66
|
+
await getConfigValue(key);
|
|
67
|
+
});
|
|
68
|
+
config
|
|
69
|
+
.command('list')
|
|
70
|
+
.description('List all configuration values')
|
|
71
|
+
.action(async () => {
|
|
72
|
+
await listConfigValues();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerFormatsCommand = registerFormatsCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const adapters_1 = require("../adapters");
|
|
9
|
+
function registerFormatsCommand(program) {
|
|
10
|
+
program
|
|
11
|
+
.command('formats')
|
|
12
|
+
.description('List available export formats for agents')
|
|
13
|
+
.option('--json', 'Output raw JSON')
|
|
14
|
+
.action(async (options) => {
|
|
15
|
+
const adapters = adapters_1.adapterRegistry.list();
|
|
16
|
+
if (options.json) {
|
|
17
|
+
const data = adapters.map(a => ({
|
|
18
|
+
id: a.id,
|
|
19
|
+
name: a.name,
|
|
20
|
+
version: a.version,
|
|
21
|
+
formatVersion: a.formatVersion,
|
|
22
|
+
supportsAgentTypes: a.supportsAgentTypes,
|
|
23
|
+
installPaths: a.installPaths,
|
|
24
|
+
}));
|
|
25
|
+
process.stdout.write(JSON.stringify(data, null, 2) + '\n');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
process.stdout.write('\nAvailable export formats:\n\n');
|
|
29
|
+
for (const adapter of adapters) {
|
|
30
|
+
process.stdout.write(` ${chalk_1.default.cyan(adapter.id)} ${adapter.name}\n`);
|
|
31
|
+
process.stdout.write(` Supports: ${adapter.supportsAgentTypes.join(', ')} agents\n`);
|
|
32
|
+
process.stdout.write(` Format version: ${adapter.formatVersion}\n`);
|
|
33
|
+
for (const installPath of adapter.installPaths) {
|
|
34
|
+
const pathDisplay = installPath.scope === 'user'
|
|
35
|
+
? installPath.path
|
|
36
|
+
: installPath.path;
|
|
37
|
+
process.stdout.write(` ${installPath.scope}: ${pathDisplay}\n`);
|
|
38
|
+
}
|
|
39
|
+
process.stdout.write('\n');
|
|
40
|
+
}
|
|
41
|
+
process.stdout.write('Use with: orch install <agent> --format <id>\n');
|
|
42
|
+
process.stdout.write('Set default: orch config set default-format <ids>\n\n');
|
|
43
|
+
});
|
|
44
|
+
}
|
package/dist/commands/index.js
CHANGED
|
@@ -21,6 +21,10 @@ const status_1 = require("./status");
|
|
|
21
21
|
const workspace_1 = require("./workspace");
|
|
22
22
|
const tree_1 = require("./tree");
|
|
23
23
|
const docs_1 = require("./docs");
|
|
24
|
+
const config_1 = require("./config");
|
|
25
|
+
const install_1 = require("./install");
|
|
26
|
+
const formats_1 = require("./formats");
|
|
27
|
+
const update_1 = require("./update");
|
|
24
28
|
function registerCommands(program) {
|
|
25
29
|
(0, login_1.registerLoginCommand)(program);
|
|
26
30
|
(0, whoami_1.registerWhoamiCommand)(program);
|
|
@@ -42,4 +46,8 @@ function registerCommands(program) {
|
|
|
42
46
|
(0, workspace_1.registerWorkspaceCommand)(program);
|
|
43
47
|
(0, tree_1.registerTreeCommand)(program);
|
|
44
48
|
(0, docs_1.registerDocsCommand)(program);
|
|
49
|
+
(0, config_1.registerConfigCommand)(program);
|
|
50
|
+
(0, install_1.registerInstallCommand)(program);
|
|
51
|
+
(0, formats_1.registerFormatsCommand)(program);
|
|
52
|
+
(0, update_1.registerUpdateCommand)(program);
|
|
45
53
|
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerInstallCommand = registerInstallCommand;
|
|
7
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const os_1 = __importDefault(require("os"));
|
|
10
|
+
const config_1 = require("../lib/config");
|
|
11
|
+
const api_1 = require("../lib/api");
|
|
12
|
+
const errors_1 = require("../lib/errors");
|
|
13
|
+
const analytics_1 = require("../lib/analytics");
|
|
14
|
+
const adapters_1 = require("../adapters");
|
|
15
|
+
const installed_1 = require("../lib/installed");
|
|
16
|
+
const DEFAULT_VERSION = 'v1';
|
|
17
|
+
function parseAgentRef(value) {
|
|
18
|
+
const [ref, versionPart] = value.split('@');
|
|
19
|
+
const version = versionPart?.trim() || DEFAULT_VERSION;
|
|
20
|
+
const segments = ref.split('/');
|
|
21
|
+
if (segments.length === 1) {
|
|
22
|
+
return { name: segments[0], version };
|
|
23
|
+
}
|
|
24
|
+
if (segments.length === 2) {
|
|
25
|
+
return { org: segments[0], name: segments[1], version };
|
|
26
|
+
}
|
|
27
|
+
throw new errors_1.CliError('Invalid agent reference. Use org/agent or agent format.');
|
|
28
|
+
}
|
|
29
|
+
async function downloadAgentWithFallback(config, org, name, version) {
|
|
30
|
+
// Try public endpoint first
|
|
31
|
+
try {
|
|
32
|
+
const agent = await (0, api_1.publicRequest)(config, `/public/agents/${org}/${name}/${version}`);
|
|
33
|
+
return { ...agent, org_slug: org };
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
if (!(err instanceof api_1.ApiError) || err.status !== 404)
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
// Fallback to authenticated endpoint for private agents
|
|
40
|
+
if (!config.apiKey) {
|
|
41
|
+
throw new api_1.ApiError(`Agent '${org}/${name}@${version}' not found`, 404);
|
|
42
|
+
}
|
|
43
|
+
const userOrg = await (0, api_1.getOrg)(config);
|
|
44
|
+
if (userOrg.slug !== org) {
|
|
45
|
+
throw new api_1.ApiError(`Agent '${org}/${name}@${version}' not found`, 404);
|
|
46
|
+
}
|
|
47
|
+
const agents = await (0, api_1.listMyAgents)(config);
|
|
48
|
+
const matching = agents.filter(a => a.name === name);
|
|
49
|
+
if (matching.length === 0) {
|
|
50
|
+
throw new api_1.ApiError(`Agent '${org}/${name}@${version}' not found`, 404);
|
|
51
|
+
}
|
|
52
|
+
let targetAgent;
|
|
53
|
+
if (version === 'latest') {
|
|
54
|
+
targetAgent = matching.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0];
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const found = matching.find(a => a.version === version);
|
|
58
|
+
if (!found) {
|
|
59
|
+
throw new api_1.ApiError(`Agent '${org}/${name}@${version}' not found`, 404);
|
|
60
|
+
}
|
|
61
|
+
targetAgent = found;
|
|
62
|
+
}
|
|
63
|
+
return { ...targetAgent, org_slug: org };
|
|
64
|
+
}
|
|
65
|
+
function registerInstallCommand(program) {
|
|
66
|
+
program
|
|
67
|
+
.command('install <agent>')
|
|
68
|
+
.description('Install agent as sub-agent (Claude Code, Cursor, etc.)')
|
|
69
|
+
.option('--format <formats>', 'Comma-separated format IDs (e.g., claude-code,cursor)')
|
|
70
|
+
.option('--scope <scope>', 'Install scope: user (home dir) or project (current dir)', 'user')
|
|
71
|
+
.option('--dry-run', 'Show what would be installed without making changes')
|
|
72
|
+
.action(async (agentArg, options) => {
|
|
73
|
+
const resolved = await (0, config_1.getResolvedConfig)();
|
|
74
|
+
const parsed = parseAgentRef(agentArg);
|
|
75
|
+
const org = parsed.org ?? resolved.defaultOrg;
|
|
76
|
+
if (!org) {
|
|
77
|
+
throw new errors_1.CliError('Missing org. Use org/agent format or set default org.');
|
|
78
|
+
}
|
|
79
|
+
// Determine target formats
|
|
80
|
+
let targetFormats = [];
|
|
81
|
+
if (options.format) {
|
|
82
|
+
targetFormats = options.format.split(',').map(f => f.trim());
|
|
83
|
+
const invalid = targetFormats.filter(f => !adapters_1.adapterRegistry.has(f));
|
|
84
|
+
if (invalid.length > 0) {
|
|
85
|
+
throw new errors_1.CliError(`Unknown format(s): ${invalid.join(', ')}. Available: ${adapters_1.adapterRegistry.getIds().join(', ')}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const defaults = await (0, config_1.getDefaultFormats)();
|
|
90
|
+
if (defaults.length > 0) {
|
|
91
|
+
targetFormats = defaults;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// No default configured - use claude-code as sensible default
|
|
95
|
+
targetFormats = ['claude-code'];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Validate scope
|
|
99
|
+
const scope = options.scope;
|
|
100
|
+
if (scope !== 'user' && scope !== 'project') {
|
|
101
|
+
throw new errors_1.CliError('Scope must be "user" or "project"');
|
|
102
|
+
}
|
|
103
|
+
// Download agent
|
|
104
|
+
process.stdout.write(`Fetching ${org}/${parsed.name}@${parsed.version}...\n`);
|
|
105
|
+
const agent = await downloadAgentWithFallback(resolved, org, parsed.name, parsed.version);
|
|
106
|
+
// Install for each format
|
|
107
|
+
for (const formatId of targetFormats) {
|
|
108
|
+
const adapter = adapters_1.adapterRegistry.get(formatId);
|
|
109
|
+
if (!adapter) {
|
|
110
|
+
process.stderr.write(`Warning: Unknown format '${formatId}', skipping\n`);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
// Check if can convert
|
|
114
|
+
const checkResult = adapter.canConvert(agent);
|
|
115
|
+
if (!checkResult.canConvert) {
|
|
116
|
+
process.stderr.write(`Cannot convert to ${adapter.name}:\n`);
|
|
117
|
+
for (const err of checkResult.errors) {
|
|
118
|
+
process.stderr.write(` - ${err}\n`);
|
|
119
|
+
}
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
// Show warnings
|
|
123
|
+
for (const warn of checkResult.warnings) {
|
|
124
|
+
process.stdout.write(`Warning (${formatId}): ${warn}\n`);
|
|
125
|
+
}
|
|
126
|
+
// Convert
|
|
127
|
+
const files = adapter.convert(agent);
|
|
128
|
+
// Determine base directory
|
|
129
|
+
const baseDir = scope === 'user' ? os_1.default.homedir() : process.cwd();
|
|
130
|
+
// Install each file
|
|
131
|
+
for (const file of files) {
|
|
132
|
+
const fullDir = path_1.default.join(baseDir, file.installPath);
|
|
133
|
+
const fullPath = path_1.default.join(fullDir, file.filename);
|
|
134
|
+
if (options.dryRun) {
|
|
135
|
+
process.stdout.write(`Would install: ${fullPath}\n`);
|
|
136
|
+
process.stdout.write(`Content preview:\n${file.content.slice(0, 500)}...\n\n`);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
// Create directory and write file
|
|
140
|
+
await promises_1.default.mkdir(fullDir, { recursive: true });
|
|
141
|
+
await promises_1.default.writeFile(fullPath, file.content);
|
|
142
|
+
// Track installation
|
|
143
|
+
const installedAgent = {
|
|
144
|
+
agent: `${org}/${parsed.name}`,
|
|
145
|
+
version: parsed.version,
|
|
146
|
+
format: formatId,
|
|
147
|
+
scope,
|
|
148
|
+
path: fullPath,
|
|
149
|
+
installedAt: new Date().toISOString(),
|
|
150
|
+
adapterVersion: adapter.version,
|
|
151
|
+
contentHash: (0, installed_1.computeHash)(file.content),
|
|
152
|
+
};
|
|
153
|
+
await (0, installed_1.trackInstall)(installedAgent);
|
|
154
|
+
process.stdout.write(`Installed: ${fullPath}\n`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (!options.dryRun) {
|
|
158
|
+
await (0, analytics_1.track)('cli_agent_install', {
|
|
159
|
+
agent: `${org}/${parsed.name}`,
|
|
160
|
+
formats: targetFormats,
|
|
161
|
+
scope,
|
|
162
|
+
});
|
|
163
|
+
process.stdout.write(`\nAgent installed successfully!\n`);
|
|
164
|
+
if (scope === 'user') {
|
|
165
|
+
process.stdout.write(`Available in all your projects.\n`);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
process.stdout.write(`Available in this project only.\n`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
package/dist/commands/skill.js
CHANGED
|
@@ -162,8 +162,29 @@ Instructions and guidance for AI agents...
|
|
|
162
162
|
.description('Install skill to local AI tool directories (Claude Code, Cursor, etc.)')
|
|
163
163
|
.option('--global', 'Install to home directory (default: current directory)')
|
|
164
164
|
.option('--dry-run', 'Show what would be installed without making changes')
|
|
165
|
+
.option('--format <formats>', 'Comma-separated format IDs (e.g., claude-code,cursor)')
|
|
165
166
|
.action(async (skillRef, options) => {
|
|
166
167
|
const resolved = await (0, config_1.getResolvedConfig)();
|
|
168
|
+
// Determine target formats
|
|
169
|
+
let targetFormats = [];
|
|
170
|
+
if (options.format) {
|
|
171
|
+
targetFormats = options.format.split(',').map((f) => f.trim());
|
|
172
|
+
// Validate format IDs
|
|
173
|
+
const invalid = targetFormats.filter(f => !config_1.VALID_FORMAT_IDS.includes(f));
|
|
174
|
+
if (invalid.length > 0) {
|
|
175
|
+
throw new errors_1.CliError(`Invalid format ID(s): ${invalid.join(', ')}. Valid: ${config_1.VALID_FORMAT_IDS.join(', ')}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
const defaults = await (0, config_1.getDefaultFormats)();
|
|
180
|
+
if (defaults.length > 0) {
|
|
181
|
+
targetFormats = defaults;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Determine target directories
|
|
185
|
+
const toolDirs = targetFormats.length > 0
|
|
186
|
+
? targetFormats.map(f => config_1.FORMAT_SKILL_DIRS[f])
|
|
187
|
+
: AI_TOOL_SKILL_DIRS; // fallback to all
|
|
167
188
|
const parsed = parseSkillRef(skillRef);
|
|
168
189
|
const org = parsed.org ?? resolved.defaultOrg;
|
|
169
190
|
if (!org) {
|
|
@@ -191,7 +212,7 @@ ${skillData.prompt}
|
|
|
191
212
|
if (options.dryRun) {
|
|
192
213
|
process.stdout.write(`Would install ${org}/${parsed.skill}@${parsed.version}\n\n`);
|
|
193
214
|
process.stdout.write(`Target directories:\n`);
|
|
194
|
-
for (const tool of
|
|
215
|
+
for (const tool of toolDirs) {
|
|
195
216
|
const skillDir = path_1.default.join(baseDir, tool.path);
|
|
196
217
|
const skillFile = path_1.default.join(skillDir, `${parsed.skill}.md`);
|
|
197
218
|
process.stdout.write(` - ${tool.name}: ${skillFile}\n`);
|
|
@@ -199,9 +220,9 @@ ${skillData.prompt}
|
|
|
199
220
|
process.stdout.write(`\nNo changes made (dry run)\n`);
|
|
200
221
|
return;
|
|
201
222
|
}
|
|
202
|
-
// Install to
|
|
223
|
+
// Install to target AI tool directories
|
|
203
224
|
const installed = [];
|
|
204
|
-
for (const tool of
|
|
225
|
+
for (const tool of toolDirs) {
|
|
205
226
|
const skillDir = path_1.default.join(baseDir, tool.path);
|
|
206
227
|
const skillFile = path_1.default.join(skillDir, `${parsed.skill}.md`);
|
|
207
228
|
try {
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerUpdateCommand = registerUpdateCommand;
|
|
7
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const config_1 = require("../lib/config");
|
|
11
|
+
const api_1 = require("../lib/api");
|
|
12
|
+
const analytics_1 = require("../lib/analytics");
|
|
13
|
+
const adapters_1 = require("../adapters");
|
|
14
|
+
const installed_1 = require("../lib/installed");
|
|
15
|
+
async function fetchLatestAgent(config, agentRef) {
|
|
16
|
+
const [org, name] = agentRef.split('/');
|
|
17
|
+
if (!org || !name)
|
|
18
|
+
return null;
|
|
19
|
+
try {
|
|
20
|
+
// Try to get latest version
|
|
21
|
+
const agent = await (0, api_1.publicRequest)(config, `/public/agents/${org}/${name}/latest`);
|
|
22
|
+
return {
|
|
23
|
+
agent: { ...agent, org_slug: org },
|
|
24
|
+
latestVersion: agent.version
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
if (err instanceof api_1.ApiError && err.status === 404) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function registerUpdateCommand(program) {
|
|
35
|
+
program
|
|
36
|
+
.command('update [agent]')
|
|
37
|
+
.description('Update installed agents to latest versions')
|
|
38
|
+
.option('--check', 'Check for updates without installing')
|
|
39
|
+
.option('--force', 'Force update even if file was modified locally')
|
|
40
|
+
.action(async (agentRef, options) => {
|
|
41
|
+
const resolved = await (0, config_1.getResolvedConfig)();
|
|
42
|
+
const installed = await (0, installed_1.getInstalled)();
|
|
43
|
+
if (installed.length === 0) {
|
|
44
|
+
process.stdout.write('No agents installed. Use "orch install <agent>" to install agents.\n');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Filter to specific agent if provided
|
|
48
|
+
const toCheck = agentRef
|
|
49
|
+
? installed.filter(i => i.agent === agentRef)
|
|
50
|
+
: installed;
|
|
51
|
+
if (toCheck.length === 0) {
|
|
52
|
+
process.stdout.write(`Agent "${agentRef}" is not installed.\n`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
process.stdout.write(`Checking ${toCheck.length} installed agent(s) for updates...\n\n`);
|
|
56
|
+
let updatesAvailable = 0;
|
|
57
|
+
let updatesApplied = 0;
|
|
58
|
+
let skippedModified = 0;
|
|
59
|
+
for (const item of toCheck) {
|
|
60
|
+
// Check if file was modified locally
|
|
61
|
+
const wasModified = await (0, installed_1.checkModified)(item);
|
|
62
|
+
// Fetch latest version
|
|
63
|
+
const latest = await fetchLatestAgent(resolved, item.agent);
|
|
64
|
+
if (!latest) {
|
|
65
|
+
process.stdout.write(` ${chalk_1.default.yellow('?')} ${item.agent} - could not fetch latest\n`);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const hasUpdate = latest.latestVersion !== item.version;
|
|
69
|
+
if (!hasUpdate && !wasModified) {
|
|
70
|
+
process.stdout.write(` ${chalk_1.default.green('✓')} ${item.agent}@${item.version} - up to date\n`);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (wasModified && !options.force) {
|
|
74
|
+
process.stdout.write(` ${chalk_1.default.yellow('!')} ${item.agent} - local modifications (use --force to overwrite)\n`);
|
|
75
|
+
skippedModified++;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (hasUpdate) {
|
|
79
|
+
updatesAvailable++;
|
|
80
|
+
process.stdout.write(` ${chalk_1.default.blue('↑')} ${item.agent}@${item.version} → ${latest.latestVersion}`);
|
|
81
|
+
if (wasModified) {
|
|
82
|
+
process.stdout.write(` ${chalk_1.default.yellow('(modified)')}`);
|
|
83
|
+
}
|
|
84
|
+
process.stdout.write('\n');
|
|
85
|
+
if (options.check) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// Apply update
|
|
89
|
+
const adapter = adapters_1.adapterRegistry.get(item.format);
|
|
90
|
+
if (!adapter) {
|
|
91
|
+
process.stderr.write(` Skipped: Unknown format "${item.format}"\n`);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const checkResult = adapter.canConvert(latest.agent);
|
|
95
|
+
if (!checkResult.canConvert) {
|
|
96
|
+
process.stderr.write(` Skipped: ${checkResult.errors.join(', ')}\n`);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const files = adapter.convert(latest.agent);
|
|
100
|
+
for (const file of files) {
|
|
101
|
+
// Use the original path from tracking
|
|
102
|
+
const fullPath = item.path;
|
|
103
|
+
try {
|
|
104
|
+
const dir = path_1.default.dirname(fullPath);
|
|
105
|
+
await promises_1.default.mkdir(dir, { recursive: true });
|
|
106
|
+
await promises_1.default.writeFile(fullPath, file.content);
|
|
107
|
+
// Update tracking
|
|
108
|
+
const updatedItem = {
|
|
109
|
+
...item,
|
|
110
|
+
version: latest.latestVersion,
|
|
111
|
+
installedAt: new Date().toISOString(),
|
|
112
|
+
adapterVersion: adapter.version,
|
|
113
|
+
contentHash: (0, installed_1.computeHash)(file.content),
|
|
114
|
+
};
|
|
115
|
+
await (0, installed_1.trackInstall)(updatedItem);
|
|
116
|
+
process.stdout.write(` Updated: ${fullPath}\n`);
|
|
117
|
+
updatesApplied++;
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
process.stderr.write(` Error: ${err.message}\n`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
process.stdout.write('\n');
|
|
126
|
+
if (options.check) {
|
|
127
|
+
process.stdout.write(`Found ${updatesAvailable} update(s) available.\n`);
|
|
128
|
+
if (skippedModified > 0) {
|
|
129
|
+
process.stdout.write(`${skippedModified} agent(s) have local modifications.\n`);
|
|
130
|
+
}
|
|
131
|
+
process.stdout.write('Run "orch update" without --check to apply updates.\n');
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
process.stdout.write(`Applied ${updatesApplied} update(s).\n`);
|
|
135
|
+
if (skippedModified > 0) {
|
|
136
|
+
process.stdout.write(`Skipped ${skippedModified} modified agent(s). Use --force to overwrite.\n`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
await (0, analytics_1.track)('cli_agent_update', {
|
|
140
|
+
checked: toCheck.length,
|
|
141
|
+
updatesAvailable,
|
|
142
|
+
updatesApplied,
|
|
143
|
+
skippedModified,
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
package/dist/lib/config.js
CHANGED
|
@@ -3,16 +3,30 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FORMAT_SKILL_DIRS = exports.VALID_FORMAT_IDS = void 0;
|
|
6
7
|
exports.loadConfig = loadConfig;
|
|
7
8
|
exports.saveConfig = saveConfig;
|
|
8
9
|
exports.getResolvedConfig = getResolvedConfig;
|
|
9
10
|
exports.getConfigPath = getConfigPath;
|
|
11
|
+
exports.getDefaultFormats = getDefaultFormats;
|
|
12
|
+
exports.setDefaultFormats = setDefaultFormats;
|
|
10
13
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
11
14
|
const path_1 = __importDefault(require("path"));
|
|
12
15
|
const os_1 = __importDefault(require("os"));
|
|
13
16
|
const CONFIG_DIR = path_1.default.join(os_1.default.homedir(), '.orchagent');
|
|
14
17
|
const CONFIG_PATH = path_1.default.join(CONFIG_DIR, 'config.json');
|
|
15
18
|
const DEFAULT_API_URL = 'https://api.orchagent.io';
|
|
19
|
+
// Valid format IDs for multi-format agent export
|
|
20
|
+
exports.VALID_FORMAT_IDS = ['claude-code', 'cursor', 'codex', 'amp', 'opencode', 'antigravity'];
|
|
21
|
+
// Map format IDs to skill directories (used by skill install and agent install)
|
|
22
|
+
exports.FORMAT_SKILL_DIRS = {
|
|
23
|
+
'claude-code': { name: 'Claude Code', path: '.claude/skills' },
|
|
24
|
+
'cursor': { name: 'Cursor', path: '.cursor/skills' },
|
|
25
|
+
'codex': { name: 'Codex', path: '.codex/skills' },
|
|
26
|
+
'amp': { name: 'Amp', path: '.agents/skills' },
|
|
27
|
+
'opencode': { name: 'OpenCode', path: '.opencode/skill' },
|
|
28
|
+
'antigravity': { name: 'Antigravity', path: '.agent/skills' },
|
|
29
|
+
};
|
|
16
30
|
async function loadConfig() {
|
|
17
31
|
try {
|
|
18
32
|
const raw = await promises_1.default.readFile(CONFIG_PATH, 'utf-8');
|
|
@@ -56,3 +70,12 @@ async function getResolvedConfig(overrides = {}, profile) {
|
|
|
56
70
|
function getConfigPath() {
|
|
57
71
|
return CONFIG_PATH;
|
|
58
72
|
}
|
|
73
|
+
async function getDefaultFormats() {
|
|
74
|
+
const config = await loadConfig();
|
|
75
|
+
return config.default_formats ?? [];
|
|
76
|
+
}
|
|
77
|
+
async function setDefaultFormats(formats) {
|
|
78
|
+
const config = await loadConfig();
|
|
79
|
+
config.default_formats = formats;
|
|
80
|
+
await saveConfig(config);
|
|
81
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.computeHash = computeHash;
|
|
7
|
+
exports.loadInstalled = loadInstalled;
|
|
8
|
+
exports.saveInstalled = saveInstalled;
|
|
9
|
+
exports.trackInstall = trackInstall;
|
|
10
|
+
exports.getInstalled = getInstalled;
|
|
11
|
+
exports.getInstalledByFormat = getInstalledByFormat;
|
|
12
|
+
exports.checkModified = checkModified;
|
|
13
|
+
exports.untrackInstall = untrackInstall;
|
|
14
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
15
|
+
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const os_1 = __importDefault(require("os"));
|
|
17
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
18
|
+
const ORCHAGENT_DIR = path_1.default.join(os_1.default.homedir(), '.orchagent');
|
|
19
|
+
const INSTALLED_PATH = path_1.default.join(ORCHAGENT_DIR, 'installed.json');
|
|
20
|
+
/**
|
|
21
|
+
* Compute SHA-256 hash of content
|
|
22
|
+
*/
|
|
23
|
+
function computeHash(content) {
|
|
24
|
+
return crypto_1.default.createHash('sha256').update(content).digest('hex');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Load installed agents from tracking file
|
|
28
|
+
*/
|
|
29
|
+
async function loadInstalled() {
|
|
30
|
+
try {
|
|
31
|
+
const raw = await promises_1.default.readFile(INSTALLED_PATH, 'utf-8');
|
|
32
|
+
return JSON.parse(raw);
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
if (err.code === 'ENOENT') {
|
|
36
|
+
return { version: 1, installed: [] };
|
|
37
|
+
}
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Save installed agents to tracking file
|
|
43
|
+
*/
|
|
44
|
+
async function saveInstalled(data) {
|
|
45
|
+
await promises_1.default.mkdir(ORCHAGENT_DIR, { recursive: true });
|
|
46
|
+
await promises_1.default.writeFile(INSTALLED_PATH, JSON.stringify(data, null, 2) + '\n');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Track a newly installed agent
|
|
50
|
+
*/
|
|
51
|
+
async function trackInstall(agent) {
|
|
52
|
+
const data = await loadInstalled();
|
|
53
|
+
// Remove any existing entry for same agent/format/scope/path
|
|
54
|
+
data.installed = data.installed.filter(i => !(i.agent === agent.agent && i.format === agent.format && i.path === agent.path));
|
|
55
|
+
// Add new entry
|
|
56
|
+
data.installed.push(agent);
|
|
57
|
+
await saveInstalled(data);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get all installed agents
|
|
61
|
+
*/
|
|
62
|
+
async function getInstalled() {
|
|
63
|
+
const data = await loadInstalled();
|
|
64
|
+
return data.installed;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get installed agents filtered by format
|
|
68
|
+
*/
|
|
69
|
+
async function getInstalledByFormat(format) {
|
|
70
|
+
const data = await loadInstalled();
|
|
71
|
+
return data.installed.filter(i => i.format === format);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if a file has been modified since installation
|
|
75
|
+
*/
|
|
76
|
+
async function checkModified(installed) {
|
|
77
|
+
try {
|
|
78
|
+
const content = await promises_1.default.readFile(installed.path, 'utf-8');
|
|
79
|
+
const currentHash = computeHash(content);
|
|
80
|
+
return currentHash !== installed.contentHash;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// File doesn't exist or can't be read
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Remove an installed agent from tracking
|
|
89
|
+
*/
|
|
90
|
+
async function untrackInstall(agentRef, format, filePath) {
|
|
91
|
+
const data = await loadInstalled();
|
|
92
|
+
data.installed = data.installed.filter(i => !(i.agent === agentRef && i.format === format && i.path === filePath));
|
|
93
|
+
await saveInstalled(data);
|
|
94
|
+
}
|