@indemn/cli 1.5.0 → 1.7.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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +9 -4
- package/.github/workflows/ci.yml +10 -0
- package/.github/workflows/publish.yml +2 -2
- package/.mcp.json +1 -4
- package/CONTRIBUTING.md +3 -1
- package/README.md +69 -176
- package/dist/cli/agents.d.ts.map +1 -1
- package/dist/cli/agents.js +226 -18
- package/dist/cli/agents.js.map +1 -1
- package/dist/cli/analytics.d.ts +3 -0
- package/dist/cli/analytics.d.ts.map +1 -0
- package/dist/cli/analytics.js +133 -0
- package/dist/cli/analytics.js.map +1 -0
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +62 -17
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/billing.d.ts +3 -0
- package/dist/cli/billing.d.ts.map +1 -0
- package/dist/cli/billing.js +23 -0
- package/dist/cli/billing.js.map +1 -0
- package/dist/cli/campaigns.d.ts +3 -0
- package/dist/cli/campaigns.d.ts.map +1 -0
- package/dist/cli/campaigns.js +34 -0
- package/dist/cli/campaigns.js.map +1 -0
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +69 -102
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +71 -27
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/conversations.d.ts +3 -0
- package/dist/cli/conversations.d.ts.map +1 -0
- package/dist/cli/conversations.js +129 -0
- package/dist/cli/conversations.js.map +1 -0
- package/dist/cli/distribution.d.ts +3 -0
- package/dist/cli/distribution.d.ts.map +1 -0
- package/dist/cli/distribution.js +122 -0
- package/dist/cli/distribution.js.map +1 -0
- package/dist/cli/eval.d.ts.map +1 -1
- package/dist/cli/eval.js +315 -71
- package/dist/cli/eval.js.map +1 -1
- package/dist/cli/functions.d.ts.map +1 -1
- package/dist/cli/functions.js +125 -35
- package/dist/cli/functions.js.map +1 -1
- package/dist/cli/index.js +63 -54
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.d.ts +27 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +152 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/kb.d.ts.map +1 -1
- package/dist/cli/kb.js +141 -15
- package/dist/cli/kb.js.map +1 -1
- package/dist/cli/link.d.ts +21 -0
- package/dist/cli/link.d.ts.map +1 -0
- package/dist/cli/link.js +112 -0
- package/dist/cli/link.js.map +1 -0
- package/dist/cli/org.d.ts.map +1 -1
- package/dist/cli/org.js +79 -67
- package/dist/cli/org.js.map +1 -1
- package/dist/cli/platform.d.ts +3 -0
- package/dist/cli/platform.d.ts.map +1 -0
- package/dist/cli/platform.js +133 -0
- package/dist/cli/platform.js.map +1 -0
- package/dist/cli/tickets.d.ts +3 -0
- package/dist/cli/tickets.d.ts.map +1 -0
- package/dist/cli/tickets.js +125 -0
- package/dist/cli/tickets.js.map +1 -0
- package/dist/cli/utils/output.d.ts +15 -9
- package/dist/cli/utils/output.d.ts.map +1 -1
- package/dist/cli/utils/output.js +53 -46
- package/dist/cli/utils/output.js.map +1 -1
- package/dist/cli/voice.d.ts +3 -0
- package/dist/cli/voice.d.ts.map +1 -0
- package/dist/cli/voice.js +206 -0
- package/dist/cli/voice.js.map +1 -0
- package/dist/core/diff.d.ts +16 -0
- package/dist/core/diff.d.ts.map +1 -0
- package/dist/core/diff.js +57 -0
- package/dist/core/diff.js.map +1 -0
- package/dist/core/org-resolver.d.ts +37 -0
- package/dist/core/org-resolver.d.ts.map +1 -0
- package/dist/core/org-resolver.js +73 -0
- package/dist/core/org-resolver.js.map +1 -0
- package/dist/core/runtime.d.ts +36 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +62 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/scope.d.ts +33 -0
- package/dist/core/scope.d.ts.map +1 -0
- package/dist/core/scope.js +37 -0
- package/dist/core/scope.js.map +1 -0
- package/dist/mcp/registry.d.ts +67 -0
- package/dist/mcp/registry.d.ts.map +1 -0
- package/dist/mcp/registry.js +195 -0
- package/dist/mcp/registry.js.map +1 -0
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +87 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tool-meta.d.ts +21 -0
- package/dist/mcp/tool-meta.d.ts.map +1 -0
- package/dist/mcp/tool-meta.js +203 -0
- package/dist/mcp/tool-meta.js.map +1 -0
- package/dist/mcp/tools.d.ts +2 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +1462 -215
- package/dist/mcp/tools.js.map +1 -1
- package/dist/sdk/agent-bundle.d.ts +99 -0
- package/dist/sdk/agent-bundle.d.ts.map +1 -0
- package/dist/sdk/agent-bundle.js +211 -0
- package/dist/sdk/agent-bundle.js.map +1 -0
- package/dist/sdk/agents.d.ts +54 -1
- package/dist/sdk/agents.d.ts.map +1 -1
- package/dist/sdk/agents.js +59 -5
- package/dist/sdk/agents.js.map +1 -1
- package/dist/sdk/analytics.d.ts +158 -0
- package/dist/sdk/analytics.d.ts.map +1 -0
- package/dist/sdk/analytics.js +185 -0
- package/dist/sdk/analytics.js.map +1 -0
- package/dist/sdk/auth.d.ts +34 -12
- package/dist/sdk/auth.d.ts.map +1 -1
- package/dist/sdk/auth.js +60 -77
- package/dist/sdk/auth.js.map +1 -1
- package/dist/sdk/billing.d.ts +25 -0
- package/dist/sdk/billing.d.ts.map +1 -0
- package/dist/sdk/billing.js +61 -0
- package/dist/sdk/billing.js.map +1 -0
- package/dist/sdk/campaigns.d.ts +35 -0
- package/dist/sdk/campaigns.d.ts.map +1 -0
- package/dist/sdk/campaigns.js +59 -0
- package/dist/sdk/campaigns.js.map +1 -0
- package/dist/sdk/chat.d.ts +25 -2
- package/dist/sdk/chat.d.ts.map +1 -1
- package/dist/sdk/chat.js +37 -10
- package/dist/sdk/chat.js.map +1 -1
- package/dist/sdk/client.d.ts +93 -5
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/client.js +362 -100
- package/dist/sdk/client.js.map +1 -1
- package/dist/sdk/config-change.d.ts +74 -0
- package/dist/sdk/config-change.d.ts.map +1 -0
- package/dist/sdk/config-change.js +117 -0
- package/dist/sdk/config-change.js.map +1 -0
- package/dist/sdk/config.d.ts.map +1 -1
- package/dist/sdk/config.js +2 -1
- package/dist/sdk/config.js.map +1 -1
- package/dist/sdk/conversations.d.ts +101 -0
- package/dist/sdk/conversations.d.ts.map +1 -0
- package/dist/sdk/conversations.js +155 -0
- package/dist/sdk/conversations.js.map +1 -0
- package/dist/sdk/credentials.d.ts +25 -0
- package/dist/sdk/credentials.d.ts.map +1 -0
- package/dist/sdk/credentials.js +44 -0
- package/dist/sdk/credentials.js.map +1 -0
- package/dist/sdk/distribution.d.ts +94 -0
- package/dist/sdk/distribution.d.ts.map +1 -0
- package/dist/sdk/distribution.js +100 -0
- package/dist/sdk/distribution.js.map +1 -0
- package/dist/sdk/eval.d.ts +81 -0
- package/dist/sdk/eval.d.ts.map +1 -1
- package/dist/sdk/eval.js +117 -0
- package/dist/sdk/eval.js.map +1 -1
- package/dist/sdk/functions.d.ts +14 -1
- package/dist/sdk/functions.d.ts.map +1 -1
- package/dist/sdk/functions.js +48 -5
- package/dist/sdk/functions.js.map +1 -1
- package/dist/sdk/index.d.ts +2 -0
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +2 -0
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/jarvis-chat.d.ts +28 -0
- package/dist/sdk/jarvis-chat.d.ts.map +1 -0
- package/dist/sdk/jarvis-chat.js +117 -0
- package/dist/sdk/jarvis-chat.js.map +1 -0
- package/dist/sdk/kb.d.ts +69 -1
- package/dist/sdk/kb.d.ts.map +1 -1
- package/dist/sdk/kb.js +111 -24
- package/dist/sdk/kb.js.map +1 -1
- package/dist/sdk/orgs.d.ts +13 -0
- package/dist/sdk/orgs.d.ts.map +1 -0
- package/dist/sdk/orgs.js +59 -0
- package/dist/sdk/orgs.js.map +1 -0
- package/dist/sdk/platform.d.ts +62 -0
- package/dist/sdk/platform.d.ts.map +1 -0
- package/dist/sdk/platform.js +95 -0
- package/dist/sdk/platform.js.map +1 -0
- package/dist/sdk/session.d.ts +25 -0
- package/dist/sdk/session.d.ts.map +1 -0
- package/dist/sdk/session.js +69 -0
- package/dist/sdk/session.js.map +1 -0
- package/dist/sdk/skills.d.ts +46 -0
- package/dist/sdk/skills.d.ts.map +1 -0
- package/dist/sdk/skills.js +203 -0
- package/dist/sdk/skills.js.map +1 -0
- package/dist/sdk/test-chat.d.ts +52 -0
- package/dist/sdk/test-chat.d.ts.map +1 -0
- package/dist/sdk/test-chat.js +134 -0
- package/dist/sdk/test-chat.js.map +1 -0
- package/dist/sdk/tickets.d.ts +98 -0
- package/dist/sdk/tickets.d.ts.map +1 -0
- package/dist/sdk/tickets.js +91 -0
- package/dist/sdk/tickets.js.map +1 -0
- package/dist/sdk/types.d.ts +91 -6
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/sdk/voice.d.ts +147 -0
- package/dist/sdk/voice.d.ts.map +1 -0
- package/dist/sdk/voice.js +236 -0
- package/dist/sdk/voice.js.map +1 -0
- package/package.json +22 -3
- package/scripts/check-skills.mjs +25 -0
- package/skills/agent-builder/SKILL.md +89 -252
- package/skills/evaluations/SKILL.md +23 -234
- package/skills/evaluations/references/analysis.md +95 -0
- package/skills/evaluations/references/cli-reference.md +28 -0
- package/skills/evaluations/references/json-formats.md +100 -0
- package/src/cli/agents.ts +202 -22
- package/src/cli/analytics.ts +138 -0
- package/src/cli/auth.ts +56 -18
- package/src/cli/billing.ts +25 -0
- package/src/cli/campaigns.ts +33 -0
- package/src/cli/chat.ts +66 -115
- package/src/cli/config.ts +65 -31
- package/src/cli/conversations.ts +133 -0
- package/src/cli/distribution.ts +116 -0
- package/src/cli/eval.ts +254 -70
- package/src/cli/functions.ts +122 -36
- package/src/cli/index.ts +58 -55
- package/src/cli/init.ts +154 -0
- package/src/cli/kb.ts +120 -17
- package/src/cli/link.ts +117 -0
- package/src/cli/org.ts +81 -75
- package/src/cli/platform.ts +128 -0
- package/src/cli/tickets.ts +130 -0
- package/src/cli/utils/output.ts +51 -42
- package/src/cli/voice.ts +204 -0
- package/src/core/diff.ts +52 -0
- package/src/core/org-resolver.ts +113 -0
- package/src/core/runtime.ts +73 -0
- package/src/core/scope.ts +64 -0
- package/src/mcp/registry.ts +236 -0
- package/src/mcp/server.ts +84 -2
- package/src/mcp/tool-meta.ts +241 -0
- package/src/mcp/tools.ts +1529 -265
- package/src/sdk/agent-bundle.ts +245 -0
- package/src/sdk/agents.ts +74 -5
- package/src/sdk/analytics.ts +220 -0
- package/src/sdk/auth.ts +87 -107
- package/src/sdk/billing.ts +59 -0
- package/src/sdk/campaigns.ts +60 -0
- package/src/sdk/chat.ts +44 -10
- package/src/sdk/client.ts +373 -102
- package/src/sdk/config-change.ts +148 -0
- package/src/sdk/config.ts +2 -1
- package/src/sdk/conversations.ts +199 -0
- package/src/sdk/credentials.ts +53 -0
- package/src/sdk/distribution.ts +132 -0
- package/src/sdk/eval.ts +140 -0
- package/src/sdk/functions.ts +52 -6
- package/src/sdk/index.ts +2 -0
- package/src/sdk/jarvis-chat.ts +112 -0
- package/src/sdk/kb.ts +116 -29
- package/src/sdk/orgs.ts +62 -0
- package/src/sdk/platform.ts +115 -0
- package/src/sdk/session.ts +90 -0
- package/src/sdk/skills.ts +188 -0
- package/src/sdk/test-chat.ts +151 -0
- package/src/sdk/tickets.ts +120 -0
- package/src/sdk/types.ts +88 -6
- package/src/sdk/voice.ts +262 -0
- package/test/cli/entry.test.ts +34 -0
- package/test/cli/init.test.ts +66 -0
- package/test/cli/link.test.ts +57 -0
- package/test/core/org-resolver.test.ts +92 -0
- package/test/core/runtime.test.ts +30 -0
- package/test/core/scope.test.ts +93 -0
- package/test/harness.test.ts +24 -0
- package/test/helpers/config-home.ts +22 -0
- package/test/helpers/fake-middleware.ts +56 -0
- package/test/helpers/fetch-recorder.ts +75 -0
- package/test/helpers/jwt.ts +9 -0
- package/test/helpers/mcp-pair.ts +38 -0
- package/test/mcp/__snapshots__/tools-snapshot.test.ts.snap +145 -0
- package/test/mcp/askers.test.ts +60 -0
- package/test/mcp/elicit-timeout.test.ts +29 -0
- package/test/mcp/registry.test.ts +169 -0
- package/test/mcp/shaping.test.ts +41 -0
- package/test/mcp/tools-snapshot.test.ts +42 -0
- package/test/sdk/agents.test.ts +232 -0
- package/test/sdk/analytics.test.ts +89 -0
- package/test/sdk/auth.test.ts +70 -0
- package/test/sdk/billing.test.ts +47 -0
- package/test/sdk/campaigns.test.ts +43 -0
- package/test/sdk/client.test.ts +80 -0
- package/test/sdk/config-change.test.ts +142 -0
- package/test/sdk/conversations.test.ts +80 -0
- package/test/sdk/credentials.test.ts +33 -0
- package/test/sdk/distribution.test.ts +55 -0
- package/test/sdk/eval.test.ts +155 -0
- package/test/sdk/kb-upload.test.ts +50 -0
- package/test/sdk/kb.test.ts +95 -0
- package/test/sdk/orgs.test.ts +48 -0
- package/test/sdk/platform.test.ts +89 -0
- package/test/sdk/renewal.test.ts +115 -0
- package/test/sdk/session.test.ts +60 -0
- package/test/sdk/skills.test.ts +235 -0
- package/test/sdk/test-chat.test.ts +112 -0
- package/test/sdk/tickets.test.ts +42 -0
- package/test/sdk/voice.test.ts +147 -0
- package/vitest.config.ts +11 -0
package/dist/cli/index.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { dirname, join, resolve } from 'node:path';
|
|
5
|
-
import { cpSync, mkdirSync, writeFileSync, existsSync } from 'node:fs';
|
|
6
3
|
import { registerAuthCommands } from './auth.js';
|
|
7
4
|
import { registerAgentCommands } from './agents.js';
|
|
8
5
|
import { registerConfigCommands } from './config.js';
|
|
@@ -11,13 +8,26 @@ import { registerKBCommands } from './kb.js';
|
|
|
11
8
|
import { registerEvalCommands } from './eval.js';
|
|
12
9
|
import { registerChatCommand } from './chat.js';
|
|
13
10
|
import { registerOrgCommands } from './org.js';
|
|
14
|
-
import {
|
|
11
|
+
import { registerLinkCommands } from './link.js';
|
|
12
|
+
import { registerConversationCommands } from './conversations.js';
|
|
13
|
+
import { registerVoiceCommands } from './voice.js';
|
|
14
|
+
import { registerDistributionCommands } from './distribution.js';
|
|
15
|
+
import { registerAnalyticsCommands } from './analytics.js';
|
|
16
|
+
import { registerTicketCommands } from './tickets.js';
|
|
17
|
+
import { registerBillingCommands } from './billing.js';
|
|
18
|
+
import { registerCampaignCommands } from './campaigns.js';
|
|
19
|
+
import { registerPlatformCommands } from './platform.js';
|
|
20
|
+
import { registerInitCommand } from './init.js';
|
|
21
|
+
import { askMfaInTerminal, askOrgInTerminal, installBanner } from './utils/output.js';
|
|
22
|
+
import { setAskers, setOrgFlag } from '../core/scope.js';
|
|
23
|
+
import { cliVersion, isNonInteractive } from '../core/runtime.js';
|
|
15
24
|
const program = new Command();
|
|
16
25
|
program
|
|
17
26
|
.name('indemn')
|
|
18
27
|
.description('CLI for managing Indemn AI agents')
|
|
19
|
-
.version(
|
|
20
|
-
program.option('--
|
|
28
|
+
.version(cliVersion());
|
|
29
|
+
program.option('--debug', 'Print every request and response status to stderr');
|
|
30
|
+
program.option('--org <id>', 'Organization to act on (otherwise: linked folder, your only org, or you are asked)');
|
|
21
31
|
program.option('--no-banner', 'Suppress the active-org banner');
|
|
22
32
|
// Commands that already surface org identity themselves — no banner needed.
|
|
23
33
|
const BANNER_SKIP = new Set([
|
|
@@ -26,7 +36,10 @@ const BANNER_SKIP = new Set([
|
|
|
26
36
|
'whoami',
|
|
27
37
|
'init',
|
|
28
38
|
'org list',
|
|
39
|
+
'org current',
|
|
29
40
|
'org switch',
|
|
41
|
+
'link',
|
|
42
|
+
'unlink',
|
|
30
43
|
'mcp serve',
|
|
31
44
|
]);
|
|
32
45
|
function fullCommandName(cmd) {
|
|
@@ -41,8 +54,14 @@ function fullCommandName(cmd) {
|
|
|
41
54
|
// Hook runs before any command action
|
|
42
55
|
program.hook('preAction', async (thisCommand, actionCommand) => {
|
|
43
56
|
const globalOpts = thisCommand.opts();
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
// The environment is fixed by `indemn login --env`; there is no per-command switch.
|
|
58
|
+
if (globalOpts.debug) {
|
|
59
|
+
process.env.INDEMN_DEBUG = '1';
|
|
60
|
+
}
|
|
61
|
+
setOrgFlag(globalOpts.org);
|
|
62
|
+
// Ask in the terminal only when a person can answer; agents and CI get exit code 2 instead.
|
|
63
|
+
if (fullCommandName(actionCommand) !== 'mcp serve' && !isNonInteractive()) {
|
|
64
|
+
setAskers({ chooseOrg: askOrgInTerminal, mfaCode: askMfaInTerminal });
|
|
46
65
|
}
|
|
47
66
|
// Banner suppression: global flag, env var, command opts-out, or JSON output mode.
|
|
48
67
|
if (globalOpts.banner === false)
|
|
@@ -54,17 +73,50 @@ program.hook('preAction', async (thisCommand, actionCommand) => {
|
|
|
54
73
|
return;
|
|
55
74
|
if (BANNER_SKIP.has(fullCommandName(actionCommand)))
|
|
56
75
|
return;
|
|
57
|
-
|
|
76
|
+
installBanner();
|
|
58
77
|
});
|
|
59
78
|
// Register all command groups
|
|
60
79
|
registerAuthCommands(program);
|
|
80
|
+
// Groups other modules extend (org, agents) are registered first.
|
|
81
|
+
registerOrgCommands(program);
|
|
82
|
+
registerLinkCommands(program);
|
|
61
83
|
registerAgentCommands(program);
|
|
62
84
|
registerConfigCommands(program);
|
|
63
85
|
registerFunctionCommands(program);
|
|
64
86
|
registerKBCommands(program);
|
|
65
87
|
registerEvalCommands(program);
|
|
66
88
|
registerChatCommand(program);
|
|
67
|
-
|
|
89
|
+
registerConversationCommands(program);
|
|
90
|
+
registerVoiceCommands(program);
|
|
91
|
+
registerDistributionCommands(program);
|
|
92
|
+
registerAnalyticsCommands(program);
|
|
93
|
+
registerTicketCommands(program);
|
|
94
|
+
registerBillingCommands(program);
|
|
95
|
+
registerCampaignCommands(program);
|
|
96
|
+
registerPlatformCommands(program);
|
|
97
|
+
program
|
|
98
|
+
.command('channels')
|
|
99
|
+
.description('Channels an agent can be published on')
|
|
100
|
+
.command('list')
|
|
101
|
+
.description('List channels')
|
|
102
|
+
.option('--json', 'Output as JSON')
|
|
103
|
+
.action(async (options) => {
|
|
104
|
+
const { IndemnClient } = await import('../sdk/client.js');
|
|
105
|
+
const { OrgsSDK } = await import('../sdk/orgs.js');
|
|
106
|
+
const { formatTable, printJson, printError } = await import('./utils/output.js');
|
|
107
|
+
try {
|
|
108
|
+
const channels = await new OrgsSDK(new IndemnClient()).listChannels();
|
|
109
|
+
if (options.json) {
|
|
110
|
+
printJson(channels);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
console.log(formatTable(['ID', 'Name', 'Type', 'Description'], channels.map((c) => [c._id, c.name, c.type ?? '', c.description ?? ''])));
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
printError(err);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
68
120
|
// MCP serve command
|
|
69
121
|
const mcp = program.command('mcp').description('MCP server commands');
|
|
70
122
|
mcp
|
|
@@ -97,49 +149,6 @@ program
|
|
|
97
149
|
process.exit(1);
|
|
98
150
|
}
|
|
99
151
|
});
|
|
100
|
-
|
|
101
|
-
program
|
|
102
|
-
.command('init')
|
|
103
|
-
.description('Set up Claude Code skills in the current project')
|
|
104
|
-
.option('--force', 'Overwrite existing files')
|
|
105
|
-
.action(async (options) => {
|
|
106
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
107
|
-
const __dirname = dirname(__filename);
|
|
108
|
-
const packageRoot = resolve(__dirname, '..', '..');
|
|
109
|
-
const skillsSource = join(packageRoot, 'skills');
|
|
110
|
-
const cwd = process.cwd();
|
|
111
|
-
const skillsTarget = join(cwd, '.claude', 'skills', 'indemn');
|
|
112
|
-
const rulesTarget = join(cwd, '.claude', 'rules');
|
|
113
|
-
if (existsSync(skillsTarget) && !options.force) {
|
|
114
|
-
console.log('Indemn skills already installed. Use --force to overwrite.');
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
// Copy skills
|
|
118
|
-
mkdirSync(skillsTarget, { recursive: true });
|
|
119
|
-
cpSync(skillsSource, skillsTarget, { recursive: true });
|
|
120
|
-
// Write rules file
|
|
121
|
-
mkdirSync(rulesTarget, { recursive: true });
|
|
122
|
-
const rulesPath = join(rulesTarget, 'indemn.md');
|
|
123
|
-
if (!existsSync(rulesPath) || options.force) {
|
|
124
|
-
writeFileSync(rulesPath, [
|
|
125
|
-
'# Indemn CLI',
|
|
126
|
-
'',
|
|
127
|
-
'The `indemn` CLI is available for managing AI agents. Run `indemn whoami` to verify authentication.',
|
|
128
|
-
'',
|
|
129
|
-
'## Skills',
|
|
130
|
-
'',
|
|
131
|
-
'- **agent-builder** — Create, configure, and test agents (prompts, functions, knowledge bases, chat)',
|
|
132
|
-
'- **evaluations** — Create rubrics and test sets, run evaluations, analyze results, export reports',
|
|
133
|
-
'',
|
|
134
|
-
'Use these skills for any agent management or evaluation task. They contain the complete command reference.',
|
|
135
|
-
'',
|
|
136
|
-
].join('\n'));
|
|
137
|
-
}
|
|
138
|
-
console.log('Indemn CLI integration set up:');
|
|
139
|
-
console.log(` Skills: ${skillsTarget}/`);
|
|
140
|
-
console.log(` Rules: ${rulesPath}`);
|
|
141
|
-
console.log('');
|
|
142
|
-
console.log('Claude Code will now discover the indemn skills automatically.');
|
|
143
|
-
});
|
|
152
|
+
registerInitCommand(program);
|
|
144
153
|
program.parse();
|
|
145
154
|
//# sourceMappingURL=index.js.map
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export declare const MCP_SERVER_ENTRY: {
|
|
3
|
+
command: string;
|
|
4
|
+
args: string[];
|
|
5
|
+
};
|
|
6
|
+
/** Claude Code permission rules: read-only tools run without asking, anything that changes the platform asks every time. */
|
|
7
|
+
export declare function permissionBlock(): {
|
|
8
|
+
allow: string[];
|
|
9
|
+
ask: string[];
|
|
10
|
+
};
|
|
11
|
+
export interface InitReport {
|
|
12
|
+
skills: string;
|
|
13
|
+
rules: string;
|
|
14
|
+
mcp: 'added' | 'kept' | 'skipped';
|
|
15
|
+
permissions: 'added' | 'merged' | 'skipped';
|
|
16
|
+
}
|
|
17
|
+
/** Set up Claude Code in `cwd`. Existing files are merged, never overwritten, unless force is set for skills and rules. */
|
|
18
|
+
export declare function initProject(cwd: string, opts?: {
|
|
19
|
+
force?: boolean;
|
|
20
|
+
mcp?: boolean;
|
|
21
|
+
permissions?: boolean;
|
|
22
|
+
packageRoot?: string;
|
|
23
|
+
}): InitReport;
|
|
24
|
+
/** What is set up in `cwd`, for `indemn init --status`. */
|
|
25
|
+
export declare function initStatus(cwd: string): Array<[string, boolean, string]>;
|
|
26
|
+
export declare function registerInitCommand(program: Command): void;
|
|
27
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,eAAO,MAAM,gBAAgB;;;CAAkE,CAAC;AAEhG,4HAA4H;AAC5H,wBAAgB,eAAe,IAAI;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,CASpE;AA0BD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IAClC,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;CAC7C;AAED,2HAA2H;AAC3H,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,UAAU,CAiD/I;AAED,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAcxE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6B1D"}
|
package/dist/cli/init.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { TOOL_META } from '../mcp/tool-meta.js';
|
|
6
|
+
import { IndemnClient } from '../sdk/client.js';
|
|
7
|
+
import { findLinkFile } from '../core/org-resolver.js';
|
|
8
|
+
import { printError, printSuccess } from './utils/output.js';
|
|
9
|
+
export const MCP_SERVER_ENTRY = { command: 'npx', args: ['-y', '@indemn/cli', 'mcp', 'serve'] };
|
|
10
|
+
/** Claude Code permission rules: read-only tools run without asking, anything that changes the platform asks every time. */
|
|
11
|
+
export function permissionBlock() {
|
|
12
|
+
const allow = [];
|
|
13
|
+
const ask = [];
|
|
14
|
+
for (const [name, meta] of Object.entries(TOOL_META)) {
|
|
15
|
+
const rule = `mcp__indemn__${name}`;
|
|
16
|
+
if (meta.annotations.readOnlyHint && !meta.guard)
|
|
17
|
+
allow.push(rule);
|
|
18
|
+
else
|
|
19
|
+
ask.push(rule);
|
|
20
|
+
}
|
|
21
|
+
return { allow: allow.sort(), ask: ask.sort() };
|
|
22
|
+
}
|
|
23
|
+
function readJson(path) {
|
|
24
|
+
if (!existsSync(path))
|
|
25
|
+
return {};
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
throw new Error(`${path} is not valid JSON; fix it or move it away, then run init again.`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const RULES = `# Indemn CLI
|
|
34
|
+
|
|
35
|
+
The \`indemn\` CLI and its MCP server manage Indemn AI agents. Run \`indemn whoami\` to see the platform (dev or production), the user and which org commands here act on.
|
|
36
|
+
|
|
37
|
+
- Every chat with an agent is a test conversation: never billed, never in analytics, shown with the tester's name.
|
|
38
|
+
- Actions that change or delete something are approved by the user first. When an approval form appears, that form is the question: call the tool and do not ask again in chat. When a tool returns a dry_run instead, show it and pass confirm: true only after the user agreed to that exact change.
|
|
39
|
+
- If a tool returns needs_input (for example which org), ask the user and call again with their answer.
|
|
40
|
+
- Talk in names: call agents, knowledge bases, test sets and runs by their names; show ids only when asked or to tell two items apart. Plain words, short answers, details on request.
|
|
41
|
+
|
|
42
|
+
## Skills
|
|
43
|
+
|
|
44
|
+
- **agent-builder**: create, configure and test agents (prompt, skills, knowledge bases, voice, chat).
|
|
45
|
+
- **evaluations**: rubrics, test sets, runs, CI gates, reports.
|
|
46
|
+
`;
|
|
47
|
+
/** Set up Claude Code in `cwd`. Existing files are merged, never overwritten, unless force is set for skills and rules. */
|
|
48
|
+
export function initProject(cwd, opts = {}) {
|
|
49
|
+
const packageRoot = opts.packageRoot ?? resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
50
|
+
// Claude Code finds project skills at .claude/skills/<name>/SKILL.md, one folder per skill.
|
|
51
|
+
const skillsTarget = join(cwd, '.claude', 'skills');
|
|
52
|
+
for (const skill of readdirSync(join(packageRoot, 'skills'), { withFileTypes: true }).filter((d) => d.isDirectory())) {
|
|
53
|
+
const target = join(skillsTarget, skill.name);
|
|
54
|
+
if (!existsSync(target) || opts.force) {
|
|
55
|
+
mkdirSync(target, { recursive: true });
|
|
56
|
+
cpSync(join(packageRoot, 'skills', skill.name), target, { recursive: true });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const rulesPath = join(cwd, '.claude', 'rules', 'indemn.md');
|
|
60
|
+
if (!existsSync(rulesPath) || opts.force) {
|
|
61
|
+
mkdirSync(dirname(rulesPath), { recursive: true });
|
|
62
|
+
writeFileSync(rulesPath, RULES);
|
|
63
|
+
}
|
|
64
|
+
let mcp = 'skipped';
|
|
65
|
+
if (opts.mcp !== false) {
|
|
66
|
+
const path = join(cwd, '.mcp.json');
|
|
67
|
+
const cfg = readJson(path);
|
|
68
|
+
cfg.mcpServers = cfg.mcpServers ?? {};
|
|
69
|
+
if (cfg.mcpServers.indemn) {
|
|
70
|
+
mcp = 'kept';
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
cfg.mcpServers.indemn = MCP_SERVER_ENTRY;
|
|
74
|
+
writeFileSync(path, JSON.stringify(cfg, null, 2) + '\n');
|
|
75
|
+
mcp = 'added';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
let permissions = 'skipped';
|
|
79
|
+
if (opts.permissions !== false) {
|
|
80
|
+
const path = join(cwd, '.claude', 'settings.json');
|
|
81
|
+
const cfg = readJson(path);
|
|
82
|
+
const had = Boolean(cfg.permissions);
|
|
83
|
+
cfg.permissions = cfg.permissions ?? {};
|
|
84
|
+
const block = permissionBlock();
|
|
85
|
+
const denied = new Set(cfg.permissions.deny ?? []);
|
|
86
|
+
const askSet = new Set([...(cfg.permissions.ask ?? []), ...block.ask]);
|
|
87
|
+
// A tool the user already restricted is never loosened.
|
|
88
|
+
const allowSet = new Set([...(cfg.permissions.allow ?? []), ...block.allow.filter((r) => !askSet.has(r) && !denied.has(r))]);
|
|
89
|
+
cfg.permissions.allow = [...allowSet].sort();
|
|
90
|
+
cfg.permissions.ask = [...askSet].filter((r) => !denied.has(r)).sort();
|
|
91
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
92
|
+
writeFileSync(path, JSON.stringify(cfg, null, 2) + '\n');
|
|
93
|
+
permissions = had ? 'merged' : 'added';
|
|
94
|
+
}
|
|
95
|
+
return { skills: skillsTarget, rules: rulesPath, mcp, permissions };
|
|
96
|
+
}
|
|
97
|
+
/** What is set up in `cwd`, for `indemn init --status`. */
|
|
98
|
+
export function initStatus(cwd) {
|
|
99
|
+
const mcp = readJson(join(cwd, '.mcp.json'));
|
|
100
|
+
const settings = readJson(join(cwd, '.claude', 'settings.json'));
|
|
101
|
+
const login = IndemnClient.loadConfig();
|
|
102
|
+
let link = null;
|
|
103
|
+
try {
|
|
104
|
+
link = findLinkFile(cwd)?.path ?? null;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
link = null;
|
|
108
|
+
}
|
|
109
|
+
return [
|
|
110
|
+
['Skills', existsSync(join(cwd, '.claude', 'skills', 'agent-builder', 'SKILL.md')), '.claude/skills/agent-builder, evaluations'],
|
|
111
|
+
['Rules', existsSync(join(cwd, '.claude', 'rules', 'indemn.md')), '.claude/rules/indemn.md'],
|
|
112
|
+
['MCP server', Boolean(mcp.mcpServers?.indemn), '.mcp.json'],
|
|
113
|
+
['Permissions', (settings.permissions?.ask ?? []).some((r) => r.startsWith('mcp__indemn__')), '.claude/settings.json'],
|
|
114
|
+
['Logged in', Boolean(login), login ? `${login.email ?? login.user_id} on ${login.environment}` : 'run `indemn login`'],
|
|
115
|
+
['Folder linked', Boolean(link), link ?? 'optional: `indemn link --org <id>`'],
|
|
116
|
+
];
|
|
117
|
+
}
|
|
118
|
+
export function registerInitCommand(program) {
|
|
119
|
+
program
|
|
120
|
+
.command('init')
|
|
121
|
+
.description('Set up Claude Code here: skills, rules, the MCP server in .mcp.json, and permissions (reads allowed, changes ask)')
|
|
122
|
+
.option('--force', 'Overwrite the installed skills and rules')
|
|
123
|
+
.option('--no-mcp', 'Do not add the MCP server to .mcp.json')
|
|
124
|
+
.option('--no-permissions', 'Do not add permission rules to .claude/settings.json')
|
|
125
|
+
.option('--status', 'Show what is set up and stop')
|
|
126
|
+
.action((options) => {
|
|
127
|
+
try {
|
|
128
|
+
const cwd = process.cwd();
|
|
129
|
+
if (options.status) {
|
|
130
|
+
for (const [what, ok, detail] of initStatus(cwd))
|
|
131
|
+
console.log(`${ok ? chalk.green('✓') : chalk.yellow('·')} ${what.padEnd(14)} ${chalk.dim(detail)}`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const r = initProject(cwd, { force: options.force, mcp: options.mcp, permissions: options.permissions });
|
|
135
|
+
printSuccess('Indemn CLI set up for Claude Code:');
|
|
136
|
+
console.log(` Skills: ${r.skills}`);
|
|
137
|
+
console.log(` Rules: ${r.rules}`);
|
|
138
|
+
console.log(` MCP server: ${r.mcp === 'added' ? 'added to .mcp.json' : r.mcp === 'kept' ? 'already in .mcp.json (kept)' : 'skipped'}`);
|
|
139
|
+
console.log(` Permissions: ${r.permissions === 'skipped' ? 'skipped' : `${r.permissions} in .claude/settings.json (reads allowed, changes ask)`}`);
|
|
140
|
+
const login = IndemnClient.loadConfig();
|
|
141
|
+
if (!login)
|
|
142
|
+
console.log(chalk.yellow('Next: run `indemn login --env dev` (or production).'));
|
|
143
|
+
else if ((login.orgs?.length ?? 0) > 1 && !findLinkFile(cwd))
|
|
144
|
+
console.log(chalk.dim('Tip: pin this folder to one org with `indemn link --org <id>`.'));
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
printError(err);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/kb.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kb.d.ts","sourceRoot":"","sources":["../../src/cli/kb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"kb.d.ts","sourceRoot":"","sources":["../../src/cli/kb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6gBzD"}
|
package/dist/cli/kb.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { confirmOrExit } from './link.js';
|
|
3
|
+
import { CliError } from '../core/runtime.js';
|
|
4
|
+
import chalk from 'chalk';
|
|
1
5
|
import ora from 'ora';
|
|
2
6
|
import { IndemnClient } from '../sdk/client.js';
|
|
3
7
|
import { KBSDK } from '../sdk/kb.js';
|
|
4
|
-
import { formatTable, printJson, printError, printSuccess
|
|
8
|
+
import { formatTable, printJson, printError, printSuccess } from './utils/output.js';
|
|
5
9
|
export function registerKBCommands(program) {
|
|
6
10
|
const kb = program.command('kb').description('Manage knowledge bases');
|
|
7
11
|
kb.command('list')
|
|
@@ -122,16 +126,22 @@ export function registerKBCommands(program) {
|
|
|
122
126
|
});
|
|
123
127
|
kb.command('delete')
|
|
124
128
|
.argument('<kb-id>', 'Knowledge base ID')
|
|
125
|
-
.
|
|
126
|
-
.
|
|
129
|
+
.option('--dry-run', 'Show what would be deleted and stop')
|
|
130
|
+
.option('--yes', 'Do not ask for confirmation')
|
|
131
|
+
.description('Delete a knowledge base and all its sources (unlink it from agents first)')
|
|
132
|
+
.action(async (kbId, options) => {
|
|
127
133
|
try {
|
|
128
|
-
const confirmed = await confirm(`Delete knowledge base ${kbId}? This cannot be undone.`);
|
|
129
|
-
if (!confirmed) {
|
|
130
|
-
console.log('Cancelled.');
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
134
|
const client = new IndemnClient();
|
|
134
135
|
const sdk = new KBSDK(client);
|
|
136
|
+
const target = await sdk.getKB(kbId);
|
|
137
|
+
const agents = (target.aiAgents ?? []).map((a) => a.name).filter(Boolean);
|
|
138
|
+
console.log(`Would delete "${target.name ?? kbId}" with ${target.totalDataSourceCount ?? '?'} source(s).`);
|
|
139
|
+
if (agents.length) {
|
|
140
|
+
throw new CliError(`It is linked to ${agents.join(', ')}. Unlink it first: indemn kb unlink <agent-id> ${kbId}`);
|
|
141
|
+
}
|
|
142
|
+
if (options.dryRun)
|
|
143
|
+
return;
|
|
144
|
+
await confirmOrExit(`Delete knowledge base "${target.name ?? kbId}"? Its vectors are removed too.`, Boolean(options.yes));
|
|
135
145
|
const spinner = ora('Deleting knowledge base...').start();
|
|
136
146
|
await sdk.deleteKB(kbId);
|
|
137
147
|
spinner.stop();
|
|
@@ -265,13 +275,10 @@ export function registerKBCommands(program) {
|
|
|
265
275
|
.argument('<kb-id>', 'Knowledge base ID')
|
|
266
276
|
.argument('<source-id>', 'Data source ID')
|
|
267
277
|
.description('Delete a data source')
|
|
268
|
-
.
|
|
278
|
+
.option('--yes', 'Do not ask for confirmation')
|
|
279
|
+
.action(async (kbId, sourceId, options) => {
|
|
269
280
|
try {
|
|
270
|
-
|
|
271
|
-
if (!confirmed) {
|
|
272
|
-
console.log('Cancelled.');
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
281
|
+
await confirmOrExit(`Delete data source ${sourceId} from knowledge base ${kbId}? Its vectors are removed too.`, Boolean(options.yes));
|
|
275
282
|
const client = new IndemnClient();
|
|
276
283
|
const sdk = new KBSDK(client);
|
|
277
284
|
const spinner = ora('Deleting data source...').start();
|
|
@@ -284,6 +291,121 @@ export function registerKBCommands(program) {
|
|
|
284
291
|
process.exit(1);
|
|
285
292
|
}
|
|
286
293
|
});
|
|
294
|
+
data.command('chunks')
|
|
295
|
+
.argument('<kb-id>', 'Knowledge base ID')
|
|
296
|
+
.argument('<source-id>', 'Data source ID')
|
|
297
|
+
.option('--json', 'Output as JSON')
|
|
298
|
+
.description('Show the text chunks the agent actually retrieves from a source')
|
|
299
|
+
.action(async (kbId, sourceId, options) => {
|
|
300
|
+
try {
|
|
301
|
+
const res = await new KBSDK(new IndemnClient()).chunks(kbId, sourceId);
|
|
302
|
+
if (options.json) {
|
|
303
|
+
printJson(res);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
console.log(chalk.bold(`${res.source ?? sourceId}`) + chalk.dim(` ${res.status ?? ''} · ${res.chunks.length} chunk(s)`));
|
|
307
|
+
res.chunks.forEach((c, i) => console.log(`${chalk.dim(`#${i + 1}`)} ${c}\n`));
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
printError(err);
|
|
311
|
+
process.exit(1);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
data.command('reimport')
|
|
315
|
+
.argument('<kb-id>', 'Knowledge base ID')
|
|
316
|
+
.argument('<source-id>', 'URL data source ID')
|
|
317
|
+
.option('--js-script <file>', 'Script to run on each page before reading it')
|
|
318
|
+
.option('--yes', 'Do not ask for confirmation')
|
|
319
|
+
.description('Crawl a URL source again after the website changed (runs in the background; see `kb status`)')
|
|
320
|
+
.action(async (kbId, sourceId, options) => {
|
|
321
|
+
try {
|
|
322
|
+
await confirmOrExit(`Re-crawl source ${sourceId}? Its chunks are replaced when the crawl finishes.`, Boolean(options.yes));
|
|
323
|
+
const js = options.jsScript ? readFileSync(options.jsScript, 'utf8') : undefined;
|
|
324
|
+
await new KBSDK(new IndemnClient()).reimport(kbId, sourceId, js);
|
|
325
|
+
printSuccess(`Re-import started. Follow it with: indemn kb status ${kbId}`);
|
|
326
|
+
}
|
|
327
|
+
catch (err) {
|
|
328
|
+
printError(err);
|
|
329
|
+
process.exit(1);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
kb.command('status')
|
|
333
|
+
.argument('<kb-id>', 'Knowledge base ID')
|
|
334
|
+
.option('--json', 'Output as JSON')
|
|
335
|
+
.description('Progress of website crawls and file imports')
|
|
336
|
+
.action(async (kbId, options) => {
|
|
337
|
+
try {
|
|
338
|
+
const rows = await new KBSDK(new IndemnClient()).scrapeStatus(kbId);
|
|
339
|
+
if (options.json) {
|
|
340
|
+
printJson(rows);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (!rows.length) {
|
|
344
|
+
console.log('No website or file sources yet.');
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
console.log(formatTable(['Source', 'Status', 'Job', 'Error'], rows.map((r) => [r.source ?? '', r.status ?? '', r.job_status ?? '', r.error ?? ''])));
|
|
348
|
+
}
|
|
349
|
+
catch (err) {
|
|
350
|
+
printError(err);
|
|
351
|
+
process.exit(1);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
kb.command('gaps')
|
|
355
|
+
.option('--agent <id>', 'Only questions asked to this agent')
|
|
356
|
+
.option('--kb <id>', 'Only questions for this knowledge base')
|
|
357
|
+
.option('--themes', 'Group into themes instead of listing questions')
|
|
358
|
+
.option('--days <n>', 'With --themes: look back this many days')
|
|
359
|
+
.option('--include-test', 'Include questions from test conversations')
|
|
360
|
+
.option('--page <n>', 'Page, starting at 0', '0')
|
|
361
|
+
.option('--limit <n>', 'Rows per page (at most 100)', '20')
|
|
362
|
+
.option('--json', 'Output as JSON')
|
|
363
|
+
.description('Questions the agents could not answer: what to add to the knowledge base next')
|
|
364
|
+
.action(async (options) => {
|
|
365
|
+
try {
|
|
366
|
+
const sdk = new KBSDK(new IndemnClient());
|
|
367
|
+
if (options.themes) {
|
|
368
|
+
printJson(await sdk.gapClusters({ days: options.days ? Number(options.days) : undefined, page: Number(options.page), limit: Number(options.limit) }));
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const res = await sdk.gaps({ agentId: options.agent, kbId: options.kb, includeTest: options.includeTest, page: Number(options.page), limit: Number(options.limit) });
|
|
372
|
+
if (options.json) {
|
|
373
|
+
printJson(res);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
const rows = res.responses ?? [];
|
|
377
|
+
if (!rows.length) {
|
|
378
|
+
console.log('No unanswered questions.');
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
console.log(formatTable(['Question', 'Status', 'Channel'], rows.map((r) => [String(r.user_query ?? '').slice(0, 80), String(r.status ?? ''), String(r.channel ?? '')])));
|
|
382
|
+
console.log(chalk.dim(`${res.total ?? rows.length} in total.`));
|
|
383
|
+
}
|
|
384
|
+
catch (err) {
|
|
385
|
+
printError(err);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
kb.command('check')
|
|
390
|
+
.argument('<question>', 'A question a customer might ask')
|
|
391
|
+
.option('--json', 'Output as JSON')
|
|
392
|
+
.description('Could the org\'s knowledge answer this? Shows the best matching chunks')
|
|
393
|
+
.action(async (question, options) => {
|
|
394
|
+
try {
|
|
395
|
+
const res = await new KBSDK(new IndemnClient()).check(question);
|
|
396
|
+
if (options.json) {
|
|
397
|
+
printJson(res);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
console.log(res.answerable ? chalk.green(`Answerable (score ${res.top_score})`) : chalk.yellow(`Not answerable (best score ${res.top_score ?? 0})`));
|
|
401
|
+
for (const src of (res.sources ?? []).slice(0, 3))
|
|
402
|
+
console.log(chalk.dim(`- (${src.score}) ${String(src.text ?? '').slice(0, 200)}`));
|
|
403
|
+
}
|
|
404
|
+
catch (err) {
|
|
405
|
+
printError(err);
|
|
406
|
+
process.exit(1);
|
|
407
|
+
}
|
|
408
|
+
});
|
|
287
409
|
// Link/unlink commands
|
|
288
410
|
kb.command('link')
|
|
289
411
|
.argument('<agent-id>', 'Agent ID')
|
|
@@ -307,8 +429,10 @@ export function registerKBCommands(program) {
|
|
|
307
429
|
.argument('<agent-id>', 'Agent ID')
|
|
308
430
|
.argument('<kb-id>', 'Knowledge base ID')
|
|
309
431
|
.description('Unlink a knowledge base from an agent')
|
|
310
|
-
.
|
|
432
|
+
.option('--yes', 'Do not ask for confirmation')
|
|
433
|
+
.action(async (agentId, kbId, options) => {
|
|
311
434
|
try {
|
|
435
|
+
await confirmOrExit(`Unlink knowledge base ${kbId} from agent ${agentId}? The agent stops using it immediately.`, Boolean(options.yes));
|
|
312
436
|
const client = new IndemnClient();
|
|
313
437
|
const sdk = new KBSDK(client);
|
|
314
438
|
const spinner = ora('Unlinking knowledge base...').start();
|
|
@@ -343,8 +467,10 @@ export function registerKBCommands(program) {
|
|
|
343
467
|
.argument('<kb-id>', 'Knowledge base ID')
|
|
344
468
|
.description('Import QNA pairs from a JSON file into a knowledge base')
|
|
345
469
|
.requiredOption('--file <path>', 'Path to JSON file with array of {question, answer} pairs')
|
|
470
|
+
.option('--yes', 'Do not ask for confirmation')
|
|
346
471
|
.action(async (kbId, options) => {
|
|
347
472
|
try {
|
|
473
|
+
await confirmOrExit(`Import into knowledge base ${kbId}? The agent starts answering from the new content once processed.`, Boolean(options.yes));
|
|
348
474
|
const fs = await import('fs');
|
|
349
475
|
const filePath = options.file;
|
|
350
476
|
if (!fs.existsSync(filePath)) {
|