skedyul 1.7.29 → 1.7.30

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/dist/.build-stamp CHANGED
@@ -1 +1 @@
1
- 1788412919726
1
+ 1789421195637
@@ -6,6 +6,9 @@ export { listModels, pullSchema, diffSchema, pushSchema, approveMigration, } fro
6
6
  export { workflows } from './workflows';
7
7
  export type { WorkflowRecord, WorkflowVersion, DeployWorkflowResult, ValidateWorkflowResult, RunWorkflowResult, WorkflowRunStatus, WorkflowSchema, PublishWorkflowResult, PullWorkflowResult, DeployWorkflowOptions, } from './workflows';
8
8
  export { listWorkflows, getWorkflow, listWorkflowVersions, validateWorkflow, validateWorkflowContent, deployWorkflow, publishWorkflow, pullWorkflow, getWorkflowSchema, runWorkflow, getWorkflowRun, } from './workflows';
9
+ export { playground } from './playground';
10
+ export type { PlaygroundSendResult, PlaygroundInspectResult, PlaygroundCreateResult, PlaygroundTurnInput, PlaygroundScheduledMessage, PlaygroundSchedulingCheck, } from './playground';
11
+ export { sendPlaygroundTurn, inspectPlaygroundSession, createPlaygroundSession, } from './playground';
9
12
  export { apps } from './apps';
10
13
  export type { LinkAppInput, LinkAppResult, InvokeToolInput, InvokeToolResult, SyncResourcesResult, PlatformTool, GetDeploymentInput, GetDeploymentResult, DeploymentLogEntry, } from './apps';
11
14
  export { linkApp, registerEndpoint, unregisterEndpoint, heartbeat, installApp, uninstallApp, getInstallation, syncResources, listTools, invokeTool, getDeployment, } from './apps';
@@ -32,6 +32,7 @@ var api_exports = {};
32
32
  __export(api_exports, {
33
33
  approveMigration: () => approveMigration,
34
34
  apps: () => apps,
35
+ createPlaygroundSession: () => createPlaygroundSession,
35
36
  crm: () => crm,
36
37
  deployWorkflow: () => deployWorkflow,
37
38
  diffSchema: () => diffSchema,
@@ -42,6 +43,7 @@ __export(api_exports, {
42
43
  getWorkflowSchema: () => getWorkflowSchema,
43
44
  getWorkplaceToken: () => getWorkplaceToken,
44
45
  heartbeat: () => heartbeat,
46
+ inspectPlaygroundSession: () => inspectPlaygroundSession,
45
47
  installApp: () => installApp,
46
48
  invokeTool: () => invokeTool,
47
49
  linkApp: () => linkApp,
@@ -50,12 +52,14 @@ __export(api_exports, {
50
52
  listWorkflowVersions: () => listWorkflowVersions,
51
53
  listWorkflows: () => listWorkflows,
52
54
  listWorkplaces: () => listWorkplaces,
55
+ playground: () => playground,
53
56
  publishWorkflow: () => publishWorkflow,
54
57
  pullSchema: () => pullSchema,
55
58
  pullWorkflow: () => pullWorkflow,
56
59
  pushSchema: () => pushSchema,
57
60
  registerEndpoint: () => registerEndpoint,
58
61
  runWorkflow: () => runWorkflow,
62
+ sendPlaygroundTurn: () => sendPlaygroundTurn,
59
63
  syncResources: () => syncResources,
60
64
  uninstallApp: () => uninstallApp,
61
65
  unregisterEndpoint: () => unregisterEndpoint,
@@ -686,6 +690,47 @@ var workflows = {
686
690
  getRun: getWorkflowRun
687
691
  };
688
692
 
693
+ // src/cli/api/playground.ts
694
+ async function sendPlaygroundTurn(ctx, workplace, input) {
695
+ const workplaceToken = await getWorkplaceToken(ctx, workplace);
696
+ return callCliApi(cliApi(ctx), "/playground", {
697
+ workplaceId: workplaceToken.workplaceId,
698
+ action: "send",
699
+ handle: input.handle,
700
+ agentId: input.agentId,
701
+ threadId: input.threadId,
702
+ content: input.message,
703
+ currentTime: input.currentTime,
704
+ contactId: input.contactId,
705
+ appInstallationId: input.appInstallationId,
706
+ title: input.title,
707
+ sandbox: input.sandbox
708
+ });
709
+ }
710
+ async function inspectPlaygroundSession(ctx, workplace, threadId) {
711
+ const workplaceToken = await getWorkplaceToken(ctx, workplace);
712
+ return callCliApi(cliApi(ctx), "/playground", void 0, {
713
+ method: "GET",
714
+ query: {
715
+ workplaceId: workplaceToken.workplaceId,
716
+ threadId
717
+ }
718
+ });
719
+ }
720
+ async function createPlaygroundSession(ctx, workplace, input) {
721
+ const workplaceToken = await getWorkplaceToken(ctx, workplace);
722
+ return callCliApi(cliApi(ctx), "/playground", {
723
+ workplaceId: workplaceToken.workplaceId,
724
+ action: "create",
725
+ ...input
726
+ });
727
+ }
728
+ var playground = {
729
+ send: sendPlaygroundTurn,
730
+ get: inspectPlaygroundSession,
731
+ create: createPlaygroundSession
732
+ };
733
+
689
734
  // src/cli/api/apps.ts
690
735
  async function linkApp(ctx, input) {
691
736
  return callCliApi(cliApi(ctx), "/link", {
@@ -782,6 +827,7 @@ var apps = {
782
827
  0 && (module.exports = {
783
828
  approveMigration,
784
829
  apps,
830
+ createPlaygroundSession,
785
831
  crm,
786
832
  deployWorkflow,
787
833
  diffSchema,
@@ -792,6 +838,7 @@ var apps = {
792
838
  getWorkflowSchema,
793
839
  getWorkplaceToken,
794
840
  heartbeat,
841
+ inspectPlaygroundSession,
795
842
  installApp,
796
843
  invokeTool,
797
844
  linkApp,
@@ -800,12 +847,14 @@ var apps = {
800
847
  listWorkflowVersions,
801
848
  listWorkflows,
802
849
  listWorkplaces,
850
+ playground,
803
851
  publishWorkflow,
804
852
  pullSchema,
805
853
  pullWorkflow,
806
854
  pushSchema,
807
855
  registerEndpoint,
808
856
  runWorkflow,
857
+ sendPlaygroundTurn,
809
858
  syncResources,
810
859
  uninstallApp,
811
860
  unregisterEndpoint,
@@ -0,0 +1,92 @@
1
+ import { type CliContext } from './context';
2
+ export interface PlaygroundScheduledMessage {
3
+ id: string;
4
+ status: string;
5
+ scheduledAt: string;
6
+ content: string;
7
+ requiresApproval?: boolean;
8
+ cancelOnActivity?: boolean;
9
+ }
10
+ export interface PlaygroundSchedulingCheck {
11
+ applicable: boolean;
12
+ passed: boolean;
13
+ reason: string;
14
+ namedDelay: boolean;
15
+ verbalFollowUp: boolean;
16
+ scheduledSend: boolean;
17
+ }
18
+ export interface PlaygroundSendResult {
19
+ success: boolean;
20
+ threadId: string;
21
+ userMessageId?: string;
22
+ agentMessageId?: string;
23
+ agentResponse: string;
24
+ agentRunId?: string;
25
+ status: string;
26
+ currentTime?: string;
27
+ scheduledMessageIds?: string[];
28
+ scheduledMessages: PlaygroundScheduledMessage[];
29
+ schedulingCheck?: PlaygroundSchedulingCheck;
30
+ session?: {
31
+ threadId: string;
32
+ agentId: string;
33
+ agentHandle: string | null;
34
+ agentName: string;
35
+ } | null;
36
+ error?: string;
37
+ }
38
+ export interface PlaygroundInspectResult {
39
+ success: boolean;
40
+ threadId: string;
41
+ title: string | null;
42
+ agentId?: string;
43
+ agentHandle?: string | null;
44
+ agentName?: string;
45
+ messages: Array<{
46
+ id: string;
47
+ role: 'user' | 'assistant';
48
+ content: string;
49
+ createdAt: string;
50
+ }>;
51
+ scheduledMessages: PlaygroundScheduledMessage[];
52
+ sendCalls: Array<{
53
+ toolName: string;
54
+ content: string | null;
55
+ sendAt: unknown;
56
+ }>;
57
+ schedulingCheck?: PlaygroundSchedulingCheck;
58
+ error?: string;
59
+ }
60
+ export interface PlaygroundCreateResult {
61
+ success: boolean;
62
+ threadId: string;
63
+ agentId: string;
64
+ agentHandle: string | null;
65
+ agentName: string;
66
+ error?: string;
67
+ }
68
+ export interface PlaygroundTurnInput {
69
+ handle?: string;
70
+ agentId?: string;
71
+ threadId?: string;
72
+ message: string;
73
+ currentTime?: string;
74
+ contactId?: string;
75
+ appInstallationId?: string;
76
+ title?: string;
77
+ sandbox?: boolean;
78
+ }
79
+ export declare function sendPlaygroundTurn(ctx: CliContext, workplace: string, input: PlaygroundTurnInput): Promise<PlaygroundSendResult>;
80
+ export declare function inspectPlaygroundSession(ctx: CliContext, workplace: string, threadId: string): Promise<PlaygroundInspectResult>;
81
+ export declare function createPlaygroundSession(ctx: CliContext, workplace: string, input: {
82
+ handle?: string;
83
+ agentId?: string;
84
+ title?: string;
85
+ contactId?: string;
86
+ appInstallationId?: string;
87
+ }): Promise<PlaygroundCreateResult>;
88
+ export declare const playground: {
89
+ send: typeof sendPlaygroundTurn;
90
+ get: typeof inspectPlaygroundSession;
91
+ create: typeof createPlaygroundSession;
92
+ };
package/dist/cli/index.js CHANGED
@@ -2811,6 +2811,34 @@ async function getWorkflowRun(ctx, workplace, workflowRunId) {
2811
2811
  });
2812
2812
  }
2813
2813
 
2814
+ // src/cli/api/playground.ts
2815
+ async function sendPlaygroundTurn(ctx, workplace, input) {
2816
+ const workplaceToken = await getWorkplaceToken(ctx, workplace);
2817
+ return callCliApi(cliApi(ctx), "/playground", {
2818
+ workplaceId: workplaceToken.workplaceId,
2819
+ action: "send",
2820
+ handle: input.handle,
2821
+ agentId: input.agentId,
2822
+ threadId: input.threadId,
2823
+ content: input.message,
2824
+ currentTime: input.currentTime,
2825
+ contactId: input.contactId,
2826
+ appInstallationId: input.appInstallationId,
2827
+ title: input.title,
2828
+ sandbox: input.sandbox
2829
+ });
2830
+ }
2831
+ async function inspectPlaygroundSession(ctx, workplace, threadId) {
2832
+ const workplaceToken = await getWorkplaceToken(ctx, workplace);
2833
+ return callCliApi(cliApi(ctx), "/playground", void 0, {
2834
+ method: "GET",
2835
+ query: {
2836
+ workplaceId: workplaceToken.workplaceId,
2837
+ threadId
2838
+ }
2839
+ });
2840
+ }
2841
+
2814
2842
  // src/cli/api/apps.ts
2815
2843
  async function linkApp(ctx, input) {
2816
2844
  return callCliApi(cliApi(ctx), "/link", {
@@ -10552,6 +10580,40 @@ var CRMModelFieldRequirementsSchema = import_v47.z.object({
10552
10580
  var CRMContextSchema = import_v47.z.object({
10553
10581
  models: import_v47.z.record(import_v47.z.string(), CRMModelFieldRequirementsSchema)
10554
10582
  });
10583
+ var EntityOperationSchema = import_v47.z.enum(["get", "list", "update", "create", "delete"]);
10584
+ var EntityPoliciesSchema = import_v47.z.record(
10585
+ import_v47.z.string(),
10586
+ // entity handle (e.g., "member", "booking")
10587
+ import_v47.z.array(EntityOperationSchema)
10588
+ // allowed operations
10589
+ );
10590
+ var EvaluatorPreconditionsSchema = import_v47.z.object({
10591
+ toolSucceeded: import_v47.z.boolean().optional(),
10592
+ anyWrittenFields: import_v47.z.array(import_v47.z.string()).optional(),
10593
+ noneOfWrittenFields: import_v47.z.array(import_v47.z.string()).optional(),
10594
+ crm: import_v47.z.array(
10595
+ import_v47.z.object({
10596
+ field: import_v47.z.string(),
10597
+ op: import_v47.z.enum(["eq", "in", "empty", "notEmpty"]),
10598
+ value: import_v47.z.unknown().optional()
10599
+ })
10600
+ ).optional(),
10601
+ skillsLoaded: import_v47.z.array(import_v47.z.string()).optional(),
10602
+ skillsNotLoaded: import_v47.z.array(import_v47.z.string()).optional()
10603
+ });
10604
+ var SkillEvaluatorSchema = import_v47.z.object({
10605
+ name: import_v47.z.string(),
10606
+ description: import_v47.z.string().optional(),
10607
+ target: import_v47.z.enum(["message", "tool", "entity"]),
10608
+ selector: import_v47.z.string().optional(),
10609
+ criteria: import_v47.z.string(),
10610
+ passThreshold: import_v47.z.number().optional(),
10611
+ checks: import_v47.z.object({
10612
+ requiredArgs: import_v47.z.array(import_v47.z.string()).optional(),
10613
+ forbiddenArgValues: import_v47.z.record(import_v47.z.string(), import_v47.z.array(import_v47.z.unknown())).optional()
10614
+ }).optional(),
10615
+ preconditions: EvaluatorPreconditionsSchema.optional()
10616
+ });
10555
10617
  var SkillYAMLSchema = import_v47.z.object({
10556
10618
  // Schema version
10557
10619
  $schema: import_v47.z.string().optional(),
@@ -10562,10 +10624,17 @@ var SkillYAMLSchema = import_v47.z.object({
10562
10624
  description: import_v47.z.string().optional(),
10563
10625
  // Instructions injected into agent system prompt
10564
10626
  instructions: import_v47.z.string(),
10627
+ // Entity policies - declares which entity operations this skill needs
10628
+ // At runtime, these are resolved to CRM tools via AppCrmMap
10629
+ entityPolicies: EntityPoliciesSchema.optional(),
10565
10630
  // Tool configuration - supports both v1 and v2 formats
10631
+ // Use for non-entity tools (MCP tools, system tools)
10566
10632
  tools: SkillToolsSchema.optional(),
10567
10633
  // CRM context - specifies which models/fields to include in schema
10568
10634
  crmContext: CRMContextSchema.optional(),
10635
+ ownedFields: import_v47.z.array(import_v47.z.string()).optional(),
10636
+ // Quality evaluators owned by this skill
10637
+ evaluators: import_v47.z.array(SkillEvaluatorSchema).optional(),
10569
10638
  // Few-shot examples
10570
10639
  examples: import_v47.z.array(SkillExampleSchema).optional()
10571
10640
  });
@@ -10576,8 +10645,11 @@ var SkillYAMLV2Schema = import_v47.z.object({
10576
10645
  version: import_v47.z.string().optional(),
10577
10646
  description: import_v47.z.string().optional(),
10578
10647
  instructions: import_v47.z.string(),
10648
+ entityPolicies: EntityPoliciesSchema.optional(),
10579
10649
  tools: import_v47.z.array(SkillToolDefinitionSchema).optional(),
10580
10650
  crmContext: CRMContextSchema.optional(),
10651
+ ownedFields: import_v47.z.array(import_v47.z.string()).optional(),
10652
+ evaluators: import_v47.z.array(SkillEvaluatorSchema).optional(),
10581
10653
  examples: import_v47.z.array(SkillExampleSchema).optional()
10582
10654
  });
10583
10655
  var SkillVersionWeightSchema = import_v47.z.object({
@@ -10591,7 +10663,10 @@ var SkillRefSchema = import_v47.z.union([
10591
10663
  skill: import_v47.z.string(),
10592
10664
  description: import_v47.z.string().optional(),
10593
10665
  // For AI SDK Agent Skills discovery
10594
- /** Auto-inject this skill's instructions and tools on every agent turn */
10666
+ /**
10667
+ * @deprecated Ignored. The agent must call system:skill:load each turn.
10668
+ * Kept so existing agent YAML still validates.
10669
+ */
10595
10670
  alwaysLoad: import_v47.z.boolean().optional(),
10596
10671
  // Version selection (pick one):
10597
10672
  version: import_v47.z.number().optional(),
@@ -10630,6 +10705,7 @@ var LoadedSkillSchema = import_v47.z.object({
10630
10705
  name: import_v47.z.string(),
10631
10706
  instructions: import_v47.z.string().optional(),
10632
10707
  description: import_v47.z.string().optional(),
10708
+ entityPolicies: EntityPoliciesSchema.optional(),
10633
10709
  tools: import_v47.z.array(SkillToolDefinitionSchema).optional(),
10634
10710
  examples: import_v47.z.array(SkillExampleSchema).optional()
10635
10711
  });
@@ -10884,6 +10960,13 @@ var ResponsesBehaviorConfigSchema = import_v49.z.object({
10884
10960
  * @default false
10885
10961
  */
10886
10962
  allowSchedule: import_v49.z.boolean().optional(),
10963
+ /**
10964
+ * Whether the agent may skip sending when no reply is warranted.
10965
+ * Platform injects silence rules and exposes system:message:skip.
10966
+ * An explicit skip satisfies requireFinal. Off by default.
10967
+ * @default false
10968
+ */
10969
+ allowSilent: import_v49.z.boolean().optional(),
10887
10970
  /**
10888
10971
  * Message splitting configuration.
10889
10972
  * Controls whether and how the agent splits responses into multiple messages.
@@ -11031,6 +11114,7 @@ Commands:
11031
11114
  versions List versions of an agent
11032
11115
  ab Set A/B testing traffic weights
11033
11116
  rollback Rollback to a previous version
11117
+ test Run a playground turn (same path as the web playground)
11034
11118
 
11035
11119
  List Options:
11036
11120
  --workplace, -w Workplace subdomain (required)
@@ -11070,6 +11154,16 @@ Rollback Options:
11070
11154
  --to Version number to rollback to
11071
11155
  --json Output as JSON
11072
11156
 
11157
+ Test Options:
11158
+ --workplace, -w Workplace subdomain (required)
11159
+ --agent, -a Agent handle (required to start a session)
11160
+ --thread, -t Continue an existing playground thread
11161
+ --message, -m User turn to send (omit to inspect the thread)
11162
+ --now ISO clock the agent should treat as now
11163
+ --contact Contact ID to impersonate
11164
+ --installation App installation ID (APP agents)
11165
+ --json Output as JSON
11166
+
11073
11167
  Examples:
11074
11168
  # List all agents in a workplace
11075
11169
  skedyul agents list --workplace gym-demo
@@ -11094,6 +11188,15 @@ Examples:
11094
11188
 
11095
11189
  # Rollback to previous version
11096
11190
  skedyul agents rollback sales-agent --workplace gym-demo --to 1
11191
+
11192
+ # Playground turn (TESTING thread + runThreadAgentWorkflow)
11193
+ skedyul agents test --agent sales-agent --workplace gym-demo --message "Hey"
11194
+
11195
+ # Continue the thread and pin studio now
11196
+ skedyul agents test --thread th_xxx --workplace gym-demo --message "I'm sick" --now 2026-09-11T22:00:00+10:00
11197
+
11198
+ # Inspect scheduled messages
11199
+ skedyul agents test --thread th_xxx --workplace gym-demo
11097
11200
  `);
11098
11201
  }
11099
11202
  async function getWorkplaceToken4(workplaceSubdomain, serverUrl, cliToken) {
@@ -11746,6 +11849,132 @@ async function handleRollback(args2) {
11746
11849
  process.exit(1);
11747
11850
  }
11748
11851
  }
11852
+ async function handleTest(args2) {
11853
+ const { flags } = parseArgs(args2);
11854
+ const workplace = flags.workplace || flags.w;
11855
+ const handle = flags.agent || flags.a;
11856
+ const threadId = flags.thread || flags.t;
11857
+ const message = flags.message || flags.m;
11858
+ const currentTime = flags.now;
11859
+ const contactId = flags.contact;
11860
+ const appInstallationId = flags.installation;
11861
+ const jsonOutput = Boolean(flags.json);
11862
+ if (!workplace) {
11863
+ console.error("Error: --workplace (-w) is required");
11864
+ console.error(
11865
+ 'Usage: skedyul agents test --workplace gym-demo --agent sales-agent --message "Hey"'
11866
+ );
11867
+ process.exit(1);
11868
+ }
11869
+ if (!threadId && !handle) {
11870
+ console.error("Error: --agent (-a) is required when starting a session");
11871
+ console.error(
11872
+ 'Usage: skedyul agents test --workplace gym-demo --agent sales-agent --message "Hey"'
11873
+ );
11874
+ process.exit(1);
11875
+ }
11876
+ if (!message && !threadId) {
11877
+ console.error("Error: --message (-m) is required when starting a session");
11878
+ process.exit(1);
11879
+ }
11880
+ const { token, serverUrl } = ensureAuth3();
11881
+ const ctx = { token, serverUrl };
11882
+ try {
11883
+ if (!message) {
11884
+ const result2 = await inspectPlaygroundSession(ctx, workplace, threadId);
11885
+ if (!result2.success) {
11886
+ throw new Error(result2.error || "Failed to inspect playground session");
11887
+ }
11888
+ if (jsonOutput) {
11889
+ console.log(JSON.stringify(result2, null, 2));
11890
+ return;
11891
+ }
11892
+ console.log("");
11893
+ console.log(`Playground ${result2.threadId}`);
11894
+ if (result2.agentHandle || result2.agentName) {
11895
+ console.log(`Agent ${result2.agentHandle ?? result2.agentName}`);
11896
+ }
11897
+ console.log("");
11898
+ for (const row of result2.messages) {
11899
+ const who = row.role === "user" ? "USER " : "AGENT";
11900
+ console.log(`${who} ${row.content}`);
11901
+ }
11902
+ if (result2.scheduledMessages.length === 0) {
11903
+ console.log("");
11904
+ console.log("SCHED (none)");
11905
+ } else {
11906
+ console.log("");
11907
+ for (const row of result2.scheduledMessages) {
11908
+ console.log(`SCHED ${row.status} ${row.scheduledAt} ${row.content}`);
11909
+ }
11910
+ }
11911
+ for (const row of result2.sendCalls) {
11912
+ if (row.sendAt != null) {
11913
+ console.log(`SENDAT ${String(row.sendAt)} ${row.content ?? ""}`);
11914
+ }
11915
+ }
11916
+ if (result2.schedulingCheck) {
11917
+ console.log(
11918
+ `CHECK ${result2.schedulingCheck.passed ? "pass" : "fail"} ${result2.schedulingCheck.reason}`
11919
+ );
11920
+ }
11921
+ console.log("");
11922
+ return;
11923
+ }
11924
+ const result = await sendPlaygroundTurn(ctx, workplace, {
11925
+ handle,
11926
+ threadId,
11927
+ message,
11928
+ currentTime,
11929
+ contactId,
11930
+ appInstallationId
11931
+ });
11932
+ if (!result.success) {
11933
+ throw new Error(result.error || "Failed to run playground turn");
11934
+ }
11935
+ if (jsonOutput) {
11936
+ console.log(JSON.stringify(result, null, 2));
11937
+ return;
11938
+ }
11939
+ console.log("");
11940
+ console.log(`THREAD ${result.threadId}`);
11941
+ console.log(`STATUS ${result.status}`);
11942
+ if (result.currentTime) {
11943
+ console.log(`NOW ${result.currentTime}`);
11944
+ }
11945
+ if (result.agentResponse) {
11946
+ console.log(`AGENT ${result.agentResponse}`);
11947
+ } else {
11948
+ console.log("AGENT (no immediate SMS)");
11949
+ }
11950
+ if (result.scheduledMessages.length === 0) {
11951
+ console.log("SCHED (none)");
11952
+ } else {
11953
+ for (const row of result.scheduledMessages) {
11954
+ console.log(`SCHED ${row.status} ${row.scheduledAt} ${row.content}`);
11955
+ }
11956
+ }
11957
+ if (result.schedulingCheck) {
11958
+ console.log(
11959
+ `CHECK ${result.schedulingCheck.passed ? "pass" : "fail"} ${result.schedulingCheck.reason}`
11960
+ );
11961
+ }
11962
+ console.log("");
11963
+ } catch (error) {
11964
+ if (jsonOutput) {
11965
+ console.log(
11966
+ JSON.stringify({
11967
+ error: error instanceof Error ? error.message : String(error)
11968
+ })
11969
+ );
11970
+ } else {
11971
+ console.error(
11972
+ `Error: ${error instanceof Error ? error.message : String(error)}`
11973
+ );
11974
+ }
11975
+ process.exit(1);
11976
+ }
11977
+ }
11749
11978
  async function agentsCommand(args2) {
11750
11979
  const subcommand = args2[0];
11751
11980
  if (!subcommand || subcommand === "--help" || subcommand === "-h") {
@@ -11781,6 +12010,9 @@ async function agentsCommand(args2) {
11781
12010
  case "rollback":
11782
12011
  await handleRollback(subArgs);
11783
12012
  break;
12013
+ case "test":
12014
+ await handleTest(subArgs);
12015
+ break;
11784
12016
  default:
11785
12017
  console.error(`Error: Unknown subcommand: ${subcommand}`);
11786
12018
  console.error("Run 'skedyul agents --help' for usage information.");
@@ -14381,7 +14613,7 @@ COMMANDS
14381
14613
  invoke Invoke a tool on a hosted app version
14382
14614
  instances Manage CRM instances (list, get, create, update, delete)
14383
14615
  crm Manage CRM schemas (push, pull, diff, models)
14384
- agents Manage agents (list, get, push)
14616
+ agents Manage agents (list, get, deploy, test)
14385
14617
  skills Manage skills (list, get, deploy, publish, versions, delete)
14386
14618
  workflows Manage workflows (list, get, deploy, run, publish, pull)
14387
14619
  event Emit test app events to the event bus (CLI testing)
@@ -106,6 +106,29 @@ export interface EntityDefinition extends BaseDefinition {
106
106
  * as channel `capabilities.messaging.send` + MessageSendInput.
107
107
  */
108
108
  tools?: EntityRuntimeTools;
109
+ /**
110
+ * Generic pre-save dialogs. Core/web render configured fields; the app
111
+ * declares copy, options, and when to show. Answers go on the CRM event
112
+ * envelope under the app handle (not into CRM scalar fields).
113
+ */
114
+ saveInteractions?: EntitySaveInteractionDefinition[];
115
+ }
116
+ export interface EntitySaveInteractionDefinition {
117
+ handle: string;
118
+ when: {
119
+ onCreate?: boolean;
120
+ onUpdate?: boolean;
121
+ fieldsChanged?: string[];
122
+ relationshipsChanged?: string[];
123
+ };
124
+ dialog: {
125
+ title: string;
126
+ message: string;
127
+ severity?: 'warning' | 'info';
128
+ /** Entity / contextField handles to render (type + options come from the entity). */
129
+ fields: string[];
130
+ defaults?: Record<string, string>;
131
+ };
109
132
  }
110
133
  /**
111
134
  * Situation → short MCP tool name. Keys are platform contracts; values are