@oxagen/cli 0.4.0 → 0.6.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/README.md +68 -5
- package/dist/agent/__tests__/code-graph.test.d.ts +2 -0
- package/dist/agent/__tests__/code-graph.test.d.ts.map +1 -0
- package/dist/agent/__tests__/code-graph.test.js +83 -0
- package/dist/agent/__tests__/code-graph.test.js.map +1 -0
- package/dist/agent/__tests__/evaluator.test.d.ts +2 -0
- package/dist/agent/__tests__/evaluator.test.d.ts.map +1 -0
- package/dist/agent/__tests__/evaluator.test.js +96 -0
- package/dist/agent/__tests__/evaluator.test.js.map +1 -0
- package/dist/agent/__tests__/fleet-memory.test.d.ts +2 -0
- package/dist/agent/__tests__/fleet-memory.test.d.ts.map +1 -0
- package/dist/agent/__tests__/fleet-memory.test.js +107 -0
- package/dist/agent/__tests__/fleet-memory.test.js.map +1 -0
- package/dist/agent/__tests__/fleet-store.test.d.ts +2 -0
- package/dist/agent/__tests__/fleet-store.test.d.ts.map +1 -0
- package/dist/agent/__tests__/fleet-store.test.js +93 -0
- package/dist/agent/__tests__/fleet-store.test.js.map +1 -0
- package/dist/agent/__tests__/git-isolation.test.d.ts +2 -0
- package/dist/agent/__tests__/git-isolation.test.d.ts.map +1 -0
- package/dist/agent/__tests__/git-isolation.test.js +119 -0
- package/dist/agent/__tests__/git-isolation.test.js.map +1 -0
- package/dist/agent/__tests__/judge.test.d.ts +2 -0
- package/dist/agent/__tests__/judge.test.d.ts.map +1 -0
- package/dist/agent/__tests__/judge.test.js +135 -0
- package/dist/agent/__tests__/judge.test.js.map +1 -0
- package/dist/agent/__tests__/loop-errors.test.d.ts +2 -0
- package/dist/agent/__tests__/loop-errors.test.d.ts.map +1 -0
- package/dist/agent/__tests__/loop-errors.test.js +44 -0
- package/dist/agent/__tests__/loop-errors.test.js.map +1 -0
- package/dist/agent/__tests__/model-router.test.d.ts +2 -0
- package/dist/agent/__tests__/model-router.test.d.ts.map +1 -0
- package/dist/agent/__tests__/model-router.test.js +122 -0
- package/dist/agent/__tests__/model-router.test.js.map +1 -0
- package/dist/agent/__tests__/orchestrator-isolation.test.d.ts +2 -0
- package/dist/agent/__tests__/orchestrator-isolation.test.d.ts.map +1 -0
- package/dist/agent/__tests__/orchestrator-isolation.test.js +134 -0
- package/dist/agent/__tests__/orchestrator-isolation.test.js.map +1 -0
- package/dist/agent/__tests__/orchestrator.test.d.ts +2 -0
- package/dist/agent/__tests__/orchestrator.test.d.ts.map +1 -0
- package/dist/agent/__tests__/orchestrator.test.js +201 -0
- package/dist/agent/__tests__/orchestrator.test.js.map +1 -0
- package/dist/agent/__tests__/pipeline.test.d.ts +2 -0
- package/dist/agent/__tests__/pipeline.test.d.ts.map +1 -0
- package/dist/agent/__tests__/pipeline.test.js +226 -0
- package/dist/agent/__tests__/pipeline.test.js.map +1 -0
- package/dist/agent/__tests__/planner.test.d.ts +2 -0
- package/dist/agent/__tests__/planner.test.d.ts.map +1 -0
- package/dist/agent/__tests__/planner.test.js +98 -0
- package/dist/agent/__tests__/planner.test.js.map +1 -0
- package/dist/agent/__tests__/prompt-enhancer.test.d.ts +2 -0
- package/dist/agent/__tests__/prompt-enhancer.test.d.ts.map +1 -0
- package/dist/agent/__tests__/prompt-enhancer.test.js +107 -0
- package/dist/agent/__tests__/prompt-enhancer.test.js.map +1 -0
- package/dist/agent/__tests__/trace-format.test.d.ts +2 -0
- package/dist/agent/__tests__/trace-format.test.d.ts.map +1 -0
- package/dist/agent/__tests__/trace-format.test.js +104 -0
- package/dist/agent/__tests__/trace-format.test.js.map +1 -0
- package/dist/agent/__tests__/trace-store.test.d.ts +2 -0
- package/dist/agent/__tests__/trace-store.test.d.ts.map +1 -0
- package/dist/agent/__tests__/trace-store.test.js +113 -0
- package/dist/agent/__tests__/trace-store.test.js.map +1 -0
- package/dist/agent/code-graph.d.ts +18 -0
- package/dist/agent/code-graph.d.ts.map +1 -0
- package/dist/agent/code-graph.js +119 -0
- package/dist/agent/code-graph.js.map +1 -0
- package/dist/agent/env.d.ts +11 -0
- package/dist/agent/env.d.ts.map +1 -0
- package/dist/agent/env.js +82 -0
- package/dist/agent/env.js.map +1 -0
- package/dist/agent/evaluator.d.ts +13 -0
- package/dist/agent/evaluator.d.ts.map +1 -0
- package/dist/agent/evaluator.js +146 -0
- package/dist/agent/evaluator.js.map +1 -0
- package/dist/agent/fleet/git-isolation.d.ts +142 -0
- package/dist/agent/fleet/git-isolation.d.ts.map +1 -0
- package/dist/agent/fleet/git-isolation.js +290 -0
- package/dist/agent/fleet/git-isolation.js.map +1 -0
- package/dist/agent/fleet/memory.d.ts +21 -0
- package/dist/agent/fleet/memory.d.ts.map +1 -0
- package/dist/agent/fleet/memory.js +129 -0
- package/dist/agent/fleet/memory.js.map +1 -0
- package/dist/agent/fleet/orchestrator.d.ts +103 -0
- package/dist/agent/fleet/orchestrator.d.ts.map +1 -0
- package/dist/agent/fleet/orchestrator.js +355 -0
- package/dist/agent/fleet/orchestrator.js.map +1 -0
- package/dist/agent/fleet/store.d.ts +13 -0
- package/dist/agent/fleet/store.d.ts.map +1 -0
- package/dist/agent/fleet/store.js +79 -0
- package/dist/agent/fleet/store.js.map +1 -0
- package/dist/agent/fleet/types.d.ts +105 -0
- package/dist/agent/fleet/types.d.ts.map +1 -0
- package/dist/agent/fleet/types.js +17 -0
- package/dist/agent/fleet/types.js.map +1 -0
- package/dist/agent/judge.d.ts +38 -0
- package/dist/agent/judge.d.ts.map +1 -0
- package/dist/agent/judge.js +170 -0
- package/dist/agent/judge.js.map +1 -0
- package/dist/agent/loop.d.ts +61 -0
- package/dist/agent/loop.d.ts.map +1 -0
- package/dist/agent/loop.js +134 -0
- package/dist/agent/loop.js.map +1 -0
- package/dist/agent/memory.d.ts +14 -0
- package/dist/agent/memory.d.ts.map +1 -0
- package/dist/agent/memory.js +118 -0
- package/dist/agent/memory.js.map +1 -0
- package/dist/agent/model-router.d.ts +79 -0
- package/dist/agent/model-router.d.ts.map +1 -0
- package/dist/agent/model-router.js +141 -0
- package/dist/agent/model-router.js.map +1 -0
- package/dist/agent/model.d.ts +9 -0
- package/dist/agent/model.d.ts.map +1 -0
- package/dist/agent/model.js +24 -0
- package/dist/agent/model.js.map +1 -0
- package/dist/agent/pipeline.d.ts +82 -0
- package/dist/agent/pipeline.d.ts.map +1 -0
- package/dist/agent/pipeline.js +320 -0
- package/dist/agent/pipeline.js.map +1 -0
- package/dist/agent/planner.d.ts +16 -0
- package/dist/agent/planner.d.ts.map +1 -0
- package/dist/agent/planner.js +126 -0
- package/dist/agent/planner.js.map +1 -0
- package/dist/agent/project-context.d.ts +13 -0
- package/dist/agent/project-context.d.ts.map +1 -0
- package/dist/agent/project-context.js +66 -0
- package/dist/agent/project-context.js.map +1 -0
- package/dist/agent/prompt-enhancer.d.ts +37 -0
- package/dist/agent/prompt-enhancer.d.ts.map +1 -0
- package/dist/agent/prompt-enhancer.js +115 -0
- package/dist/agent/prompt-enhancer.js.map +1 -0
- package/dist/agent/system-prompt.d.ts +9 -0
- package/dist/agent/system-prompt.d.ts.map +1 -0
- package/dist/agent/system-prompt.js +38 -0
- package/dist/agent/system-prompt.js.map +1 -0
- package/dist/agent/tools.d.ts +19 -0
- package/dist/agent/tools.d.ts.map +1 -0
- package/dist/agent/tools.js +323 -0
- package/dist/agent/tools.js.map +1 -0
- package/dist/agent/trace-format.d.ts +6 -0
- package/dist/agent/trace-format.d.ts.map +1 -0
- package/dist/agent/trace-format.js +74 -0
- package/dist/agent/trace-format.js.map +1 -0
- package/dist/agent/trace-store.d.ts +19 -0
- package/dist/agent/trace-store.d.ts.map +1 -0
- package/dist/agent/trace-store.js +82 -0
- package/dist/agent/trace-store.js.map +1 -0
- package/dist/agent/trace.d.ts +121 -0
- package/dist/agent/trace.d.ts.map +1 -0
- package/dist/agent/trace.js +2 -0
- package/dist/agent/trace.js.map +1 -0
- package/dist/commands/__tests__/replay.test.d.ts +2 -0
- package/dist/commands/__tests__/replay.test.d.ts.map +1 -0
- package/dist/commands/__tests__/replay.test.js +76 -0
- package/dist/commands/__tests__/replay.test.js.map +1 -0
- package/dist/commands/agent.mcp.consent.list.d.ts +3 -0
- package/dist/commands/agent.mcp.consent.list.d.ts.map +1 -0
- package/dist/commands/agent.mcp.consent.list.js +30 -0
- package/dist/commands/agent.mcp.consent.list.js.map +1 -0
- package/dist/commands/agent.mcp.consent.resolve.d.ts +3 -0
- package/dist/commands/agent.mcp.consent.resolve.d.ts.map +1 -0
- package/dist/commands/agent.mcp.consent.resolve.js +34 -0
- package/dist/commands/agent.mcp.consent.resolve.js.map +1 -0
- package/dist/commands/agent.mcp.delete.d.ts +3 -0
- package/dist/commands/agent.mcp.delete.d.ts.map +1 -0
- package/dist/commands/agent.mcp.delete.js +27 -0
- package/dist/commands/agent.mcp.delete.js.map +1 -0
- package/dist/commands/agent.mcp.set_enabled.d.ts +3 -0
- package/dist/commands/agent.mcp.set_enabled.d.ts.map +1 -0
- package/dist/commands/agent.mcp.set_enabled.js +33 -0
- package/dist/commands/agent.mcp.set_enabled.js.map +1 -0
- package/dist/commands/agent.skill.load.d.ts +3 -0
- package/dist/commands/agent.skill.load.d.ts.map +1 -0
- package/dist/commands/agent.skill.load.js +57 -0
- package/dist/commands/agent.skill.load.js.map +1 -0
- package/dist/commands/audit.log.query.d.ts +3 -0
- package/dist/commands/audit.log.query.d.ts.map +1 -0
- package/dist/commands/audit.log.query.js +42 -0
- package/dist/commands/audit.log.query.js.map +1 -0
- package/dist/commands/automation.create.d.ts.map +1 -1
- package/dist/commands/automation.create.js +43 -4
- package/dist/commands/automation.create.js.map +1 -1
- package/dist/commands/automation.disable.d.ts +3 -0
- package/dist/commands/automation.disable.d.ts.map +1 -0
- package/dist/commands/automation.disable.js +24 -0
- package/dist/commands/automation.disable.js.map +1 -0
- package/dist/commands/automation.enable.d.ts +3 -0
- package/dist/commands/automation.enable.d.ts.map +1 -0
- package/dist/commands/automation.enable.js +24 -0
- package/dist/commands/automation.enable.js.map +1 -0
- package/dist/commands/automation.update.d.ts +3 -0
- package/dist/commands/automation.update.d.ts.map +1 -0
- package/dist/commands/automation.update.js +42 -0
- package/dist/commands/automation.update.js.map +1 -0
- package/dist/commands/code.d.ts +14 -0
- package/dist/commands/code.d.ts.map +1 -0
- package/dist/commands/code.js +100 -0
- package/dist/commands/code.js.map +1 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +66 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/conversation.files.list.d.ts +3 -0
- package/dist/commands/conversation.files.list.d.ts.map +1 -0
- package/dist/commands/conversation.files.list.js +39 -0
- package/dist/commands/conversation.files.list.js.map +1 -0
- package/dist/commands/env.d.ts +19 -0
- package/dist/commands/env.d.ts.map +1 -0
- package/dist/commands/env.js +64 -0
- package/dist/commands/env.js.map +1 -0
- package/dist/commands/graph.search.d.ts +10 -0
- package/dist/commands/graph.search.d.ts.map +1 -0
- package/dist/commands/graph.search.js +25 -0
- package/dist/commands/graph.search.js.map +1 -0
- package/dist/commands/markdown.generate.d.ts +3 -0
- package/dist/commands/markdown.generate.d.ts.map +1 -0
- package/dist/commands/markdown.generate.js +37 -0
- package/dist/commands/markdown.generate.js.map +1 -0
- package/dist/commands/mcp.add.d.ts +13 -0
- package/dist/commands/mcp.add.d.ts.map +1 -0
- package/dist/commands/mcp.add.js +110 -0
- package/dist/commands/mcp.add.js.map +1 -0
- package/dist/commands/mcp.auth.d.ts +10 -0
- package/dist/commands/mcp.auth.d.ts.map +1 -0
- package/dist/commands/mcp.auth.js +132 -0
- package/dist/commands/mcp.auth.js.map +1 -0
- package/dist/commands/mcp.check.d.ts +10 -0
- package/dist/commands/mcp.check.d.ts.map +1 -0
- package/dist/commands/mcp.check.js +114 -0
- package/dist/commands/mcp.check.js.map +1 -0
- package/dist/commands/mcp.list.d.ts +9 -0
- package/dist/commands/mcp.list.d.ts.map +1 -0
- package/dist/commands/mcp.list.js +93 -0
- package/dist/commands/mcp.list.js.map +1 -0
- package/dist/commands/mcp.permit.d.ts +12 -0
- package/dist/commands/mcp.permit.d.ts.map +1 -0
- package/dist/commands/mcp.permit.js +117 -0
- package/dist/commands/mcp.permit.js.map +1 -0
- package/dist/commands/mcp.remove.d.ts +9 -0
- package/dist/commands/mcp.remove.d.ts.map +1 -0
- package/dist/commands/mcp.remove.js +65 -0
- package/dist/commands/mcp.remove.js.map +1 -0
- package/dist/commands/mermaid.generate.d.ts +3 -0
- package/dist/commands/mermaid.generate.d.ts.map +1 -0
- package/dist/commands/mermaid.generate.js +33 -0
- package/dist/commands/mermaid.generate.js.map +1 -0
- package/dist/commands/ontology.neighbors.d.ts +3 -0
- package/dist/commands/ontology.neighbors.d.ts.map +1 -0
- package/dist/commands/ontology.neighbors.js +34 -0
- package/dist/commands/ontology.neighbors.js.map +1 -0
- package/dist/commands/ontology.query.d.ts +3 -0
- package/dist/commands/ontology.query.d.ts.map +1 -0
- package/dist/commands/ontology.query.js +36 -0
- package/dist/commands/ontology.query.js.map +1 -0
- package/dist/commands/plugin.org.install_bulk.js +1 -1
- package/dist/commands/plugin.org.install_bulk.js.map +1 -1
- package/dist/commands/privacy.erase.d.ts.map +1 -1
- package/dist/commands/privacy.erase.js +2 -1
- package/dist/commands/privacy.erase.js.map +1 -1
- package/dist/commands/privacy.erase.test.d.ts +2 -0
- package/dist/commands/privacy.erase.test.d.ts.map +1 -0
- package/dist/commands/privacy.erase.test.js +132 -0
- package/dist/commands/privacy.erase.test.js.map +1 -0
- package/dist/commands/replay.d.ts +5 -0
- package/dist/commands/replay.d.ts.map +1 -0
- package/dist/commands/replay.js +28 -0
- package/dist/commands/replay.js.map +1 -0
- package/dist/commands/schema/schema.config.d.ts +3 -0
- package/dist/commands/schema/schema.config.d.ts.map +1 -0
- package/dist/commands/schema/schema.config.js +34 -0
- package/dist/commands/schema/schema.config.js.map +1 -0
- package/dist/commands/schema/schema.disable.d.ts +3 -0
- package/dist/commands/schema/schema.disable.d.ts.map +1 -0
- package/dist/commands/schema/schema.disable.js +22 -0
- package/dist/commands/schema/schema.disable.js.map +1 -0
- package/dist/commands/schema/schema.enable.d.ts +3 -0
- package/dist/commands/schema/schema.enable.d.ts.map +1 -0
- package/dist/commands/schema/schema.enable.js +22 -0
- package/dist/commands/schema/schema.enable.js.map +1 -0
- package/dist/commands/schema/schema.export.d.ts +3 -0
- package/dist/commands/schema/schema.export.d.ts.map +1 -0
- package/dist/commands/schema/schema.export.js +31 -0
- package/dist/commands/schema/schema.export.js.map +1 -0
- package/dist/commands/schema/schema.get.d.ts +3 -0
- package/dist/commands/schema/schema.get.d.ts.map +1 -0
- package/dist/commands/schema/schema.get.js +23 -0
- package/dist/commands/schema/schema.get.js.map +1 -0
- package/dist/commands/schema/schema.label.d.ts +5 -0
- package/dist/commands/schema/schema.label.d.ts.map +1 -0
- package/dist/commands/schema/schema.label.js +60 -0
- package/dist/commands/schema/schema.label.js.map +1 -0
- package/dist/commands/schema/schema.list.d.ts +3 -0
- package/dist/commands/schema/schema.list.d.ts.map +1 -0
- package/dist/commands/schema/schema.list.js +30 -0
- package/dist/commands/schema/schema.list.js.map +1 -0
- package/dist/commands/schema/schema.prop.d.ts +5 -0
- package/dist/commands/schema/schema.prop.d.ts.map +1 -0
- package/dist/commands/schema/schema.prop.js +72 -0
- package/dist/commands/schema/schema.prop.js.map +1 -0
- package/dist/commands/schema/schema.reconcile.d.ts +10 -0
- package/dist/commands/schema/schema.reconcile.d.ts.map +1 -0
- package/dist/commands/schema/schema.reconcile.js +65 -0
- package/dist/commands/schema/schema.reconcile.js.map +1 -0
- package/dist/commands/schema/schema.rel.d.ts +5 -0
- package/dist/commands/schema/schema.rel.d.ts.map +1 -0
- package/dist/commands/schema/schema.rel.js +65 -0
- package/dist/commands/schema/schema.rel.js.map +1 -0
- package/dist/commands/schema/schema.version.d.ts +7 -0
- package/dist/commands/schema/schema.version.d.ts.map +1 -0
- package/dist/commands/schema/schema.version.js +96 -0
- package/dist/commands/schema/schema.version.js.map +1 -0
- package/dist/commands/secret.d.ts +23 -0
- package/dist/commands/secret.d.ts.map +1 -0
- package/dist/commands/secret.js +90 -0
- package/dist/commands/secret.js.map +1 -0
- package/dist/commands/skill.create.d.ts +3 -0
- package/dist/commands/skill.create.d.ts.map +1 -0
- package/dist/commands/skill.create.js +52 -0
- package/dist/commands/skill.create.js.map +1 -0
- package/dist/commands/skill.edit.d.ts +3 -0
- package/dist/commands/skill.edit.d.ts.map +1 -0
- package/dist/commands/skill.edit.js +28 -0
- package/dist/commands/skill.edit.js.map +1 -0
- package/dist/commands/skill.enable.d.ts +3 -0
- package/dist/commands/skill.enable.d.ts.map +1 -0
- package/dist/commands/skill.enable.js +31 -0
- package/dist/commands/skill.enable.js.map +1 -0
- package/dist/commands/skill.export.d.ts +3 -0
- package/dist/commands/skill.export.d.ts.map +1 -0
- package/dist/commands/skill.export.js +25 -0
- package/dist/commands/skill.export.js.map +1 -0
- package/dist/commands/skill.metrics.read.d.ts +3 -0
- package/dist/commands/skill.metrics.read.d.ts.map +1 -0
- package/dist/commands/skill.metrics.read.js +56 -0
- package/dist/commands/skill.metrics.read.js.map +1 -0
- package/dist/commands/skill.version.activate.d.ts +3 -0
- package/dist/commands/skill.version.activate.d.ts.map +1 -0
- package/dist/commands/skill.version.activate.js +24 -0
- package/dist/commands/skill.version.activate.js.map +1 -0
- package/dist/commands/skill.version.get.d.ts +3 -0
- package/dist/commands/skill.version.get.d.ts.map +1 -0
- package/dist/commands/skill.version.get.js +43 -0
- package/dist/commands/skill.version.get.js.map +1 -0
- package/dist/commands/skill.version.list.d.ts +3 -0
- package/dist/commands/skill.version.list.d.ts.map +1 -0
- package/dist/commands/skill.version.list.js +38 -0
- package/dist/commands/skill.version.list.js.map +1 -0
- package/dist/commands/skill.version.upload.d.ts +3 -0
- package/dist/commands/skill.version.upload.d.ts.map +1 -0
- package/dist/commands/skill.version.upload.js +28 -0
- package/dist/commands/skill.version.upload.js.map +1 -0
- package/dist/commands/skill.workspace.install.d.ts +3 -0
- package/dist/commands/skill.workspace.install.d.ts.map +1 -0
- package/dist/commands/skill.workspace.install.js +52 -0
- package/dist/commands/skill.workspace.install.js.map +1 -0
- package/dist/commands.test.js +1391 -337
- package/dist/commands.test.js.map +1 -1
- package/dist/components/DevStatus.d.ts.map +1 -1
- package/dist/components/DevStatus.js +3 -2
- package/dist/components/DevStatus.js.map +1 -1
- package/dist/daemon/client.d.ts +30 -0
- package/dist/daemon/client.d.ts.map +1 -0
- package/dist/daemon/client.js +97 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/code-graph/builder.d.ts +6 -0
- package/dist/daemon/code-graph/builder.d.ts.map +1 -0
- package/dist/daemon/code-graph/builder.js +215 -0
- package/dist/daemon/code-graph/builder.js.map +1 -0
- package/dist/daemon/code-graph/query.d.ts +29 -0
- package/dist/daemon/code-graph/query.d.ts.map +1 -0
- package/dist/daemon/code-graph/query.js +98 -0
- package/dist/daemon/code-graph/query.js.map +1 -0
- package/dist/daemon/code-graph/types.d.ts +37 -0
- package/dist/daemon/code-graph/types.d.ts.map +1 -0
- package/dist/daemon/code-graph/types.js +5 -0
- package/dist/daemon/code-graph/types.js.map +1 -0
- package/dist/daemon/code-graph/watcher.d.ts +37 -0
- package/dist/daemon/code-graph/watcher.d.ts.map +1 -0
- package/dist/daemon/code-graph/watcher.js +79 -0
- package/dist/daemon/code-graph/watcher.js.map +1 -0
- package/dist/daemon/lifecycle.d.ts +6 -0
- package/dist/daemon/lifecycle.d.ts.map +1 -0
- package/dist/daemon/lifecycle.js +132 -0
- package/dist/daemon/lifecycle.js.map +1 -0
- package/dist/daemon/protocol.d.ts +113 -0
- package/dist/daemon/protocol.d.ts.map +1 -0
- package/dist/daemon/protocol.js +16 -0
- package/dist/daemon/protocol.js.map +1 -0
- package/dist/daemon/server.d.ts +26 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +168 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +262 -310
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +5 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +52 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/config.d.ts +3 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +16 -3
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/config.test.js +21 -3
- package/dist/lib/config.test.js.map +1 -1
- package/dist/lib/differential-context.d.ts +46 -0
- package/dist/lib/differential-context.d.ts.map +1 -0
- package/dist/lib/differential-context.js +89 -0
- package/dist/lib/differential-context.js.map +1 -0
- package/dist/lib/resolve.d.ts +3 -0
- package/dist/lib/resolve.d.ts.map +1 -0
- package/dist/lib/resolve.js +29 -0
- package/dist/lib/resolve.js.map +1 -0
- package/dist/lib/structured-tool-io.d.ts +31 -0
- package/dist/lib/structured-tool-io.d.ts.map +1 -0
- package/dist/lib/structured-tool-io.js +56 -0
- package/dist/lib/structured-tool-io.js.map +1 -0
- package/dist/repl/__tests__/_queue_demo.test.d.ts +2 -0
- package/dist/repl/__tests__/_queue_demo.test.d.ts.map +1 -0
- package/dist/repl/__tests__/_queue_demo.test.js +40 -0
- package/dist/repl/__tests__/_queue_demo.test.js.map +1 -0
- package/dist/repl/__tests__/components.test.d.ts +2 -0
- package/dist/repl/__tests__/components.test.d.ts.map +1 -0
- package/dist/repl/__tests__/components.test.js +38 -0
- package/dist/repl/__tests__/components.test.js.map +1 -0
- package/dist/repl/__tests__/interactive.queue.test.d.ts +2 -0
- package/dist/repl/__tests__/interactive.queue.test.d.ts.map +1 -0
- package/dist/repl/__tests__/interactive.queue.test.js +124 -0
- package/dist/repl/__tests__/interactive.queue.test.js.map +1 -0
- package/dist/repl/components.d.ts +59 -0
- package/dist/repl/components.d.ts.map +1 -0
- package/dist/repl/components.js +152 -0
- package/dist/repl/components.js.map +1 -0
- package/dist/repl/interactive.d.ts +12 -0
- package/dist/repl/interactive.d.ts.map +1 -0
- package/dist/repl/interactive.js +326 -0
- package/dist/repl/interactive.js.map +1 -0
- package/dist/repl/one-shot.d.ts +9 -0
- package/dist/repl/one-shot.d.ts.map +1 -0
- package/dist/repl/one-shot.js +83 -0
- package/dist/repl/one-shot.js.map +1 -0
- package/dist/tui/__tests__/app.test.d.ts +2 -0
- package/dist/tui/__tests__/app.test.d.ts.map +1 -0
- package/dist/tui/__tests__/app.test.js +136 -0
- package/dist/tui/__tests__/app.test.js.map +1 -0
- package/dist/tui/__tests__/banner.test.d.ts +2 -0
- package/dist/tui/__tests__/banner.test.d.ts.map +1 -0
- package/dist/tui/__tests__/banner.test.js +15 -0
- package/dist/tui/__tests__/banner.test.js.map +1 -0
- package/dist/tui/__tests__/command-form.test.d.ts +2 -0
- package/dist/tui/__tests__/command-form.test.d.ts.map +1 -0
- package/dist/tui/__tests__/command-form.test.js +96 -0
- package/dist/tui/__tests__/command-form.test.js.map +1 -0
- package/dist/tui/__tests__/command-tree.test.d.ts +2 -0
- package/dist/tui/__tests__/command-tree.test.d.ts.map +1 -0
- package/dist/tui/__tests__/command-tree.test.js +55 -0
- package/dist/tui/__tests__/command-tree.test.js.map +1 -0
- package/dist/tui/__tests__/runner.test.d.ts +2 -0
- package/dist/tui/__tests__/runner.test.d.ts.map +1 -0
- package/dist/tui/__tests__/runner.test.js +38 -0
- package/dist/tui/__tests__/runner.test.js.map +1 -0
- package/dist/tui/__tests__/theme.test.d.ts +2 -0
- package/dist/tui/__tests__/theme.test.d.ts.map +1 -0
- package/dist/tui/__tests__/theme.test.js +11 -0
- package/dist/tui/__tests__/theme.test.js.map +1 -0
- package/dist/tui/agent-view/activity-feed.d.ts +3 -0
- package/dist/tui/agent-view/activity-feed.d.ts.map +1 -0
- package/dist/tui/agent-view/activity-feed.js +34 -0
- package/dist/tui/agent-view/activity-feed.js.map +1 -0
- package/dist/tui/agent-view/budget-bar.d.ts +3 -0
- package/dist/tui/agent-view/budget-bar.d.ts.map +1 -0
- package/dist/tui/agent-view/budget-bar.js +53 -0
- package/dist/tui/agent-view/budget-bar.js.map +1 -0
- package/dist/tui/agent-view/compile-panel.d.ts +3 -0
- package/dist/tui/agent-view/compile-panel.d.ts.map +1 -0
- package/dist/tui/agent-view/compile-panel.js +34 -0
- package/dist/tui/agent-view/compile-panel.js.map +1 -0
- package/dist/tui/agent-view/index.d.ts +4 -0
- package/dist/tui/agent-view/index.d.ts.map +1 -0
- package/dist/tui/agent-view/index.js +31 -0
- package/dist/tui/agent-view/index.js.map +1 -0
- package/dist/tui/agent-view/memory-panel.d.ts +3 -0
- package/dist/tui/agent-view/memory-panel.d.ts.map +1 -0
- package/dist/tui/agent-view/memory-panel.js +80 -0
- package/dist/tui/agent-view/memory-panel.js.map +1 -0
- package/dist/tui/agent-view/session-panel.d.ts +3 -0
- package/dist/tui/agent-view/session-panel.d.ts.map +1 -0
- package/dist/tui/agent-view/session-panel.js +44 -0
- package/dist/tui/agent-view/session-panel.js.map +1 -0
- package/dist/tui/agent-view/status-bar.d.ts +7 -0
- package/dist/tui/agent-view/status-bar.d.ts.map +1 -0
- package/dist/tui/agent-view/status-bar.js +22 -0
- package/dist/tui/agent-view/status-bar.js.map +1 -0
- package/dist/tui/app.d.ts +9 -0
- package/dist/tui/app.d.ts.map +1 -0
- package/dist/tui/app.js +115 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/banner.d.ts +5 -0
- package/dist/tui/banner.d.ts.map +1 -0
- package/dist/tui/banner.js +17 -0
- package/dist/tui/banner.js.map +1 -0
- package/dist/tui/command-form.d.ts +9 -0
- package/dist/tui/command-form.d.ts.map +1 -0
- package/dist/tui/command-form.js +76 -0
- package/dist/tui/command-form.js.map +1 -0
- package/dist/tui/command-tree.d.ts +30 -0
- package/dist/tui/command-tree.d.ts.map +1 -0
- package/dist/tui/command-tree.js +43 -0
- package/dist/tui/command-tree.js.map +1 -0
- package/dist/tui/fleet-view/agent-row.d.ts +10 -0
- package/dist/tui/fleet-view/agent-row.d.ts.map +1 -0
- package/dist/tui/fleet-view/agent-row.js +80 -0
- package/dist/tui/fleet-view/agent-row.js.map +1 -0
- package/dist/tui/fleet-view/dispatch-input.d.ts +5 -0
- package/dist/tui/fleet-view/dispatch-input.d.ts.map +1 -0
- package/dist/tui/fleet-view/dispatch-input.js +36 -0
- package/dist/tui/fleet-view/dispatch-input.js.map +1 -0
- package/dist/tui/fleet-view/fleet-app.d.ts +11 -0
- package/dist/tui/fleet-view/fleet-app.d.ts.map +1 -0
- package/dist/tui/fleet-view/fleet-app.js +95 -0
- package/dist/tui/fleet-view/fleet-app.js.map +1 -0
- package/dist/tui/fleet-view/fleet-summary.d.ts +6 -0
- package/dist/tui/fleet-view/fleet-summary.d.ts.map +1 -0
- package/dist/tui/fleet-view/fleet-summary.js +19 -0
- package/dist/tui/fleet-view/fleet-summary.js.map +1 -0
- package/dist/tui/fleet-view/index.d.ts +16 -0
- package/dist/tui/fleet-view/index.d.ts.map +1 -0
- package/dist/tui/fleet-view/index.js +61 -0
- package/dist/tui/fleet-view/index.js.map +1 -0
- package/dist/tui/runner.d.ts +7 -0
- package/dist/tui/runner.d.ts.map +1 -0
- package/dist/tui/runner.js +36 -0
- package/dist/tui/runner.js.map +1 -0
- package/dist/tui/theme.d.ts +8 -0
- package/dist/tui/theme.d.ts.map +1 -0
- package/dist/tui/theme.js +10 -0
- package/dist/tui/theme.js.map +1 -0
- package/package.json +12 -7
- package/README.html +0 -379
package/dist/commands.test.js
CHANGED
|
@@ -3,7 +3,11 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
|
3
3
|
vi.mock("./lib/config.js", () => ({
|
|
4
4
|
getToken: vi.fn(() => "test-token"),
|
|
5
5
|
getApiUrl: vi.fn(() => "http://localhost:4000"),
|
|
6
|
-
readConfig: vi.fn(() => ({
|
|
6
|
+
readConfig: vi.fn(() => ({
|
|
7
|
+
token: "test-token",
|
|
8
|
+
orgSlug: "my-org",
|
|
9
|
+
workspaceSlug: "default",
|
|
10
|
+
})),
|
|
7
11
|
writeConfig: vi.fn(),
|
|
8
12
|
clearConfig: vi.fn(),
|
|
9
13
|
getOrgId: vi.fn(() => "my-org"),
|
|
@@ -67,9 +71,9 @@ import { imageListCommand } from "./commands/image.list.js";
|
|
|
67
71
|
import { imageAnalyzeCommand } from "./commands/image.analyze.js";
|
|
68
72
|
import { documentListCommand } from "./commands/document.list.js";
|
|
69
73
|
import { documentReadCommand } from "./commands/document.read.js";
|
|
70
|
-
import { formCreateCommand } from "./commands/form.create.js";
|
|
71
|
-
import { formSubmitCommand } from "./commands/form.submit.js";
|
|
72
74
|
import { automationCreateCommand } from "./commands/automation.create.js";
|
|
75
|
+
import { automationEnableCommand } from "./commands/automation.enable.js";
|
|
76
|
+
import { automationDisableCommand } from "./commands/automation.disable.js";
|
|
73
77
|
import { automationTriggerCommand } from "./commands/automation.trigger.js";
|
|
74
78
|
import { skillWorkspaceListCommand } from "./commands/skill.workspace.list.js";
|
|
75
79
|
import { agentMemoryRecallCommand } from "./commands/agent.memory.recall.js";
|
|
@@ -92,20 +96,16 @@ import { agentTaskBackgroundReadCommand } from "./commands/agent.task.background
|
|
|
92
96
|
import { agentTaskBackgroundCancelCommand } from "./commands/agent.task.background.cancel.js";
|
|
93
97
|
import { assetUploadCommand } from "./commands/asset.upload.js";
|
|
94
98
|
import { billingSubscriptionUpgradeStartCommand } from "./commands/billing.subscription.upgrade.start.js";
|
|
95
|
-
import { brandkitApplyCommand } from "./commands/brandkit.apply.js";
|
|
96
99
|
import { conversationPurgeCommand } from "./commands/conversation.purge.js";
|
|
97
100
|
import { documentsPdfCreateCommand } from "./commands/documents.pdf.create.js";
|
|
98
101
|
import { formFillCommand } from "./commands/form.fill.js";
|
|
99
102
|
import { orgMemberInviteDeclineCommand } from "./commands/org.member.invite.decline.js";
|
|
100
103
|
import { organizationCreateCommand } from "./commands/organization.create.js";
|
|
101
104
|
import { pluginCredentialSetSecretCommand } from "./commands/plugin.credential.set_secret.js";
|
|
102
|
-
import { pluginDenylistAddCommand } from "./commands/plugin.denylist.add.js";
|
|
103
|
-
import { pluginDenylistRemoveCommand } from "./commands/plugin.denylist.remove.js";
|
|
104
105
|
import { pluginOrgInstallBulkCommand } from "./commands/plugin.org.install_bulk.js";
|
|
105
106
|
import { pluginOrgListCommand } from "./commands/plugin.org.list.js";
|
|
106
107
|
import { pluginOrgSetEnabledCommand } from "./commands/plugin.org.set_enabled.js";
|
|
107
108
|
import { pluginRegistryRemoveCommand } from "./commands/plugin.registry.remove.js";
|
|
108
|
-
import { pluginRegistrySyncCommand } from "./commands/plugin.registry.sync.js";
|
|
109
109
|
import { pluginSettingsSetAuthAlertsCommand } from "./commands/plugin.settings.set_auth_alerts.js";
|
|
110
110
|
import { pluginWorkspaceSetEnabledCommand } from "./commands/plugin.workspace.set_enabled.js";
|
|
111
111
|
import { systemInstallInstructionsCommand } from "./commands/system.install.instructions.js";
|
|
@@ -140,7 +140,9 @@ afterEach(() => {
|
|
|
140
140
|
describe("auth login", () => {
|
|
141
141
|
it("exits 1 if email or password is missing", async () => {
|
|
142
142
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
143
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
143
|
+
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
144
|
+
throw new Error("exit");
|
|
145
|
+
});
|
|
144
146
|
await expect(() => authLoginCommand.parseAsync(["node", "cli"])).rejects.toThrow("exit");
|
|
145
147
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("email and password are required"));
|
|
146
148
|
consoleSpy.mockRestore();
|
|
@@ -148,8 +150,18 @@ describe("auth login", () => {
|
|
|
148
150
|
});
|
|
149
151
|
it("calls API with credentials and stores token", async () => {
|
|
150
152
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
151
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
152
|
-
|
|
153
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
154
|
+
token: "new-token",
|
|
155
|
+
user: { email: "user@example.com" },
|
|
156
|
+
});
|
|
157
|
+
await authLoginCommand.parseAsync([
|
|
158
|
+
"node",
|
|
159
|
+
"cli",
|
|
160
|
+
"--email",
|
|
161
|
+
"user@example.com",
|
|
162
|
+
"--password",
|
|
163
|
+
"secret",
|
|
164
|
+
]);
|
|
153
165
|
expect(mockApiRequest).toHaveBeenCalledWith("/auth/sign-in/email", expect.objectContaining({ method: "POST" }));
|
|
154
166
|
expect(mockWriteConfig).toHaveBeenCalledWith(expect.objectContaining({ token: "new-token" }));
|
|
155
167
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Authenticated"));
|
|
@@ -157,9 +169,18 @@ describe("auth login", () => {
|
|
|
157
169
|
});
|
|
158
170
|
it("exits 1 on API error during login", async () => {
|
|
159
171
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
160
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
172
|
+
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
173
|
+
throw new Error("exit");
|
|
174
|
+
});
|
|
161
175
|
mockApiRequest.mockRejectedValueOnce(new Error("Unauthorized"));
|
|
162
|
-
await expect(() => authLoginCommand.parseAsync([
|
|
176
|
+
await expect(() => authLoginCommand.parseAsync([
|
|
177
|
+
"node",
|
|
178
|
+
"cli",
|
|
179
|
+
"--email",
|
|
180
|
+
"a@b.com",
|
|
181
|
+
"--password",
|
|
182
|
+
"pw",
|
|
183
|
+
])).rejects.toThrow("exit");
|
|
163
184
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Error:"));
|
|
164
185
|
consoleSpy.mockRestore();
|
|
165
186
|
exitSpy.mockRestore();
|
|
@@ -167,7 +188,14 @@ describe("auth login", () => {
|
|
|
167
188
|
it("handles response with session.token shape", async () => {
|
|
168
189
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
169
190
|
mockApiRequest.mockResolvedValueOnce({ session: { token: "session-tok" } });
|
|
170
|
-
await authLoginCommand.parseAsync([
|
|
191
|
+
await authLoginCommand.parseAsync([
|
|
192
|
+
"node",
|
|
193
|
+
"cli",
|
|
194
|
+
"-e",
|
|
195
|
+
"a@b.com",
|
|
196
|
+
"-p",
|
|
197
|
+
"pw",
|
|
198
|
+
]);
|
|
171
199
|
expect(mockWriteConfig).toHaveBeenCalledWith(expect.objectContaining({ token: "session-tok" }));
|
|
172
200
|
consoleSpy.mockRestore();
|
|
173
201
|
});
|
|
@@ -222,15 +250,22 @@ describe("auth whoami", () => {
|
|
|
222
250
|
});
|
|
223
251
|
it("falls back to config values for org/workspace", async () => {
|
|
224
252
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
225
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
226
|
-
|
|
253
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
254
|
+
user: { email: "mac@example.com" },
|
|
255
|
+
});
|
|
256
|
+
vi.mocked(config.readConfig).mockReturnValue({
|
|
257
|
+
orgSlug: "cfg-org",
|
|
258
|
+
workspaceSlug: "cfg-ws",
|
|
259
|
+
});
|
|
227
260
|
await authWhoamiCommand.parseAsync(["node", "cli"]);
|
|
228
261
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("cfg-org"));
|
|
229
262
|
consoleSpy.mockRestore();
|
|
230
263
|
});
|
|
231
264
|
it("exits 1 on API error", async () => {
|
|
232
265
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
233
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
266
|
+
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
267
|
+
throw new Error("exit");
|
|
268
|
+
});
|
|
234
269
|
mockApiRequest.mockRejectedValueOnce(new Error("Forbidden"));
|
|
235
270
|
await expect(() => authWhoamiCommand.parseAsync(["node", "cli"])).rejects.toThrow("exit");
|
|
236
271
|
consoleSpy.mockRestore();
|
|
@@ -260,7 +295,9 @@ describe("org list", () => {
|
|
|
260
295
|
});
|
|
261
296
|
it("handles data array shape from API", async () => {
|
|
262
297
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
263
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
298
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
299
|
+
data: [{ id: "id1", slug: "org-1", name: "Org 1" }],
|
|
300
|
+
});
|
|
264
301
|
await orgListCommand.parseAsync(["node", "cli"]);
|
|
265
302
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("org-1"));
|
|
266
303
|
consoleSpy.mockRestore();
|
|
@@ -272,7 +309,9 @@ describe("org list", () => {
|
|
|
272
309
|
describe("org create", () => {
|
|
273
310
|
it("creates org and prints slug", async () => {
|
|
274
311
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
275
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
312
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
313
|
+
organization: { slug: "new-org", name: "New Org" },
|
|
314
|
+
});
|
|
276
315
|
await orgCreateCommand.parseAsync(["node", "cli", "New Org"]);
|
|
277
316
|
expect(mockApiRequest).toHaveBeenCalledWith("/organizations", expect.objectContaining({ method: "POST" }));
|
|
278
317
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("new-org"));
|
|
@@ -280,7 +319,9 @@ describe("org create", () => {
|
|
|
280
319
|
});
|
|
281
320
|
it("exits 1 on API error", async () => {
|
|
282
321
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
283
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
322
|
+
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
323
|
+
throw new Error("exit");
|
|
324
|
+
});
|
|
284
325
|
mockApiRequest.mockRejectedValueOnce(new Error("Conflict"));
|
|
285
326
|
await expect(() => orgCreateCommand.parseAsync(["node", "cli", "Dup"])).rejects.toThrow("exit");
|
|
286
327
|
consoleSpy.mockRestore();
|
|
@@ -294,7 +335,13 @@ describe("org member add", () => {
|
|
|
294
335
|
it("adds member and confirms", async () => {
|
|
295
336
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
296
337
|
mockApiRequest.mockResolvedValueOnce({});
|
|
297
|
-
await orgMemberAddCommand.parseAsync([
|
|
338
|
+
await orgMemberAddCommand.parseAsync([
|
|
339
|
+
"node",
|
|
340
|
+
"cli",
|
|
341
|
+
"new@example.com",
|
|
342
|
+
"--role",
|
|
343
|
+
"admin",
|
|
344
|
+
]);
|
|
298
345
|
expect(mockApiRequest).toHaveBeenCalledWith("/org/members", expect.objectContaining({ method: "POST" }));
|
|
299
346
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("new@example.com"));
|
|
300
347
|
consoleSpy.mockRestore();
|
|
@@ -302,7 +349,13 @@ describe("org member add", () => {
|
|
|
302
349
|
it("defaults role to member when no --role flag given", async () => {
|
|
303
350
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
304
351
|
mockApiRequest.mockResolvedValueOnce({});
|
|
305
|
-
await orgMemberAddCommand.parseAsync([
|
|
352
|
+
await orgMemberAddCommand.parseAsync([
|
|
353
|
+
"node",
|
|
354
|
+
"cli",
|
|
355
|
+
"x@example.com",
|
|
356
|
+
"--role",
|
|
357
|
+
"member",
|
|
358
|
+
]);
|
|
306
359
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("member"));
|
|
307
360
|
consoleSpy.mockRestore();
|
|
308
361
|
});
|
|
@@ -349,7 +402,9 @@ describe("workspace list", () => {
|
|
|
349
402
|
describe("workspace create", () => {
|
|
350
403
|
it("creates workspace and prints slug", async () => {
|
|
351
404
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
352
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
405
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
406
|
+
workspace: { slug: "my-ws", name: "My WS" },
|
|
407
|
+
});
|
|
353
408
|
await workspaceCreateCommand.parseAsync(["node", "cli", "My WS"]);
|
|
354
409
|
expect(mockApiRequest).toHaveBeenCalledWith("/workspaces", expect.objectContaining({ method: "POST" }));
|
|
355
410
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("my-ws"));
|
|
@@ -365,7 +420,10 @@ function makeSseResponse(text) {
|
|
|
365
420
|
const line = `data: ${JSON.stringify({ type: "text", text })}\n\nevent: done\ndata: [DONE]\n\n`;
|
|
366
421
|
const encoder = new TextEncoder();
|
|
367
422
|
const stream = new ReadableStream({
|
|
368
|
-
start(c) {
|
|
423
|
+
start(c) {
|
|
424
|
+
c.enqueue(encoder.encode(line));
|
|
425
|
+
c.close();
|
|
426
|
+
},
|
|
369
427
|
});
|
|
370
428
|
return new Response(stream, {
|
|
371
429
|
status: 200,
|
|
@@ -379,9 +437,13 @@ function makeErrorResponse(status, message) {
|
|
|
379
437
|
});
|
|
380
438
|
}
|
|
381
439
|
describe("chat send", () => {
|
|
382
|
-
afterEach(() => {
|
|
440
|
+
afterEach(() => {
|
|
441
|
+
vi.restoreAllMocks();
|
|
442
|
+
});
|
|
383
443
|
it("sends message and streams response to stdout", async () => {
|
|
384
|
-
const stdoutSpy = vi
|
|
444
|
+
const stdoutSpy = vi
|
|
445
|
+
.spyOn(process.stdout, "write")
|
|
446
|
+
.mockImplementation(() => true);
|
|
385
447
|
vi.spyOn(global, "fetch").mockResolvedValueOnce(makeSseResponse("Hello back!"));
|
|
386
448
|
await chatSendCommand.parseAsync(["node", "cli", "hello"]);
|
|
387
449
|
const written = stdoutSpy.mock.calls.map((c) => String(c[0])).join("");
|
|
@@ -389,19 +451,29 @@ describe("chat send", () => {
|
|
|
389
451
|
stdoutSpy.mockRestore();
|
|
390
452
|
});
|
|
391
453
|
it("passes conversationId when --conversation is provided", async () => {
|
|
392
|
-
const stdoutSpy = vi
|
|
454
|
+
const stdoutSpy = vi
|
|
455
|
+
.spyOn(process.stdout, "write")
|
|
456
|
+
.mockImplementation(() => true);
|
|
393
457
|
let capturedBody = null;
|
|
394
458
|
vi.spyOn(global, "fetch").mockImplementationOnce(async (_url, init) => {
|
|
395
459
|
capturedBody = JSON.parse(init.body);
|
|
396
460
|
return makeSseResponse("ok");
|
|
397
461
|
});
|
|
398
|
-
await chatSendCommand.parseAsync([
|
|
462
|
+
await chatSendCommand.parseAsync([
|
|
463
|
+
"node",
|
|
464
|
+
"cli",
|
|
465
|
+
"hi",
|
|
466
|
+
"--conversation",
|
|
467
|
+
"cnv_abc",
|
|
468
|
+
]);
|
|
399
469
|
expect(capturedBody["conversationId"]).toBe("cnv_abc");
|
|
400
470
|
stdoutSpy.mockRestore();
|
|
401
471
|
});
|
|
402
472
|
it("exits 1 when fetch throws a network error", async () => {
|
|
403
473
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
404
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
474
|
+
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
475
|
+
throw new Error("exit");
|
|
476
|
+
});
|
|
405
477
|
vi.spyOn(global, "fetch").mockRejectedValueOnce(new Error("ECONNREFUSED"));
|
|
406
478
|
await expect(() => chatSendCommand.parseAsync(["node", "cli", "msg"])).rejects.toThrow("exit");
|
|
407
479
|
consoleSpy.mockRestore();
|
|
@@ -409,7 +481,9 @@ describe("chat send", () => {
|
|
|
409
481
|
});
|
|
410
482
|
it("exits 1 on non-ok HTTP response", async () => {
|
|
411
483
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
412
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
484
|
+
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
485
|
+
throw new Error("exit");
|
|
486
|
+
});
|
|
413
487
|
vi.spyOn(global, "fetch").mockResolvedValueOnce(makeErrorResponse(503, "Service unavailable"));
|
|
414
488
|
await expect(() => chatSendCommand.parseAsync(["node", "cli", "test"])).rejects.toThrow();
|
|
415
489
|
consoleSpy.mockRestore();
|
|
@@ -440,7 +514,14 @@ describe("conversation list", () => {
|
|
|
440
514
|
it("passes filter and limit params", async () => {
|
|
441
515
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
442
516
|
mockApiRequest.mockResolvedValueOnce({ conversations: [] });
|
|
443
|
-
await conversationListCommand.parseAsync([
|
|
517
|
+
await conversationListCommand.parseAsync([
|
|
518
|
+
"node",
|
|
519
|
+
"cli",
|
|
520
|
+
"--filter",
|
|
521
|
+
"archived",
|
|
522
|
+
"--limit",
|
|
523
|
+
"5",
|
|
524
|
+
]);
|
|
444
525
|
expect(mockApiRequest).toHaveBeenCalledWith(expect.stringContaining("archived"));
|
|
445
526
|
consoleSpy.mockRestore();
|
|
446
527
|
});
|
|
@@ -456,7 +537,9 @@ describe("conversation delete", () => {
|
|
|
456
537
|
});
|
|
457
538
|
it("exits 1 on not found", async () => {
|
|
458
539
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
459
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
540
|
+
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
541
|
+
throw new Error("exit");
|
|
542
|
+
});
|
|
460
543
|
mockApiRequest.mockRejectedValueOnce(new Error("Not found"));
|
|
461
544
|
await expect(() => conversationDeleteCommand.parseAsync(["node", "cli", "bad"])).rejects.toThrow("exit");
|
|
462
545
|
consoleSpy.mockRestore();
|
|
@@ -475,7 +558,12 @@ describe("conversation archive", () => {
|
|
|
475
558
|
it("unarchives when --unarchive flag is set", async () => {
|
|
476
559
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
477
560
|
mockApiRequest.mockResolvedValueOnce({});
|
|
478
|
-
await conversationArchiveCommand.parseAsync([
|
|
561
|
+
await conversationArchiveCommand.parseAsync([
|
|
562
|
+
"node",
|
|
563
|
+
"cli",
|
|
564
|
+
"cnv_abc",
|
|
565
|
+
"--unarchive",
|
|
566
|
+
]);
|
|
479
567
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("unarchived"));
|
|
480
568
|
consoleSpy.mockRestore();
|
|
481
569
|
});
|
|
@@ -484,7 +572,12 @@ describe("conversation rename", () => {
|
|
|
484
572
|
it("renames conversation", async () => {
|
|
485
573
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
486
574
|
mockApiRequest.mockResolvedValueOnce({});
|
|
487
|
-
await conversationRenameCommand.parseAsync([
|
|
575
|
+
await conversationRenameCommand.parseAsync([
|
|
576
|
+
"node",
|
|
577
|
+
"cli",
|
|
578
|
+
"cnv_abc",
|
|
579
|
+
"New Title",
|
|
580
|
+
]);
|
|
488
581
|
expect(mockApiRequest).toHaveBeenCalledWith("/conversations/cnv_abc/rename", expect.objectContaining({ method: "POST" }));
|
|
489
582
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("New Title"));
|
|
490
583
|
consoleSpy.mockRestore();
|
|
@@ -496,7 +589,10 @@ describe("conversation rename", () => {
|
|
|
496
589
|
describe("api-key create", () => {
|
|
497
590
|
it("creates API key and displays secret", async () => {
|
|
498
591
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
499
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
592
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
593
|
+
id: "key_123",
|
|
594
|
+
key: "oxk_abc123secret",
|
|
595
|
+
});
|
|
500
596
|
const origIsTTY = process.stdout.isTTY;
|
|
501
597
|
process.stdout.isTTY = true; // Simulate interactive TTY to show full secret
|
|
502
598
|
await apiKeyCreateCommand.parseAsync(["node", "cli", "my-key"]);
|
|
@@ -508,7 +604,9 @@ describe("api-key create", () => {
|
|
|
508
604
|
});
|
|
509
605
|
it("exits 1 on API error", async () => {
|
|
510
606
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
511
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
607
|
+
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
608
|
+
throw new Error("exit");
|
|
609
|
+
});
|
|
512
610
|
mockApiRequest.mockRejectedValueOnce(new Error("Quota exceeded"));
|
|
513
611
|
await expect(() => apiKeyCreateCommand.parseAsync(["node", "cli", "key"])).rejects.toThrow("exit");
|
|
514
612
|
consoleSpy.mockRestore();
|
|
@@ -534,7 +632,11 @@ describe("notifications list", () => {
|
|
|
534
632
|
mockApiRequest.mockResolvedValueOnce({
|
|
535
633
|
notifications: [
|
|
536
634
|
{ publicId: "ntf_1", title: "New member joined", readAt: null },
|
|
537
|
-
{
|
|
635
|
+
{
|
|
636
|
+
publicId: "ntf_2",
|
|
637
|
+
title: "Subscription renewed",
|
|
638
|
+
readAt: "2026-06-01",
|
|
639
|
+
},
|
|
538
640
|
],
|
|
539
641
|
});
|
|
540
642
|
await notificationsListCommand.parseAsync(["node", "cli"]);
|
|
@@ -569,7 +671,12 @@ describe("notifications mark", () => {
|
|
|
569
671
|
it("marks notification as unread with --unread flag", async () => {
|
|
570
672
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
571
673
|
mockApiRequest.mockResolvedValueOnce({});
|
|
572
|
-
await notificationsMarkCommand.parseAsync([
|
|
674
|
+
await notificationsMarkCommand.parseAsync([
|
|
675
|
+
"node",
|
|
676
|
+
"cli",
|
|
677
|
+
"ntf_1",
|
|
678
|
+
"--unread",
|
|
679
|
+
]);
|
|
573
680
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("unread"));
|
|
574
681
|
consoleSpy.mockRestore();
|
|
575
682
|
});
|
|
@@ -581,7 +688,10 @@ describe("plugin list", () => {
|
|
|
581
688
|
it("lists installed plugins", async () => {
|
|
582
689
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
583
690
|
mockApiRequest.mockResolvedValueOnce({
|
|
584
|
-
plugins: [
|
|
691
|
+
plugins: [
|
|
692
|
+
{ pluginId: "github", enabled: true },
|
|
693
|
+
{ pluginId: "slack", enabled: false },
|
|
694
|
+
],
|
|
585
695
|
});
|
|
586
696
|
await pluginListCommand.parseAsync(["node", "cli"]);
|
|
587
697
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("github"));
|
|
@@ -607,7 +717,9 @@ describe("plugin install", () => {
|
|
|
607
717
|
});
|
|
608
718
|
it("exits 1 on install failure", async () => {
|
|
609
719
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
610
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
720
|
+
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
721
|
+
throw new Error("exit");
|
|
722
|
+
});
|
|
611
723
|
mockApiRequest.mockRejectedValueOnce(new Error("Not found in catalog"));
|
|
612
724
|
await expect(() => pluginInstallCommand.parseAsync(["node", "cli", "bad-plugin"])).rejects.toThrow("exit");
|
|
613
725
|
consoleSpy.mockRestore();
|
|
@@ -653,7 +765,9 @@ describe("billing status", () => {
|
|
|
653
765
|
});
|
|
654
766
|
it("exits 1 on API error", async () => {
|
|
655
767
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
656
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
768
|
+
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
769
|
+
throw new Error("exit");
|
|
770
|
+
});
|
|
657
771
|
mockApiRequest.mockRejectedValueOnce(new Error("Forbidden"));
|
|
658
772
|
await expect(() => billingStatusCommand.parseAsync(["node", "cli"])).rejects.toThrow("exit");
|
|
659
773
|
consoleSpy.mockRestore();
|
|
@@ -682,7 +796,9 @@ describe("agent skill list", () => {
|
|
|
682
796
|
it("lists agent skills successfully", async () => {
|
|
683
797
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
684
798
|
mockApiRequest.mockResolvedValueOnce({
|
|
685
|
-
skills: [
|
|
799
|
+
skills: [
|
|
800
|
+
{ id: "skill1", name: "memory", description: "Memory management" },
|
|
801
|
+
],
|
|
686
802
|
});
|
|
687
803
|
await agentSkillListCommand.parseAsync(["node", "cli"]);
|
|
688
804
|
expect(mockApiRequest).toHaveBeenCalledWith(expect.stringContaining("/agent/skill/list"), expect.objectContaining({ method: "GET" }));
|
|
@@ -697,7 +813,9 @@ describe("agent tool list", () => {
|
|
|
697
813
|
it("lists agent tools successfully", async () => {
|
|
698
814
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
699
815
|
mockApiRequest.mockResolvedValueOnce({
|
|
700
|
-
tools: [
|
|
816
|
+
tools: [
|
|
817
|
+
{ id: "tool1", name: "search", description: "Search capability" },
|
|
818
|
+
],
|
|
701
819
|
});
|
|
702
820
|
await agentToolListCommand.parseAsync(["node", "cli"]);
|
|
703
821
|
expect(mockApiRequest).toHaveBeenCalledWith(expect.stringContaining("/agent/tool/list"), expect.objectContaining({ method: "GET" }));
|
|
@@ -715,7 +833,12 @@ describe("billing credits purchase", () => {
|
|
|
715
833
|
credits: 100,
|
|
716
834
|
totalCost: 10,
|
|
717
835
|
});
|
|
718
|
-
await billingCreditsPurchaseCommand.parseAsync([
|
|
836
|
+
await billingCreditsPurchaseCommand.parseAsync([
|
|
837
|
+
"node",
|
|
838
|
+
"cli",
|
|
839
|
+
"-a",
|
|
840
|
+
"100",
|
|
841
|
+
]);
|
|
719
842
|
expect(mockApiRequest).toHaveBeenCalledWith("/billing/credits/purchase", expect.objectContaining({ method: "POST" }));
|
|
720
843
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Purchase initiated"));
|
|
721
844
|
consoleSpy.mockRestore();
|
|
@@ -763,7 +886,12 @@ describe("plugin org uninstall", () => {
|
|
|
763
886
|
id: "plugin1",
|
|
764
887
|
status: "uninstalled",
|
|
765
888
|
});
|
|
766
|
-
await pluginOrgUninstallCommand.parseAsync([
|
|
889
|
+
await pluginOrgUninstallCommand.parseAsync([
|
|
890
|
+
"node",
|
|
891
|
+
"cli",
|
|
892
|
+
"-p",
|
|
893
|
+
"plugin1",
|
|
894
|
+
]);
|
|
767
895
|
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/org/uninstall", expect.objectContaining({ method: "POST" }));
|
|
768
896
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Plugin uninstalled"));
|
|
769
897
|
consoleSpy.mockRestore();
|
|
@@ -776,7 +904,14 @@ describe("plugin catalog get", () => {
|
|
|
776
904
|
it("browses plugin catalog", async () => {
|
|
777
905
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
778
906
|
mockApiRequest.mockResolvedValueOnce({
|
|
779
|
-
plugins: [
|
|
907
|
+
plugins: [
|
|
908
|
+
{
|
|
909
|
+
id: "p1",
|
|
910
|
+
name: "github",
|
|
911
|
+
description: "GitHub integration",
|
|
912
|
+
category: "vcs",
|
|
913
|
+
},
|
|
914
|
+
],
|
|
780
915
|
});
|
|
781
916
|
await pluginCatalogGetCommand.parseAsync(["node", "cli"]);
|
|
782
917
|
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/catalog/get?", expect.objectContaining({ method: "GET" }));
|
|
@@ -795,7 +930,14 @@ describe("org member role change", () => {
|
|
|
795
930
|
role: "admin",
|
|
796
931
|
updated: true,
|
|
797
932
|
});
|
|
798
|
-
await orgMemberRoleChangeCommand.parseAsync([
|
|
933
|
+
await orgMemberRoleChangeCommand.parseAsync([
|
|
934
|
+
"node",
|
|
935
|
+
"cli",
|
|
936
|
+
"-u",
|
|
937
|
+
"user1",
|
|
938
|
+
"-r",
|
|
939
|
+
"admin",
|
|
940
|
+
]);
|
|
799
941
|
expect(mockApiRequest).toHaveBeenCalledWith("/org/member/role-change", expect.objectContaining({ method: "POST" }));
|
|
800
942
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Role updated"));
|
|
801
943
|
consoleSpy.mockRestore();
|
|
@@ -808,14 +950,30 @@ describe("agent approval resolve", () => {
|
|
|
808
950
|
it("resolves approval with approve decision", async () => {
|
|
809
951
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
810
952
|
mockApiRequest.mockResolvedValueOnce({ id: "apr1", status: "approved" });
|
|
811
|
-
await agentApprovalResolveCommand.parseAsync([
|
|
953
|
+
await agentApprovalResolveCommand.parseAsync([
|
|
954
|
+
"node",
|
|
955
|
+
"cli",
|
|
956
|
+
"-a",
|
|
957
|
+
"apr1",
|
|
958
|
+
"-d",
|
|
959
|
+
"approve",
|
|
960
|
+
]);
|
|
812
961
|
expect(mockApiRequest).toHaveBeenCalledWith("/agent/approval/resolve", expect.objectContaining({ method: "POST" }));
|
|
813
962
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("approved"));
|
|
814
963
|
consoleSpy.mockRestore();
|
|
815
964
|
});
|
|
816
965
|
it("rejects invalid decision", async () => {
|
|
817
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
818
|
-
|
|
966
|
+
const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => {
|
|
967
|
+
throw new Error("exit");
|
|
968
|
+
});
|
|
969
|
+
await expect(() => agentApprovalResolveCommand.parseAsync([
|
|
970
|
+
"node",
|
|
971
|
+
"cli",
|
|
972
|
+
"-a",
|
|
973
|
+
"apr1",
|
|
974
|
+
"-d",
|
|
975
|
+
"invalid",
|
|
976
|
+
])).rejects.toThrow();
|
|
819
977
|
exitSpy.mockRestore();
|
|
820
978
|
});
|
|
821
979
|
});
|
|
@@ -825,8 +983,19 @@ describe("agent approval resolve", () => {
|
|
|
825
983
|
describe("archive create", () => {
|
|
826
984
|
it("creates archive from conversation", async () => {
|
|
827
985
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
828
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
829
|
-
|
|
986
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
987
|
+
id: "arc1",
|
|
988
|
+
name: "Archive 1",
|
|
989
|
+
status: "created",
|
|
990
|
+
});
|
|
991
|
+
await archiveCreateCommand.parseAsync([
|
|
992
|
+
"node",
|
|
993
|
+
"cli",
|
|
994
|
+
"-c",
|
|
995
|
+
"conv1",
|
|
996
|
+
"-n",
|
|
997
|
+
"My Archive",
|
|
998
|
+
]);
|
|
830
999
|
expect(mockApiRequest).toHaveBeenCalledWith("/archive/create", expect.objectContaining({ method: "POST" }));
|
|
831
1000
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Archive created"));
|
|
832
1001
|
consoleSpy.mockRestore();
|
|
@@ -839,7 +1008,14 @@ describe("workflow run", () => {
|
|
|
839
1008
|
it("runs workflow with input", async () => {
|
|
840
1009
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
841
1010
|
mockApiRequest.mockResolvedValueOnce({ id: "run1", status: "started" });
|
|
842
|
-
await workflowRunCommand.parseAsync([
|
|
1011
|
+
await workflowRunCommand.parseAsync([
|
|
1012
|
+
"node",
|
|
1013
|
+
"cli",
|
|
1014
|
+
"-w",
|
|
1015
|
+
"wf1",
|
|
1016
|
+
"--input",
|
|
1017
|
+
'{"key":"value"}',
|
|
1018
|
+
]);
|
|
843
1019
|
expect(mockApiRequest).toHaveBeenCalledWith("/workflow/run", expect.objectContaining({ method: "POST" }));
|
|
844
1020
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("started"));
|
|
845
1021
|
consoleSpy.mockRestore();
|
|
@@ -862,7 +1038,12 @@ describe("user preferences update", () => {
|
|
|
862
1038
|
it("updates user preferences", async () => {
|
|
863
1039
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
864
1040
|
mockApiRequest.mockResolvedValueOnce({ theme: "light" });
|
|
865
|
-
await userPreferencesUpdateCommand.parseAsync([
|
|
1041
|
+
await userPreferencesUpdateCommand.parseAsync([
|
|
1042
|
+
"node",
|
|
1043
|
+
"cli",
|
|
1044
|
+
"-t",
|
|
1045
|
+
"light",
|
|
1046
|
+
]);
|
|
866
1047
|
expect(mockApiRequest).toHaveBeenCalledWith("/user/preferences/update", expect.objectContaining({ method: "POST" }));
|
|
867
1048
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("light"));
|
|
868
1049
|
consoleSpy.mockRestore();
|
|
@@ -874,7 +1055,14 @@ describe("user preferences update", () => {
|
|
|
874
1055
|
describe("workspace member list", () => {
|
|
875
1056
|
it("lists workspace members", async () => {
|
|
876
1057
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
877
|
-
mockApiRequest.mockResolvedValueOnce([
|
|
1058
|
+
mockApiRequest.mockResolvedValueOnce([
|
|
1059
|
+
{
|
|
1060
|
+
id: "m1",
|
|
1061
|
+
email: "user@example.com",
|
|
1062
|
+
role: "member",
|
|
1063
|
+
joined_at: "2026-06-08",
|
|
1064
|
+
},
|
|
1065
|
+
]);
|
|
878
1066
|
await workspaceMemberListCommand.parseAsync(["node", "cli"]);
|
|
879
1067
|
expect(mockApiRequest).toHaveBeenCalled();
|
|
880
1068
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("member(s)"));
|
|
@@ -885,7 +1073,12 @@ describe("workspace invite send", () => {
|
|
|
885
1073
|
it("sends workspace invitation", async () => {
|
|
886
1074
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
887
1075
|
mockApiRequest.mockResolvedValueOnce({ id: "inv1", status: "sent" });
|
|
888
|
-
await workspaceInviteSendCommand.parseAsync([
|
|
1076
|
+
await workspaceInviteSendCommand.parseAsync([
|
|
1077
|
+
"node",
|
|
1078
|
+
"cli",
|
|
1079
|
+
"-e",
|
|
1080
|
+
"user@example.com",
|
|
1081
|
+
]);
|
|
889
1082
|
expect(mockApiRequest).toHaveBeenCalledWith("/workspace/invite/send", expect.objectContaining({ method: "POST" }));
|
|
890
1083
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Invitation sent"));
|
|
891
1084
|
consoleSpy.mockRestore();
|
|
@@ -897,8 +1090,18 @@ describe("workspace invite send", () => {
|
|
|
897
1090
|
describe("conversation chat", () => {
|
|
898
1091
|
it("sends chat message", async () => {
|
|
899
1092
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
900
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
901
|
-
|
|
1093
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1094
|
+
id: "msg1",
|
|
1095
|
+
created_at: "2026-06-08T00:00:00Z",
|
|
1096
|
+
});
|
|
1097
|
+
await conversationChatCommand.parseAsync([
|
|
1098
|
+
"node",
|
|
1099
|
+
"cli",
|
|
1100
|
+
"-c",
|
|
1101
|
+
"conv1",
|
|
1102
|
+
"-m",
|
|
1103
|
+
"Hello",
|
|
1104
|
+
]);
|
|
902
1105
|
expect(mockApiRequest).toHaveBeenCalledWith("/conversation/chat", expect.objectContaining({ method: "POST" }));
|
|
903
1106
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Message sent"));
|
|
904
1107
|
consoleSpy.mockRestore();
|
|
@@ -910,7 +1113,10 @@ describe("conversation chat", () => {
|
|
|
910
1113
|
describe("image create", () => {
|
|
911
1114
|
it("creates image from prompt", async () => {
|
|
912
1115
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
913
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1116
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1117
|
+
id: "img1",
|
|
1118
|
+
url: "https://example.com/img1.jpg",
|
|
1119
|
+
});
|
|
914
1120
|
await imageCreateCommand.parseAsync(["node", "cli", "-p", "A blue sky"]);
|
|
915
1121
|
expect(mockApiRequest).toHaveBeenCalledWith("/image/create", expect.objectContaining({ method: "POST" }));
|
|
916
1122
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Image created"));
|
|
@@ -920,7 +1126,16 @@ describe("image create", () => {
|
|
|
920
1126
|
describe("image list", () => {
|
|
921
1127
|
it("lists images", async () => {
|
|
922
1128
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
923
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1129
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1130
|
+
images: [
|
|
1131
|
+
{
|
|
1132
|
+
id: "img1",
|
|
1133
|
+
url: "https://example.com/img1.jpg",
|
|
1134
|
+
prompt: "Blue sky",
|
|
1135
|
+
created_at: "2026-06-08",
|
|
1136
|
+
},
|
|
1137
|
+
],
|
|
1138
|
+
});
|
|
924
1139
|
await imageListCommand.parseAsync(["node", "cli"]);
|
|
925
1140
|
expect(mockApiRequest).toHaveBeenCalled();
|
|
926
1141
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Images"));
|
|
@@ -930,7 +1145,10 @@ describe("image list", () => {
|
|
|
930
1145
|
describe("image analyze", () => {
|
|
931
1146
|
it("analyzes image", async () => {
|
|
932
1147
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
933
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1148
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1149
|
+
analysis: "sky",
|
|
1150
|
+
tags: ["nature", "outdoor"],
|
|
1151
|
+
});
|
|
934
1152
|
await imageAnalyzeCommand.parseAsync(["node", "cli", "-i", "img1"]);
|
|
935
1153
|
expect(mockApiRequest).toHaveBeenCalledWith("/image/analyze", expect.objectContaining({ method: "POST" }));
|
|
936
1154
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Analysis"));
|
|
@@ -953,7 +1171,17 @@ describe("document create", () => {
|
|
|
953
1171
|
describe("document list", () => {
|
|
954
1172
|
it("lists documents", async () => {
|
|
955
1173
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
956
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1174
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1175
|
+
documents: [
|
|
1176
|
+
{
|
|
1177
|
+
id: "doc1",
|
|
1178
|
+
title: "Doc 1",
|
|
1179
|
+
created_at: "2026-06-08",
|
|
1180
|
+
updated_at: "2026-06-08",
|
|
1181
|
+
author: "user",
|
|
1182
|
+
},
|
|
1183
|
+
],
|
|
1184
|
+
});
|
|
957
1185
|
await documentListCommand.parseAsync(["node", "cli"]);
|
|
958
1186
|
expect(mockApiRequest).toHaveBeenCalled();
|
|
959
1187
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Documents"));
|
|
@@ -963,7 +1191,12 @@ describe("document list", () => {
|
|
|
963
1191
|
describe("document read", () => {
|
|
964
1192
|
it("reads document", async () => {
|
|
965
1193
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
966
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1194
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1195
|
+
title: "Doc 1",
|
|
1196
|
+
content: "Content...",
|
|
1197
|
+
metadata: {},
|
|
1198
|
+
created_at: "2026-06-08",
|
|
1199
|
+
});
|
|
967
1200
|
await documentReadCommand.parseAsync(["node", "cli", "-d", "doc1"]);
|
|
968
1201
|
expect(mockApiRequest).toHaveBeenCalled();
|
|
969
1202
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Title:"));
|
|
@@ -971,35 +1204,14 @@ describe("document read", () => {
|
|
|
971
1204
|
});
|
|
972
1205
|
});
|
|
973
1206
|
// ---------------------------------------------------------------------------
|
|
974
|
-
// form management
|
|
975
|
-
// ---------------------------------------------------------------------------
|
|
976
|
-
describe("form create", () => {
|
|
977
|
-
it("creates form", async () => {
|
|
978
|
-
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
979
|
-
mockApiRequest.mockResolvedValueOnce({ id: "form1", title: "Survey" });
|
|
980
|
-
await formCreateCommand.parseAsync(["node", "cli", "-t", "Survey"]);
|
|
981
|
-
expect(mockApiRequest).toHaveBeenCalledWith("/form/create", expect.objectContaining({ method: "POST" }));
|
|
982
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Form created"));
|
|
983
|
-
consoleSpy.mockRestore();
|
|
984
|
-
});
|
|
985
|
-
});
|
|
986
|
-
describe("form submit", () => {
|
|
987
|
-
it("submits form", async () => {
|
|
988
|
-
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
989
|
-
mockApiRequest.mockResolvedValueOnce({ id: "sub1", status: "submitted" });
|
|
990
|
-
await formSubmitCommand.parseAsync(["node", "cli", "-f", "form1"]);
|
|
991
|
-
expect(mockApiRequest).toHaveBeenCalledWith("/form/submit", expect.objectContaining({ method: "POST" }));
|
|
992
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("submitted"));
|
|
993
|
-
consoleSpy.mockRestore();
|
|
994
|
-
});
|
|
995
|
-
});
|
|
996
|
-
// ---------------------------------------------------------------------------
|
|
997
1207
|
// automation management
|
|
998
1208
|
// ---------------------------------------------------------------------------
|
|
999
1209
|
describe("automation list", () => {
|
|
1000
1210
|
it("lists automations", async () => {
|
|
1001
1211
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1002
|
-
mockApiRequest.mockResolvedValueOnce([
|
|
1212
|
+
mockApiRequest.mockResolvedValueOnce([
|
|
1213
|
+
{ id: "auto1", name: "Auto 1", status: "active", triggers: ["event1"] },
|
|
1214
|
+
]);
|
|
1003
1215
|
await automationListCommand.parseAsync(["node", "cli"]);
|
|
1004
1216
|
expect(mockApiRequest).toHaveBeenCalled();
|
|
1005
1217
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("automation(s)"));
|
|
@@ -1007,14 +1219,138 @@ describe("automation list", () => {
|
|
|
1007
1219
|
});
|
|
1008
1220
|
});
|
|
1009
1221
|
describe("automation create", () => {
|
|
1010
|
-
it("creates automation", async () => {
|
|
1222
|
+
it("creates automation with the contract payload shape", async () => {
|
|
1011
1223
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1012
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1013
|
-
|
|
1224
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1225
|
+
automation_id: "plt_1",
|
|
1226
|
+
playbook_id: "plb_1",
|
|
1227
|
+
name: "My Automation",
|
|
1228
|
+
status: "inactive",
|
|
1229
|
+
triggerType: "api",
|
|
1230
|
+
enabled: false,
|
|
1231
|
+
});
|
|
1232
|
+
await automationCreateCommand.parseAsync([
|
|
1233
|
+
"node",
|
|
1234
|
+
"cli",
|
|
1235
|
+
"-n",
|
|
1236
|
+
"My Automation",
|
|
1237
|
+
]);
|
|
1014
1238
|
expect(mockApiRequest).toHaveBeenCalledWith("/automation/create", expect.objectContaining({ method: "POST" }));
|
|
1239
|
+
const body = JSON.parse((mockApiRequest.mock.calls[0]?.[1]).body);
|
|
1240
|
+
expect(body).toMatchObject({
|
|
1241
|
+
name: "My Automation",
|
|
1242
|
+
triggerType: "api",
|
|
1243
|
+
triggerConfig: {},
|
|
1244
|
+
steps: [],
|
|
1245
|
+
enabled: false,
|
|
1246
|
+
});
|
|
1015
1247
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Automation created"));
|
|
1016
1248
|
consoleSpy.mockRestore();
|
|
1017
1249
|
});
|
|
1250
|
+
it("builds event triggerConfig from --entity-type/--event-type/--conditions and passes --enabled", async () => {
|
|
1251
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1252
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1253
|
+
automation_id: "plt_2",
|
|
1254
|
+
playbook_id: "plb_2",
|
|
1255
|
+
name: "Watcher",
|
|
1256
|
+
status: "active",
|
|
1257
|
+
triggerType: "event",
|
|
1258
|
+
enabled: true,
|
|
1259
|
+
});
|
|
1260
|
+
await automationCreateCommand.parseAsync([
|
|
1261
|
+
"node",
|
|
1262
|
+
"cli",
|
|
1263
|
+
"-n",
|
|
1264
|
+
"Watcher",
|
|
1265
|
+
"--trigger-type",
|
|
1266
|
+
"event",
|
|
1267
|
+
"--entity-type",
|
|
1268
|
+
"Contact",
|
|
1269
|
+
"--event-type",
|
|
1270
|
+
"node.updated",
|
|
1271
|
+
"--conditions",
|
|
1272
|
+
'[{"property":"status","toValue":"customer","operator":"eq"}]',
|
|
1273
|
+
"--enabled",
|
|
1274
|
+
]);
|
|
1275
|
+
const body = JSON.parse((mockApiRequest.mock.calls[0]?.[1]).body);
|
|
1276
|
+
expect(body).toMatchObject({
|
|
1277
|
+
name: "Watcher",
|
|
1278
|
+
triggerType: "event",
|
|
1279
|
+
triggerConfig: {
|
|
1280
|
+
entityType: "Contact",
|
|
1281
|
+
eventType: "node.updated",
|
|
1282
|
+
propertyConditions: [
|
|
1283
|
+
{ property: "status", toValue: "customer", operator: "eq" },
|
|
1284
|
+
],
|
|
1285
|
+
},
|
|
1286
|
+
enabled: true,
|
|
1287
|
+
});
|
|
1288
|
+
consoleSpy.mockRestore();
|
|
1289
|
+
});
|
|
1290
|
+
it("builds schedule triggerConfig from --cron/--timezone", async () => {
|
|
1291
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1292
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1293
|
+
automation_id: "plt_3",
|
|
1294
|
+
playbook_id: "plb_3",
|
|
1295
|
+
name: "Report",
|
|
1296
|
+
status: "inactive",
|
|
1297
|
+
triggerType: "schedule",
|
|
1298
|
+
enabled: false,
|
|
1299
|
+
});
|
|
1300
|
+
await automationCreateCommand.parseAsync([
|
|
1301
|
+
"node",
|
|
1302
|
+
"cli",
|
|
1303
|
+
"-n",
|
|
1304
|
+
"Report",
|
|
1305
|
+
"--trigger-type",
|
|
1306
|
+
"schedule",
|
|
1307
|
+
"--cron",
|
|
1308
|
+
"0 9 * * 1",
|
|
1309
|
+
"--timezone",
|
|
1310
|
+
"America/New_York",
|
|
1311
|
+
]);
|
|
1312
|
+
const body = JSON.parse((mockApiRequest.mock.calls[0]?.[1]).body);
|
|
1313
|
+
expect(body).toMatchObject({
|
|
1314
|
+
triggerType: "schedule",
|
|
1315
|
+
triggerConfig: {
|
|
1316
|
+
cronExpression: "0 9 * * 1",
|
|
1317
|
+
timezone: "America/New_York",
|
|
1318
|
+
},
|
|
1319
|
+
});
|
|
1320
|
+
consoleSpy.mockRestore();
|
|
1321
|
+
});
|
|
1322
|
+
});
|
|
1323
|
+
describe("automation enable", () => {
|
|
1324
|
+
it("enables automation", async () => {
|
|
1325
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1326
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1327
|
+
automation_id: "plt_1",
|
|
1328
|
+
enabled: true,
|
|
1329
|
+
status: "active",
|
|
1330
|
+
});
|
|
1331
|
+
await automationEnableCommand.parseAsync(["node", "cli", "plt_1"]);
|
|
1332
|
+
expect(mockApiRequest).toHaveBeenCalledWith("/automation/enable", expect.objectContaining({ method: "POST" }));
|
|
1333
|
+
const body = JSON.parse((mockApiRequest.mock.calls[0]?.[1]).body);
|
|
1334
|
+
expect(body).toEqual({ automation_id: "plt_1" });
|
|
1335
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Automation enabled"));
|
|
1336
|
+
consoleSpy.mockRestore();
|
|
1337
|
+
});
|
|
1338
|
+
});
|
|
1339
|
+
describe("automation disable", () => {
|
|
1340
|
+
it("disables automation", async () => {
|
|
1341
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1342
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1343
|
+
automation_id: "plt_1",
|
|
1344
|
+
enabled: false,
|
|
1345
|
+
status: "paused",
|
|
1346
|
+
});
|
|
1347
|
+
await automationDisableCommand.parseAsync(["node", "cli", "plt_1"]);
|
|
1348
|
+
expect(mockApiRequest).toHaveBeenCalledWith("/automation/disable", expect.objectContaining({ method: "POST" }));
|
|
1349
|
+
const body = JSON.parse((mockApiRequest.mock.calls[0]?.[1]).body);
|
|
1350
|
+
expect(body).toEqual({ automation_id: "plt_1" });
|
|
1351
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Automation disabled"));
|
|
1352
|
+
consoleSpy.mockRestore();
|
|
1353
|
+
});
|
|
1018
1354
|
});
|
|
1019
1355
|
describe("automation trigger", () => {
|
|
1020
1356
|
it("triggers automation", async () => {
|
|
@@ -1032,7 +1368,16 @@ describe("automation trigger", () => {
|
|
|
1032
1368
|
describe("skill workspace list", () => {
|
|
1033
1369
|
it("lists workspace skills", async () => {
|
|
1034
1370
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1035
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1371
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1372
|
+
skills: [
|
|
1373
|
+
{
|
|
1374
|
+
id: "skill1",
|
|
1375
|
+
name: "Research",
|
|
1376
|
+
enabled: true,
|
|
1377
|
+
description: "Research skill",
|
|
1378
|
+
},
|
|
1379
|
+
],
|
|
1380
|
+
});
|
|
1036
1381
|
await skillWorkspaceListCommand.parseAsync(["node", "cli"]);
|
|
1037
1382
|
expect(mockApiRequest).toHaveBeenCalled();
|
|
1038
1383
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Workspace skills"));
|
|
@@ -1045,18 +1390,40 @@ describe("skill workspace list", () => {
|
|
|
1045
1390
|
describe("agent memory recall", () => {
|
|
1046
1391
|
it("recalls memory observations", async () => {
|
|
1047
1392
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1048
|
-
const mockResult = {
|
|
1393
|
+
const mockResult = {
|
|
1394
|
+
observations: [
|
|
1395
|
+
{ id: "obs1", text: "User prefers dark mode", score: 0.9 },
|
|
1396
|
+
],
|
|
1397
|
+
};
|
|
1049
1398
|
mockApiRequest.mockResolvedValueOnce(mockResult);
|
|
1050
|
-
await agentMemoryRecallCommand.parseAsync([
|
|
1399
|
+
await agentMemoryRecallCommand.parseAsync([
|
|
1400
|
+
"node",
|
|
1401
|
+
"cli",
|
|
1402
|
+
"-a",
|
|
1403
|
+
"agent1",
|
|
1404
|
+
"-q",
|
|
1405
|
+
"user preferences",
|
|
1406
|
+
]);
|
|
1051
1407
|
expect(mockApiRequest).toHaveBeenCalledWith("/agent/memory/recall", expect.objectContaining({ method: "POST" }));
|
|
1052
1408
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("obs1"));
|
|
1053
1409
|
consoleSpy.mockRestore();
|
|
1054
1410
|
});
|
|
1055
1411
|
it("handles recall failure", async () => {
|
|
1056
1412
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1057
|
-
const exitSpy = vi
|
|
1413
|
+
const exitSpy = vi
|
|
1414
|
+
.spyOn(process, "exit")
|
|
1415
|
+
.mockImplementation((_code) => {
|
|
1416
|
+
throw new Error("process.exit");
|
|
1417
|
+
});
|
|
1058
1418
|
mockApiRequest.mockRejectedValueOnce(new Error("Network error"));
|
|
1059
|
-
await expect(agentMemoryRecallCommand.parseAsync([
|
|
1419
|
+
await expect(agentMemoryRecallCommand.parseAsync([
|
|
1420
|
+
"node",
|
|
1421
|
+
"cli",
|
|
1422
|
+
"-a",
|
|
1423
|
+
"agent1",
|
|
1424
|
+
"-q",
|
|
1425
|
+
"query",
|
|
1426
|
+
])).rejects.toThrow();
|
|
1060
1427
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to recall"), expect.any(Error));
|
|
1061
1428
|
consoleSpy.mockRestore();
|
|
1062
1429
|
exitSpy.mockRestore();
|
|
@@ -1067,7 +1434,14 @@ describe("agent memory write", () => {
|
|
|
1067
1434
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1068
1435
|
const mockResult = { id: "obs2", status: "stored" };
|
|
1069
1436
|
mockApiRequest.mockResolvedValueOnce(mockResult);
|
|
1070
|
-
await agentMemoryWriteCommand.parseAsync([
|
|
1437
|
+
await agentMemoryWriteCommand.parseAsync([
|
|
1438
|
+
"node",
|
|
1439
|
+
"cli",
|
|
1440
|
+
"-a",
|
|
1441
|
+
"agent1",
|
|
1442
|
+
"-t",
|
|
1443
|
+
"User prefers TypeScript",
|
|
1444
|
+
]);
|
|
1071
1445
|
expect(mockApiRequest).toHaveBeenCalledWith("/agent/memory/write", expect.objectContaining({ method: "POST" }));
|
|
1072
1446
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("obs2"));
|
|
1073
1447
|
consoleSpy.mockRestore();
|
|
@@ -1075,16 +1449,36 @@ describe("agent memory write", () => {
|
|
|
1075
1449
|
it("writes a memory observation with tags", async () => {
|
|
1076
1450
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1077
1451
|
mockApiRequest.mockResolvedValueOnce({ id: "obs3", status: "stored" });
|
|
1078
|
-
await agentMemoryWriteCommand.parseAsync([
|
|
1452
|
+
await agentMemoryWriteCommand.parseAsync([
|
|
1453
|
+
"node",
|
|
1454
|
+
"cli",
|
|
1455
|
+
"-a",
|
|
1456
|
+
"agent1",
|
|
1457
|
+
"-t",
|
|
1458
|
+
"Uses dark mode",
|
|
1459
|
+
"--tags",
|
|
1460
|
+
"ui,preferences",
|
|
1461
|
+
]);
|
|
1079
1462
|
const callBody = JSON.parse(mockApiRequest.mock.calls[0][1].body);
|
|
1080
1463
|
expect(callBody.tags).toEqual(["ui", "preferences"]);
|
|
1081
1464
|
consoleSpy.mockRestore();
|
|
1082
1465
|
});
|
|
1083
1466
|
it("handles write failure", async () => {
|
|
1084
1467
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1085
|
-
const exitSpy = vi
|
|
1468
|
+
const exitSpy = vi
|
|
1469
|
+
.spyOn(process, "exit")
|
|
1470
|
+
.mockImplementation((_code) => {
|
|
1471
|
+
throw new Error("process.exit");
|
|
1472
|
+
});
|
|
1086
1473
|
mockApiRequest.mockRejectedValueOnce(new Error("Network error"));
|
|
1087
|
-
await expect(agentMemoryWriteCommand.parseAsync([
|
|
1474
|
+
await expect(agentMemoryWriteCommand.parseAsync([
|
|
1475
|
+
"node",
|
|
1476
|
+
"cli",
|
|
1477
|
+
"-a",
|
|
1478
|
+
"agent1",
|
|
1479
|
+
"-t",
|
|
1480
|
+
"text",
|
|
1481
|
+
])).rejects.toThrow();
|
|
1088
1482
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to write"), expect.any(Error));
|
|
1089
1483
|
consoleSpy.mockRestore();
|
|
1090
1484
|
exitSpy.mockRestore();
|
|
@@ -1096,26 +1490,59 @@ describe("agent memory write", () => {
|
|
|
1096
1490
|
describe("documents generate", () => {
|
|
1097
1491
|
it("generates a document from template", async () => {
|
|
1098
1492
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1099
|
-
const mockResult = {
|
|
1493
|
+
const mockResult = {
|
|
1494
|
+
id: "doc1",
|
|
1495
|
+
status: "complete",
|
|
1496
|
+
url: "https://example.com/doc.pdf",
|
|
1497
|
+
};
|
|
1100
1498
|
mockApiRequest.mockResolvedValueOnce(mockResult);
|
|
1101
|
-
await documentsGenerateCommand.parseAsync([
|
|
1499
|
+
await documentsGenerateCommand.parseAsync([
|
|
1500
|
+
"node",
|
|
1501
|
+
"cli",
|
|
1502
|
+
"-t",
|
|
1503
|
+
"report",
|
|
1504
|
+
"-c",
|
|
1505
|
+
'{"title":"Q1 Report"}',
|
|
1506
|
+
]);
|
|
1102
1507
|
expect(mockApiRequest).toHaveBeenCalledWith("/documents/generate", expect.objectContaining({ method: "POST" }));
|
|
1103
1508
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("doc1"));
|
|
1104
1509
|
consoleSpy.mockRestore();
|
|
1105
1510
|
});
|
|
1106
1511
|
it("fails on invalid JSON context", async () => {
|
|
1107
1512
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1108
|
-
const exitSpy = vi
|
|
1109
|
-
|
|
1513
|
+
const exitSpy = vi
|
|
1514
|
+
.spyOn(process, "exit")
|
|
1515
|
+
.mockImplementation((_code) => {
|
|
1516
|
+
throw new Error("process.exit");
|
|
1517
|
+
});
|
|
1518
|
+
await expect(documentsGenerateCommand.parseAsync([
|
|
1519
|
+
"node",
|
|
1520
|
+
"cli",
|
|
1521
|
+
"-t",
|
|
1522
|
+
"report",
|
|
1523
|
+
"-c",
|
|
1524
|
+
"not-json",
|
|
1525
|
+
])).rejects.toThrow();
|
|
1110
1526
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Invalid JSON"), expect.anything());
|
|
1111
1527
|
consoleSpy.mockRestore();
|
|
1112
1528
|
exitSpy.mockRestore();
|
|
1113
1529
|
});
|
|
1114
1530
|
it("handles generate failure", async () => {
|
|
1115
1531
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1116
|
-
const exitSpy = vi
|
|
1532
|
+
const exitSpy = vi
|
|
1533
|
+
.spyOn(process, "exit")
|
|
1534
|
+
.mockImplementation((_code) => {
|
|
1535
|
+
throw new Error("process.exit");
|
|
1536
|
+
});
|
|
1117
1537
|
mockApiRequest.mockRejectedValueOnce(new Error("Template not found"));
|
|
1118
|
-
await expect(documentsGenerateCommand.parseAsync([
|
|
1538
|
+
await expect(documentsGenerateCommand.parseAsync([
|
|
1539
|
+
"node",
|
|
1540
|
+
"cli",
|
|
1541
|
+
"-t",
|
|
1542
|
+
"report",
|
|
1543
|
+
"-c",
|
|
1544
|
+
"{}",
|
|
1545
|
+
])).rejects.toThrow();
|
|
1119
1546
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to generate"), expect.any(Error));
|
|
1120
1547
|
consoleSpy.mockRestore();
|
|
1121
1548
|
exitSpy.mockRestore();
|
|
@@ -1129,14 +1556,23 @@ describe("image generate", () => {
|
|
|
1129
1556
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1130
1557
|
const mockResult = { url: "https://example.com/img.png", id: "img1" };
|
|
1131
1558
|
mockApiRequest.mockResolvedValueOnce(mockResult);
|
|
1132
|
-
await imageGenerateCommand.parseAsync([
|
|
1559
|
+
await imageGenerateCommand.parseAsync([
|
|
1560
|
+
"node",
|
|
1561
|
+
"cli",
|
|
1562
|
+
"-p",
|
|
1563
|
+
"A sunset over the ocean",
|
|
1564
|
+
]);
|
|
1133
1565
|
expect(mockApiRequest).toHaveBeenCalledWith("/image/generate", expect.objectContaining({ method: "POST" }));
|
|
1134
1566
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("img1"));
|
|
1135
1567
|
consoleSpy.mockRestore();
|
|
1136
1568
|
});
|
|
1137
1569
|
it("handles generate failure", async () => {
|
|
1138
1570
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1139
|
-
const exitSpy = vi
|
|
1571
|
+
const exitSpy = vi
|
|
1572
|
+
.spyOn(process, "exit")
|
|
1573
|
+
.mockImplementation((_code) => {
|
|
1574
|
+
throw new Error("process.exit");
|
|
1575
|
+
});
|
|
1140
1576
|
mockApiRequest.mockRejectedValueOnce(new Error("Model not found"));
|
|
1141
1577
|
await expect(imageGenerateCommand.parseAsync(["node", "cli", "-p", "a cat"])).rejects.toThrow();
|
|
1142
1578
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to generate"), expect.any(Error));
|
|
@@ -1150,15 +1586,27 @@ describe("image generate", () => {
|
|
|
1150
1586
|
describe("org member invite accept", () => {
|
|
1151
1587
|
it("accepts an invitation", async () => {
|
|
1152
1588
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1153
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1154
|
-
|
|
1589
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1590
|
+
status: "accepted",
|
|
1591
|
+
orgSlug: "my-org",
|
|
1592
|
+
});
|
|
1593
|
+
await orgMemberInviteAcceptCommand.parseAsync([
|
|
1594
|
+
"node",
|
|
1595
|
+
"cli",
|
|
1596
|
+
"-i",
|
|
1597
|
+
"invite123",
|
|
1598
|
+
]);
|
|
1155
1599
|
expect(mockApiRequest).toHaveBeenCalledWith("/org/member/invite/accept", expect.objectContaining({ method: "POST" }));
|
|
1156
1600
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("accepted"));
|
|
1157
1601
|
consoleSpy.mockRestore();
|
|
1158
1602
|
});
|
|
1159
1603
|
it("handles accept failure", async () => {
|
|
1160
1604
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1161
|
-
const exitSpy = vi
|
|
1605
|
+
const exitSpy = vi
|
|
1606
|
+
.spyOn(process, "exit")
|
|
1607
|
+
.mockImplementation((_code) => {
|
|
1608
|
+
throw new Error("process.exit");
|
|
1609
|
+
});
|
|
1162
1610
|
mockApiRequest.mockRejectedValueOnce(new Error("Invitation expired"));
|
|
1163
1611
|
await expect(orgMemberInviteAcceptCommand.parseAsync(["node", "cli", "-i", "inv1"])).rejects.toThrow();
|
|
1164
1612
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to accept"), expect.any(Error));
|
|
@@ -1172,7 +1620,10 @@ describe("org member invite accept", () => {
|
|
|
1172
1620
|
describe("plugin catalog browse", () => {
|
|
1173
1621
|
it("browses the plugin catalog", async () => {
|
|
1174
1622
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1175
|
-
const mockResult = {
|
|
1623
|
+
const mockResult = {
|
|
1624
|
+
plugins: [{ id: "p1", name: "Slack", category: "messaging" }],
|
|
1625
|
+
total: 1,
|
|
1626
|
+
};
|
|
1176
1627
|
mockApiRequest.mockResolvedValueOnce(mockResult);
|
|
1177
1628
|
await pluginCatalogBrowseCommand.parseAsync(["node", "cli"]);
|
|
1178
1629
|
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/catalog/browse", expect.objectContaining({ method: "GET" }));
|
|
@@ -1181,7 +1632,11 @@ describe("plugin catalog browse", () => {
|
|
|
1181
1632
|
});
|
|
1182
1633
|
it("handles browse failure", async () => {
|
|
1183
1634
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1184
|
-
const exitSpy = vi
|
|
1635
|
+
const exitSpy = vi
|
|
1636
|
+
.spyOn(process, "exit")
|
|
1637
|
+
.mockImplementation((_code) => {
|
|
1638
|
+
throw new Error("process.exit");
|
|
1639
|
+
});
|
|
1185
1640
|
mockApiRequest.mockRejectedValueOnce(new Error("Service unavailable"));
|
|
1186
1641
|
await expect(pluginCatalogBrowseCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
1187
1642
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to browse"), expect.any(Error));
|
|
@@ -1195,15 +1650,27 @@ describe("plugin catalog browse", () => {
|
|
|
1195
1650
|
describe("plugin credential reauth", () => {
|
|
1196
1651
|
it("re-authenticates plugin credentials", async () => {
|
|
1197
1652
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1198
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1199
|
-
|
|
1653
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1654
|
+
status: "reauthenticated",
|
|
1655
|
+
pluginId: "slack",
|
|
1656
|
+
});
|
|
1657
|
+
await pluginCredentialReauthCommand.parseAsync([
|
|
1658
|
+
"node",
|
|
1659
|
+
"cli",
|
|
1660
|
+
"-p",
|
|
1661
|
+
"slack",
|
|
1662
|
+
]);
|
|
1200
1663
|
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/credential/reauth", expect.objectContaining({ method: "POST" }));
|
|
1201
1664
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("reauthenticated"));
|
|
1202
1665
|
consoleSpy.mockRestore();
|
|
1203
1666
|
});
|
|
1204
1667
|
it("handles reauth failure", async () => {
|
|
1205
1668
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1206
|
-
const exitSpy = vi
|
|
1669
|
+
const exitSpy = vi
|
|
1670
|
+
.spyOn(process, "exit")
|
|
1671
|
+
.mockImplementation((_code) => {
|
|
1672
|
+
throw new Error("process.exit");
|
|
1673
|
+
});
|
|
1207
1674
|
mockApiRequest.mockRejectedValueOnce(new Error("OAuth error"));
|
|
1208
1675
|
await expect(pluginCredentialReauthCommand.parseAsync(["node", "cli", "-p", "slack"])).rejects.toThrow();
|
|
1209
1676
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to re-authenticate"), expect.any(Error));
|
|
@@ -1217,7 +1684,11 @@ describe("plugin credential reauth", () => {
|
|
|
1217
1684
|
describe("plugin registry list", () => {
|
|
1218
1685
|
it("lists plugin registries", async () => {
|
|
1219
1686
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1220
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1687
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1688
|
+
registries: [
|
|
1689
|
+
{ id: "reg1", name: "Official", url: "https://registry.oxagen.ai" },
|
|
1690
|
+
],
|
|
1691
|
+
});
|
|
1221
1692
|
await pluginRegistryListCommand.parseAsync(["node", "cli"]);
|
|
1222
1693
|
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/registry/list", expect.objectContaining({ method: "GET" }));
|
|
1223
1694
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Official"));
|
|
@@ -1225,7 +1696,11 @@ describe("plugin registry list", () => {
|
|
|
1225
1696
|
});
|
|
1226
1697
|
it("handles list failure", async () => {
|
|
1227
1698
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1228
|
-
const exitSpy = vi
|
|
1699
|
+
const exitSpy = vi
|
|
1700
|
+
.spyOn(process, "exit")
|
|
1701
|
+
.mockImplementation((_code) => {
|
|
1702
|
+
throw new Error("process.exit");
|
|
1703
|
+
});
|
|
1229
1704
|
mockApiRequest.mockRejectedValueOnce(new Error("Network error"));
|
|
1230
1705
|
await expect(pluginRegistryListCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
1231
1706
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to list"), expect.any(Error));
|
|
@@ -1236,17 +1711,39 @@ describe("plugin registry list", () => {
|
|
|
1236
1711
|
describe("plugin registry add", () => {
|
|
1237
1712
|
it("adds a plugin registry", async () => {
|
|
1238
1713
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1239
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1240
|
-
|
|
1714
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1715
|
+
id: "reg2",
|
|
1716
|
+
name: "Private",
|
|
1717
|
+
url: "https://private.example.com",
|
|
1718
|
+
});
|
|
1719
|
+
await pluginRegistryAddCommand.parseAsync([
|
|
1720
|
+
"node",
|
|
1721
|
+
"cli",
|
|
1722
|
+
"-n",
|
|
1723
|
+
"Private",
|
|
1724
|
+
"-u",
|
|
1725
|
+
"https://private.example.com",
|
|
1726
|
+
]);
|
|
1241
1727
|
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/registry/add", expect.objectContaining({ method: "POST" }));
|
|
1242
1728
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("reg2"));
|
|
1243
1729
|
consoleSpy.mockRestore();
|
|
1244
1730
|
});
|
|
1245
1731
|
it("handles add failure", async () => {
|
|
1246
1732
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1247
|
-
const exitSpy = vi
|
|
1733
|
+
const exitSpy = vi
|
|
1734
|
+
.spyOn(process, "exit")
|
|
1735
|
+
.mockImplementation((_code) => {
|
|
1736
|
+
throw new Error("process.exit");
|
|
1737
|
+
});
|
|
1248
1738
|
mockApiRequest.mockRejectedValueOnce(new Error("Registry already exists"));
|
|
1249
|
-
await expect(pluginRegistryAddCommand.parseAsync([
|
|
1739
|
+
await expect(pluginRegistryAddCommand.parseAsync([
|
|
1740
|
+
"node",
|
|
1741
|
+
"cli",
|
|
1742
|
+
"-n",
|
|
1743
|
+
"Private",
|
|
1744
|
+
"-u",
|
|
1745
|
+
"https://x.com",
|
|
1746
|
+
])).rejects.toThrow();
|
|
1250
1747
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to add"), expect.any(Error));
|
|
1251
1748
|
consoleSpy.mockRestore();
|
|
1252
1749
|
exitSpy.mockRestore();
|
|
@@ -1266,7 +1763,11 @@ describe("svg generate", () => {
|
|
|
1266
1763
|
});
|
|
1267
1764
|
it("handles generate failure", async () => {
|
|
1268
1765
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1269
|
-
const exitSpy = vi
|
|
1766
|
+
const exitSpy = vi
|
|
1767
|
+
.spyOn(process, "exit")
|
|
1768
|
+
.mockImplementation((_code) => {
|
|
1769
|
+
throw new Error("process.exit");
|
|
1770
|
+
});
|
|
1270
1771
|
mockApiRequest.mockRejectedValueOnce(new Error("Generation failed"));
|
|
1271
1772
|
await expect(svgGenerateCommand.parseAsync(["node", "cli", "-d", "circle"])).rejects.toThrow();
|
|
1272
1773
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to generate"), expect.any(Error));
|
|
@@ -1280,15 +1781,28 @@ describe("svg generate", () => {
|
|
|
1280
1781
|
describe("video generate", () => {
|
|
1281
1782
|
it("generates a video", async () => {
|
|
1282
1783
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1283
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1284
|
-
|
|
1784
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1785
|
+
id: "vid1",
|
|
1786
|
+
status: "processing",
|
|
1787
|
+
url: null,
|
|
1788
|
+
});
|
|
1789
|
+
await videoGenerateCommand.parseAsync([
|
|
1790
|
+
"node",
|
|
1791
|
+
"cli",
|
|
1792
|
+
"-p",
|
|
1793
|
+
"A flying eagle",
|
|
1794
|
+
]);
|
|
1285
1795
|
expect(mockApiRequest).toHaveBeenCalledWith("/video/generate", expect.objectContaining({ method: "POST" }));
|
|
1286
1796
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("vid1"));
|
|
1287
1797
|
consoleSpy.mockRestore();
|
|
1288
1798
|
});
|
|
1289
1799
|
it("handles generate failure", async () => {
|
|
1290
1800
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1291
|
-
const exitSpy = vi
|
|
1801
|
+
const exitSpy = vi
|
|
1802
|
+
.spyOn(process, "exit")
|
|
1803
|
+
.mockImplementation((_code) => {
|
|
1804
|
+
throw new Error("process.exit");
|
|
1805
|
+
});
|
|
1292
1806
|
mockApiRequest.mockRejectedValueOnce(new Error("Model not available"));
|
|
1293
1807
|
await expect(videoGenerateCommand.parseAsync(["node", "cli", "-p", "a cat"])).rejects.toThrow();
|
|
1294
1808
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to generate"), expect.any(Error));
|
|
@@ -1302,7 +1816,10 @@ describe("video generate", () => {
|
|
|
1302
1816
|
describe("workspace model settings read", () => {
|
|
1303
1817
|
it("reads workspace model settings", async () => {
|
|
1304
1818
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1305
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1819
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1820
|
+
defaultModel: "claude-haiku-4-5-20251001",
|
|
1821
|
+
maxTokens: 4096,
|
|
1822
|
+
});
|
|
1306
1823
|
await workspaceModelSettingsReadCommand.parseAsync(["node", "cli"]);
|
|
1307
1824
|
expect(mockApiRequest).toHaveBeenCalledWith("/workspace/model-settings/read", expect.objectContaining({ method: "POST" }));
|
|
1308
1825
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("defaultModel"));
|
|
@@ -1310,7 +1827,11 @@ describe("workspace model settings read", () => {
|
|
|
1310
1827
|
});
|
|
1311
1828
|
it("handles read failure", async () => {
|
|
1312
1829
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1313
|
-
const exitSpy = vi
|
|
1830
|
+
const exitSpy = vi
|
|
1831
|
+
.spyOn(process, "exit")
|
|
1832
|
+
.mockImplementation((_code) => {
|
|
1833
|
+
throw new Error("process.exit");
|
|
1834
|
+
});
|
|
1314
1835
|
mockApiRequest.mockRejectedValueOnce(new Error("Workspace not found"));
|
|
1315
1836
|
await expect(workspaceModelSettingsReadCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
1316
1837
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to read"), expect.any(Error));
|
|
@@ -1321,17 +1842,39 @@ describe("workspace model settings read", () => {
|
|
|
1321
1842
|
describe("workspace model settings write", () => {
|
|
1322
1843
|
it("writes workspace model settings", async () => {
|
|
1323
1844
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1324
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1325
|
-
|
|
1845
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1846
|
+
success: true,
|
|
1847
|
+
key: "defaultModel",
|
|
1848
|
+
value: "claude-sonnet-4-6",
|
|
1849
|
+
});
|
|
1850
|
+
await workspaceModelSettingsWriteCommand.parseAsync([
|
|
1851
|
+
"node",
|
|
1852
|
+
"cli",
|
|
1853
|
+
"-k",
|
|
1854
|
+
"defaultModel",
|
|
1855
|
+
"-v",
|
|
1856
|
+
"claude-sonnet-4-6",
|
|
1857
|
+
]);
|
|
1326
1858
|
expect(mockApiRequest).toHaveBeenCalledWith("/workspace/model-settings/write", expect.objectContaining({ method: "POST" }));
|
|
1327
1859
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("defaultModel"));
|
|
1328
1860
|
consoleSpy.mockRestore();
|
|
1329
1861
|
});
|
|
1330
1862
|
it("handles write failure", async () => {
|
|
1331
1863
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1332
|
-
const exitSpy = vi
|
|
1864
|
+
const exitSpy = vi
|
|
1865
|
+
.spyOn(process, "exit")
|
|
1866
|
+
.mockImplementation((_code) => {
|
|
1867
|
+
throw new Error("process.exit");
|
|
1868
|
+
});
|
|
1333
1869
|
mockApiRequest.mockRejectedValueOnce(new Error("Invalid setting key"));
|
|
1334
|
-
await expect(workspaceModelSettingsWriteCommand.parseAsync([
|
|
1870
|
+
await expect(workspaceModelSettingsWriteCommand.parseAsync([
|
|
1871
|
+
"node",
|
|
1872
|
+
"cli",
|
|
1873
|
+
"-k",
|
|
1874
|
+
"badKey",
|
|
1875
|
+
"-v",
|
|
1876
|
+
"value",
|
|
1877
|
+
])).rejects.toThrow();
|
|
1335
1878
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Failed to write"), expect.any(Error));
|
|
1336
1879
|
consoleSpy.mockRestore();
|
|
1337
1880
|
exitSpy.mockRestore();
|
|
@@ -1343,17 +1886,43 @@ describe("workspace model settings write", () => {
|
|
|
1343
1886
|
describe("agent mcp register", () => {
|
|
1344
1887
|
it("registers an MCP server", async () => {
|
|
1345
1888
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1346
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1347
|
-
|
|
1889
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1890
|
+
mcpServerId: "mcp1",
|
|
1891
|
+
healthStatus: "healthy",
|
|
1892
|
+
discoveredTools: ["tool1", "tool2"],
|
|
1893
|
+
});
|
|
1894
|
+
await agentMcpRegisterCommand.parseAsync([
|
|
1895
|
+
"node",
|
|
1896
|
+
"cli",
|
|
1897
|
+
"-n",
|
|
1898
|
+
"My MCP",
|
|
1899
|
+
"-u",
|
|
1900
|
+
"https://mcp.example.com",
|
|
1901
|
+
"-t",
|
|
1902
|
+
"streamable-http",
|
|
1903
|
+
]);
|
|
1348
1904
|
expect(mockApiRequest).toHaveBeenCalledWith("/agent/mcp/register", expect.objectContaining({ method: "POST" }));
|
|
1349
1905
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("mcp1"));
|
|
1350
1906
|
consoleSpy.mockRestore();
|
|
1351
1907
|
});
|
|
1352
1908
|
it("handles registration failure", async () => {
|
|
1353
1909
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1354
|
-
const exitSpy = vi
|
|
1910
|
+
const exitSpy = vi
|
|
1911
|
+
.spyOn(process, "exit")
|
|
1912
|
+
.mockImplementation((_code) => {
|
|
1913
|
+
throw new Error("process.exit");
|
|
1914
|
+
});
|
|
1355
1915
|
mockApiRequest.mockRejectedValueOnce(new Error("Bad URL"));
|
|
1356
|
-
await expect(agentMcpRegisterCommand.parseAsync([
|
|
1916
|
+
await expect(agentMcpRegisterCommand.parseAsync([
|
|
1917
|
+
"node",
|
|
1918
|
+
"cli",
|
|
1919
|
+
"-n",
|
|
1920
|
+
"M",
|
|
1921
|
+
"-u",
|
|
1922
|
+
"http://x",
|
|
1923
|
+
"-t",
|
|
1924
|
+
"stdio",
|
|
1925
|
+
])).rejects.toThrow();
|
|
1357
1926
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Error:"));
|
|
1358
1927
|
consoleSpy.mockRestore();
|
|
1359
1928
|
exitSpy.mockRestore();
|
|
@@ -1365,17 +1934,38 @@ describe("agent mcp register", () => {
|
|
|
1365
1934
|
describe("agent plan approve", () => {
|
|
1366
1935
|
it("approves a plan", async () => {
|
|
1367
1936
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1368
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1369
|
-
|
|
1937
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1938
|
+
planId: "plan1",
|
|
1939
|
+
status: "approved",
|
|
1940
|
+
});
|
|
1941
|
+
await agentPlanApproveCommand.parseAsync([
|
|
1942
|
+
"node",
|
|
1943
|
+
"cli",
|
|
1944
|
+
"-p",
|
|
1945
|
+
"plan1",
|
|
1946
|
+
"-d",
|
|
1947
|
+
"approve",
|
|
1948
|
+
]);
|
|
1370
1949
|
expect(mockApiRequest).toHaveBeenCalledWith("/agent/plan/approve", expect.objectContaining({ method: "POST" }));
|
|
1371
1950
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("approved"));
|
|
1372
1951
|
consoleSpy.mockRestore();
|
|
1373
1952
|
});
|
|
1374
1953
|
it("handles approval failure", async () => {
|
|
1375
1954
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1376
|
-
const exitSpy = vi
|
|
1955
|
+
const exitSpy = vi
|
|
1956
|
+
.spyOn(process, "exit")
|
|
1957
|
+
.mockImplementation((_code) => {
|
|
1958
|
+
throw new Error("process.exit");
|
|
1959
|
+
});
|
|
1377
1960
|
mockApiRequest.mockRejectedValueOnce(new Error("Plan not found"));
|
|
1378
|
-
await expect(agentPlanApproveCommand.parseAsync([
|
|
1961
|
+
await expect(agentPlanApproveCommand.parseAsync([
|
|
1962
|
+
"node",
|
|
1963
|
+
"cli",
|
|
1964
|
+
"-p",
|
|
1965
|
+
"p1",
|
|
1966
|
+
"-d",
|
|
1967
|
+
"deny",
|
|
1968
|
+
])).rejects.toThrow();
|
|
1379
1969
|
consoleSpy.mockRestore();
|
|
1380
1970
|
exitSpy.mockRestore();
|
|
1381
1971
|
});
|
|
@@ -1386,17 +1976,38 @@ describe("agent plan approve", () => {
|
|
|
1386
1976
|
describe("agent task background start", () => {
|
|
1387
1977
|
it("starts a background task", async () => {
|
|
1388
1978
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1389
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1390
|
-
|
|
1979
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
1980
|
+
taskId: "task1",
|
|
1981
|
+
inngestRunId: "run1",
|
|
1982
|
+
});
|
|
1983
|
+
await agentTaskBackgroundStartCommand.parseAsync([
|
|
1984
|
+
"node",
|
|
1985
|
+
"cli",
|
|
1986
|
+
"-k",
|
|
1987
|
+
"research",
|
|
1988
|
+
"--payload",
|
|
1989
|
+
'{"query":"test"}',
|
|
1990
|
+
]);
|
|
1391
1991
|
expect(mockApiRequest).toHaveBeenCalledWith("/agent/task/background/start", expect.objectContaining({ method: "POST" }));
|
|
1392
1992
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("task1"));
|
|
1393
1993
|
consoleSpy.mockRestore();
|
|
1394
1994
|
});
|
|
1395
1995
|
it("handles start failure", async () => {
|
|
1396
1996
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1397
|
-
const exitSpy = vi
|
|
1997
|
+
const exitSpy = vi
|
|
1998
|
+
.spyOn(process, "exit")
|
|
1999
|
+
.mockImplementation((_code) => {
|
|
2000
|
+
throw new Error("process.exit");
|
|
2001
|
+
});
|
|
1398
2002
|
mockApiRequest.mockRejectedValueOnce(new Error("Queue full"));
|
|
1399
|
-
await expect(agentTaskBackgroundStartCommand.parseAsync([
|
|
2003
|
+
await expect(agentTaskBackgroundStartCommand.parseAsync([
|
|
2004
|
+
"node",
|
|
2005
|
+
"cli",
|
|
2006
|
+
"-k",
|
|
2007
|
+
"kind",
|
|
2008
|
+
"--payload",
|
|
2009
|
+
"{}",
|
|
2010
|
+
])).rejects.toThrow();
|
|
1400
2011
|
consoleSpy.mockRestore();
|
|
1401
2012
|
exitSpy.mockRestore();
|
|
1402
2013
|
});
|
|
@@ -1404,15 +2015,34 @@ describe("agent task background start", () => {
|
|
|
1404
2015
|
describe("agent task background read", () => {
|
|
1405
2016
|
it("reads task status", async () => {
|
|
1406
2017
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1407
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1408
|
-
|
|
2018
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
2019
|
+
taskId: "task1",
|
|
2020
|
+
kind: "research",
|
|
2021
|
+
status: "completed",
|
|
2022
|
+
label: "My task",
|
|
2023
|
+
resultPayload: { answer: "42" },
|
|
2024
|
+
failureReason: null,
|
|
2025
|
+
createdAt: "2026-06-08",
|
|
2026
|
+
startedAt: "2026-06-08",
|
|
2027
|
+
completedAt: "2026-06-08",
|
|
2028
|
+
});
|
|
2029
|
+
await agentTaskBackgroundReadCommand.parseAsync([
|
|
2030
|
+
"node",
|
|
2031
|
+
"cli",
|
|
2032
|
+
"-t",
|
|
2033
|
+
"task1",
|
|
2034
|
+
]);
|
|
1409
2035
|
expect(mockApiRequest).toHaveBeenCalled();
|
|
1410
2036
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("completed"));
|
|
1411
2037
|
consoleSpy.mockRestore();
|
|
1412
2038
|
});
|
|
1413
2039
|
it("handles read failure", async () => {
|
|
1414
2040
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1415
|
-
const exitSpy = vi
|
|
2041
|
+
const exitSpy = vi
|
|
2042
|
+
.spyOn(process, "exit")
|
|
2043
|
+
.mockImplementation((_code) => {
|
|
2044
|
+
throw new Error("process.exit");
|
|
2045
|
+
});
|
|
1416
2046
|
mockApiRequest.mockRejectedValueOnce(new Error("Not found"));
|
|
1417
2047
|
await expect(agentTaskBackgroundReadCommand.parseAsync(["node", "cli", "-t", "t1"])).rejects.toThrow();
|
|
1418
2048
|
consoleSpy.mockRestore();
|
|
@@ -1423,7 +2053,12 @@ describe("agent task background cancel", () => {
|
|
|
1423
2053
|
it("cancels a background task", async () => {
|
|
1424
2054
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1425
2055
|
mockApiRequest.mockResolvedValueOnce({ cancelled: true });
|
|
1426
|
-
await agentTaskBackgroundCancelCommand.parseAsync([
|
|
2056
|
+
await agentTaskBackgroundCancelCommand.parseAsync([
|
|
2057
|
+
"node",
|
|
2058
|
+
"cli",
|
|
2059
|
+
"-t",
|
|
2060
|
+
"task1",
|
|
2061
|
+
]);
|
|
1427
2062
|
expect(mockApiRequest).toHaveBeenCalledWith("/agent/task/background/cancel", expect.objectContaining({ method: "POST" }));
|
|
1428
2063
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("cancelled"));
|
|
1429
2064
|
consoleSpy.mockRestore();
|
|
@@ -1431,13 +2066,22 @@ describe("agent task background cancel", () => {
|
|
|
1431
2066
|
it("reports task could not be cancelled", async () => {
|
|
1432
2067
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1433
2068
|
mockApiRequest.mockResolvedValueOnce({ cancelled: false });
|
|
1434
|
-
await agentTaskBackgroundCancelCommand.parseAsync([
|
|
2069
|
+
await agentTaskBackgroundCancelCommand.parseAsync([
|
|
2070
|
+
"node",
|
|
2071
|
+
"cli",
|
|
2072
|
+
"-t",
|
|
2073
|
+
"task1",
|
|
2074
|
+
]);
|
|
1435
2075
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("could not be cancelled"));
|
|
1436
2076
|
consoleSpy.mockRestore();
|
|
1437
2077
|
});
|
|
1438
2078
|
it("handles cancel failure", async () => {
|
|
1439
2079
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1440
|
-
const exitSpy = vi
|
|
2080
|
+
const exitSpy = vi
|
|
2081
|
+
.spyOn(process, "exit")
|
|
2082
|
+
.mockImplementation((_code) => {
|
|
2083
|
+
throw new Error("process.exit");
|
|
2084
|
+
});
|
|
1441
2085
|
mockApiRequest.mockRejectedValueOnce(new Error("Not found"));
|
|
1442
2086
|
await expect(agentTaskBackgroundCancelCommand.parseAsync(["node", "cli", "-t", "t1"])).rejects.toThrow();
|
|
1443
2087
|
consoleSpy.mockRestore();
|
|
@@ -1450,17 +2094,40 @@ describe("agent task background cancel", () => {
|
|
|
1450
2094
|
describe("asset upload", () => {
|
|
1451
2095
|
it("uploads an asset", async () => {
|
|
1452
2096
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1453
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1454
|
-
|
|
2097
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
2098
|
+
url: "https://cdn.example.com/img.png",
|
|
2099
|
+
key: "img/abc.png",
|
|
2100
|
+
contentType: "image/png",
|
|
2101
|
+
bytes: 12345,
|
|
2102
|
+
});
|
|
2103
|
+
await assetUploadCommand.parseAsync([
|
|
2104
|
+
"node",
|
|
2105
|
+
"cli",
|
|
2106
|
+
"-s",
|
|
2107
|
+
"https://example.com/img.png",
|
|
2108
|
+
"-k",
|
|
2109
|
+
"image",
|
|
2110
|
+
]);
|
|
1455
2111
|
expect(mockApiRequest).toHaveBeenCalledWith("/asset/upload", expect.objectContaining({ method: "POST" }));
|
|
1456
2112
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Asset uploaded"));
|
|
1457
2113
|
consoleSpy.mockRestore();
|
|
1458
2114
|
});
|
|
1459
2115
|
it("handles upload failure", async () => {
|
|
1460
2116
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1461
|
-
const exitSpy = vi
|
|
2117
|
+
const exitSpy = vi
|
|
2118
|
+
.spyOn(process, "exit")
|
|
2119
|
+
.mockImplementation((_code) => {
|
|
2120
|
+
throw new Error("process.exit");
|
|
2121
|
+
});
|
|
1462
2122
|
mockApiRequest.mockRejectedValueOnce(new Error("Source URL unreachable"));
|
|
1463
|
-
await expect(assetUploadCommand.parseAsync([
|
|
2123
|
+
await expect(assetUploadCommand.parseAsync([
|
|
2124
|
+
"node",
|
|
2125
|
+
"cli",
|
|
2126
|
+
"-s",
|
|
2127
|
+
"https://bad.url",
|
|
2128
|
+
"-k",
|
|
2129
|
+
"image",
|
|
2130
|
+
])).rejects.toThrow();
|
|
1464
2131
|
consoleSpy.mockRestore();
|
|
1465
2132
|
exitSpy.mockRestore();
|
|
1466
2133
|
});
|
|
@@ -1471,38 +2138,47 @@ describe("asset upload", () => {
|
|
|
1471
2138
|
describe("billing subscription upgrade start", () => {
|
|
1472
2139
|
it("starts a checkout session", async () => {
|
|
1473
2140
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1474
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1475
|
-
|
|
2141
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
2142
|
+
checkoutUrl: "https://checkout.stripe.com/pay/cs_test_123",
|
|
2143
|
+
planSlug: "scale",
|
|
2144
|
+
interval: "month",
|
|
2145
|
+
});
|
|
2146
|
+
await billingSubscriptionUpgradeStartCommand.parseAsync([
|
|
2147
|
+
"node",
|
|
2148
|
+
"cli",
|
|
2149
|
+
"-p",
|
|
2150
|
+
"scale",
|
|
2151
|
+
"-i",
|
|
2152
|
+
"month",
|
|
2153
|
+
"--success-url",
|
|
2154
|
+
"https://app.oxagen.ai/success",
|
|
2155
|
+
"--cancel-url",
|
|
2156
|
+
"https://app.oxagen.ai/cancel",
|
|
2157
|
+
]);
|
|
1476
2158
|
expect(mockApiRequest).toHaveBeenCalledWith("/billing/subscription/upgrade/start", expect.objectContaining({ method: "POST" }));
|
|
1477
2159
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Checkout session created"));
|
|
1478
2160
|
consoleSpy.mockRestore();
|
|
1479
2161
|
});
|
|
1480
2162
|
it("handles upgrade failure", async () => {
|
|
1481
2163
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1482
|
-
const exitSpy = vi
|
|
2164
|
+
const exitSpy = vi
|
|
2165
|
+
.spyOn(process, "exit")
|
|
2166
|
+
.mockImplementation((_code) => {
|
|
2167
|
+
throw new Error("process.exit");
|
|
2168
|
+
});
|
|
1483
2169
|
mockApiRequest.mockRejectedValueOnce(new Error("Stripe error"));
|
|
1484
|
-
await expect(billingSubscriptionUpgradeStartCommand.parseAsync([
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
await brandkitApplyCommand.parseAsync(["node", "cli", "-b", "bk1", "-f", "file1", "-w", "ws1"]);
|
|
1497
|
-
expect(mockApiRequest).toHaveBeenCalledWith("/brandkit/apply", expect.objectContaining({ method: "POST" }));
|
|
1498
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("stub"));
|
|
1499
|
-
consoleSpy.mockRestore();
|
|
1500
|
-
});
|
|
1501
|
-
it("handles apply failure", async () => {
|
|
1502
|
-
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1503
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
|
|
1504
|
-
mockApiRequest.mockRejectedValueOnce(new Error("Brand kit not found"));
|
|
1505
|
-
await expect(brandkitApplyCommand.parseAsync(["node", "cli", "-b", "bk1", "-f", "f1", "-w", "ws1"])).rejects.toThrow();
|
|
2170
|
+
await expect(billingSubscriptionUpgradeStartCommand.parseAsync([
|
|
2171
|
+
"node",
|
|
2172
|
+
"cli",
|
|
2173
|
+
"-p",
|
|
2174
|
+
"scale",
|
|
2175
|
+
"-i",
|
|
2176
|
+
"month",
|
|
2177
|
+
"--success-url",
|
|
2178
|
+
"https://a.com/ok",
|
|
2179
|
+
"--cancel-url",
|
|
2180
|
+
"https://a.com/cancel",
|
|
2181
|
+
])).rejects.toThrow();
|
|
1506
2182
|
consoleSpy.mockRestore();
|
|
1507
2183
|
exitSpy.mockRestore();
|
|
1508
2184
|
});
|
|
@@ -1514,14 +2190,24 @@ describe("conversation purge", () => {
|
|
|
1514
2190
|
it("purges archived conversations with --yes", async () => {
|
|
1515
2191
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1516
2192
|
mockApiRequest.mockResolvedValueOnce({ deleted: 5 });
|
|
1517
|
-
await conversationPurgeCommand.parseAsync([
|
|
2193
|
+
await conversationPurgeCommand.parseAsync([
|
|
2194
|
+
"node",
|
|
2195
|
+
"cli",
|
|
2196
|
+
"-w",
|
|
2197
|
+
"ws1",
|
|
2198
|
+
"--yes",
|
|
2199
|
+
]);
|
|
1518
2200
|
expect(mockApiRequest).toHaveBeenCalledWith("/conversation/purge", expect.objectContaining({ method: "POST" }));
|
|
1519
2201
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Purged 5"));
|
|
1520
2202
|
consoleSpy.mockRestore();
|
|
1521
2203
|
});
|
|
1522
2204
|
it("exits without --yes", async () => {
|
|
1523
2205
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1524
|
-
const exitSpy = vi
|
|
2206
|
+
const exitSpy = vi
|
|
2207
|
+
.spyOn(process, "exit")
|
|
2208
|
+
.mockImplementation((_code) => {
|
|
2209
|
+
throw new Error("process.exit");
|
|
2210
|
+
});
|
|
1525
2211
|
await expect(conversationPurgeCommand.parseAsync(["node", "cli", "-w", "ws1"])).rejects.toThrow();
|
|
1526
2212
|
expect(consoleSpy).toHaveBeenCalled();
|
|
1527
2213
|
consoleSpy.mockRestore();
|
|
@@ -1529,9 +2215,19 @@ describe("conversation purge", () => {
|
|
|
1529
2215
|
});
|
|
1530
2216
|
it("handles purge failure", async () => {
|
|
1531
2217
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1532
|
-
const exitSpy = vi
|
|
2218
|
+
const exitSpy = vi
|
|
2219
|
+
.spyOn(process, "exit")
|
|
2220
|
+
.mockImplementation((_code) => {
|
|
2221
|
+
throw new Error("process.exit");
|
|
2222
|
+
});
|
|
1533
2223
|
mockApiRequest.mockRejectedValueOnce(new Error("Workspace not found"));
|
|
1534
|
-
await expect(conversationPurgeCommand.parseAsync([
|
|
2224
|
+
await expect(conversationPurgeCommand.parseAsync([
|
|
2225
|
+
"node",
|
|
2226
|
+
"cli",
|
|
2227
|
+
"-w",
|
|
2228
|
+
"ws1",
|
|
2229
|
+
"--yes",
|
|
2230
|
+
])).rejects.toThrow();
|
|
1535
2231
|
consoleSpy.mockRestore();
|
|
1536
2232
|
exitSpy.mockRestore();
|
|
1537
2233
|
});
|
|
@@ -1542,15 +2238,32 @@ describe("conversation purge", () => {
|
|
|
1542
2238
|
describe("documents pdf create", () => {
|
|
1543
2239
|
it("creates a PDF document", async () => {
|
|
1544
2240
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1545
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1546
|
-
|
|
2241
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
2242
|
+
assetId: "asset1",
|
|
2243
|
+
publicId: "pub1",
|
|
2244
|
+
kind: "pdf",
|
|
2245
|
+
mimeType: "application/pdf",
|
|
2246
|
+
sizeBytes: 50000,
|
|
2247
|
+
url: "https://blob.example.com/doc.pdf",
|
|
2248
|
+
serveUrl: "https://api.example.com/assets/asset1",
|
|
2249
|
+
});
|
|
2250
|
+
await documentsPdfCreateCommand.parseAsync([
|
|
2251
|
+
"node",
|
|
2252
|
+
"cli",
|
|
2253
|
+
"-t",
|
|
2254
|
+
"Q1 Report",
|
|
2255
|
+
]);
|
|
1547
2256
|
expect(mockApiRequest).toHaveBeenCalledWith("/documents/pdf/create", expect.objectContaining({ method: "POST" }));
|
|
1548
2257
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("PDF created"));
|
|
1549
2258
|
consoleSpy.mockRestore();
|
|
1550
2259
|
});
|
|
1551
2260
|
it("handles pdf create failure", async () => {
|
|
1552
2261
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1553
|
-
const exitSpy = vi
|
|
2262
|
+
const exitSpy = vi
|
|
2263
|
+
.spyOn(process, "exit")
|
|
2264
|
+
.mockImplementation((_code) => {
|
|
2265
|
+
throw new Error("process.exit");
|
|
2266
|
+
});
|
|
1554
2267
|
mockApiRequest.mockRejectedValueOnce(new Error("Generation failed"));
|
|
1555
2268
|
await expect(documentsPdfCreateCommand.parseAsync(["node", "cli", "-t", "Report"])).rejects.toThrow();
|
|
1556
2269
|
consoleSpy.mockRestore();
|
|
@@ -1563,18 +2276,50 @@ describe("documents pdf create", () => {
|
|
|
1563
2276
|
describe("form fill", () => {
|
|
1564
2277
|
it("fills form fields", async () => {
|
|
1565
2278
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1566
|
-
const fields = [
|
|
2279
|
+
const fields = [
|
|
2280
|
+
{
|
|
2281
|
+
name: "firstName",
|
|
2282
|
+
label: "First Name",
|
|
2283
|
+
type: "text",
|
|
2284
|
+
current: "",
|
|
2285
|
+
changed: false,
|
|
2286
|
+
proposed: "Alice",
|
|
2287
|
+
reason: "Inferred from instruction",
|
|
2288
|
+
},
|
|
2289
|
+
];
|
|
1567
2290
|
mockApiRequest.mockResolvedValueOnce({ fields });
|
|
1568
|
-
await formFillCommand.parseAsync([
|
|
2291
|
+
await formFillCommand.parseAsync([
|
|
2292
|
+
"node",
|
|
2293
|
+
"cli",
|
|
2294
|
+
"-r",
|
|
2295
|
+
"/profile",
|
|
2296
|
+
"-i",
|
|
2297
|
+
"Fill with Alice's info",
|
|
2298
|
+
"--fields",
|
|
2299
|
+
'[{"name":"firstName","label":"First Name","type":"text","current":""}]',
|
|
2300
|
+
]);
|
|
1569
2301
|
expect(mockApiRequest).toHaveBeenCalledWith("/form/fill", expect.objectContaining({ method: "POST" }));
|
|
1570
2302
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Form fill suggestion"));
|
|
1571
2303
|
consoleSpy.mockRestore();
|
|
1572
2304
|
});
|
|
1573
2305
|
it("handles form fill failure", async () => {
|
|
1574
2306
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1575
|
-
const exitSpy = vi
|
|
2307
|
+
const exitSpy = vi
|
|
2308
|
+
.spyOn(process, "exit")
|
|
2309
|
+
.mockImplementation((_code) => {
|
|
2310
|
+
throw new Error("process.exit");
|
|
2311
|
+
});
|
|
1576
2312
|
mockApiRequest.mockRejectedValueOnce(new Error("LLM error"));
|
|
1577
|
-
await expect(formFillCommand.parseAsync([
|
|
2313
|
+
await expect(formFillCommand.parseAsync([
|
|
2314
|
+
"node",
|
|
2315
|
+
"cli",
|
|
2316
|
+
"-r",
|
|
2317
|
+
"/p",
|
|
2318
|
+
"-i",
|
|
2319
|
+
"fill",
|
|
2320
|
+
"--fields",
|
|
2321
|
+
"[]",
|
|
2322
|
+
])).rejects.toThrow();
|
|
1578
2323
|
consoleSpy.mockRestore();
|
|
1579
2324
|
exitSpy.mockRestore();
|
|
1580
2325
|
});
|
|
@@ -1585,15 +2330,27 @@ describe("form fill", () => {
|
|
|
1585
2330
|
describe("org member invite decline", () => {
|
|
1586
2331
|
it("declines an invitation", async () => {
|
|
1587
2332
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1588
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1589
|
-
|
|
2333
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
2334
|
+
invitationPublicId: "inv1",
|
|
2335
|
+
status: "declined",
|
|
2336
|
+
});
|
|
2337
|
+
await orgMemberInviteDeclineCommand.parseAsync([
|
|
2338
|
+
"node",
|
|
2339
|
+
"cli",
|
|
2340
|
+
"-i",
|
|
2341
|
+
"inv1",
|
|
2342
|
+
]);
|
|
1590
2343
|
expect(mockApiRequest).toHaveBeenCalledWith("/org/member/invite/decline", expect.objectContaining({ method: "POST" }));
|
|
1591
2344
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("declined"));
|
|
1592
2345
|
consoleSpy.mockRestore();
|
|
1593
2346
|
});
|
|
1594
2347
|
it("handles decline failure", async () => {
|
|
1595
2348
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1596
|
-
const exitSpy = vi
|
|
2349
|
+
const exitSpy = vi
|
|
2350
|
+
.spyOn(process, "exit")
|
|
2351
|
+
.mockImplementation((_code) => {
|
|
2352
|
+
throw new Error("process.exit");
|
|
2353
|
+
});
|
|
1597
2354
|
mockApiRequest.mockRejectedValueOnce(new Error("Invitation not found"));
|
|
1598
2355
|
await expect(orgMemberInviteDeclineCommand.parseAsync(["node", "cli", "-i", "inv1"])).rejects.toThrow();
|
|
1599
2356
|
consoleSpy.mockRestore();
|
|
@@ -1606,17 +2363,41 @@ describe("org member invite decline", () => {
|
|
|
1606
2363
|
describe("organization create", () => {
|
|
1607
2364
|
it("creates an organization", async () => {
|
|
1608
2365
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1609
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1610
|
-
|
|
2366
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
2367
|
+
publicId: "org1",
|
|
2368
|
+
name: "Acme Corp",
|
|
2369
|
+
slug: "acme-corp",
|
|
2370
|
+
type: "business",
|
|
2371
|
+
createdAt: "2026-06-08",
|
|
2372
|
+
});
|
|
2373
|
+
await organizationCreateCommand.parseAsync([
|
|
2374
|
+
"node",
|
|
2375
|
+
"cli",
|
|
2376
|
+
"-n",
|
|
2377
|
+
"Acme Corp",
|
|
2378
|
+
"-s",
|
|
2379
|
+
"acme-corp",
|
|
2380
|
+
]);
|
|
1611
2381
|
expect(mockApiRequest).toHaveBeenCalledWith("/organization/create", expect.objectContaining({ method: "POST" }));
|
|
1612
2382
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Organization created"));
|
|
1613
2383
|
consoleSpy.mockRestore();
|
|
1614
2384
|
});
|
|
1615
2385
|
it("handles create failure", async () => {
|
|
1616
2386
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1617
|
-
const exitSpy = vi
|
|
2387
|
+
const exitSpy = vi
|
|
2388
|
+
.spyOn(process, "exit")
|
|
2389
|
+
.mockImplementation((_code) => {
|
|
2390
|
+
throw new Error("process.exit");
|
|
2391
|
+
});
|
|
1618
2392
|
mockApiRequest.mockRejectedValueOnce(new Error("Slug already taken"));
|
|
1619
|
-
await expect(organizationCreateCommand.parseAsync([
|
|
2393
|
+
await expect(organizationCreateCommand.parseAsync([
|
|
2394
|
+
"node",
|
|
2395
|
+
"cli",
|
|
2396
|
+
"-n",
|
|
2397
|
+
"Acme",
|
|
2398
|
+
"-s",
|
|
2399
|
+
"acme",
|
|
2400
|
+
])).rejects.toThrow();
|
|
1620
2401
|
consoleSpy.mockRestore();
|
|
1621
2402
|
exitSpy.mockRestore();
|
|
1622
2403
|
});
|
|
@@ -1628,55 +2409,36 @@ describe("plugin credential set_secret", () => {
|
|
|
1628
2409
|
it("stores a credential", async () => {
|
|
1629
2410
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1630
2411
|
mockApiRequest.mockResolvedValueOnce({ ok: true });
|
|
1631
|
-
await pluginCredentialSetSecretCommand.parseAsync([
|
|
2412
|
+
await pluginCredentialSetSecretCommand.parseAsync([
|
|
2413
|
+
"node",
|
|
2414
|
+
"cli",
|
|
2415
|
+
"-l",
|
|
2416
|
+
"listing1",
|
|
2417
|
+
"-a",
|
|
2418
|
+
"secret",
|
|
2419
|
+
"--secret",
|
|
2420
|
+
"my-secret",
|
|
2421
|
+
]);
|
|
1632
2422
|
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/credential/set_secret", expect.objectContaining({ method: "POST" }));
|
|
1633
2423
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Credential stored"));
|
|
1634
2424
|
consoleSpy.mockRestore();
|
|
1635
2425
|
});
|
|
1636
2426
|
it("handles credential failure", async () => {
|
|
1637
2427
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1638
|
-
const exitSpy = vi
|
|
2428
|
+
const exitSpy = vi
|
|
2429
|
+
.spyOn(process, "exit")
|
|
2430
|
+
.mockImplementation((_code) => {
|
|
2431
|
+
throw new Error("process.exit");
|
|
2432
|
+
});
|
|
1639
2433
|
mockApiRequest.mockRejectedValueOnce(new Error("Listing not found"));
|
|
1640
|
-
await expect(pluginCredentialSetSecretCommand.parseAsync([
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
describe("plugin denylist add", () => {
|
|
1649
|
-
it("adds a server to the denylist", async () => {
|
|
1650
|
-
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1651
|
-
mockApiRequest.mockResolvedValueOnce({ ok: true });
|
|
1652
|
-
await pluginDenylistAddCommand.parseAsync(["node", "cli", "-s", "bad-server"]);
|
|
1653
|
-
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/denylist/add", expect.objectContaining({ method: "POST" }));
|
|
1654
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("bad-server"));
|
|
1655
|
-
consoleSpy.mockRestore();
|
|
1656
|
-
});
|
|
1657
|
-
it("handles denylist add failure", async () => {
|
|
1658
|
-
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1659
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
|
|
1660
|
-
mockApiRequest.mockRejectedValueOnce(new Error("Server not found"));
|
|
1661
|
-
await expect(pluginDenylistAddCommand.parseAsync(["node", "cli", "-s", "srv"])).rejects.toThrow();
|
|
1662
|
-
consoleSpy.mockRestore();
|
|
1663
|
-
exitSpy.mockRestore();
|
|
1664
|
-
});
|
|
1665
|
-
});
|
|
1666
|
-
describe("plugin denylist remove", () => {
|
|
1667
|
-
it("removes a server from the denylist", async () => {
|
|
1668
|
-
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1669
|
-
mockApiRequest.mockResolvedValueOnce({ ok: true });
|
|
1670
|
-
await pluginDenylistRemoveCommand.parseAsync(["node", "cli", "-s", "bad-server"]);
|
|
1671
|
-
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/denylist/remove", expect.objectContaining({ method: "POST" }));
|
|
1672
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("bad-server"));
|
|
1673
|
-
consoleSpy.mockRestore();
|
|
1674
|
-
});
|
|
1675
|
-
it("handles denylist remove failure", async () => {
|
|
1676
|
-
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1677
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
|
|
1678
|
-
mockApiRequest.mockRejectedValueOnce(new Error("Entry not found"));
|
|
1679
|
-
await expect(pluginDenylistRemoveCommand.parseAsync(["node", "cli", "-s", "srv"])).rejects.toThrow();
|
|
2434
|
+
await expect(pluginCredentialSetSecretCommand.parseAsync([
|
|
2435
|
+
"node",
|
|
2436
|
+
"cli",
|
|
2437
|
+
"-l",
|
|
2438
|
+
"l1",
|
|
2439
|
+
"-a",
|
|
2440
|
+
"secret",
|
|
2441
|
+
])).rejects.toThrow();
|
|
1680
2442
|
consoleSpy.mockRestore();
|
|
1681
2443
|
exitSpy.mockRestore();
|
|
1682
2444
|
});
|
|
@@ -1687,22 +2449,41 @@ describe("plugin denylist remove", () => {
|
|
|
1687
2449
|
describe("plugin org install bulk", () => {
|
|
1688
2450
|
it("bulk installs plugins", async () => {
|
|
1689
2451
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1690
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1691
|
-
|
|
2452
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
2453
|
+
installed: [{ pluginId: "srv1", orgListingId: "listing1", error: null }],
|
|
2454
|
+
});
|
|
2455
|
+
await pluginOrgInstallBulkCommand.parseAsync([
|
|
2456
|
+
"node",
|
|
2457
|
+
"cli",
|
|
2458
|
+
"--items",
|
|
2459
|
+
'[{"catalogServerId":"srv1"}]',
|
|
2460
|
+
]);
|
|
1692
2461
|
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/org/install_bulk", expect.objectContaining({ method: "POST" }));
|
|
1693
2462
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("1 succeeded"));
|
|
1694
2463
|
consoleSpy.mockRestore();
|
|
1695
2464
|
});
|
|
1696
2465
|
it("reports partial failures", async () => {
|
|
1697
2466
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1698
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
1699
|
-
|
|
2467
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
2468
|
+
installed: [{ pluginId: "srv1", orgListingId: null, error: "Not found" }],
|
|
2469
|
+
});
|
|
2470
|
+
await pluginOrgInstallBulkCommand.parseAsync([
|
|
2471
|
+
"node",
|
|
2472
|
+
"cli",
|
|
2473
|
+
"--items",
|
|
2474
|
+
'[{"catalogServerId":"srv1"}]',
|
|
2475
|
+
]);
|
|
1700
2476
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("0 succeeded, 1 failed"));
|
|
2477
|
+
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("srv1: Not found"));
|
|
1701
2478
|
consoleSpy.mockRestore();
|
|
1702
2479
|
});
|
|
1703
2480
|
it("handles bulk install failure", async () => {
|
|
1704
2481
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1705
|
-
const exitSpy = vi
|
|
2482
|
+
const exitSpy = vi
|
|
2483
|
+
.spyOn(process, "exit")
|
|
2484
|
+
.mockImplementation((_code) => {
|
|
2485
|
+
throw new Error("process.exit");
|
|
2486
|
+
});
|
|
1706
2487
|
mockApiRequest.mockRejectedValueOnce(new Error("Bad request"));
|
|
1707
2488
|
await expect(pluginOrgInstallBulkCommand.parseAsync(["node", "cli", "--items", "[]"])).rejects.toThrow();
|
|
1708
2489
|
consoleSpy.mockRestore();
|
|
@@ -1716,7 +2497,15 @@ describe("plugin org list", () => {
|
|
|
1716
2497
|
it("lists org plugins", async () => {
|
|
1717
2498
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1718
2499
|
mockApiRequest.mockResolvedValueOnce({
|
|
1719
|
-
listings: [
|
|
2500
|
+
listings: [
|
|
2501
|
+
{
|
|
2502
|
+
id: "l1",
|
|
2503
|
+
publicId: "pub1",
|
|
2504
|
+
name: "Slack",
|
|
2505
|
+
pluginType: "mcp_server",
|
|
2506
|
+
enabled: true,
|
|
2507
|
+
},
|
|
2508
|
+
],
|
|
1720
2509
|
denylist: [],
|
|
1721
2510
|
});
|
|
1722
2511
|
await pluginOrgListCommand.parseAsync(["node", "cli"]);
|
|
@@ -1728,7 +2517,14 @@ describe("plugin org list", () => {
|
|
|
1728
2517
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1729
2518
|
mockApiRequest.mockResolvedValueOnce({
|
|
1730
2519
|
listings: [],
|
|
1731
|
-
denylist: [
|
|
2520
|
+
denylist: [
|
|
2521
|
+
{
|
|
2522
|
+
id: "d1",
|
|
2523
|
+
serverName: "bad-server",
|
|
2524
|
+
pluginType: "mcp_server",
|
|
2525
|
+
reason: "Security risk",
|
|
2526
|
+
},
|
|
2527
|
+
],
|
|
1732
2528
|
});
|
|
1733
2529
|
await pluginOrgListCommand.parseAsync(["node", "cli"]);
|
|
1734
2530
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Denylist"));
|
|
@@ -1736,7 +2532,11 @@ describe("plugin org list", () => {
|
|
|
1736
2532
|
});
|
|
1737
2533
|
it("handles list failure", async () => {
|
|
1738
2534
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1739
|
-
const exitSpy = vi
|
|
2535
|
+
const exitSpy = vi
|
|
2536
|
+
.spyOn(process, "exit")
|
|
2537
|
+
.mockImplementation((_code) => {
|
|
2538
|
+
throw new Error("process.exit");
|
|
2539
|
+
});
|
|
1740
2540
|
mockApiRequest.mockRejectedValueOnce(new Error("Unauthorized"));
|
|
1741
2541
|
await expect(pluginOrgListCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
1742
2542
|
consoleSpy.mockRestore();
|
|
@@ -1750,7 +2550,14 @@ describe("plugin org set_enabled", () => {
|
|
|
1750
2550
|
it("enables a plugin listing", async () => {
|
|
1751
2551
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1752
2552
|
mockApiRequest.mockResolvedValueOnce({ ok: true });
|
|
1753
|
-
await pluginOrgSetEnabledCommand.parseAsync([
|
|
2553
|
+
await pluginOrgSetEnabledCommand.parseAsync([
|
|
2554
|
+
"node",
|
|
2555
|
+
"cli",
|
|
2556
|
+
"-l",
|
|
2557
|
+
"listing1",
|
|
2558
|
+
"--enabled",
|
|
2559
|
+
"true",
|
|
2560
|
+
]);
|
|
1754
2561
|
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/org/set_enabled", expect.objectContaining({ method: "POST" }));
|
|
1755
2562
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("enabled"));
|
|
1756
2563
|
consoleSpy.mockRestore();
|
|
@@ -1758,15 +2565,33 @@ describe("plugin org set_enabled", () => {
|
|
|
1758
2565
|
it("disables a plugin listing", async () => {
|
|
1759
2566
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1760
2567
|
mockApiRequest.mockResolvedValueOnce({ ok: true });
|
|
1761
|
-
await pluginOrgSetEnabledCommand.parseAsync([
|
|
2568
|
+
await pluginOrgSetEnabledCommand.parseAsync([
|
|
2569
|
+
"node",
|
|
2570
|
+
"cli",
|
|
2571
|
+
"-l",
|
|
2572
|
+
"listing1",
|
|
2573
|
+
"--enabled",
|
|
2574
|
+
"false",
|
|
2575
|
+
]);
|
|
1762
2576
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("disabled"));
|
|
1763
2577
|
consoleSpy.mockRestore();
|
|
1764
2578
|
});
|
|
1765
2579
|
it("handles set_enabled failure", async () => {
|
|
1766
2580
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1767
|
-
const exitSpy = vi
|
|
2581
|
+
const exitSpy = vi
|
|
2582
|
+
.spyOn(process, "exit")
|
|
2583
|
+
.mockImplementation((_code) => {
|
|
2584
|
+
throw new Error("process.exit");
|
|
2585
|
+
});
|
|
1768
2586
|
mockApiRequest.mockRejectedValueOnce(new Error("Listing not found"));
|
|
1769
|
-
await expect(pluginOrgSetEnabledCommand.parseAsync([
|
|
2587
|
+
await expect(pluginOrgSetEnabledCommand.parseAsync([
|
|
2588
|
+
"node",
|
|
2589
|
+
"cli",
|
|
2590
|
+
"-l",
|
|
2591
|
+
"l1",
|
|
2592
|
+
"--enabled",
|
|
2593
|
+
"true",
|
|
2594
|
+
])).rejects.toThrow();
|
|
1770
2595
|
consoleSpy.mockRestore();
|
|
1771
2596
|
exitSpy.mockRestore();
|
|
1772
2597
|
});
|
|
@@ -1785,7 +2610,11 @@ describe("plugin registry remove", () => {
|
|
|
1785
2610
|
});
|
|
1786
2611
|
it("handles remove failure", async () => {
|
|
1787
2612
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1788
|
-
const exitSpy = vi
|
|
2613
|
+
const exitSpy = vi
|
|
2614
|
+
.spyOn(process, "exit")
|
|
2615
|
+
.mockImplementation((_code) => {
|
|
2616
|
+
throw new Error("process.exit");
|
|
2617
|
+
});
|
|
1789
2618
|
mockApiRequest.mockRejectedValueOnce(new Error("Registry is global default"));
|
|
1790
2619
|
await expect(pluginRegistryRemoveCommand.parseAsync(["node", "cli", "-r", "r1"])).rejects.toThrow();
|
|
1791
2620
|
consoleSpy.mockRestore();
|
|
@@ -1793,42 +2622,18 @@ describe("plugin registry remove", () => {
|
|
|
1793
2622
|
});
|
|
1794
2623
|
});
|
|
1795
2624
|
// ---------------------------------------------------------------------------
|
|
1796
|
-
// plugin registry sync
|
|
1797
|
-
// ---------------------------------------------------------------------------
|
|
1798
|
-
describe("plugin registry sync", () => {
|
|
1799
|
-
it("triggers a registry sync", async () => {
|
|
1800
|
-
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1801
|
-
mockApiRequest.mockResolvedValueOnce({ accepted: true });
|
|
1802
|
-
await pluginRegistrySyncCommand.parseAsync(["node", "cli", "-r", "reg1"]);
|
|
1803
|
-
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/registry/sync", expect.objectContaining({ method: "POST" }));
|
|
1804
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Sync accepted"));
|
|
1805
|
-
consoleSpy.mockRestore();
|
|
1806
|
-
});
|
|
1807
|
-
it("reports sync not accepted", async () => {
|
|
1808
|
-
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1809
|
-
mockApiRequest.mockResolvedValueOnce({ accepted: false });
|
|
1810
|
-
await pluginRegistrySyncCommand.parseAsync(["node", "cli", "-r", "reg1"]);
|
|
1811
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("not accepted"));
|
|
1812
|
-
consoleSpy.mockRestore();
|
|
1813
|
-
});
|
|
1814
|
-
it("handles sync failure", async () => {
|
|
1815
|
-
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1816
|
-
const exitSpy = vi.spyOn(process, "exit").mockImplementation((_code) => { throw new Error("process.exit"); });
|
|
1817
|
-
mockApiRequest.mockRejectedValueOnce(new Error("Registry not found"));
|
|
1818
|
-
await expect(pluginRegistrySyncCommand.parseAsync(["node", "cli", "-r", "reg1"])).rejects.toThrow();
|
|
1819
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Error:"));
|
|
1820
|
-
consoleSpy.mockRestore();
|
|
1821
|
-
exitSpy.mockRestore();
|
|
1822
|
-
});
|
|
1823
|
-
});
|
|
1824
|
-
// ---------------------------------------------------------------------------
|
|
1825
2625
|
// plugin settings set_auth_alerts
|
|
1826
2626
|
// ---------------------------------------------------------------------------
|
|
1827
2627
|
describe("plugin settings set_auth_alerts", () => {
|
|
1828
2628
|
it("updates auth alert settings", async () => {
|
|
1829
2629
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1830
2630
|
mockApiRequest.mockResolvedValueOnce({ ok: true });
|
|
1831
|
-
await pluginSettingsSetAuthAlertsCommand.parseAsync([
|
|
2631
|
+
await pluginSettingsSetAuthAlertsCommand.parseAsync([
|
|
2632
|
+
"node",
|
|
2633
|
+
"cli",
|
|
2634
|
+
"--roles",
|
|
2635
|
+
"Owner,Admin",
|
|
2636
|
+
]);
|
|
1832
2637
|
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/settings/set_auth_alerts", expect.objectContaining({ method: "POST" }));
|
|
1833
2638
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("updated"));
|
|
1834
2639
|
consoleSpy.mockRestore();
|
|
@@ -1836,15 +2641,29 @@ describe("plugin settings set_auth_alerts", () => {
|
|
|
1836
2641
|
it("reports update failed when ok=false", async () => {
|
|
1837
2642
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1838
2643
|
mockApiRequest.mockResolvedValueOnce({ ok: false });
|
|
1839
|
-
await pluginSettingsSetAuthAlertsCommand.parseAsync([
|
|
2644
|
+
await pluginSettingsSetAuthAlertsCommand.parseAsync([
|
|
2645
|
+
"node",
|
|
2646
|
+
"cli",
|
|
2647
|
+
"--roles",
|
|
2648
|
+
"Owner",
|
|
2649
|
+
]);
|
|
1840
2650
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("Update failed"));
|
|
1841
2651
|
consoleSpy.mockRestore();
|
|
1842
2652
|
});
|
|
1843
2653
|
it("handles failure", async () => {
|
|
1844
2654
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1845
|
-
const exitSpy = vi
|
|
2655
|
+
const exitSpy = vi
|
|
2656
|
+
.spyOn(process, "exit")
|
|
2657
|
+
.mockImplementation((_code) => {
|
|
2658
|
+
throw new Error("process.exit");
|
|
2659
|
+
});
|
|
1846
2660
|
mockApiRequest.mockRejectedValueOnce(new Error("Permission denied"));
|
|
1847
|
-
await expect(pluginSettingsSetAuthAlertsCommand.parseAsync([
|
|
2661
|
+
await expect(pluginSettingsSetAuthAlertsCommand.parseAsync([
|
|
2662
|
+
"node",
|
|
2663
|
+
"cli",
|
|
2664
|
+
"--roles",
|
|
2665
|
+
"Owner",
|
|
2666
|
+
])).rejects.toThrow();
|
|
1848
2667
|
consoleSpy.mockRestore();
|
|
1849
2668
|
exitSpy.mockRestore();
|
|
1850
2669
|
});
|
|
@@ -1856,7 +2675,14 @@ describe("plugin workspace set_enabled", () => {
|
|
|
1856
2675
|
it("enables a plugin for workspace", async () => {
|
|
1857
2676
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1858
2677
|
mockApiRequest.mockResolvedValueOnce({ workspaceServerId: "wsrv1" });
|
|
1859
|
-
await pluginWorkspaceSetEnabledCommand.parseAsync([
|
|
2678
|
+
await pluginWorkspaceSetEnabledCommand.parseAsync([
|
|
2679
|
+
"node",
|
|
2680
|
+
"cli",
|
|
2681
|
+
"-l",
|
|
2682
|
+
"listing1",
|
|
2683
|
+
"--enabled",
|
|
2684
|
+
"true",
|
|
2685
|
+
]);
|
|
1860
2686
|
expect(mockApiRequest).toHaveBeenCalledWith("/plugin/workspace/set_enabled", expect.objectContaining({ method: "POST" }));
|
|
1861
2687
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("enabled"));
|
|
1862
2688
|
consoleSpy.mockRestore();
|
|
@@ -1864,15 +2690,33 @@ describe("plugin workspace set_enabled", () => {
|
|
|
1864
2690
|
it("disables a plugin for workspace (no server ID)", async () => {
|
|
1865
2691
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
1866
2692
|
mockApiRequest.mockResolvedValueOnce({ workspaceServerId: null });
|
|
1867
|
-
await pluginWorkspaceSetEnabledCommand.parseAsync([
|
|
2693
|
+
await pluginWorkspaceSetEnabledCommand.parseAsync([
|
|
2694
|
+
"node",
|
|
2695
|
+
"cli",
|
|
2696
|
+
"-l",
|
|
2697
|
+
"listing1",
|
|
2698
|
+
"--enabled",
|
|
2699
|
+
"false",
|
|
2700
|
+
]);
|
|
1868
2701
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("disabled"));
|
|
1869
2702
|
consoleSpy.mockRestore();
|
|
1870
2703
|
});
|
|
1871
2704
|
it("handles failure", async () => {
|
|
1872
2705
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1873
|
-
const exitSpy = vi
|
|
2706
|
+
const exitSpy = vi
|
|
2707
|
+
.spyOn(process, "exit")
|
|
2708
|
+
.mockImplementation((_code) => {
|
|
2709
|
+
throw new Error("process.exit");
|
|
2710
|
+
});
|
|
1874
2711
|
mockApiRequest.mockRejectedValueOnce(new Error("Listing not found"));
|
|
1875
|
-
await expect(pluginWorkspaceSetEnabledCommand.parseAsync([
|
|
2712
|
+
await expect(pluginWorkspaceSetEnabledCommand.parseAsync([
|
|
2713
|
+
"node",
|
|
2714
|
+
"cli",
|
|
2715
|
+
"-l",
|
|
2716
|
+
"l1",
|
|
2717
|
+
"--enabled",
|
|
2718
|
+
"true",
|
|
2719
|
+
])).rejects.toThrow();
|
|
1876
2720
|
consoleSpy.mockRestore();
|
|
1877
2721
|
exitSpy.mockRestore();
|
|
1878
2722
|
});
|
|
@@ -1890,16 +2734,30 @@ describe("system install instructions", () => {
|
|
|
1890
2734
|
{ label: "Authenticate", command: "oxagen auth login" },
|
|
1891
2735
|
],
|
|
1892
2736
|
});
|
|
1893
|
-
await systemInstallInstructionsCommand.parseAsync([
|
|
2737
|
+
await systemInstallInstructionsCommand.parseAsync([
|
|
2738
|
+
"node",
|
|
2739
|
+
"cli",
|
|
2740
|
+
"-c",
|
|
2741
|
+
"claude-code",
|
|
2742
|
+
]);
|
|
1894
2743
|
expect(mockApiRequest).toHaveBeenCalled();
|
|
1895
2744
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("claude-code"));
|
|
1896
2745
|
consoleSpy.mockRestore();
|
|
1897
2746
|
});
|
|
1898
2747
|
it("handles fetch failure", async () => {
|
|
1899
2748
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1900
|
-
const exitSpy = vi
|
|
2749
|
+
const exitSpy = vi
|
|
2750
|
+
.spyOn(process, "exit")
|
|
2751
|
+
.mockImplementation((_code) => {
|
|
2752
|
+
throw new Error("process.exit");
|
|
2753
|
+
});
|
|
1901
2754
|
mockApiRequest.mockRejectedValueOnce(new Error("Unknown client"));
|
|
1902
|
-
await expect(systemInstallInstructionsCommand.parseAsync([
|
|
2755
|
+
await expect(systemInstallInstructionsCommand.parseAsync([
|
|
2756
|
+
"node",
|
|
2757
|
+
"cli",
|
|
2758
|
+
"-c",
|
|
2759
|
+
"unknown",
|
|
2760
|
+
])).rejects.toThrow();
|
|
1903
2761
|
consoleSpy.mockRestore();
|
|
1904
2762
|
exitSpy.mockRestore();
|
|
1905
2763
|
});
|
|
@@ -1943,7 +2801,11 @@ describe("user preferences read", () => {
|
|
|
1943
2801
|
});
|
|
1944
2802
|
it("handles read failure", async () => {
|
|
1945
2803
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1946
|
-
const exitSpy = vi
|
|
2804
|
+
const exitSpy = vi
|
|
2805
|
+
.spyOn(process, "exit")
|
|
2806
|
+
.mockImplementation((_code) => {
|
|
2807
|
+
throw new Error("process.exit");
|
|
2808
|
+
});
|
|
1947
2809
|
mockApiRequest.mockRejectedValueOnce(new Error("Unauthorized"));
|
|
1948
2810
|
await expect(userPreferencesReadCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
1949
2811
|
consoleSpy.mockRestore();
|
|
@@ -1963,16 +2825,30 @@ describe("user preferences write", () => {
|
|
|
1963
2825
|
defaultImageModel: null,
|
|
1964
2826
|
defaultVideoModel: null,
|
|
1965
2827
|
});
|
|
1966
|
-
await userPreferencesWriteCommand.parseAsync([
|
|
2828
|
+
await userPreferencesWriteCommand.parseAsync([
|
|
2829
|
+
"node",
|
|
2830
|
+
"cli",
|
|
2831
|
+
"--font-size",
|
|
2832
|
+
"large",
|
|
2833
|
+
]);
|
|
1967
2834
|
expect(mockApiRequest).toHaveBeenCalledWith("/user/preferences/write", expect.objectContaining({ method: "POST" }));
|
|
1968
2835
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("updated"));
|
|
1969
2836
|
consoleSpy.mockRestore();
|
|
1970
2837
|
});
|
|
1971
2838
|
it("handles write failure", async () => {
|
|
1972
2839
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
1973
|
-
const exitSpy = vi
|
|
2840
|
+
const exitSpy = vi
|
|
2841
|
+
.spyOn(process, "exit")
|
|
2842
|
+
.mockImplementation((_code) => {
|
|
2843
|
+
throw new Error("process.exit");
|
|
2844
|
+
});
|
|
1974
2845
|
mockApiRequest.mockRejectedValueOnce(new Error("Validation failed"));
|
|
1975
|
-
await expect(userPreferencesWriteCommand.parseAsync([
|
|
2846
|
+
await expect(userPreferencesWriteCommand.parseAsync([
|
|
2847
|
+
"node",
|
|
2848
|
+
"cli",
|
|
2849
|
+
"--density",
|
|
2850
|
+
"bad",
|
|
2851
|
+
])).rejects.toThrow();
|
|
1976
2852
|
consoleSpy.mockRestore();
|
|
1977
2853
|
exitSpy.mockRestore();
|
|
1978
2854
|
});
|
|
@@ -1998,7 +2874,11 @@ describe("workflow cancel", () => {
|
|
|
1998
2874
|
});
|
|
1999
2875
|
it("handles cancel failure", async () => {
|
|
2000
2876
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2001
|
-
const exitSpy = vi
|
|
2877
|
+
const exitSpy = vi
|
|
2878
|
+
.spyOn(process, "exit")
|
|
2879
|
+
.mockImplementation((_code) => {
|
|
2880
|
+
throw new Error("process.exit");
|
|
2881
|
+
});
|
|
2002
2882
|
mockApiRequest.mockRejectedValueOnce(new Error("Not found"));
|
|
2003
2883
|
await expect(workflowCancelCommand.parseAsync(["node", "cli", "-w", "wfr_abc"])).rejects.toThrow();
|
|
2004
2884
|
consoleSpy.mockRestore();
|
|
@@ -2009,7 +2889,15 @@ describe("workflow status", () => {
|
|
|
2009
2889
|
it("shows workflow status and tasks", async () => {
|
|
2010
2890
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
2011
2891
|
mockApiRequest.mockResolvedValueOnce({
|
|
2012
|
-
workflow: {
|
|
2892
|
+
workflow: {
|
|
2893
|
+
id: "wf1",
|
|
2894
|
+
publicId: "wfr_abc",
|
|
2895
|
+
title: "Research task",
|
|
2896
|
+
status: "running",
|
|
2897
|
+
totalTasks: 5,
|
|
2898
|
+
completedTasks: 3,
|
|
2899
|
+
failedTasks: 0,
|
|
2900
|
+
},
|
|
2013
2901
|
tasks: [
|
|
2014
2902
|
{ id: "t1", title: "Gather data", status: "completed" },
|
|
2015
2903
|
{ id: "t2", title: "Analyze data", status: "running" },
|
|
@@ -2022,7 +2910,11 @@ describe("workflow status", () => {
|
|
|
2022
2910
|
});
|
|
2023
2911
|
it("handles status fetch failure", async () => {
|
|
2024
2912
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2025
|
-
const exitSpy = vi
|
|
2913
|
+
const exitSpy = vi
|
|
2914
|
+
.spyOn(process, "exit")
|
|
2915
|
+
.mockImplementation((_code) => {
|
|
2916
|
+
throw new Error("process.exit");
|
|
2917
|
+
});
|
|
2026
2918
|
mockApiRequest.mockRejectedValueOnce(new Error("Workflow not found"));
|
|
2027
2919
|
await expect(workflowStatusCommand.parseAsync(["node", "cli", "-w", "wfr_xyz"])).rejects.toThrow();
|
|
2028
2920
|
consoleSpy.mockRestore();
|
|
@@ -2037,7 +2929,11 @@ describe("workflow status", () => {
|
|
|
2037
2929
|
describe("branch coverage: ApiError error paths", () => {
|
|
2038
2930
|
it("automation list returns ApiError message", async () => {
|
|
2039
2931
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2040
|
-
const exitSpy = vi
|
|
2932
|
+
const exitSpy = vi
|
|
2933
|
+
.spyOn(process, "exit")
|
|
2934
|
+
.mockImplementation((_code) => {
|
|
2935
|
+
throw new Error("exit");
|
|
2936
|
+
});
|
|
2041
2937
|
mockApiError(403, "Forbidden");
|
|
2042
2938
|
await expect(automationListCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
2043
2939
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Forbidden");
|
|
@@ -2046,16 +2942,50 @@ describe("branch coverage: ApiError error paths", () => {
|
|
|
2046
2942
|
});
|
|
2047
2943
|
it("automation create returns ApiError message", async () => {
|
|
2048
2944
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2049
|
-
const exitSpy = vi
|
|
2945
|
+
const exitSpy = vi
|
|
2946
|
+
.spyOn(process, "exit")
|
|
2947
|
+
.mockImplementation((_code) => {
|
|
2948
|
+
throw new Error("exit");
|
|
2949
|
+
});
|
|
2050
2950
|
mockApiError(400, "Name required");
|
|
2051
2951
|
await expect(automationCreateCommand.parseAsync(["node", "cli", "-n", "A"])).rejects.toThrow();
|
|
2052
2952
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Name required");
|
|
2053
2953
|
consoleSpy.mockRestore();
|
|
2054
2954
|
exitSpy.mockRestore();
|
|
2055
2955
|
});
|
|
2956
|
+
it("automation enable returns ApiError message", async () => {
|
|
2957
|
+
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2958
|
+
const exitSpy = vi
|
|
2959
|
+
.spyOn(process, "exit")
|
|
2960
|
+
.mockImplementation((_code) => {
|
|
2961
|
+
throw new Error("exit");
|
|
2962
|
+
});
|
|
2963
|
+
mockApiError(404, "Automation not found");
|
|
2964
|
+
await expect(automationEnableCommand.parseAsync(["node", "cli", "plt_missing"])).rejects.toThrow();
|
|
2965
|
+
expect(consoleSpy).toHaveBeenCalledWith("Error: Automation not found");
|
|
2966
|
+
consoleSpy.mockRestore();
|
|
2967
|
+
exitSpy.mockRestore();
|
|
2968
|
+
});
|
|
2969
|
+
it("automation disable returns ApiError message", async () => {
|
|
2970
|
+
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2971
|
+
const exitSpy = vi
|
|
2972
|
+
.spyOn(process, "exit")
|
|
2973
|
+
.mockImplementation((_code) => {
|
|
2974
|
+
throw new Error("exit");
|
|
2975
|
+
});
|
|
2976
|
+
mockApiError(404, "Automation not found");
|
|
2977
|
+
await expect(automationDisableCommand.parseAsync(["node", "cli", "plt_missing"])).rejects.toThrow();
|
|
2978
|
+
expect(consoleSpy).toHaveBeenCalledWith("Error: Automation not found");
|
|
2979
|
+
consoleSpy.mockRestore();
|
|
2980
|
+
exitSpy.mockRestore();
|
|
2981
|
+
});
|
|
2056
2982
|
it("automation trigger returns ApiError message", async () => {
|
|
2057
2983
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2058
|
-
const exitSpy = vi
|
|
2984
|
+
const exitSpy = vi
|
|
2985
|
+
.spyOn(process, "exit")
|
|
2986
|
+
.mockImplementation((_code) => {
|
|
2987
|
+
throw new Error("exit");
|
|
2988
|
+
});
|
|
2059
2989
|
mockApiError(404, "Automation not found");
|
|
2060
2990
|
await expect(automationTriggerCommand.parseAsync(["node", "cli", "-a", "a1"])).rejects.toThrow();
|
|
2061
2991
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Automation not found");
|
|
@@ -2064,7 +2994,11 @@ describe("branch coverage: ApiError error paths", () => {
|
|
|
2064
2994
|
});
|
|
2065
2995
|
it("billing credits purchase returns ApiError message", async () => {
|
|
2066
2996
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2067
|
-
const exitSpy = vi
|
|
2997
|
+
const exitSpy = vi
|
|
2998
|
+
.spyOn(process, "exit")
|
|
2999
|
+
.mockImplementation((_code) => {
|
|
3000
|
+
throw new Error("exit");
|
|
3001
|
+
});
|
|
2068
3002
|
mockApiError(402, "Payment failed");
|
|
2069
3003
|
await expect(billingCreditsPurchaseCommand.parseAsync(["node", "cli", "-a", "10"])).rejects.toThrow();
|
|
2070
3004
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Payment failed");
|
|
@@ -2073,7 +3007,11 @@ describe("branch coverage: ApiError error paths", () => {
|
|
|
2073
3007
|
});
|
|
2074
3008
|
it("billing subscription read returns ApiError message", async () => {
|
|
2075
3009
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2076
|
-
const exitSpy = vi
|
|
3010
|
+
const exitSpy = vi
|
|
3011
|
+
.spyOn(process, "exit")
|
|
3012
|
+
.mockImplementation((_code) => {
|
|
3013
|
+
throw new Error("exit");
|
|
3014
|
+
});
|
|
2077
3015
|
mockApiError(404, "Subscription not found");
|
|
2078
3016
|
await expect(billingSubscriptionReadCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
2079
3017
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Subscription not found");
|
|
@@ -2082,7 +3020,11 @@ describe("branch coverage: ApiError error paths", () => {
|
|
|
2082
3020
|
});
|
|
2083
3021
|
it("document list returns ApiError message", async () => {
|
|
2084
3022
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2085
|
-
const exitSpy = vi
|
|
3023
|
+
const exitSpy = vi
|
|
3024
|
+
.spyOn(process, "exit")
|
|
3025
|
+
.mockImplementation((_code) => {
|
|
3026
|
+
throw new Error("exit");
|
|
3027
|
+
});
|
|
2086
3028
|
mockApiError(403, "Access denied");
|
|
2087
3029
|
await expect(documentListCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
2088
3030
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Access denied");
|
|
@@ -2091,7 +3033,11 @@ describe("branch coverage: ApiError error paths", () => {
|
|
|
2091
3033
|
});
|
|
2092
3034
|
it("workspace member list returns ApiError message", async () => {
|
|
2093
3035
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2094
|
-
const exitSpy = vi
|
|
3036
|
+
const exitSpy = vi
|
|
3037
|
+
.spyOn(process, "exit")
|
|
3038
|
+
.mockImplementation((_code) => {
|
|
3039
|
+
throw new Error("exit");
|
|
3040
|
+
});
|
|
2095
3041
|
mockApiError(403, "Not a member");
|
|
2096
3042
|
await expect(workspaceMemberListCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
2097
3043
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Not a member");
|
|
@@ -2100,7 +3046,11 @@ describe("branch coverage: ApiError error paths", () => {
|
|
|
2100
3046
|
});
|
|
2101
3047
|
it("workflow cancel returns ApiError message", async () => {
|
|
2102
3048
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2103
|
-
const exitSpy = vi
|
|
3049
|
+
const exitSpy = vi
|
|
3050
|
+
.spyOn(process, "exit")
|
|
3051
|
+
.mockImplementation((_code) => {
|
|
3052
|
+
throw new Error("exit");
|
|
3053
|
+
});
|
|
2104
3054
|
mockApiError(404, "Workflow not found");
|
|
2105
3055
|
await expect(workflowCancelCommand.parseAsync(["node", "cli", "-w", "wfr_abc"])).rejects.toThrow();
|
|
2106
3056
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Workflow not found");
|
|
@@ -2109,7 +3059,11 @@ describe("branch coverage: ApiError error paths", () => {
|
|
|
2109
3059
|
});
|
|
2110
3060
|
it("workflow status returns ApiError message", async () => {
|
|
2111
3061
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2112
|
-
const exitSpy = vi
|
|
3062
|
+
const exitSpy = vi
|
|
3063
|
+
.spyOn(process, "exit")
|
|
3064
|
+
.mockImplementation((_code) => {
|
|
3065
|
+
throw new Error("exit");
|
|
3066
|
+
});
|
|
2113
3067
|
mockApiError(404, "Run expired");
|
|
2114
3068
|
await expect(workflowStatusCommand.parseAsync(["node", "cli", "-w", "wfr_abc"])).rejects.toThrow();
|
|
2115
3069
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Run expired");
|
|
@@ -2118,7 +3072,11 @@ describe("branch coverage: ApiError error paths", () => {
|
|
|
2118
3072
|
});
|
|
2119
3073
|
it("user preferences read returns ApiError message", async () => {
|
|
2120
3074
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2121
|
-
const exitSpy = vi
|
|
3075
|
+
const exitSpy = vi
|
|
3076
|
+
.spyOn(process, "exit")
|
|
3077
|
+
.mockImplementation((_code) => {
|
|
3078
|
+
throw new Error("exit");
|
|
3079
|
+
});
|
|
2122
3080
|
mockApiError(401, "Unauthorized");
|
|
2123
3081
|
await expect(userPreferencesReadCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
2124
3082
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Unauthorized");
|
|
@@ -2127,9 +3085,18 @@ describe("branch coverage: ApiError error paths", () => {
|
|
|
2127
3085
|
});
|
|
2128
3086
|
it("user preferences write returns ApiError message", async () => {
|
|
2129
3087
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2130
|
-
const exitSpy = vi
|
|
3088
|
+
const exitSpy = vi
|
|
3089
|
+
.spyOn(process, "exit")
|
|
3090
|
+
.mockImplementation((_code) => {
|
|
3091
|
+
throw new Error("exit");
|
|
3092
|
+
});
|
|
2131
3093
|
mockApiError(400, "Invalid font size");
|
|
2132
|
-
await expect(userPreferencesWriteCommand.parseAsync([
|
|
3094
|
+
await expect(userPreferencesWriteCommand.parseAsync([
|
|
3095
|
+
"node",
|
|
3096
|
+
"cli",
|
|
3097
|
+
"--font-size",
|
|
3098
|
+
"xxx",
|
|
3099
|
+
])).rejects.toThrow();
|
|
2133
3100
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Invalid font size");
|
|
2134
3101
|
consoleSpy.mockRestore();
|
|
2135
3102
|
exitSpy.mockRestore();
|
|
@@ -2145,27 +3112,40 @@ describe("branch coverage: empty/optional data branches", () => {
|
|
|
2145
3112
|
});
|
|
2146
3113
|
it("automation list with workspace option", async () => {
|
|
2147
3114
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
2148
|
-
mockApiRequest.mockResolvedValueOnce([
|
|
3115
|
+
mockApiRequest.mockResolvedValueOnce([
|
|
3116
|
+
{ id: "a1", name: "Test", status: "active", triggers: [] },
|
|
3117
|
+
]);
|
|
2149
3118
|
await automationListCommand.parseAsync(["node", "cli", "-w", "ws1"]);
|
|
2150
3119
|
expect(mockApiRequest).toHaveBeenCalledWith(expect.stringContaining("workspace_id=ws1"), expect.anything());
|
|
2151
3120
|
consoleSpy.mockRestore();
|
|
2152
3121
|
});
|
|
2153
3122
|
it("automation list shows 'none' when triggers are empty", async () => {
|
|
2154
3123
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
2155
|
-
mockApiRequest.mockResolvedValueOnce([
|
|
3124
|
+
mockApiRequest.mockResolvedValueOnce([
|
|
3125
|
+
{ id: "a1", name: "Untriggered", status: "active", triggers: [] },
|
|
3126
|
+
]);
|
|
2156
3127
|
await automationListCommand.parseAsync(["node", "cli"]);
|
|
2157
3128
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining("triggers=none"));
|
|
2158
3129
|
consoleSpy.mockRestore();
|
|
2159
3130
|
});
|
|
2160
3131
|
it("image create with save-to option", async () => {
|
|
2161
3132
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
2162
|
-
mockApiRequest.mockResolvedValueOnce({
|
|
3133
|
+
mockApiRequest.mockResolvedValueOnce({
|
|
3134
|
+
id: "img1",
|
|
3135
|
+
url: "https://cdn.example.com/img.png",
|
|
3136
|
+
created_at: "2026-06-08",
|
|
3137
|
+
workspace_id: "ws1",
|
|
3138
|
+
});
|
|
2163
3139
|
await imageCreateCommand.parseAsync(["node", "cli", "-p", "A cat"]);
|
|
2164
3140
|
consoleSpy.mockRestore();
|
|
2165
3141
|
});
|
|
2166
3142
|
it("conversation chat ApiError path", async () => {
|
|
2167
3143
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2168
|
-
const exitSpy = vi
|
|
3144
|
+
const exitSpy = vi
|
|
3145
|
+
.spyOn(process, "exit")
|
|
3146
|
+
.mockImplementation((_code) => {
|
|
3147
|
+
throw new Error("exit");
|
|
3148
|
+
});
|
|
2169
3149
|
mockApiError(401, "Not authenticated");
|
|
2170
3150
|
await expect(conversationChatCommand.parseAsync(["node", "cli", "-m", "Hello"])).rejects.toThrow();
|
|
2171
3151
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Not authenticated");
|
|
@@ -2174,7 +3154,11 @@ describe("branch coverage: empty/optional data branches", () => {
|
|
|
2174
3154
|
});
|
|
2175
3155
|
it("workspace list ApiError path", async () => {
|
|
2176
3156
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2177
|
-
const exitSpy = vi
|
|
3157
|
+
const exitSpy = vi
|
|
3158
|
+
.spyOn(process, "exit")
|
|
3159
|
+
.mockImplementation((_code) => {
|
|
3160
|
+
throw new Error("exit");
|
|
3161
|
+
});
|
|
2178
3162
|
mockApiError(403, "Org not found");
|
|
2179
3163
|
await expect(workspaceListCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
2180
3164
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Org not found");
|
|
@@ -2183,7 +3167,11 @@ describe("branch coverage: empty/optional data branches", () => {
|
|
|
2183
3167
|
});
|
|
2184
3168
|
it("org list ApiError path", async () => {
|
|
2185
3169
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2186
|
-
const exitSpy = vi
|
|
3170
|
+
const exitSpy = vi
|
|
3171
|
+
.spyOn(process, "exit")
|
|
3172
|
+
.mockImplementation((_code) => {
|
|
3173
|
+
throw new Error("exit");
|
|
3174
|
+
});
|
|
2187
3175
|
mockApiError(401, "Token expired");
|
|
2188
3176
|
await expect(orgListCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
2189
3177
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Token expired");
|
|
@@ -2192,7 +3180,11 @@ describe("branch coverage: empty/optional data branches", () => {
|
|
|
2192
3180
|
});
|
|
2193
3181
|
it("api-key create ApiError path", async () => {
|
|
2194
3182
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2195
|
-
const exitSpy = vi
|
|
3183
|
+
const exitSpy = vi
|
|
3184
|
+
.spyOn(process, "exit")
|
|
3185
|
+
.mockImplementation((_code) => {
|
|
3186
|
+
throw new Error("exit");
|
|
3187
|
+
});
|
|
2196
3188
|
mockApiError(429, "Rate limit exceeded");
|
|
2197
3189
|
await expect(apiKeyCreateCommand.parseAsync(["node", "cli", "mykey"])).rejects.toThrow();
|
|
2198
3190
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Rate limit exceeded");
|
|
@@ -2201,7 +3193,11 @@ describe("branch coverage: empty/optional data branches", () => {
|
|
|
2201
3193
|
});
|
|
2202
3194
|
it("plugin list ApiError path", async () => {
|
|
2203
3195
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2204
|
-
const exitSpy = vi
|
|
3196
|
+
const exitSpy = vi
|
|
3197
|
+
.spyOn(process, "exit")
|
|
3198
|
+
.mockImplementation((_code) => {
|
|
3199
|
+
throw new Error("exit");
|
|
3200
|
+
});
|
|
2205
3201
|
mockApiError(403, "Permission denied");
|
|
2206
3202
|
await expect(pluginListCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
2207
3203
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Permission denied");
|
|
@@ -2210,7 +3206,11 @@ describe("branch coverage: empty/optional data branches", () => {
|
|
|
2210
3206
|
});
|
|
2211
3207
|
it("billing status ApiError path", async () => {
|
|
2212
3208
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2213
|
-
const exitSpy = vi
|
|
3209
|
+
const exitSpy = vi
|
|
3210
|
+
.spyOn(process, "exit")
|
|
3211
|
+
.mockImplementation((_code) => {
|
|
3212
|
+
throw new Error("exit");
|
|
3213
|
+
});
|
|
2214
3214
|
mockApiError(402, "Billing error");
|
|
2215
3215
|
await expect(billingStatusCommand.parseAsync(["node", "cli"])).rejects.toThrow();
|
|
2216
3216
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Billing error");
|
|
@@ -2219,7 +3219,11 @@ describe("branch coverage: empty/optional data branches", () => {
|
|
|
2219
3219
|
});
|
|
2220
3220
|
it("chat send ApiError path", async () => {
|
|
2221
3221
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2222
|
-
const exitSpy = vi
|
|
3222
|
+
const exitSpy = vi
|
|
3223
|
+
.spyOn(process, "exit")
|
|
3224
|
+
.mockImplementation((_code) => {
|
|
3225
|
+
throw new Error("exit");
|
|
3226
|
+
});
|
|
2223
3227
|
// chat.send uses native fetch (not apiRequest); mock fetch directly.
|
|
2224
3228
|
vi.spyOn(global, "fetch").mockResolvedValueOnce(new Response(JSON.stringify({ error: "Service unavailable" }), {
|
|
2225
3229
|
status: 503,
|
|
@@ -2231,7 +3235,11 @@ describe("branch coverage: empty/optional data branches", () => {
|
|
|
2231
3235
|
});
|
|
2232
3236
|
it("document read ApiError path", async () => {
|
|
2233
3237
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2234
|
-
const exitSpy = vi
|
|
3238
|
+
const exitSpy = vi
|
|
3239
|
+
.spyOn(process, "exit")
|
|
3240
|
+
.mockImplementation((_code) => {
|
|
3241
|
+
throw new Error("exit");
|
|
3242
|
+
});
|
|
2235
3243
|
mockApiError(404, "Document not found");
|
|
2236
3244
|
await expect(documentReadCommand.parseAsync(["node", "cli", "-d", "doc1"])).rejects.toThrow();
|
|
2237
3245
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Document not found");
|
|
@@ -2246,7 +3254,11 @@ describe("branch coverage: empty/optional data branches", () => {
|
|
|
2246
3254
|
});
|
|
2247
3255
|
it("workflow run ApiError path", async () => {
|
|
2248
3256
|
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
2249
|
-
const exitSpy = vi
|
|
3257
|
+
const exitSpy = vi
|
|
3258
|
+
.spyOn(process, "exit")
|
|
3259
|
+
.mockImplementation((_code) => {
|
|
3260
|
+
throw new Error("exit");
|
|
3261
|
+
});
|
|
2250
3262
|
mockApiError(400, "Invalid workflow spec");
|
|
2251
3263
|
await expect(workflowRunCommand.parseAsync(["node", "cli", "-w", "wf1"])).rejects.toThrow();
|
|
2252
3264
|
expect(consoleSpy).toHaveBeenCalledWith("Error: Invalid workflow spec");
|
|
@@ -2271,7 +3283,13 @@ describe("Environment Variable Defaults", () => {
|
|
|
2271
3283
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
2272
3284
|
mockGetOrgId.mockReturnValue("env-org-123");
|
|
2273
3285
|
mockApiRequest.mockResolvedValueOnce({ members: [] });
|
|
2274
|
-
await orgMemberAddCommand.parseAsync([
|
|
3286
|
+
await orgMemberAddCommand.parseAsync([
|
|
3287
|
+
"node",
|
|
3288
|
+
"cli",
|
|
3289
|
+
"user@example.com",
|
|
3290
|
+
"--role",
|
|
3291
|
+
"admin",
|
|
3292
|
+
]);
|
|
2275
3293
|
expect(mockApiRequest).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
|
|
2276
3294
|
body: expect.stringContaining("env-org-123"),
|
|
2277
3295
|
}));
|
|
@@ -2281,7 +3299,15 @@ describe("Environment Variable Defaults", () => {
|
|
|
2281
3299
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
2282
3300
|
mockGetOrgId.mockReturnValue("env-org-123");
|
|
2283
3301
|
mockApiRequest.mockResolvedValueOnce({ members: [] });
|
|
2284
|
-
await orgMemberAddCommand.parseAsync([
|
|
3302
|
+
await orgMemberAddCommand.parseAsync([
|
|
3303
|
+
"node",
|
|
3304
|
+
"cli",
|
|
3305
|
+
"user@example.com",
|
|
3306
|
+
"--role",
|
|
3307
|
+
"admin",
|
|
3308
|
+
"--org",
|
|
3309
|
+
"cli-org-456",
|
|
3310
|
+
]);
|
|
2285
3311
|
expect(mockApiRequest).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
|
|
2286
3312
|
body: expect.stringContaining("cli-org-456"),
|
|
2287
3313
|
}));
|
|
@@ -2306,7 +3332,12 @@ describe("Environment Variable Defaults", () => {
|
|
|
2306
3332
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
2307
3333
|
mockGetWorkspaceId.mockReturnValue("env-workspace-789");
|
|
2308
3334
|
mockApiRequest.mockResolvedValueOnce([]);
|
|
2309
|
-
await workspaceMemberListCommand.parseAsync([
|
|
3335
|
+
await workspaceMemberListCommand.parseAsync([
|
|
3336
|
+
"node",
|
|
3337
|
+
"cli",
|
|
3338
|
+
"-w",
|
|
3339
|
+
"cli-workspace-xyz",
|
|
3340
|
+
]);
|
|
2310
3341
|
const calls = mockApiRequest.mock.calls;
|
|
2311
3342
|
expect(calls.length).toBeGreaterThan(0);
|
|
2312
3343
|
expect(calls[0]?.[0]).toContain("workspace_id=cli-workspace-xyz");
|
|
@@ -2331,11 +3362,17 @@ describe("Environment Variable Defaults", () => {
|
|
|
2331
3362
|
discoveredTools: ["tool1"],
|
|
2332
3363
|
});
|
|
2333
3364
|
await agentMcpRegisterCommand.parseAsync([
|
|
2334
|
-
"node",
|
|
2335
|
-
"
|
|
2336
|
-
"
|
|
2337
|
-
"-
|
|
2338
|
-
"-
|
|
3365
|
+
"node",
|
|
3366
|
+
"cli",
|
|
3367
|
+
"register",
|
|
3368
|
+
"-n",
|
|
3369
|
+
"my-mcp",
|
|
3370
|
+
"-u",
|
|
3371
|
+
"http://localhost:9000",
|
|
3372
|
+
"-t",
|
|
3373
|
+
"streamable-http",
|
|
3374
|
+
"-w",
|
|
3375
|
+
"explicit-workspace-888",
|
|
2339
3376
|
]);
|
|
2340
3377
|
expect(mockApiRequest).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
|
|
2341
3378
|
body: expect.stringContaining("explicit-workspace-888"),
|
|
@@ -2352,10 +3389,15 @@ describe("Environment Variable Defaults", () => {
|
|
|
2352
3389
|
discoveredTools: [],
|
|
2353
3390
|
});
|
|
2354
3391
|
await agentMcpRegisterCommand.parseAsync([
|
|
2355
|
-
"node",
|
|
2356
|
-
"
|
|
2357
|
-
"
|
|
2358
|
-
"-
|
|
3392
|
+
"node",
|
|
3393
|
+
"cli",
|
|
3394
|
+
"register",
|
|
3395
|
+
"-n",
|
|
3396
|
+
"my-mcp",
|
|
3397
|
+
"-u",
|
|
3398
|
+
"http://localhost:9000",
|
|
3399
|
+
"-t",
|
|
3400
|
+
"streamable-http",
|
|
2359
3401
|
]);
|
|
2360
3402
|
expect(mockApiRequest).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
|
|
2361
3403
|
body: expect.stringContaining("fallback-org-111"),
|
|
@@ -2373,7 +3415,12 @@ describe("Environment Variable Defaults", () => {
|
|
|
2373
3415
|
it("workspace member list uses OXAGEN_WORKSPACE_ID as default when no --workspace flag", async () => {
|
|
2374
3416
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
2375
3417
|
mockApiRequest.mockResolvedValueOnce([
|
|
2376
|
-
{
|
|
3418
|
+
{
|
|
3419
|
+
id: "user1",
|
|
3420
|
+
email: "user@test.com",
|
|
3421
|
+
role: "member",
|
|
3422
|
+
joined_at: "2024-01-01",
|
|
3423
|
+
},
|
|
2377
3424
|
]);
|
|
2378
3425
|
await workspaceMemberListCommand.parseAsync(["node", "cli"]);
|
|
2379
3426
|
const calls = mockApiRequest.mock.calls;
|
|
@@ -2384,11 +3431,18 @@ describe("Environment Variable Defaults", () => {
|
|
|
2384
3431
|
it("workspace member list uses explicit --workspace to override OXAGEN_WORKSPACE_ID", async () => {
|
|
2385
3432
|
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
2386
3433
|
mockApiRequest.mockResolvedValueOnce([
|
|
2387
|
-
{
|
|
3434
|
+
{
|
|
3435
|
+
id: "user1",
|
|
3436
|
+
email: "user@test.com",
|
|
3437
|
+
role: "member",
|
|
3438
|
+
joined_at: "2024-01-01",
|
|
3439
|
+
},
|
|
2388
3440
|
]);
|
|
2389
3441
|
await workspaceMemberListCommand.parseAsync([
|
|
2390
|
-
"node",
|
|
2391
|
-
"
|
|
3442
|
+
"node",
|
|
3443
|
+
"cli",
|
|
3444
|
+
"-w",
|
|
3445
|
+
"explicit-ws",
|
|
2392
3446
|
]);
|
|
2393
3447
|
const calls = mockApiRequest.mock.calls;
|
|
2394
3448
|
expect(calls.length).toBeGreaterThan(0);
|