@stigmer/cli 3.4.0 → 3.4.1
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/commands/setup.d.ts.map +1 -1
- package/commands/setup.js +11 -16
- package/commands/setup.js.map +1 -1
- package/local/daemon/components.d.ts.map +1 -1
- package/local/daemon/components.js +3 -2
- package/local/daemon/components.js.map +1 -1
- package/local/daemon/env.d.ts +0 -3
- package/local/daemon/env.d.ts.map +1 -1
- package/local/daemon/env.js +4 -8
- package/local/daemon/env.js.map +1 -1
- package/local/daemon/launch.d.ts.map +1 -1
- package/local/daemon/launch.js +9 -17
- package/local/daemon/launch.js.map +1 -1
- package/local/llm-config.d.ts +7 -7
- package/local/llm-config.d.ts.map +1 -1
- package/local/llm-config.js +29 -42
- package/local/llm-config.js.map +1 -1
- package/local/setup/wizard.d.ts +16 -7
- package/local/setup/wizard.d.ts.map +1 -1
- package/local/setup/wizard.js +41 -44
- package/local/setup/wizard.js.map +1 -1
- package/local/status.d.ts.map +1 -1
- package/local/status.js +16 -15
- package/local/status.js.map +1 -1
- package/package.json +5 -5
- package/resources/list.d.ts.map +1 -1
- package/resources/list.js +70 -4
- package/resources/list.js.map +1 -1
- package/src/commands/setup.ts +13 -20
- package/src/local/daemon/components.test.ts +8 -2
- package/src/local/daemon/components.ts +3 -1
- package/src/local/daemon/env.test.ts +13 -6
- package/src/local/daemon/env.ts +10 -13
- package/src/local/daemon/launch.ts +9 -17
- package/src/local/llm-config.test.ts +16 -27
- package/src/local/llm-config.ts +27 -41
- package/src/local/setup/wizard.test.ts +19 -11
- package/src/local/setup/wizard.ts +42 -47
- package/src/local/status.test.ts +20 -0
- package/src/local/status.ts +17 -15
- package/src/resources/list.ts +76 -4
- package/src/resources/read-verbs.integration.test.ts +127 -3
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
// to the right CLI exit code via classify().
|
|
8
8
|
|
|
9
9
|
import { create, toJson } from "@bufbuild/protobuf";
|
|
10
|
+
import { timestampFromDate } from "@bufbuild/protobuf/wkt";
|
|
10
11
|
import { Code, ConnectError, type ConnectRouter } from "@connectrpc/connect";
|
|
11
12
|
import { connectNodeAdapter } from "@connectrpc/connect-node";
|
|
12
13
|
import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
13
14
|
import { AgentQueryController } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/query_pb";
|
|
14
15
|
import { AgentChannelSchema } from "@stigmer/protos/ai/stigmer/agentic/agentchannel/v1/api_pb";
|
|
15
16
|
import { AgentChannelQueryController } from "@stigmer/protos/ai/stigmer/agentic/agentchannel/v1/query_pb";
|
|
17
|
+
import { AgentChannelInstallState } from "@stigmer/protos/ai/stigmer/agentic/agentchannel/v1/status_pb";
|
|
16
18
|
import { AgentInstanceSchema } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/api_pb";
|
|
17
19
|
import { AgentInstanceQueryController } from "@stigmer/protos/ai/stigmer/agentic/agentinstance/v1/query_pb";
|
|
18
20
|
import { ChannelAppSchema } from "@stigmer/protos/ai/stigmer/agentic/channelapp/v1/api_pb";
|
|
@@ -73,24 +75,71 @@ const knownSearchResult = create(SearchResultSchema, {
|
|
|
73
75
|
description: "reviews code",
|
|
74
76
|
});
|
|
75
77
|
|
|
76
|
-
// The three T07 cutover kinds — wired into get-bindings
|
|
78
|
+
// The three T07 cutover kinds — wired into get-bindings and list alongside
|
|
79
|
+
// this test. environment lists via the SearchService (it is search-indexed);
|
|
80
|
+
// the two channel kinds list via their dedicated query RPCs.
|
|
77
81
|
const knownEnvironment = create(EnvironmentSchema, {
|
|
78
82
|
apiVersion: "agentic.stigmer.ai/v1",
|
|
79
83
|
kind: "Environment",
|
|
80
84
|
metadata: { name: "clinic-patient-db", slug: "clinic-patient-db", org: "acme", id: "env_1" },
|
|
81
85
|
});
|
|
82
86
|
|
|
87
|
+
const knownEnvironmentSearchResult = create(SearchResultSchema, {
|
|
88
|
+
kind: ApiResourceKind.environment,
|
|
89
|
+
id: "env_1",
|
|
90
|
+
name: "clinic-patient-db",
|
|
91
|
+
slug: "clinic-patient-db",
|
|
92
|
+
qualifiedSlug: "acme/clinic-patient-db",
|
|
93
|
+
org: "acme",
|
|
94
|
+
description: "clinic patient database credentials",
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Spec/status populated to exercise every AGENT_CHANNEL_TABLE column:
|
|
98
|
+
// agent_ref, the provider oneof, install_state, and enabled.
|
|
83
99
|
const knownChannel = create(AgentChannelSchema, {
|
|
84
100
|
apiVersion: "agentic.stigmer.ai/v1",
|
|
85
101
|
kind: "AgentChannel",
|
|
86
102
|
metadata: { name: "clinic-patient-whatsapp", slug: "clinic-patient-whatsapp", org: "acme", id: "ach_1" },
|
|
87
|
-
spec: {
|
|
103
|
+
spec: {
|
|
104
|
+
enabled: true,
|
|
105
|
+
agentRef: { kind: ApiResourceKind.agent, org: "acme", slug: "clinic-assistant" },
|
|
106
|
+
providerConfig: { case: "whatsapp", value: { phoneNumberId: "106540352242922" } },
|
|
107
|
+
},
|
|
108
|
+
status: { installState: AgentChannelInstallState.installed },
|
|
88
109
|
});
|
|
89
110
|
|
|
111
|
+
// Secret fields carry the redaction marker, matching what the server's
|
|
112
|
+
// RedactChannelApp pipeline returns on every list/get response.
|
|
90
113
|
const knownChannelApp = create(ChannelAppSchema, {
|
|
91
114
|
apiVersion: "agentic.stigmer.ai/v1",
|
|
92
115
|
kind: "ChannelApp",
|
|
93
116
|
metadata: { name: "clinic-meta-app", slug: "clinic-meta-app", org: "acme", id: "chapp_1" },
|
|
117
|
+
spec: {
|
|
118
|
+
providerConfig: {
|
|
119
|
+
case: "whatsapp",
|
|
120
|
+
value: {
|
|
121
|
+
appId: "108954",
|
|
122
|
+
appSecret: "***REDACTED***",
|
|
123
|
+
accessToken: "***REDACTED***",
|
|
124
|
+
verifyToken: "***REDACTED***",
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
status: { audit: { specAudit: { createdAt: timestampFromDate(new Date("2026-07-20T10:00:00Z")) } } },
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Second entry (slack arm) so the list tests cover both provider derivations
|
|
132
|
+
// and the client-side --limit slice (listByOrg has no pagination).
|
|
133
|
+
const secondChannelApp = create(ChannelAppSchema, {
|
|
134
|
+
apiVersion: "agentic.stigmer.ai/v1",
|
|
135
|
+
kind: "ChannelApp",
|
|
136
|
+
metadata: { name: "clinic-slack-app", slug: "clinic-slack-app", org: "acme", id: "chapp_2" },
|
|
137
|
+
spec: {
|
|
138
|
+
providerConfig: {
|
|
139
|
+
case: "slack",
|
|
140
|
+
value: { clientId: "12.34", clientSecret: "***REDACTED***", signingSecret: "***REDACTED***" },
|
|
141
|
+
},
|
|
142
|
+
},
|
|
94
143
|
});
|
|
95
144
|
|
|
96
145
|
let backend: Http2Server;
|
|
@@ -124,7 +173,14 @@ beforeAll(async () => {
|
|
|
124
173
|
},
|
|
125
174
|
});
|
|
126
175
|
router.service(SearchService, {
|
|
127
|
-
|
|
176
|
+
// Kind-aware: search-backed list sends a single-kind query, so the
|
|
177
|
+
// environment arm proves the kind actually rode the request.
|
|
178
|
+
search: (req) => {
|
|
179
|
+
if (req.kinds.length === 1 && req.kinds[0] === ApiResourceKind.environment) {
|
|
180
|
+
return { entries: [knownEnvironmentSearchResult], totalCount: 1, totalPages: 1 };
|
|
181
|
+
}
|
|
182
|
+
return { entries: [knownSearchResult], totalCount: 1, totalPages: 1 };
|
|
183
|
+
},
|
|
128
184
|
});
|
|
129
185
|
router.service(OrganizationQueryController, {
|
|
130
186
|
findMyOrganizations: () => ({ entries: [knownOrg] }),
|
|
@@ -151,6 +207,10 @@ beforeAll(async () => {
|
|
|
151
207
|
if (req.slug !== "clinic-patient-whatsapp") throw new ConnectError("agent channel not found", Code.NotFound);
|
|
152
208
|
return knownChannel;
|
|
153
209
|
},
|
|
210
|
+
list: (req) => {
|
|
211
|
+
if (req.org !== "acme") throw new ConnectError("org is required", Code.InvalidArgument);
|
|
212
|
+
return { totalCount: 1, items: [knownChannel] };
|
|
213
|
+
},
|
|
154
214
|
});
|
|
155
215
|
router.service(ChannelAppQueryController, {
|
|
156
216
|
get: (req) => {
|
|
@@ -161,6 +221,10 @@ beforeAll(async () => {
|
|
|
161
221
|
if (req.slug !== "clinic-meta-app") throw new ConnectError("channel app not found", Code.NotFound);
|
|
162
222
|
return knownChannelApp;
|
|
163
223
|
},
|
|
224
|
+
listByOrg: (req) => {
|
|
225
|
+
if (req.org !== "acme") throw new ConnectError("org is required", Code.InvalidArgument);
|
|
226
|
+
return { entries: [knownChannelApp, secondChannelApp] };
|
|
227
|
+
},
|
|
164
228
|
});
|
|
165
229
|
};
|
|
166
230
|
backend = createHttp2Server(connectNodeAdapter({ routes }));
|
|
@@ -324,4 +388,64 @@ describe("list integration", () => {
|
|
|
324
388
|
expect(out).toContain("reviewer-default");
|
|
325
389
|
expect(out).toContain("agt_1");
|
|
326
390
|
});
|
|
391
|
+
|
|
392
|
+
it("lists environments via the search service as JSON", async () => {
|
|
393
|
+
const out = await listResources(client, ApiResourceKind.environment, "acme", 50, "json");
|
|
394
|
+
expect(JSON.parse(out)).toEqual([
|
|
395
|
+
toJson(SearchResultSchema, knownEnvironmentSearchResult, { useProtoFieldName: true }),
|
|
396
|
+
]);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it("renders a human table for environment lists", async () => {
|
|
400
|
+
const out = await listResources(client, ApiResourceKind.environment, "acme", 50, "table");
|
|
401
|
+
expect(out).toContain("NAME");
|
|
402
|
+
expect(out).toContain("acme/clinic-patient-db");
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
it("lists agent channels via the dedicated list RPC as JSON", async () => {
|
|
406
|
+
const out = await listResources(client, ApiResourceKind.agent_channel, "acme", 50, "json");
|
|
407
|
+
expect(JSON.parse(out)).toEqual([toJson(AgentChannelSchema, knownChannel, { useProtoFieldName: true })]);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it("renders a human table for agent channels with the serving signals", async () => {
|
|
411
|
+
const out = await listResources(client, ApiResourceKind.agent_channel, "acme", 50, "table");
|
|
412
|
+
expect(out).toContain("PROVIDER");
|
|
413
|
+
expect(out).toContain("STATE");
|
|
414
|
+
expect(out).toContain("ENABLED");
|
|
415
|
+
expect(out).toContain("acme/clinic-assistant"); // agent_ref as org/slug
|
|
416
|
+
expect(out).toContain("whatsapp"); // derived from the provider oneof
|
|
417
|
+
expect(out).toContain("installed"); // status.install_state
|
|
418
|
+
expect(out).toContain("true"); // spec.enabled
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it("lists channel apps via listByOrg as JSON", async () => {
|
|
422
|
+
const out = await listResources(client, ApiResourceKind.channel_app, "acme", 50, "json");
|
|
423
|
+
expect(JSON.parse(out)).toEqual([
|
|
424
|
+
toJson(ChannelAppSchema, knownChannelApp, { useProtoFieldName: true }),
|
|
425
|
+
toJson(ChannelAppSchema, secondChannelApp, { useProtoFieldName: true }),
|
|
426
|
+
]);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it("renders a human table for channel apps with provider and created date", async () => {
|
|
430
|
+
const out = await listResources(client, ApiResourceKind.channel_app, "acme", 50, "table");
|
|
431
|
+
expect(out).toContain("PROVIDER");
|
|
432
|
+
expect(out).toContain("whatsapp");
|
|
433
|
+
expect(out).toContain("slack");
|
|
434
|
+
expect(out).toContain("2026-07-20"); // status.audit.spec_audit.created_at
|
|
435
|
+
// Secrets never reach the table (redaction markers stay in json/yaml only).
|
|
436
|
+
expect(out).not.toContain("***REDACTED***");
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
it("applies --limit client-side for channel apps (listByOrg has no pagination)", async () => {
|
|
440
|
+
const out = await listResources(client, ApiResourceKind.channel_app, "acme", 1, "json");
|
|
441
|
+
expect(JSON.parse(out)).toEqual([toJson(ChannelAppSchema, knownChannelApp, { useProtoFieldName: true })]);
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
it("rejects a kind whose list is unwired with a usage error", async () => {
|
|
445
|
+
// agent_share declares List in the registry but has no list branch —
|
|
446
|
+
// the canonical still-unwired list kind (the three cutover kinds and
|
|
447
|
+
// environment gained branches).
|
|
448
|
+
const err = await listResources(client, ApiResourceKind.agent_share, "acme", 50, "json").catch((e) => e);
|
|
449
|
+
expect(classify(err)?.exitCode).toBe(ExitCode.Usage);
|
|
450
|
+
});
|
|
327
451
|
});
|