@orchagent/cli 0.3.31 → 0.3.34

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.
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveSkills = resolveSkills;
4
+ const api_1 = require("./api");
5
+ function parseSkillRef(ref) {
6
+ const [namePart, versionPart] = ref.split('@');
7
+ const version = versionPart?.trim() || 'latest';
8
+ const segments = namePart.split('/');
9
+ if (segments.length !== 2 || !segments[0] || !segments[1]) {
10
+ throw new Error(`Invalid skill reference: ${ref}. Expected format: org/name[@version]`);
11
+ }
12
+ return { org: segments[0], name: segments[1], version };
13
+ }
14
+ /**
15
+ * Download a single skill's content.
16
+ * Tries public endpoint first, falls back to authenticated for private skills.
17
+ * Returns null if the skill can't be found.
18
+ */
19
+ async function downloadSkill(config, org, name, version) {
20
+ // Try public download endpoint first
21
+ try {
22
+ return await (0, api_1.publicRequest)(config, `/public/agents/${org}/${name}/${version}/download`);
23
+ }
24
+ catch (err) {
25
+ if (!(err instanceof api_1.ApiError) || err.status !== 404) {
26
+ // Non-404 errors (network, 500, etc.) - rethrow
27
+ throw err;
28
+ }
29
+ }
30
+ // Public not found - try authenticated endpoint for private skills
31
+ if (!config.apiKey) {
32
+ return null;
33
+ }
34
+ try {
35
+ const userOrg = await (0, api_1.getOrg)(config);
36
+ if (userOrg.slug !== org) {
37
+ return null;
38
+ }
39
+ const agents = await (0, api_1.listMyAgents)(config);
40
+ const matching = agents.filter(a => a.name === name && a.type === 'skill');
41
+ if (matching.length === 0) {
42
+ return null;
43
+ }
44
+ let target;
45
+ if (version === 'latest') {
46
+ target = matching.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0];
47
+ }
48
+ else {
49
+ const found = matching.find(a => a.version === version);
50
+ if (!found)
51
+ return null;
52
+ target = found;
53
+ }
54
+ return {
55
+ name: target.name,
56
+ version: target.version,
57
+ description: target.description,
58
+ prompt: target.prompt,
59
+ };
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ }
65
+ /**
66
+ * Resolve an array of skill references to their full content.
67
+ * Fetches each skill from the API and returns resolved skills with prompts.
68
+ * Skills that can't be fetched are skipped with a warning.
69
+ */
70
+ async function resolveSkills(config, skillRefs, onWarning) {
71
+ const resolved = [];
72
+ for (const ref of skillRefs) {
73
+ let parsed;
74
+ try {
75
+ parsed = parseSkillRef(ref);
76
+ }
77
+ catch {
78
+ onWarning?.(`Skipping invalid skill reference: ${ref}`);
79
+ continue;
80
+ }
81
+ try {
82
+ const skill = await downloadSkill(config, parsed.org, parsed.name, parsed.version);
83
+ if (!skill || !skill.prompt) {
84
+ onWarning?.(`Could not resolve skill '${ref}' (not found or empty)`);
85
+ continue;
86
+ }
87
+ resolved.push({
88
+ ref,
89
+ name: skill.name,
90
+ description: skill.description,
91
+ prompt: skill.prompt,
92
+ });
93
+ }
94
+ catch (err) {
95
+ onWarning?.(`Could not fetch skill '${ref}': ${err instanceof Error ? err.message : String(err)}`);
96
+ }
97
+ }
98
+ return resolved;
99
+ }
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ /**
3
+ * Lightweight CLI update notifier.
4
+ *
5
+ * Design goals:
6
+ * 1. NEVER crash or block the CLI — every call is wrapped in try/catch
7
+ * 2. Zero npm dependencies — uses only Node built-ins (https, fs, path, os)
8
+ * 3. Works on Node 14+ — avoids fetch(), AbortController, and other modern APIs
9
+ * 4. Non-blocking — the HTTP check uses req.unref() so it won't prevent process exit
10
+ * 5. Cached — checks npm registry at most once per 24 hours
11
+ *
12
+ * Flow:
13
+ * - On startup: read ~/.orchagent/update-check.json (sync, ~1ms)
14
+ * - If cache is stale (>24h): fire off a background HTTPS GET to registry, write result
15
+ * - After command completes: if cached version > current version, print one-line notice
16
+ */
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.checkForUpdates = checkForUpdates;
22
+ exports.printUpdateNotification = printUpdateNotification;
23
+ const https_1 = __importDefault(require("https"));
24
+ const fs_1 = __importDefault(require("fs"));
25
+ const path_1 = __importDefault(require("path"));
26
+ const os_1 = __importDefault(require("os"));
27
+ const package_json_1 = __importDefault(require("../../package.json"));
28
+ const PACKAGE_NAME = '@orchagent/cli';
29
+ const CACHE_DIR = path_1.default.join(os_1.default.homedir(), '.orchagent');
30
+ const CACHE_PATH = path_1.default.join(CACHE_DIR, 'update-check.json');
31
+ const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
32
+ const REQUEST_TIMEOUT_MS = 5000;
33
+ // ── Cache I/O ──────────────────────────────────────────────────────────
34
+ function readCache() {
35
+ try {
36
+ const raw = fs_1.default.readFileSync(CACHE_PATH, 'utf-8');
37
+ const parsed = JSON.parse(raw);
38
+ if (parsed && typeof parsed.latest === 'string' && typeof parsed.checkedAt === 'number') {
39
+ return parsed;
40
+ }
41
+ return null;
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ function writeCache(latest) {
48
+ try {
49
+ fs_1.default.mkdirSync(CACHE_DIR, { recursive: true });
50
+ fs_1.default.writeFileSync(CACHE_PATH, JSON.stringify({ latest, checkedAt: Date.now() }));
51
+ }
52
+ catch {
53
+ // Best-effort — silently ignore write failures
54
+ }
55
+ }
56
+ function isCacheStale(cache) {
57
+ if (!cache)
58
+ return true;
59
+ return Date.now() - cache.checkedAt > CHECK_INTERVAL_MS;
60
+ }
61
+ // ── Version comparison ─────────────────────────────────────────────────
62
+ function isNewer(latest, current) {
63
+ const a = latest.split('.').map(Number);
64
+ const b = current.split('.').map(Number);
65
+ for (let i = 0; i < 3; i++) {
66
+ if ((a[i] || 0) > (b[i] || 0))
67
+ return true;
68
+ if ((a[i] || 0) < (b[i] || 0))
69
+ return false;
70
+ }
71
+ return false;
72
+ }
73
+ // ── Background check ───────────────────────────────────────────────────
74
+ function triggerBackgroundCheck() {
75
+ try {
76
+ const url = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`;
77
+ const req = https_1.default.get(url, { timeout: REQUEST_TIMEOUT_MS }, (res) => {
78
+ if (res.statusCode !== 200) {
79
+ res.resume(); // drain
80
+ return;
81
+ }
82
+ let data = '';
83
+ res.on('data', (chunk) => { data += chunk; });
84
+ res.on('end', () => {
85
+ try {
86
+ const parsed = JSON.parse(data);
87
+ if (typeof parsed.latest === 'string') {
88
+ writeCache(parsed.latest);
89
+ }
90
+ }
91
+ catch {
92
+ // Malformed JSON — ignore
93
+ }
94
+ });
95
+ });
96
+ req.on('error', () => { });
97
+ req.on('timeout', () => { req.destroy(); });
98
+ // Don't keep the process alive waiting for this response
99
+ req.on('socket', (socket) => { socket.unref(); });
100
+ }
101
+ catch {
102
+ // Spawn/setup failure — ignore
103
+ }
104
+ }
105
+ // ── Public API ──────────────────────────────────────────────────────────
106
+ /** State captured at startup; used later by printUpdateNotification(). */
107
+ let cachedLatest = null;
108
+ /**
109
+ * Call once at CLI startup. Reads the cache (sync, fast) and fires off
110
+ * a background registry check if the cache is stale. Never throws.
111
+ */
112
+ function checkForUpdates() {
113
+ try {
114
+ // Respect opt-out
115
+ if (process.env.NO_UPDATE_NOTIFIER)
116
+ return;
117
+ const cache = readCache();
118
+ if (cache) {
119
+ cachedLatest = cache.latest;
120
+ }
121
+ if (isCacheStale(cache)) {
122
+ triggerBackgroundCheck();
123
+ }
124
+ }
125
+ catch {
126
+ // Absolutely never crash
127
+ }
128
+ }
129
+ /**
130
+ * Call after the command finishes. Prints a one-line update notice to
131
+ * stderr if a newer version is available. Never throws.
132
+ */
133
+ function printUpdateNotification() {
134
+ try {
135
+ if (!cachedLatest)
136
+ return;
137
+ const current = package_json_1.default.version;
138
+ if (isNewer(cachedLatest, current)) {
139
+ process.stderr.write(`\nUpdate available: v${current} → v${cachedLatest}\n` +
140
+ `Run \`npm update -g @orchagent/cli\` to update\n`);
141
+ }
142
+ }
143
+ catch {
144
+ // Absolutely never crash
145
+ }
146
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchagent/cli",
3
- "version": "0.3.31",
3
+ "version": "0.3.34",
4
4
  "description": "Command-line interface for the orchagent AI agent marketplace",
5
5
  "license": "MIT",
6
6
  "author": "orchagent <hello@orchagent.io>",