@stigmer/react 3.4.0 → 3.5.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/agent/AgentDetailView.d.ts +14 -4
- package/agent/AgentDetailView.d.ts.map +1 -1
- package/agent/AgentDetailView.js +73 -11
- package/agent/AgentDetailView.js.map +1 -1
- package/agent/internal/agentToInput.d.ts +3 -0
- package/agent/internal/agentToInput.d.ts.map +1 -1
- package/agent/internal/agentToInput.js +21 -1
- package/agent/internal/agentToInput.js.map +1 -1
- package/agent/useAgentCount.d.ts +2 -0
- package/agent/useAgentCount.d.ts.map +1 -1
- package/agent/useAgentCount.js.map +1 -1
- package/api-key/ApiKeyListPanel.d.ts +8 -1
- package/api-key/ApiKeyListPanel.d.ts.map +1 -1
- package/api-key/ApiKeyListPanel.js +9 -7
- package/api-key/ApiKeyListPanel.js.map +1 -1
- package/api-key/CreateApiKeyForm.d.ts +7 -1
- package/api-key/CreateApiKeyForm.d.ts.map +1 -1
- package/api-key/CreateApiKeyForm.js +2 -2
- package/api-key/CreateApiKeyForm.js.map +1 -1
- package/datastore/useDatastoreCount.d.ts +2 -0
- package/datastore/useDatastoreCount.d.ts.map +1 -1
- package/datastore/useDatastoreCount.js.map +1 -1
- package/dependency-graph/DependencyTreeNode.d.ts.map +1 -1
- package/dependency-graph/DependencyTreeNode.js +8 -0
- package/dependency-graph/DependencyTreeNode.js.map +1 -1
- package/dependency-graph/types.d.ts +20 -8
- package/dependency-graph/types.d.ts.map +1 -1
- package/dependency-graph/useDependencyGraph.d.ts.map +1 -1
- package/dependency-graph/useDependencyGraph.js +21 -1
- package/dependency-graph/useDependencyGraph.js.map +1 -1
- package/index.d.ts +6 -4
- package/index.d.ts.map +1 -1
- package/index.js +6 -2
- package/index.js.map +1 -1
- package/internal/scroll-area.d.ts +4 -0
- package/internal/scroll-area.d.ts.map +1 -0
- package/internal/scroll-area.js +15 -0
- package/internal/scroll-area.js.map +1 -0
- package/internal/tooltip.d.ts +7 -0
- package/internal/tooltip.d.ts.map +1 -0
- package/internal/tooltip.js +31 -0
- package/internal/tooltip.js.map +1 -0
- package/manifest/ApplyManifestDialog.d.ts +10 -5
- package/manifest/ApplyManifestDialog.d.ts.map +1 -1
- package/manifest/ApplyManifestDialog.js +30 -13
- package/manifest/ApplyManifestDialog.js.map +1 -1
- package/manifest/useApplyManifest.d.ts +6 -2
- package/manifest/useApplyManifest.d.ts.map +1 -1
- package/manifest/useApplyManifest.js +5 -5
- package/manifest/useApplyManifest.js.map +1 -1
- package/mcp-server/McpServerDetailView.d.ts +38 -2
- package/mcp-server/McpServerDetailView.d.ts.map +1 -1
- package/mcp-server/McpServerDetailView.js +21 -5
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/mcp-server/StdioSandboxNotice.d.ts +12 -11
- package/mcp-server/StdioSandboxNotice.d.ts.map +1 -1
- package/mcp-server/StdioSandboxNotice.js +13 -12
- package/mcp-server/StdioSandboxNotice.js.map +1 -1
- package/mcp-server/index.d.ts +7 -0
- package/mcp-server/index.d.ts.map +1 -1
- package/mcp-server/index.js +9 -0
- package/mcp-server/index.js.map +1 -1
- package/mcp-server/steps/EnvironmentAuthStep.d.ts +4 -0
- package/mcp-server/steps/EnvironmentAuthStep.d.ts.map +1 -1
- package/mcp-server/steps/EnvironmentAuthStep.js +4 -0
- package/mcp-server/steps/EnvironmentAuthStep.js.map +1 -1
- package/mcp-server/steps/IdentityTransportStep.d.ts +6 -0
- package/mcp-server/steps/IdentityTransportStep.d.ts.map +1 -1
- package/mcp-server/steps/IdentityTransportStep.js +7 -1
- package/mcp-server/steps/IdentityTransportStep.js.map +1 -1
- package/mcp-server/steps/ReviewStep.d.ts +5 -0
- package/mcp-server/steps/ReviewStep.d.ts.map +1 -1
- package/mcp-server/steps/ReviewStep.js +16 -2
- package/mcp-server/steps/ReviewStep.js.map +1 -1
- package/mcp-server/useMcpServerCount.d.ts +2 -0
- package/mcp-server/useMcpServerCount.d.ts.map +1 -1
- package/mcp-server/useMcpServerCount.js.map +1 -1
- package/package.json +4 -4
- package/resource-creation/CreationPicker.d.ts.map +1 -1
- package/resource-creation/CreationPicker.js +3 -3
- package/resource-creation/CreationPicker.js.map +1 -1
- package/resource-creation/WizardNav.d.ts.map +1 -1
- package/resource-creation/WizardNav.js +1 -1
- package/resource-creation/WizardNav.js.map +1 -1
- package/resource-creation/templates/mcp-server-templates.d.ts.map +1 -1
- package/resource-creation/templates/mcp-server-templates.js +17 -14
- package/resource-creation/templates/mcp-server-templates.js.map +1 -1
- package/resource-detail/Section.d.ts +8 -1
- package/resource-detail/Section.d.ts.map +1 -1
- package/resource-detail/Section.js +2 -2
- package/resource-detail/Section.js.map +1 -1
- package/resource-workbench/components/ResourceWorkbench.d.ts +9 -1
- package/resource-workbench/components/ResourceWorkbench.d.ts.map +1 -1
- package/resource-workbench/components/ResourceWorkbench.js +2 -1
- package/resource-workbench/components/ResourceWorkbench.js.map +1 -1
- package/resource-workbench/hooks/useResourceCollection.d.ts +9 -0
- package/resource-workbench/hooks/useResourceCollection.d.ts.map +1 -1
- package/resource-workbench/hooks/useResourceCollection.js +2 -2
- package/resource-workbench/hooks/useResourceCollection.js.map +1 -1
- package/search/useResourceCount.d.ts +7 -0
- package/search/useResourceCount.d.ts.map +1 -1
- package/search/useResourceCount.js +2 -1
- package/search/useResourceCount.js.map +1 -1
- package/session/NewSessionViewer.d.ts.map +1 -1
- package/session/NewSessionViewer.js +17 -3
- package/session/NewSessionViewer.js.map +1 -1
- package/session/SessionViewer.d.ts +2 -1
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +19 -11
- package/session/SessionViewer.js.map +1 -1
- package/session/SessionViewerLayout.d.ts +90 -0
- package/session/SessionViewerLayout.d.ts.map +1 -0
- package/session/SessionViewerLayout.js +32 -0
- package/session/SessionViewerLayout.js.map +1 -0
- package/session/index.d.ts +4 -0
- package/session/index.d.ts.map +1 -1
- package/session/index.js +10 -0
- package/session/index.js.map +1 -1
- package/session/useSessionRailViews.d.ts +2 -2
- package/sidebar/SettingsSidebar.d.ts +62 -0
- package/sidebar/SettingsSidebar.d.ts.map +1 -0
- package/sidebar/SettingsSidebar.js +60 -0
- package/sidebar/SettingsSidebar.js.map +1 -0
- package/sidebar/WorkspaceSidebar.d.ts +87 -0
- package/sidebar/WorkspaceSidebar.d.ts.map +1 -0
- package/sidebar/WorkspaceSidebar.js +95 -0
- package/sidebar/WorkspaceSidebar.js.map +1 -0
- package/sidebar/chrome.d.ts +48 -0
- package/sidebar/chrome.d.ts.map +1 -0
- package/sidebar/chrome.js +32 -0
- package/sidebar/chrome.js.map +1 -0
- package/sidebar/index.d.ts +6 -0
- package/sidebar/index.d.ts.map +1 -0
- package/sidebar/index.js +9 -0
- package/sidebar/index.js.map +1 -0
- package/sidebar/types.d.ts +54 -0
- package/sidebar/types.d.ts.map +1 -0
- package/sidebar/types.js +2 -0
- package/sidebar/types.js.map +1 -0
- package/skill/useSkillCount.d.ts +2 -0
- package/skill/useSkillCount.d.ts.map +1 -1
- package/skill/useSkillCount.js.map +1 -1
- package/src/agent/AgentDetailView.tsx +198 -11
- package/src/agent/__tests__/AgentDetailView.datastores.test.tsx +166 -0
- package/src/agent/internal/__tests__/agentToInput.test.ts +154 -0
- package/src/agent/internal/agentToInput.ts +25 -7
- package/src/agent/useAgentCount.ts +2 -0
- package/src/api-key/ApiKeyListPanel.tsx +17 -4
- package/src/api-key/CreateApiKeyForm.tsx +8 -1
- package/src/api-key/__tests__/CreateApiKeyForm.test.tsx +58 -0
- package/src/datastore/useDatastoreCount.ts +2 -0
- package/src/dependency-graph/DependencyTreeNode.tsx +8 -0
- package/src/dependency-graph/__tests__/useDependencyGraph.test.ts +108 -0
- package/src/dependency-graph/types.ts +20 -8
- package/src/dependency-graph/useDependencyGraph.ts +23 -1
- package/src/index.ts +24 -0
- package/src/internal/scroll-area.tsx +37 -0
- package/src/internal/tooltip.tsx +66 -0
- package/src/manifest/ApplyManifestDialog.tsx +40 -16
- package/src/manifest/__tests__/ApplyManifestDialog.test.tsx +147 -0
- package/src/manifest/__tests__/useApplyManifest.test.tsx +6 -6
- package/src/manifest/useApplyManifest.ts +12 -8
- package/src/mcp-server/McpServerDetailView.tsx +52 -4
- package/src/mcp-server/StdioSandboxNotice.tsx +16 -14
- package/src/mcp-server/__tests__/McpServerDetailView.test.tsx +345 -0
- package/src/mcp-server/__tests__/StdioSandboxNotice.test.tsx +3 -2
- package/src/mcp-server/index.ts +13 -0
- package/src/mcp-server/steps/EnvironmentAuthStep.tsx +4 -0
- package/src/mcp-server/steps/IdentityTransportStep.tsx +16 -1
- package/src/mcp-server/steps/ReviewStep.tsx +18 -1
- package/src/mcp-server/useMcpServerCount.ts +2 -0
- package/src/resource-creation/CreationPicker.tsx +7 -0
- package/src/resource-creation/WizardNav.tsx +1 -0
- package/src/resource-creation/templates/mcp-server-templates.ts +17 -14
- package/src/resource-detail/Section.tsx +9 -1
- package/src/resource-workbench/components/ResourceWorkbench.tsx +13 -0
- package/src/resource-workbench/hooks/useResourceCollection.ts +11 -1
- package/src/search/useResourceCount.ts +9 -1
- package/src/session/NewSessionViewer.tsx +48 -61
- package/src/session/SessionViewer.tsx +71 -86
- package/src/session/SessionViewerLayout.tsx +131 -0
- package/src/session/__tests__/SessionViewerLayout.test.tsx +140 -0
- package/src/session/index.ts +14 -0
- package/src/session/useSessionRailViews.tsx +2 -2
- package/src/sidebar/SettingsSidebar.tsx +173 -0
- package/src/sidebar/WorkspaceSidebar.tsx +386 -0
- package/src/sidebar/__tests__/SettingsSidebar.test.tsx +107 -0
- package/src/sidebar/__tests__/WorkspaceSidebar.test.tsx +236 -0
- package/src/sidebar/chrome.tsx +129 -0
- package/src/sidebar/index.ts +16 -0
- package/src/sidebar/types.ts +55 -0
- package/src/skill/useSkillCount.ts +2 -0
- package/src/test/__tests__/samples.test.ts +161 -2
- package/src/test/index.ts +1 -1
- package/src/test/samples.ts +157 -14
- package/src/workflow/useWorkflowCount.ts +2 -0
- package/styles.css +1 -1
- package/test/index.d.ts +1 -1
- package/test/index.d.ts.map +1 -1
- package/test/index.js +1 -1
- package/test/index.js.map +1 -1
- package/test/samples.d.ts +100 -7
- package/test/samples.d.ts.map +1 -1
- package/test/samples.js +133 -14
- package/test/samples.js.map +1 -1
- package/workflow/useWorkflowCount.d.ts +2 -0
- package/workflow/useWorkflowCount.d.ts.map +1 -1
- package/workflow/useWorkflowCount.js.map +1 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
1
|
+
import { describe, it, expect, afterEach, vi } from "vitest";
|
|
2
|
+
import { timestampDate } from "@bufbuild/protobuf/wkt";
|
|
2
3
|
import { ExecutionPhase, MessageType, ToolCallStatus, ExecutionArtifactKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
3
4
|
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
4
|
-
import {
|
|
5
|
+
import { formatDuration } from "../../execution/ToolCallDetail";
|
|
6
|
+
import { samples, SAMPLE_INSTANT, sampleInstant, sampleDate } from "../samples";
|
|
5
7
|
|
|
6
8
|
describe("samples", () => {
|
|
7
9
|
describe("session", () => {
|
|
@@ -169,3 +171,160 @@ describe("samples", () => {
|
|
|
169
171
|
});
|
|
170
172
|
});
|
|
171
173
|
});
|
|
174
|
+
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
// Determinism — the reason these factories exist. A `samples.*` value is
|
|
177
|
+
// rendered into Scenar tours that replay in the browser and export to video
|
|
178
|
+
// frame by frame, so any live-clock read paints a pixel that changes between
|
|
179
|
+
// runs (scenar-cloud DD-006). These tests are the regression lock: each one
|
|
180
|
+
// FAILS if a factory is reverted to reading the clock.
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
|
|
183
|
+
describe("samples determinism", () => {
|
|
184
|
+
afterEach(() => {
|
|
185
|
+
vi.useRealTimers();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// A zero-arg call for every factory, with representative arguments. The
|
|
189
|
+
// completeness test below asserts this map covers `samples` exactly, so a
|
|
190
|
+
// newly-added factory that reads the clock cannot slip past the stability
|
|
191
|
+
// sweep unnoticed.
|
|
192
|
+
const invoke: Record<keyof typeof samples, () => unknown> = {
|
|
193
|
+
session: () => samples.session(),
|
|
194
|
+
agent: () => samples.agent(),
|
|
195
|
+
agentExecution: () => samples.agentExecution(),
|
|
196
|
+
skill: () => samples.skill(),
|
|
197
|
+
mcpServer: () => samples.mcpServer(),
|
|
198
|
+
environment: () => samples.environment(),
|
|
199
|
+
agentInstance: () => samples.agentInstance(),
|
|
200
|
+
apiKey: () => samples.apiKey(),
|
|
201
|
+
organization: () => samples.organization(),
|
|
202
|
+
organizationList: () => samples.organizationList(),
|
|
203
|
+
humanMessage: () => samples.humanMessage("hello"),
|
|
204
|
+
aiMessage: () => samples.aiMessage("hi"),
|
|
205
|
+
toolCall: () => samples.toolCall("lookup_order", '{"orderId":"123"}'),
|
|
206
|
+
artifact: () => samples.artifact("report.md"),
|
|
207
|
+
sessionList: () => samples.sessionList(),
|
|
208
|
+
agentExecutionList: () => samples.agentExecutionList(),
|
|
209
|
+
searchResponse: () => samples.searchResponse(),
|
|
210
|
+
apiKeyList: () => samples.apiKeyList(),
|
|
211
|
+
searchResult: () => samples.searchResult(),
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
it("the stability sweep covers every factory", () => {
|
|
215
|
+
expect(Object.keys(invoke).sort()).toEqual(Object.keys(samples).sort());
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Two calls under system clocks a full calendar day apart must produce
|
|
219
|
+
// identical objects. The day boundary is deliberate: it is what reproduces
|
|
220
|
+
// the `apiKey` bug (a `createdAt` date that changed daily) and the message
|
|
221
|
+
// and tool-call timestamp drift, none of which a same-millisecond back-to-
|
|
222
|
+
// back call would expose.
|
|
223
|
+
it.each(Object.keys(invoke) as (keyof typeof samples)[])(
|
|
224
|
+
"%s is identical across a day boundary",
|
|
225
|
+
(name) => {
|
|
226
|
+
vi.useFakeTimers();
|
|
227
|
+
|
|
228
|
+
vi.setSystemTime(new Date("2026-03-01T08:15:00Z"));
|
|
229
|
+
const first = invoke[name]();
|
|
230
|
+
|
|
231
|
+
vi.setSystemTime(new Date("2026-03-02T21:45:30Z"));
|
|
232
|
+
const second = invoke[name]();
|
|
233
|
+
|
|
234
|
+
expect(second).toEqual(first);
|
|
235
|
+
},
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
it("stamps the frozen instant on every timestamped primitive", () => {
|
|
239
|
+
expect(samples.humanMessage("x").timestamp).toBe(SAMPLE_INSTANT);
|
|
240
|
+
expect(samples.aiMessage("x").timestamp).toBe(SAMPLE_INSTANT);
|
|
241
|
+
expect(samples.artifact("x").createdAt).toBe(SAMPLE_INSTANT);
|
|
242
|
+
expect(samples.toolCall("x", "y").startedAt).toBe(SAMPLE_INSTANT);
|
|
243
|
+
|
|
244
|
+
const createdAt = samples.apiKey().status?.audit?.specAudit?.createdAt;
|
|
245
|
+
expect(createdAt).toBeDefined();
|
|
246
|
+
expect(timestampDate(createdAt!).toISOString()).toBe(SAMPLE_INSTANT);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("renders a stable duration chip rather than the old 0ms flake", () => {
|
|
250
|
+
const tc = samples.toolCall("lookup_order", "{}");
|
|
251
|
+
expect(formatDuration(tc.startedAt, tc.completedAt)).toBe("1.2s");
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it("derives a clock-free tool-call id from the name", () => {
|
|
255
|
+
expect(samples.toolCall("process_return", "{}").id).toBe("tc-process_return");
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it("honors an ApiKeyOverrides.createdAt override", () => {
|
|
259
|
+
const frozen = "2026-01-02T03:04:05.000Z";
|
|
260
|
+
const key = samples.apiKey({ createdAt: frozen });
|
|
261
|
+
const createdAt = key.status?.audit?.specAudit?.createdAt;
|
|
262
|
+
expect(timestampDate(createdAt!).toISOString()).toBe(frozen);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// ---------------------------------------------------------------------------
|
|
267
|
+
// The reader offset window — why SAMPLE_INSTANT is 11:00 UTC. Components
|
|
268
|
+
// format dates in the reader's local time, and real UTC offsets span −11:00
|
|
269
|
+
// to +14:00 (25 hours against a 24-hour day), so no instant renders one
|
|
270
|
+
// calendar date everywhere. The supported window is UTC−11:00 (Midway)
|
|
271
|
+
// through UTC+12:45 (Chatham, southern winter): every inhabited zone except
|
|
272
|
+
// Tongatapu (+13) and Kiritimati (+14). Local date is monotonic in offset,
|
|
273
|
+
// so agreement at the two boundaries proves agreement throughout.
|
|
274
|
+
//
|
|
275
|
+
// `scripts/verify-scenar-tours.mjs` exports the same boundaries as
|
|
276
|
+
// READER_OFFSET_WINDOW (its own test locks those values); this suite locks
|
|
277
|
+
// the anchor's side of the contract.
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
|
|
280
|
+
describe("SAMPLE_INSTANT reader offset window", () => {
|
|
281
|
+
const WEST_OFFSET_MINUTES = -11 * 60; // UTC−11:00, Midway
|
|
282
|
+
const EAST_OFFSET_MINUTES = 12 * 60 + 45; // UTC+12:45, Chatham (Jul)
|
|
283
|
+
|
|
284
|
+
/** Calendar date (YYYY-MM-DD) the instant renders at a fixed UTC offset. */
|
|
285
|
+
const localDateAtOffset = (iso: string, offsetMinutes: number): string =>
|
|
286
|
+
new Date(Date.parse(iso) + offsetMinutes * 60_000).toISOString().slice(0, 10);
|
|
287
|
+
|
|
288
|
+
it("renders one calendar date at both window boundaries", () => {
|
|
289
|
+
const west = localDateAtOffset(SAMPLE_INSTANT, WEST_OFFSET_MINUTES);
|
|
290
|
+
const east = localDateAtOffset(SAMPLE_INSTANT, EAST_OFFSET_MINUTES);
|
|
291
|
+
expect(west).toBe("2026-07-20");
|
|
292
|
+
expect(east).toBe("2026-07-20");
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// The two anchors this one replaced, kept as negative cases so nobody
|
|
296
|
+
// "corrects" the constant back: 09:30Z was the original tour-world instant
|
|
297
|
+
// (read Jul 19 in Honolulu); noon was SAMPLE_INSTANT's first value and the
|
|
298
|
+
// once-planned fix (read Jul 21 in Auckland, Fiji, and Chatham).
|
|
299
|
+
it.each([
|
|
300
|
+
["2026-07-20T09:30:00.000Z", "drifts at the west boundary"],
|
|
301
|
+
["2026-07-20T12:00:00.000Z", "drifts at the east boundary"],
|
|
302
|
+
])("rejected anchor %s %s", (iso) => {
|
|
303
|
+
expect(localDateAtOffset(iso, WEST_OFFSET_MINUTES)).not.toBe(
|
|
304
|
+
localDateAtOffset(iso, EAST_OFFSET_MINUTES),
|
|
305
|
+
);
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
describe("sampleInstant / sampleDate derivation", () => {
|
|
310
|
+
it("sampleInstant with no delta is the anchor itself", () => {
|
|
311
|
+
expect(sampleInstant()).toBe(SAMPLE_INSTANT);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it("applies positive and negative deltas exactly", () => {
|
|
315
|
+
expect(sampleInstant(2_400)).toBe("2026-07-20T11:00:02.400Z");
|
|
316
|
+
expect(sampleInstant(-86_400_000)).toBe("2026-07-19T11:00:00.000Z");
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it("sampleDate agrees with sampleInstant at every delta", () => {
|
|
320
|
+
for (const deltaMs of [0, 1_200, 2_400, -3_600_000, 86_400_000]) {
|
|
321
|
+
expect(sampleDate(deltaMs).toISOString()).toBe(sampleInstant(deltaMs));
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it("the default toolCall span derives from the anchor", () => {
|
|
326
|
+
const tc = samples.toolCall("lookup_order", "{}");
|
|
327
|
+
expect(tc.startedAt).toBe(sampleInstant());
|
|
328
|
+
expect(tc.completedAt).toBe(sampleInstant(1_200));
|
|
329
|
+
});
|
|
330
|
+
});
|
package/src/test/index.ts
CHANGED
package/src/test/samples.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { create } from "@bufbuild/protobuf";
|
|
2
|
+
import { timestampFromDate } from "@bufbuild/protobuf/wkt";
|
|
2
3
|
import { AgentSchema, type Agent } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
3
4
|
import { AgentSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
|
|
4
5
|
import {
|
|
@@ -66,6 +67,15 @@ import {
|
|
|
66
67
|
import { SessionSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/spec_pb";
|
|
67
68
|
import { SkillSchema, type Skill } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/api_pb";
|
|
68
69
|
import { SkillSpecSchema } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/spec_pb";
|
|
70
|
+
import {
|
|
71
|
+
OrganizationSchema,
|
|
72
|
+
type Organization,
|
|
73
|
+
} from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/api_pb";
|
|
74
|
+
import {
|
|
75
|
+
OrganizationsSchema,
|
|
76
|
+
type Organizations,
|
|
77
|
+
} from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/io_pb";
|
|
78
|
+
import { OrganizationSpecSchema } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/spec_pb";
|
|
69
79
|
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
70
80
|
import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
|
|
71
81
|
import {
|
|
@@ -75,6 +85,77 @@ import {
|
|
|
75
85
|
type SearchResult,
|
|
76
86
|
} from "@stigmer/protos/ai/stigmer/search/v1/io_pb";
|
|
77
87
|
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// The frozen instant
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The frozen instant every timestamped `samples.*` factory defaults to — the
|
|
94
|
+
* tour world's single clock. Anything in a demo that needs an instant derives
|
|
95
|
+
* from this one via {@link sampleInstant} / {@link sampleDate}; nothing
|
|
96
|
+
* authors a second instant of its own (`scripts/verify-scenar-tours.mjs`
|
|
97
|
+
* enforces that under `demos/tours/`).
|
|
98
|
+
*
|
|
99
|
+
* These factories must never read the live clock. A `samples.*` value is
|
|
100
|
+
* rendered into Scenar tours that replay in the browser and export to video
|
|
101
|
+
* frame by frame; a clock read paints a pixel that changes between runs, which
|
|
102
|
+
* breaks the "same source, same result" guarantee (scenar-cloud DD-006).
|
|
103
|
+
*
|
|
104
|
+
* The date is `2026-07-20`, the tour world's demo day. The time is 11:00 UTC,
|
|
105
|
+
* chosen by the *reader offset window*: components format dates in the
|
|
106
|
+
* reader's local time (e.g. `ApiKeyListPanel` via `toLocaleDateString`), and
|
|
107
|
+
* real UTC offsets span −11:00 (Midway) to +14:00 (Kiritimati) — a 25-hour
|
|
108
|
+
* range against a 24-hour day, so **no instant renders one calendar date
|
|
109
|
+
* everywhere**. The supported window is UTC−11:00 through UTC+12:45 — every
|
|
110
|
+
* inhabited zone except Tongatapu (+13, ~100k) and Kiritimati (+14, ~6k).
|
|
111
|
+
* 11:00Z holds `Jul 20` across that whole window; the previous noon anchor
|
|
112
|
+
* flipped to `Jul 21` at UTC+12:45 and beyond (Auckland, Fiji, Chatham).
|
|
113
|
+
* Instants whose calendar *date* is rendered must stay inside the window's
|
|
114
|
+
* stable band, 11:00:00Z–11:14:59Z — the anchor sits at its start so all
|
|
115
|
+
* derivation headroom points forward. Duration deltas (end minus start) are
|
|
116
|
+
* zone-invariant and may leave the band freely.
|
|
117
|
+
*
|
|
118
|
+
* The window stabilises the rendered *date*, not the rendered *string*:
|
|
119
|
+
* locale-unpinned formatters still vary the format per reader ("Jul 20, 2026"
|
|
120
|
+
* vs "20 Jul 2026"), and a component that renders a *time of day* is
|
|
121
|
+
* zone-dependent no matter which instant is chosen. The property test in
|
|
122
|
+
* `__tests__/samples.test.ts` locks the date-stability claim at both window
|
|
123
|
+
* boundaries.
|
|
124
|
+
*/
|
|
125
|
+
export const SAMPLE_INSTANT = "2026-07-20T11:00:00.000Z";
|
|
126
|
+
|
|
127
|
+
/** {@link SAMPLE_INSTANT} in epoch milliseconds, the base all derivation uses. */
|
|
128
|
+
const SAMPLE_INSTANT_MS = Date.parse(SAMPLE_INSTANT);
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* An ISO-8601 instant `deltaMs` after {@link SAMPLE_INSTANT} — the way a
|
|
132
|
+
* fixture expresses "2.4 seconds later" or "a day earlier" without authoring
|
|
133
|
+
* a second instant. `sampleInstant()` with no argument is the anchor itself.
|
|
134
|
+
*
|
|
135
|
+
* Prefer this over a hand-written literal even for values that never render:
|
|
136
|
+
* derivation keeps the whole fixture world moving together if the demo day is
|
|
137
|
+
* ever refreshed, and the tour gate rejects authored instant literals anyway.
|
|
138
|
+
*/
|
|
139
|
+
export function sampleInstant(deltaMs = 0): string {
|
|
140
|
+
return new Date(SAMPLE_INSTANT_MS + deltaMs).toISOString();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* {@link sampleInstant} as a `Date`, for APIs that take one (e.g. protobuf's
|
|
145
|
+
* `timestampFromDate`). Same instant, same derivation rule.
|
|
146
|
+
*/
|
|
147
|
+
export function sampleDate(deltaMs = 0): Date {
|
|
148
|
+
return new Date(SAMPLE_INSTANT_MS + deltaMs);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* When a default {@link samples.toolCall} completes: {@link SAMPLE_INSTANT}
|
|
153
|
+
* plus 1.2s, so the rendered duration chip reads a stable "1.2s" — long
|
|
154
|
+
* enough to never collapse to the "0ms" that two adjacent live clock reads
|
|
155
|
+
* used to produce.
|
|
156
|
+
*/
|
|
157
|
+
const SAMPLE_TOOL_CALL_COMPLETED_AT = sampleInstant(1_200);
|
|
158
|
+
|
|
78
159
|
// ---------------------------------------------------------------------------
|
|
79
160
|
// Override interfaces — flat projections of commonly-customized fields
|
|
80
161
|
// ---------------------------------------------------------------------------
|
|
@@ -145,6 +226,16 @@ export interface ApiKeyOverrides {
|
|
|
145
226
|
readonly fingerprint?: string;
|
|
146
227
|
readonly neverExpires?: boolean;
|
|
147
228
|
readonly keyHash?: string;
|
|
229
|
+
/** Frozen ISO-8601 instant for the key's `createdAt`. Defaults to {@link SAMPLE_INSTANT}. */
|
|
230
|
+
readonly createdAt?: string;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface OrganizationOverrides {
|
|
234
|
+
readonly id?: string;
|
|
235
|
+
readonly name?: string;
|
|
236
|
+
readonly slug?: string;
|
|
237
|
+
/** Personal orgs render a person icon in the switcher; teams a building. */
|
|
238
|
+
readonly isPersonal?: boolean;
|
|
148
239
|
}
|
|
149
240
|
|
|
150
241
|
export interface SearchResultOverrides {
|
|
@@ -166,17 +257,30 @@ export interface SearchResultOverrides {
|
|
|
166
257
|
*
|
|
167
258
|
* Each factory returns a realistic protobuf object with sensible defaults.
|
|
168
259
|
* Pass an overrides object to customize the most commonly-needed fields.
|
|
169
|
-
*
|
|
170
|
-
*
|
|
260
|
+
*
|
|
261
|
+
* Every timestamp is frozen at {@link SAMPLE_INSTANT} — these factories never
|
|
262
|
+
* read the live clock, so a fixture renders identical pixels on every browser
|
|
263
|
+
* replay and every video-export frame (scenar-cloud DD-006). Do not
|
|
264
|
+
* reintroduce `Date.now()` or `new Date()` here.
|
|
265
|
+
*
|
|
266
|
+
* For a value the overrides do not cover — a different timestamp, a distinct
|
|
267
|
+
* tool-call id — modify the returned object directly rather than growing the
|
|
268
|
+
* override surface: protobuf messages from `create()` are mutable plain
|
|
269
|
+
* objects. Timestamps derive from the anchor via {@link sampleInstant} rather
|
|
270
|
+
* than a hand-written literal, so the fixture world keeps a single clock.
|
|
171
271
|
*
|
|
172
272
|
* @example
|
|
173
273
|
* ```ts
|
|
174
|
-
* import { samples } from "@stigmer/react/test";
|
|
274
|
+
* import { samples, sampleInstant } from "@stigmer/react/test";
|
|
175
275
|
*
|
|
176
276
|
* const scenario = buildScenario(
|
|
177
277
|
* fixtures.session.get(() => samples.session({ subject: "My topic" })),
|
|
178
278
|
* fixtures.agent.getByReference(() => samples.agent({ name: "My Agent" })),
|
|
179
279
|
* );
|
|
280
|
+
*
|
|
281
|
+
* // Deeper customization — derive "5 seconds later" from the anchor:
|
|
282
|
+
* const later = samples.humanMessage("later");
|
|
283
|
+
* later.timestamp = sampleInstant(5_000);
|
|
180
284
|
* ```
|
|
181
285
|
*/
|
|
182
286
|
export const samples = {
|
|
@@ -363,53 +467,92 @@ export const samples = {
|
|
|
363
467
|
status: create(ApiKeyStatusSchema, {
|
|
364
468
|
audit: create(ApiResourceAuditSchema, {
|
|
365
469
|
specAudit: create(ApiResourceAuditInfoSchema, {
|
|
366
|
-
createdAt:
|
|
470
|
+
createdAt: timestampFromDate(new Date(o?.createdAt ?? SAMPLE_INSTANT)),
|
|
367
471
|
}),
|
|
368
472
|
}),
|
|
369
473
|
}),
|
|
370
474
|
});
|
|
371
475
|
},
|
|
372
476
|
|
|
477
|
+
/**
|
|
478
|
+
* An organization resource with metadata and spec.
|
|
479
|
+
* Default: team org `Acme Corp` (slug `acme`) — the tour world's
|
|
480
|
+
* depicted organization, matching `DEMO_ORG` in the demos workspace.
|
|
481
|
+
*/
|
|
482
|
+
organization(o?: OrganizationOverrides): Organization {
|
|
483
|
+
return create(OrganizationSchema, {
|
|
484
|
+
apiVersion: "tenancy.stigmer.ai/v1",
|
|
485
|
+
kind: "Organization",
|
|
486
|
+
metadata: create(ApiResourceMetadataSchema, {
|
|
487
|
+
id: o?.id ?? "org-00000000-0000-0000-0000-000000000001",
|
|
488
|
+
name: o?.name ?? "Acme Corp",
|
|
489
|
+
slug: o?.slug ?? "acme",
|
|
490
|
+
}),
|
|
491
|
+
spec: create(OrganizationSpecSchema, {
|
|
492
|
+
isPersonal: o?.isPersonal ?? false,
|
|
493
|
+
}),
|
|
494
|
+
});
|
|
495
|
+
},
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* An `Organizations` response for `findMyOrganizations` — what
|
|
499
|
+
* `OrgProvider` fetches to drive the org switcher.
|
|
500
|
+
* Default: a single {@link samples.organization}.
|
|
501
|
+
*/
|
|
502
|
+
organizationList(entries?: Organization[]): Organizations {
|
|
503
|
+
return create(OrganizationsSchema, {
|
|
504
|
+
entries: entries ?? [samples.organization()],
|
|
505
|
+
});
|
|
506
|
+
},
|
|
507
|
+
|
|
373
508
|
// ---- Message & artifact primitives ----
|
|
374
509
|
|
|
375
|
-
/** A human (user) message. */
|
|
510
|
+
/** A human (user) message, stamped at {@link SAMPLE_INSTANT}. */
|
|
376
511
|
humanMessage(content: string): AgentMessage {
|
|
377
512
|
return create(AgentMessageSchema, {
|
|
378
513
|
type: MessageType.MESSAGE_HUMAN,
|
|
379
514
|
content,
|
|
380
|
-
timestamp:
|
|
515
|
+
timestamp: SAMPLE_INSTANT,
|
|
381
516
|
});
|
|
382
517
|
},
|
|
383
518
|
|
|
384
|
-
/** An AI (assistant) message, optionally with tool calls. */
|
|
519
|
+
/** An AI (assistant) message, optionally with tool calls, stamped at {@link SAMPLE_INSTANT}. */
|
|
385
520
|
aiMessage(content: string, toolCalls?: ToolCall[]): AgentMessage {
|
|
386
521
|
return create(AgentMessageSchema, {
|
|
387
522
|
type: MessageType.MESSAGE_AI,
|
|
388
523
|
content,
|
|
389
|
-
timestamp:
|
|
524
|
+
timestamp: SAMPLE_INSTANT,
|
|
390
525
|
toolCalls: toolCalls ?? [],
|
|
391
526
|
});
|
|
392
527
|
},
|
|
393
528
|
|
|
394
|
-
/**
|
|
529
|
+
/**
|
|
530
|
+
* A completed tool call with a result, spanning {@link SAMPLE_INSTANT} to 1.2s
|
|
531
|
+
* later so its duration chip reads a stable "1.2s".
|
|
532
|
+
*
|
|
533
|
+
* The `id` is `tc-${name}`, derived from the name so it is stable across
|
|
534
|
+
* runs. Two tool calls sharing a name therefore share an id — if a single
|
|
535
|
+
* demo renders both and one drives an approval (`useApproval(toolCall.id)`),
|
|
536
|
+
* build the second by hand with a distinct id via `create(ToolCallSchema)`.
|
|
537
|
+
*/
|
|
395
538
|
toolCall(name: string, result: string): ToolCall {
|
|
396
539
|
return create(ToolCallSchema, {
|
|
397
|
-
id: `tc-${name}
|
|
540
|
+
id: `tc-${name}`,
|
|
398
541
|
name,
|
|
399
542
|
result,
|
|
400
543
|
status: ToolCallStatus.TOOL_CALL_COMPLETED,
|
|
401
|
-
startedAt:
|
|
402
|
-
completedAt:
|
|
544
|
+
startedAt: SAMPLE_INSTANT,
|
|
545
|
+
completedAt: SAMPLE_TOOL_CALL_COMPLETED_AT,
|
|
403
546
|
});
|
|
404
547
|
},
|
|
405
548
|
|
|
406
|
-
/** A file artifact produced by an execution. */
|
|
549
|
+
/** A file artifact produced by an execution, stamped at {@link SAMPLE_INSTANT}. */
|
|
407
550
|
artifact(name: string, kind?: ExecutionArtifactKind): ExecutionArtifact {
|
|
408
551
|
return create(ExecutionArtifactSchema, {
|
|
409
552
|
name,
|
|
410
553
|
kind: kind ?? ExecutionArtifactKind.FILE,
|
|
411
554
|
storageKey: `demo-artifact-${name}`,
|
|
412
|
-
createdAt:
|
|
555
|
+
createdAt: SAMPLE_INSTANT,
|
|
413
556
|
});
|
|
414
557
|
},
|
|
415
558
|
|
|
@@ -17,6 +17,8 @@ export interface UseWorkflowCountOptions {
|
|
|
17
17
|
* @default "org"
|
|
18
18
|
*/
|
|
19
19
|
readonly scope?: ResourceListScope;
|
|
20
|
+
/** Opaque token that forces a recount when its value changes. */
|
|
21
|
+
readonly refetchToken?: unknown;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
/** Return value of {@link useWorkflowCount}. */
|