@agentuity/cli 0.1.23 → 0.1.24

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.
Files changed (130) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +36 -5
  3. package/dist/cli.js.map +1 -1
  4. package/dist/cmd/ai/cadence/index.d.ts +3 -0
  5. package/dist/cmd/ai/cadence/index.d.ts.map +1 -0
  6. package/dist/cmd/ai/cadence/index.js +29 -0
  7. package/dist/cmd/ai/cadence/index.js.map +1 -0
  8. package/dist/cmd/ai/cadence/list.d.ts +3 -0
  9. package/dist/cmd/ai/cadence/list.d.ts.map +1 -0
  10. package/dist/cmd/ai/cadence/list.js +167 -0
  11. package/dist/cmd/ai/cadence/list.js.map +1 -0
  12. package/dist/cmd/ai/cadence/pause.d.ts +3 -0
  13. package/dist/cmd/ai/cadence/pause.d.ts.map +1 -0
  14. package/dist/cmd/ai/cadence/pause.js +103 -0
  15. package/dist/cmd/ai/cadence/pause.js.map +1 -0
  16. package/dist/cmd/ai/cadence/resume.d.ts +3 -0
  17. package/dist/cmd/ai/cadence/resume.d.ts.map +1 -0
  18. package/dist/cmd/ai/cadence/resume.js +106 -0
  19. package/dist/cmd/ai/cadence/resume.js.map +1 -0
  20. package/dist/cmd/ai/cadence/status.d.ts +3 -0
  21. package/dist/cmd/ai/cadence/status.d.ts.map +1 -0
  22. package/dist/cmd/ai/cadence/status.js +129 -0
  23. package/dist/cmd/ai/cadence/status.js.map +1 -0
  24. package/dist/cmd/ai/cadence/stop.d.ts +3 -0
  25. package/dist/cmd/ai/cadence/stop.d.ts.map +1 -0
  26. package/dist/cmd/ai/cadence/stop.js +107 -0
  27. package/dist/cmd/ai/cadence/stop.js.map +1 -0
  28. package/dist/cmd/ai/cadence/util.d.ts +44 -0
  29. package/dist/cmd/ai/cadence/util.d.ts.map +1 -0
  30. package/dist/cmd/ai/cadence/util.js +52 -0
  31. package/dist/cmd/ai/cadence/util.js.map +1 -0
  32. package/dist/cmd/ai/index.d.ts.map +1 -1
  33. package/dist/cmd/ai/index.js +2 -1
  34. package/dist/cmd/ai/index.js.map +1 -1
  35. package/dist/cmd/auth/machine/setup.js +1 -1
  36. package/dist/cmd/auth/machine/setup.js.map +1 -1
  37. package/dist/cmd/auth/ssh/add.js +1 -1
  38. package/dist/cmd/auth/ssh/add.js.map +1 -1
  39. package/dist/cmd/cloud/eval/get.d.ts +2 -0
  40. package/dist/cmd/cloud/eval/get.d.ts.map +1 -0
  41. package/dist/cmd/cloud/eval/get.js +79 -0
  42. package/dist/cmd/cloud/eval/get.js.map +1 -0
  43. package/dist/cmd/cloud/eval/index.d.ts +2 -0
  44. package/dist/cmd/cloud/eval/index.d.ts.map +1 -0
  45. package/dist/cmd/cloud/eval/index.js +15 -0
  46. package/dist/cmd/cloud/eval/index.js.map +1 -0
  47. package/dist/cmd/cloud/eval/list.d.ts +2 -0
  48. package/dist/cmd/cloud/eval/list.d.ts.map +1 -0
  49. package/dist/cmd/cloud/eval/list.js +119 -0
  50. package/dist/cmd/cloud/eval/list.js.map +1 -0
  51. package/dist/cmd/cloud/eval-run/get.d.ts +2 -0
  52. package/dist/cmd/cloud/eval-run/get.d.ts.map +1 -0
  53. package/dist/cmd/cloud/eval-run/get.js +106 -0
  54. package/dist/cmd/cloud/eval-run/get.js.map +1 -0
  55. package/dist/cmd/cloud/eval-run/index.d.ts +2 -0
  56. package/dist/cmd/cloud/eval-run/index.d.ts.map +1 -0
  57. package/dist/cmd/cloud/eval-run/index.js +15 -0
  58. package/dist/cmd/cloud/eval-run/index.js.map +1 -0
  59. package/dist/cmd/cloud/eval-run/list.d.ts +2 -0
  60. package/dist/cmd/cloud/eval-run/list.d.ts.map +1 -0
  61. package/dist/cmd/cloud/eval-run/list.js +140 -0
  62. package/dist/cmd/cloud/eval-run/list.js.map +1 -0
  63. package/dist/cmd/cloud/index.d.ts.map +1 -1
  64. package/dist/cmd/cloud/index.js +4 -0
  65. package/dist/cmd/cloud/index.js.map +1 -1
  66. package/dist/cmd/cloud/machine/list.d.ts.map +1 -1
  67. package/dist/cmd/cloud/machine/list.js +16 -0
  68. package/dist/cmd/cloud/machine/list.js.map +1 -1
  69. package/dist/cmd/cloud/queue/dlq.d.ts.map +1 -1
  70. package/dist/cmd/cloud/queue/dlq.js +15 -10
  71. package/dist/cmd/cloud/queue/dlq.js.map +1 -1
  72. package/dist/cmd/cloud/sandbox/snapshot/build.d.ts.map +1 -1
  73. package/dist/cmd/cloud/sandbox/snapshot/build.js.map +1 -1
  74. package/dist/cmd/cloud/sandbox/snapshot/create.d.ts.map +1 -1
  75. package/dist/cmd/cloud/sandbox/snapshot/create.js +5 -1
  76. package/dist/cmd/cloud/sandbox/snapshot/create.js.map +1 -1
  77. package/dist/cmd/cloud/storage/upload.js +1 -1
  78. package/dist/cmd/cloud/storage/upload.js.map +1 -1
  79. package/dist/cmd/cloud/vector/stats.d.ts.map +1 -1
  80. package/dist/cmd/cloud/vector/stats.js +3 -1
  81. package/dist/cmd/cloud/vector/stats.js.map +1 -1
  82. package/dist/cmd/cloud/vector/upsert.js +1 -1
  83. package/dist/cmd/cloud/vector/upsert.js.map +1 -1
  84. package/dist/cmd/project/delete.d.ts.map +1 -1
  85. package/dist/cmd/project/delete.js +46 -10
  86. package/dist/cmd/project/delete.js.map +1 -1
  87. package/dist/cmd/setup/index.d.ts.map +1 -1
  88. package/dist/cmd/setup/index.js +4 -1
  89. package/dist/cmd/setup/index.js.map +1 -1
  90. package/dist/env-util.d.ts.map +1 -1
  91. package/dist/env-util.js +4 -1
  92. package/dist/env-util.js.map +1 -1
  93. package/dist/schema-parser.d.ts +17 -1
  94. package/dist/schema-parser.d.ts.map +1 -1
  95. package/dist/schema-parser.js +131 -2
  96. package/dist/schema-parser.js.map +1 -1
  97. package/dist/tui.d.ts.map +1 -1
  98. package/dist/tui.js +4 -0
  99. package/dist/tui.js.map +1 -1
  100. package/package.json +6 -6
  101. package/src/cli.ts +40 -5
  102. package/src/cmd/ai/cadence/index.ts +30 -0
  103. package/src/cmd/ai/cadence/list.ts +183 -0
  104. package/src/cmd/ai/cadence/pause.ts +119 -0
  105. package/src/cmd/ai/cadence/resume.ts +124 -0
  106. package/src/cmd/ai/cadence/status.ts +141 -0
  107. package/src/cmd/ai/cadence/stop.ts +124 -0
  108. package/src/cmd/ai/cadence/util.ts +86 -0
  109. package/src/cmd/ai/index.ts +2 -1
  110. package/src/cmd/auth/machine/setup.ts +1 -1
  111. package/src/cmd/auth/ssh/add.ts +1 -1
  112. package/src/cmd/cloud/eval/get.ts +85 -0
  113. package/src/cmd/cloud/eval/index.ts +15 -0
  114. package/src/cmd/cloud/eval/list.ts +129 -0
  115. package/src/cmd/cloud/eval-run/get.ts +113 -0
  116. package/src/cmd/cloud/eval-run/index.ts +15 -0
  117. package/src/cmd/cloud/eval-run/list.ts +150 -0
  118. package/src/cmd/cloud/index.ts +4 -0
  119. package/src/cmd/cloud/machine/list.ts +16 -0
  120. package/src/cmd/cloud/queue/dlq.ts +15 -10
  121. package/src/cmd/cloud/sandbox/snapshot/build.ts +5 -1
  122. package/src/cmd/cloud/sandbox/snapshot/create.ts +5 -1
  123. package/src/cmd/cloud/storage/upload.ts +1 -1
  124. package/src/cmd/cloud/vector/stats.ts +3 -1
  125. package/src/cmd/cloud/vector/upsert.ts +1 -1
  126. package/src/cmd/project/delete.ts +55 -10
  127. package/src/cmd/setup/index.ts +4 -1
  128. package/src/env-util.ts +4 -1
  129. package/src/schema-parser.ts +150 -2
  130. package/src/tui.ts +5 -0
@@ -0,0 +1,119 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../../types';
3
+ import * as tui from '../../../tui';
4
+ import {
5
+ createCadenceKVAdapter,
6
+ CADENCE_NAMESPACE,
7
+ getLoopStateKey,
8
+ parseLoopState,
9
+ type CadenceLoop,
10
+ } from './util';
11
+ import { getCommand } from '../../../command-prefix';
12
+
13
+ const CadencePauseResponseSchema = z.object({
14
+ success: z.boolean(),
15
+ loopId: z.string(),
16
+ previousStatus: z.string().optional(),
17
+ newStatus: z.string().optional(),
18
+ message: z.string(),
19
+ });
20
+
21
+ export const pauseSubcommand = createCommand({
22
+ name: 'pause',
23
+ description: 'Pause a running Cadence loop',
24
+ tags: ['mutating', 'updates-resource', 'fast', 'requires-auth'],
25
+ requires: { auth: true },
26
+ examples: [{ command: getCommand('cadence pause lp_auth_impl'), description: 'Pause a loop' }],
27
+ schema: {
28
+ args: z.object({
29
+ loopId: z.string().min(1).describe('The loop ID to pause'),
30
+ }),
31
+ response: CadencePauseResponseSchema,
32
+ },
33
+
34
+ async handler(ctx) {
35
+ const { args, options } = ctx;
36
+ const kv = await createCadenceKVAdapter(ctx);
37
+
38
+ const key = getLoopStateKey(args.loopId);
39
+ const result = await kv.get(CADENCE_NAMESPACE, key);
40
+
41
+ if (!result.exists || !result.data) {
42
+ if (!options.json) {
43
+ tui.error(`Loop ${args.loopId} not found.`);
44
+ }
45
+ return {
46
+ success: false,
47
+ loopId: args.loopId,
48
+ message: 'Loop not found',
49
+ };
50
+ }
51
+
52
+ let data: unknown;
53
+ if (typeof result.data === 'string') {
54
+ try {
55
+ data = JSON.parse(result.data);
56
+ } catch {
57
+ if (!options.json) {
58
+ tui.error(`Failed to parse loop state for ${args.loopId}`);
59
+ }
60
+ return {
61
+ success: false,
62
+ loopId: args.loopId,
63
+ message: 'Failed to parse loop state',
64
+ };
65
+ }
66
+ } else {
67
+ data = result.data;
68
+ }
69
+
70
+ const loop = parseLoopState(data);
71
+ if (!loop) {
72
+ if (!options.json) {
73
+ tui.error(`Invalid loop state for ${args.loopId}`);
74
+ }
75
+ return {
76
+ success: false,
77
+ loopId: args.loopId,
78
+ message: 'Invalid loop state',
79
+ };
80
+ }
81
+
82
+ if (loop.status !== 'running') {
83
+ if (!options.json) {
84
+ tui.warning(`Loop ${args.loopId} is not running (status: ${loop.status})`);
85
+ }
86
+ return {
87
+ success: false,
88
+ loopId: args.loopId,
89
+ previousStatus: loop.status,
90
+ message: `Cannot pause loop with status: ${loop.status}`,
91
+ };
92
+ }
93
+
94
+ // Update status to paused
95
+ const updatedLoop: CadenceLoop = {
96
+ ...loop,
97
+ status: 'paused',
98
+ updatedAt: new Date().toISOString(),
99
+ };
100
+
101
+ await kv.set(CADENCE_NAMESPACE, key, JSON.stringify(updatedLoop), {
102
+ contentType: 'application/json',
103
+ });
104
+
105
+ if (!options.json) {
106
+ tui.success(`Paused loop ${args.loopId}`);
107
+ }
108
+
109
+ return {
110
+ success: true,
111
+ loopId: args.loopId,
112
+ previousStatus: 'running',
113
+ newStatus: 'paused',
114
+ message: 'Loop paused successfully',
115
+ };
116
+ },
117
+ });
118
+
119
+ export default pauseSubcommand;
@@ -0,0 +1,124 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../../types';
3
+ import * as tui from '../../../tui';
4
+ import {
5
+ createCadenceKVAdapter,
6
+ CADENCE_NAMESPACE,
7
+ getLoopStateKey,
8
+ parseLoopState,
9
+ type CadenceLoop,
10
+ } from './util';
11
+ import { getCommand } from '../../../command-prefix';
12
+
13
+ const CadenceResumeResponseSchema = z.object({
14
+ success: z.boolean(),
15
+ loopId: z.string(),
16
+ previousStatus: z.string().optional(),
17
+ newStatus: z.string().optional(),
18
+ message: z.string(),
19
+ });
20
+
21
+ export const resumeSubcommand = createCommand({
22
+ name: 'resume',
23
+ description: 'Resume a paused Cadence loop',
24
+ tags: ['mutating', 'updates-resource', 'fast', 'requires-auth'],
25
+ requires: { auth: true },
26
+ examples: [
27
+ { command: getCommand('cadence resume lp_auth_impl'), description: 'Resume a paused loop' },
28
+ ],
29
+ schema: {
30
+ args: z.object({
31
+ loopId: z.string().min(1).describe('The loop ID to resume'),
32
+ }),
33
+ response: CadenceResumeResponseSchema,
34
+ },
35
+
36
+ async handler(ctx) {
37
+ const { args, options } = ctx;
38
+ const kv = await createCadenceKVAdapter(ctx);
39
+
40
+ const key = getLoopStateKey(args.loopId);
41
+ const result = await kv.get(CADENCE_NAMESPACE, key);
42
+
43
+ if (!result.exists || !result.data) {
44
+ if (!options.json) {
45
+ tui.error(`Loop ${args.loopId} not found.`);
46
+ }
47
+ return {
48
+ success: false,
49
+ loopId: args.loopId,
50
+ message: 'Loop not found',
51
+ };
52
+ }
53
+
54
+ let data: unknown;
55
+ if (typeof result.data === 'string') {
56
+ try {
57
+ data = JSON.parse(result.data);
58
+ } catch {
59
+ if (!options.json) {
60
+ tui.error(`Failed to parse loop state for ${args.loopId}`);
61
+ }
62
+ return {
63
+ success: false,
64
+ loopId: args.loopId,
65
+ message: 'Failed to parse loop state',
66
+ };
67
+ }
68
+ } else {
69
+ data = result.data;
70
+ }
71
+
72
+ const loop = parseLoopState(data);
73
+ if (!loop) {
74
+ if (!options.json) {
75
+ tui.error(`Invalid loop state for ${args.loopId}`);
76
+ }
77
+ return {
78
+ success: false,
79
+ loopId: args.loopId,
80
+ message: 'Invalid loop state',
81
+ };
82
+ }
83
+
84
+ if (loop.status !== 'paused') {
85
+ if (!options.json) {
86
+ tui.warning(`Loop ${args.loopId} is not paused (status: ${loop.status})`);
87
+ }
88
+ return {
89
+ success: false,
90
+ loopId: args.loopId,
91
+ previousStatus: loop.status,
92
+ message: `Cannot resume loop with status: ${loop.status}`,
93
+ };
94
+ }
95
+
96
+ // Update status to running
97
+ const updatedLoop: CadenceLoop = {
98
+ ...loop,
99
+ status: 'running',
100
+ updatedAt: new Date().toISOString(),
101
+ };
102
+
103
+ await kv.set(CADENCE_NAMESPACE, key, JSON.stringify(updatedLoop), {
104
+ contentType: 'application/json',
105
+ });
106
+
107
+ if (!options.json) {
108
+ tui.success(`Resumed loop ${args.loopId}`);
109
+ tui.info(
110
+ 'Note: The loop will continue when the Open Code session checks for status updates.'
111
+ );
112
+ }
113
+
114
+ return {
115
+ success: true,
116
+ loopId: args.loopId,
117
+ previousStatus: 'paused',
118
+ newStatus: 'running',
119
+ message: 'Loop resumed successfully',
120
+ };
121
+ },
122
+ });
123
+
124
+ export default resumeSubcommand;
@@ -0,0 +1,141 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../../types';
3
+ import * as tui from '../../../tui';
4
+ import { createCadenceKVAdapter, CADENCE_NAMESPACE, getLoopStateKey, parseLoopState } from './util';
5
+ import { getCommand } from '../../../command-prefix';
6
+
7
+ const CadenceStatusResponseSchema = z.object({
8
+ found: z.boolean(),
9
+ loop: z
10
+ .object({
11
+ loopId: z.string(),
12
+ status: z.string(),
13
+ iteration: z.number(),
14
+ maxIterations: z.number(),
15
+ prompt: z.string(),
16
+ projectLabel: z.string().optional(),
17
+ sessionId: z.string().optional(),
18
+ createdAt: z.string(),
19
+ updatedAt: z.string(),
20
+ lastError: z.string().optional(),
21
+ })
22
+ .optional(),
23
+ });
24
+
25
+ export const statusSubcommand = createCommand({
26
+ name: 'status',
27
+ aliases: ['get', 'show'],
28
+ description: 'Get status of a Cadence loop',
29
+ tags: ['read-only', 'fast', 'requires-auth'],
30
+ requires: { auth: true },
31
+ examples: [
32
+ { command: getCommand('cadence status lp_auth_impl'), description: 'Get loop status' },
33
+ ],
34
+ schema: {
35
+ args: z.object({
36
+ loopId: z.string().min(1).describe('The loop ID (e.g., lp_auth_impl)'),
37
+ }),
38
+ response: CadenceStatusResponseSchema,
39
+ },
40
+ idempotent: true,
41
+
42
+ async handler(ctx) {
43
+ const { args, options } = ctx;
44
+ const kv = await createCadenceKVAdapter(ctx);
45
+
46
+ const key = getLoopStateKey(args.loopId);
47
+ const result = await kv.get(CADENCE_NAMESPACE, key);
48
+
49
+ if (!result.exists || !result.data) {
50
+ if (!options.json) {
51
+ tui.warning(`Loop ${args.loopId} not found.`);
52
+ }
53
+ return { found: false };
54
+ }
55
+
56
+ let data: unknown;
57
+ if (typeof result.data === 'string') {
58
+ try {
59
+ data = JSON.parse(result.data);
60
+ } catch {
61
+ if (!options.json) {
62
+ tui.error(`Failed to parse loop state for ${args.loopId}`);
63
+ }
64
+ return { found: false };
65
+ }
66
+ } else {
67
+ data = result.data;
68
+ }
69
+
70
+ const loop = parseLoopState(data);
71
+ if (!loop) {
72
+ if (!options.json) {
73
+ tui.error(`Invalid loop state for ${args.loopId}`);
74
+ }
75
+ return { found: false };
76
+ }
77
+
78
+ if (!options.json) {
79
+ console.log();
80
+ tui.info(`Cadence Loop: ${tui.colorPrimary(loop.loopId)}`);
81
+ console.log();
82
+
83
+ const details = [
84
+ ['Status', formatStatus(loop.status)],
85
+ ['Iteration', `${loop.iteration} / ${loop.maxIterations}`],
86
+ ['Project', loop.projectLabel ?? '-'],
87
+ ['Session', loop.sessionId ?? '-'],
88
+ ['Created', loop.createdAt],
89
+ ['Updated', loop.updatedAt],
90
+ ];
91
+
92
+ if (loop.lastError) {
93
+ details.push(['Last Error', tui.colorError(loop.lastError)]);
94
+ }
95
+
96
+ for (const [label, value] of details) {
97
+ console.log(` ${tui.muted(label + ':')} ${value}`);
98
+ }
99
+
100
+ console.log();
101
+ console.log(tui.muted('Task:'));
102
+ console.log(` ${loop.prompt}`);
103
+ console.log();
104
+ }
105
+
106
+ return {
107
+ found: true,
108
+ loop: {
109
+ loopId: loop.loopId,
110
+ status: loop.status,
111
+ iteration: loop.iteration,
112
+ maxIterations: loop.maxIterations,
113
+ prompt: loop.prompt,
114
+ projectLabel: loop.projectLabel,
115
+ sessionId: loop.sessionId,
116
+ createdAt: loop.createdAt,
117
+ updatedAt: loop.updatedAt,
118
+ lastError: loop.lastError,
119
+ },
120
+ };
121
+ },
122
+ });
123
+
124
+ function formatStatus(status: string): string {
125
+ switch (status) {
126
+ case 'running':
127
+ return tui.colorSuccess('● running');
128
+ case 'paused':
129
+ return tui.colorWarning('⏸ paused');
130
+ case 'completed':
131
+ return tui.colorSuccess('✓ completed');
132
+ case 'failed':
133
+ return tui.colorError('✗ failed');
134
+ case 'cancelled':
135
+ return tui.muted('○ cancelled');
136
+ default:
137
+ return status;
138
+ }
139
+ }
140
+
141
+ export default statusSubcommand;
@@ -0,0 +1,124 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../../types';
3
+ import * as tui from '../../../tui';
4
+ import {
5
+ createCadenceKVAdapter,
6
+ CADENCE_NAMESPACE,
7
+ getLoopStateKey,
8
+ parseLoopState,
9
+ type CadenceLoop,
10
+ } from './util';
11
+ import { getCommand } from '../../../command-prefix';
12
+
13
+ const CadenceStopResponseSchema = z.object({
14
+ success: z.boolean(),
15
+ loopId: z.string(),
16
+ previousStatus: z.string().optional(),
17
+ newStatus: z.string().optional(),
18
+ message: z.string(),
19
+ });
20
+
21
+ export const stopSubcommand = createCommand({
22
+ name: 'stop',
23
+ aliases: ['cancel'],
24
+ description: 'Stop and cancel a Cadence loop',
25
+ tags: ['mutating', 'updates-resource', 'fast', 'requires-auth'],
26
+ requires: { auth: true },
27
+ examples: [
28
+ { command: getCommand('cadence stop lp_auth_impl'), description: 'Stop and cancel a loop' },
29
+ ],
30
+ schema: {
31
+ args: z.object({
32
+ loopId: z.string().min(1).describe('The loop ID to stop'),
33
+ }),
34
+ response: CadenceStopResponseSchema,
35
+ },
36
+
37
+ async handler(ctx) {
38
+ const { args, options } = ctx;
39
+ const kv = await createCadenceKVAdapter(ctx);
40
+
41
+ const key = getLoopStateKey(args.loopId);
42
+ const result = await kv.get(CADENCE_NAMESPACE, key);
43
+
44
+ if (!result.exists || !result.data) {
45
+ if (!options.json) {
46
+ tui.error(`Loop ${args.loopId} not found.`);
47
+ }
48
+ return {
49
+ success: false,
50
+ loopId: args.loopId,
51
+ message: 'Loop not found',
52
+ };
53
+ }
54
+
55
+ let data: unknown;
56
+ if (typeof result.data === 'string') {
57
+ try {
58
+ data = JSON.parse(result.data);
59
+ } catch {
60
+ if (!options.json) {
61
+ tui.error(`Failed to parse loop state for ${args.loopId}`);
62
+ }
63
+ return {
64
+ success: false,
65
+ loopId: args.loopId,
66
+ message: 'Failed to parse loop state',
67
+ };
68
+ }
69
+ } else {
70
+ data = result.data;
71
+ }
72
+
73
+ const loop = parseLoopState(data);
74
+ if (!loop) {
75
+ if (!options.json) {
76
+ tui.error(`Invalid loop state for ${args.loopId}`);
77
+ }
78
+ return {
79
+ success: false,
80
+ loopId: args.loopId,
81
+ message: 'Invalid loop state',
82
+ };
83
+ }
84
+
85
+ const previousStatus = loop.status;
86
+
87
+ if (loop.status === 'completed' || loop.status === 'cancelled') {
88
+ if (!options.json) {
89
+ tui.warning(`Loop ${args.loopId} is already ${loop.status}`);
90
+ }
91
+ return {
92
+ success: false,
93
+ loopId: args.loopId,
94
+ previousStatus,
95
+ message: `Loop is already ${loop.status}`,
96
+ };
97
+ }
98
+
99
+ // Update status to cancelled
100
+ const updatedLoop: CadenceLoop = {
101
+ ...loop,
102
+ status: 'cancelled',
103
+ updatedAt: new Date().toISOString(),
104
+ };
105
+
106
+ await kv.set(CADENCE_NAMESPACE, key, JSON.stringify(updatedLoop), {
107
+ contentType: 'application/json',
108
+ });
109
+
110
+ if (!options.json) {
111
+ tui.success(`Stopped loop ${args.loopId}`);
112
+ }
113
+
114
+ return {
115
+ success: true,
116
+ loopId: args.loopId,
117
+ previousStatus,
118
+ newStatus: 'cancelled',
119
+ message: 'Loop cancelled successfully',
120
+ };
121
+ },
122
+ });
123
+
124
+ export default stopSubcommand;
@@ -0,0 +1,86 @@
1
+ import { KeyValueStorageService, type Logger } from '@agentuity/core';
2
+ import { createServerFetchAdapter, getServiceUrls } from '@agentuity/server';
3
+ import { getDefaultRegion } from '../../../config';
4
+ import type { AuthData, Config } from '../../../types';
5
+
6
+ /** KV namespace for Cadence loop state */
7
+ export const CADENCE_NAMESPACE = 'agentuity-opencode-tasks';
8
+
9
+ /** Prefix for loop state keys */
10
+ export const LOOP_KEY_PREFIX = 'loop:';
11
+
12
+ export interface CadenceLoop {
13
+ loopId: string;
14
+ parentId?: string;
15
+ projectLabel?: string;
16
+ sessionId?: string;
17
+ status: 'running' | 'paused' | 'completed' | 'failed' | 'cancelled';
18
+ iteration: number;
19
+ maxIterations: number;
20
+ prompt: string;
21
+ createdAt: string;
22
+ updatedAt: string;
23
+ lastError?: string;
24
+ sandbox?: {
25
+ mode: 'off' | 'per_iteration' | 'persistent';
26
+ sandboxId?: string;
27
+ };
28
+ }
29
+
30
+ export interface CadenceContext {
31
+ logger: Logger;
32
+ config: Config | null;
33
+ auth: AuthData;
34
+ project?: { region: string };
35
+ }
36
+
37
+ /**
38
+ * Creates a KV storage service for Cadence operations.
39
+ */
40
+ export async function createCadenceKVAdapter(ctx: CadenceContext): Promise<KeyValueStorageService> {
41
+ const adapter = createServerFetchAdapter(
42
+ {
43
+ headers: {
44
+ Authorization: `Bearer ${ctx.auth.apiKey}`,
45
+ },
46
+ },
47
+ ctx.logger
48
+ );
49
+
50
+ const region = ctx.project?.region || (await getDefaultRegion(ctx.config?.name, ctx.config));
51
+ const urls = getServiceUrls(region);
52
+ const baseUrl = urls.catalyst;
53
+ return new KeyValueStorageService(baseUrl, adapter);
54
+ }
55
+
56
+ /**
57
+ * Gets the state key for a loop.
58
+ */
59
+ export function getLoopStateKey(loopId: string): string {
60
+ return `${LOOP_KEY_PREFIX}${loopId}:state`;
61
+ }
62
+
63
+ /**
64
+ * Parses a loop state from KV storage.
65
+ */
66
+ export function parseLoopState(data: unknown): CadenceLoop | null {
67
+ if (!data || typeof data !== 'object') return null;
68
+
69
+ const loop = data as Record<string, unknown>;
70
+ if (!loop.loopId || !loop.status || !loop.prompt) return null;
71
+
72
+ return {
73
+ loopId: String(loop.loopId),
74
+ parentId: loop.parentId ? String(loop.parentId) : undefined,
75
+ projectLabel: loop.projectLabel ? String(loop.projectLabel) : undefined,
76
+ sessionId: loop.sessionId ? String(loop.sessionId) : undefined,
77
+ status: loop.status as CadenceLoop['status'],
78
+ iteration: Number(loop.iteration) || 1,
79
+ maxIterations: Number(loop.maxIterations) || 50,
80
+ prompt: String(loop.prompt),
81
+ createdAt: String(loop.createdAt),
82
+ updatedAt: String(loop.updatedAt),
83
+ lastError: loop.lastError ? String(loop.lastError) : undefined,
84
+ sandbox: loop.sandbox as CadenceLoop['sandbox'],
85
+ };
86
+ }
@@ -1,4 +1,5 @@
1
1
  import { createCommand } from '../../types';
2
+ import cadenceCommand from './cadence';
2
3
  import capabilitiesCommand from './capabilities';
3
4
  import promptCommand from './prompt';
4
5
  import schemaCommand from './schema';
@@ -29,5 +30,5 @@ export const command = createCommand({
29
30
  description: 'Generate Agent Skills from CLI schema',
30
31
  },
31
32
  ],
32
- subcommands: [opencodeCommand, capabilitiesCommand, promptCommand, schemaCommand, skillsCommand],
33
+ subcommands: [opencodeCommand, cadenceCommand, capabilitiesCommand, promptCommand, schemaCommand, skillsCommand],
33
34
  });
@@ -15,7 +15,7 @@ export const setupSubcommand = createSubcommand({
15
15
  name: 'setup',
16
16
  description:
17
17
  'Set up machine authentication by uploading a public key for self-hosted infrastructure',
18
- tags: ['mutating', 'slow', 'requires-auth'],
18
+ tags: ['mutating', 'slow', 'requires-auth', 'uses-stdin'],
19
19
  examples: [
20
20
  {
21
21
  command: `${getCommand('auth machine setup')} --file ./public-key.pem`,
@@ -115,7 +115,7 @@ export const addCommand = createSubcommand({
115
115
  name: 'add',
116
116
  aliases: ['create'],
117
117
  description: 'Add an SSH public key to your account (reads from file or stdin)',
118
- tags: ['mutating', 'creates-resource', 'slow', 'requires-auth'],
118
+ tags: ['mutating', 'creates-resource', 'slow', 'requires-auth', 'uses-stdin'],
119
119
  idempotent: false,
120
120
  requires: { apiClient: true, auth: true },
121
121
  examples: [