@awak-app/simy-cli 0.5.31 → 0.5.32

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awak-app/simy-cli",
3
- "version": "0.5.31",
3
+ "version": "0.5.32",
4
4
  "description": "Local SIMY executor for non-coding Local Tasks and Agentic Loop runs.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,7 @@ import {
13
13
  } from "./durable-local-task-steps-contract.js";
14
14
  import { buildExecutionCapabilityContract } from "./execution-capability-contract.js";
15
15
 
16
- export const CLI_VERSION = "0.5.31";
16
+ export const CLI_VERSION = "0.5.32";
17
17
  export const CLI_API_CONTRACT_VERSION = 10;
18
18
 
19
19
  export function withCliContract(
@@ -15,7 +15,8 @@ import { createAgentShutdown } from "./shutdown.js";
15
15
  import { resolveWebOrigin } from "./web-origin.js";
16
16
  import { openAuthorizationUrl } from "./browser.js";
17
17
  import { inspectBackendExecutable } from "./backend-executable.js";
18
- import { startWorkflowUpdates } from "./sqm/workflow-update.js";
18
+ import { inspectSqmAgentSkill } from "./sqm/agent-skill.js";
19
+ import { startWorkflowUpdates, syncInstalledWorkflows } from "./sqm/workflow-update.js";
19
20
  import {
20
21
  acquireDesktopProcessLock,
21
22
  assertNoLegacyCliDaemon,
@@ -40,11 +41,20 @@ export async function startDesktopHost({ input = process.stdin, output = process
40
41
  let agent, updater, stopWorkflows = async () => {}, timer, closed = false, relay = null, publishing = null;
41
42
  let shuttingDown = null;
42
43
  let commands;
44
+ let pluginSetup = { state: "unknown" };
45
+ const inspectPlugins = dependencies.inspectPlugins || inspectSqmAgentSkill;
46
+ const refreshPlugins = async () => {
47
+ try {
48
+ const status = await inspectPlugins();
49
+ pluginSetup = { state: status.installed ? "ready" : "missing", refreshPending: status.installed && pluginSetup.refreshPending === true };
50
+ } catch { pluginSetup = { state: "error" }; }
51
+ };
43
52
  const packageInfo = dependencies.packageInfo || await readCliPackageInfo();
44
53
  const publish = () => {
45
54
  if (closed || relay || !agent) return Promise.resolve();
46
55
  if (publishing) return publishing;
47
56
  publishing = Promise.resolve(agent.getDesktopStatus()).then(async (status) => {
57
+ status.pluginSetup = { ...pluginSetup };
48
58
  status.deliveryHooks = await (dependencies.deliveryHookStatus || deliveryHookStatus)({ root: join(root, "delivery-hooks") }).catch(() => ({ error: "Delivery hook status unavailable", providers: {}, runs: [] }));
49
59
  if (!closed && !relay) emit({ type: "status", status });
50
60
  }).finally(() => { publishing = null; });
@@ -135,6 +145,7 @@ export async function startDesktopHost({ input = process.stdin, output = process
135
145
  lines.close(); child.kill("SIGTERM"); throw error;
136
146
  }
137
147
  } });
148
+ await refreshPlugins();
138
149
  await publish();
139
150
  timer = setInterval(() => { void publish().catch(() => emit({ type: "error", message: "SIMY status could not be refreshed." })); }, 3_000);
140
151
  } catch (error) { await close(); throw error; }
@@ -163,6 +174,7 @@ export async function startDesktopHost({ input = process.stdin, output = process
163
174
  if (agent.refreshProviderStatus) await agent.refreshProviderStatus();
164
175
  else await agent.refreshCodexStatus?.();
165
176
  await agent.refreshDesktopStatus();
177
+ await refreshPlugins();
166
178
  }
167
179
  else if (action === "login") {
168
180
  const url = await agent.requestDesktopLogin();
@@ -181,6 +193,21 @@ export async function startDesktopHost({ input = process.stdin, output = process
181
193
  if (login) await login(root);
182
194
  else await openProviderLogin(provider, root);
183
195
  }
196
+ else if (action === "install_plugins") {
197
+ pluginSetup = { state: "installing" };
198
+ await publish();
199
+ try {
200
+ const result = await (dependencies.installPlugins || syncInstalledWorkflows)({ installMissing: true });
201
+ if (result.outcome === "busy") throw new Error("Plugin installation is busy.");
202
+ await refreshPlugins();
203
+ if (pluginSetup.state !== "ready") throw new Error("Plugin files could not be verified.");
204
+ pluginSetup.refreshPending = result.refreshPending === true;
205
+ } catch {
206
+ pluginSetup = { state: "error" };
207
+ await publish();
208
+ throw new Error("Plugin setup failed.");
209
+ }
210
+ }
184
211
  else if (action === "codex_hooks" || action === "claude_hooks") {
185
212
  const provider = action === "codex_hooks" ? "codex" : "claude";
186
213
  await (dependencies.openHookSettings || openHookSetup)(provider);
@@ -31,7 +31,7 @@ export function startWorkflowUpdates({ enabled, sync = syncInstalledWorkflows, i
31
31
  };
32
32
  }
33
33
 
34
- export async function syncInstalledWorkflows({ home = homedir(),
34
+ export async function syncInstalledWorkflows({ home = homedir(), installMissing = false,
35
35
  codexHome = process.env.CODEX_HOME || path.join(home, ".codex"),
36
36
  claudeHome = process.env.CLAUDE_CONFIG_DIR || path.join(home, ".claude"),
37
37
  inspect = inspectSqmAgentSkill, install = installSqmAgentSkill,
@@ -52,7 +52,7 @@ export async function syncInstalledWorkflows({ home = homedir(),
52
52
  const migrated = await retireLegacySqmGate({ home });
53
53
  let status = await inspect({ home });
54
54
  const platforms = Object.entries(status.platforms)
55
- .filter(([, entry]) => entry.state === "outdated").map(([platform]) => platform);
55
+ .filter(([, entry]) => entry.state === "outdated" || (installMissing && entry.state === "missing")).map(([platform]) => platform);
56
56
  if (platforms.length) status = await install({ home, platforms });
57
57
  const results = {};
58
58
  const failures = [];
@@ -63,6 +63,9 @@ export async function syncInstalledWorkflows({ home = homedir(),
63
63
  try { results[provider] = await refresh(); }
64
64
  catch (error) { failures.push(error); }
65
65
  }
66
+ // Explicit desktop setup prepares both sources even when a provider CLI is
67
+ // absent. Cache refresh remains retryable; no provider is enabled here.
68
+ if (failures.length && installMissing) return { outcome: "prepared", refreshPending: true };
66
69
  if (failures.length) throw new AggregateError(failures, failures.map((error) => error.message).join("; "));
67
70
  if (results.claude.outcome === "updated") return { ...results.claude, providers: results };
68
71
  if (results.codex.outcome !== "not_enabled") return results.codex;