pilotswarm-cli 0.1.5 → 0.1.6

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.
Files changed (2) hide show
  1. package/cli/tui.js +39 -19
  2. package/package.json +1 -1
package/cli/tui.js CHANGED
@@ -13,7 +13,7 @@
13
13
  * npx pilotswarm remote --env .env.remote # client-only (AKS)
14
14
  */
15
15
 
16
- import { PilotSwarmClient, PilotSwarmWorker, PilotSwarmManagementClient, SessionBlobStore, systemAgentUUID } from "pilotswarm-sdk";
16
+ import { PilotSwarmClient, PilotSwarmWorker, PilotSwarmManagementClient, SessionBlobStore, FilesystemArtifactStore, systemAgentUUID, loadAgentFiles } from "pilotswarm-sdk";
17
17
  import { createRequire } from "node:module";
18
18
  import { marked } from "marked";
19
19
  import { markedTerminal } from "marked-terminal";
@@ -340,15 +340,19 @@ const sessionArtifacts = new Map();
340
340
  const _registeredArtifacts = new Set();
341
341
  const MAX_ARTIFACT_REGISTRY = 500;
342
342
 
343
- /** TUI-level blob store for on-demand artifact downloads. Created lazily. */
344
- let _tuiBlobStore = null;
345
- function getTuiBlobStore() {
346
- if (_tuiBlobStore) return _tuiBlobStore;
343
+ /** TUI-level artifact store for on-demand downloads. Created lazily.
344
+ * Uses Azure Blob when configured, otherwise falls back to local filesystem. */
345
+ let _tuiArtifactStore = null;
346
+ function getTuiArtifactStore() {
347
+ if (_tuiArtifactStore) return _tuiArtifactStore;
347
348
  const connStr = process.env.AZURE_STORAGE_CONNECTION_STRING;
348
- const container = process.env.AZURE_STORAGE_CONTAINER || "copilot-sessions";
349
- if (!connStr) return null;
350
- _tuiBlobStore = new SessionBlobStore(connStr, container);
351
- return _tuiBlobStore;
349
+ if (connStr) {
350
+ const container = process.env.AZURE_STORAGE_CONTAINER || "copilot-sessions";
351
+ _tuiArtifactStore = new SessionBlobStore(connStr, container);
352
+ } else {
353
+ _tuiArtifactStore = new FilesystemArtifactStore();
354
+ }
355
+ return _tuiArtifactStore;
352
356
  }
353
357
 
354
358
  /**
@@ -381,17 +385,13 @@ function detectArtifactLinks(text, orchId) {
381
385
  * Returns the local path on success, null on failure.
382
386
  */
383
387
  async function downloadArtifact(sessionId, filename) {
384
- const bs = getTuiBlobStore();
385
- if (!bs) {
386
- appendLog("{red-fg}📥 No blob storage configured — cannot download artifacts.{/red-fg}");
387
- return null;
388
- }
388
+ const store = getTuiArtifactStore();
389
389
  const sessionDir = path.join(EXPORTS_DIR, sessionId.slice(0, 8));
390
390
  fs.mkdirSync(sessionDir, { recursive: true });
391
391
  const localPath = path.join(sessionDir, filename);
392
392
 
393
393
  try {
394
- const content = await bs.downloadArtifact(sessionId, filename);
394
+ const content = await store.downloadArtifact(sessionId, filename);
395
395
  fs.writeFileSync(localPath, content, "utf-8");
396
396
  appendLog(`{green-fg}📥 Downloaded: ~/${path.relative(os.homedir(), localPath)} (${(content.length / 1024).toFixed(1)}KB){/green-fg}`);
397
397
  return localPath;
@@ -3276,10 +3276,30 @@ if (!modelProviders) {
3276
3276
  // Will be populated from mgmt.getModelsByProvider() after mgmt.start()
3277
3277
  }
3278
3278
 
3279
- // Capture session policy + agent list from the first worker
3280
- const _workerSessionPolicy = workers[0]?.sessionPolicy || null;
3281
- const _workerAllowedAgentNames = workers[0]?.allowedAgentNames || [];
3282
- const _workerLoadedAgents = workers[0]?.loadedAgents || [];
3279
+ // Capture session policy + agent list from the first worker.
3280
+ // In remote mode (no local workers), load directly from the plugin directory
3281
+ // so the TUI enforces the same session creation restrictions as the backend.
3282
+ let _workerSessionPolicy = workers[0]?.sessionPolicy || null;
3283
+ let _workerAllowedAgentNames = workers[0]?.allowedAgentNames || [];
3284
+ let _workerLoadedAgents = workers[0]?.loadedAgents || [];
3285
+
3286
+ if (workers.length === 0 && process.env.PLUGIN_DIRS) {
3287
+ const pluginDirsArr = process.env.PLUGIN_DIRS.split(",").map(d => d.trim()).filter(Boolean);
3288
+ for (const dir of pluginDirsArr) {
3289
+ const policyFile = path.join(dir, "session-policy.json");
3290
+ if (fs.existsSync(policyFile)) {
3291
+ try { _workerSessionPolicy = JSON.parse(fs.readFileSync(policyFile, "utf-8")); } catch {}
3292
+ }
3293
+ const agentsDir = path.join(dir, "agents");
3294
+ if (fs.existsSync(agentsDir)) {
3295
+ try {
3296
+ const agents = loadAgentFiles(agentsDir).filter(a => !a.system && a.name !== "default");
3297
+ _workerLoadedAgents = agents;
3298
+ _workerAllowedAgentNames = agents.map(a => a.name).filter(Boolean);
3299
+ } catch {}
3300
+ }
3301
+ }
3302
+ }
3283
3303
  if (_workerSessionPolicy) {
3284
3304
  appendLog(`Session policy: mode=${_workerSessionPolicy.creation?.mode || "open"}, allowGeneric=${_workerSessionPolicy.creation?.allowGeneric ?? true}`);
3285
3305
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pilotswarm-cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Terminal UI for pilotswarm — interactive durable agent orchestration.",
5
5
  "type": "module",
6
6
  "bin": {