@cursor/july 0.1.42 → 0.1.43

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 (189) hide show
  1. package/AGENTS.md +1 -0
  2. package/dist/bin/agent-serve.js +3 -1
  3. package/dist/channels/github/api.d.ts +5 -0
  4. package/dist/channels/github/api.d.ts.map +1 -1
  5. package/dist/channels/github/api.js +18 -0
  6. package/dist/channels/github/defaults.d.ts +4 -5
  7. package/dist/channels/github/defaults.d.ts.map +1 -1
  8. package/dist/channels/github/defaults.js +27 -1
  9. package/dist/channels/github/github-channel.d.ts.map +1 -1
  10. package/dist/channels/github/github-channel.js +28 -5
  11. package/dist/channels/github/index.d.ts +1 -0
  12. package/dist/channels/github/index.d.ts.map +1 -1
  13. package/dist/channels/github/index.js +1 -0
  14. package/dist/channels/github/progress.d.ts +54 -0
  15. package/dist/channels/github/progress.d.ts.map +1 -0
  16. package/dist/channels/github/progress.js +168 -0
  17. package/dist/channels/github/state.d.ts +2 -0
  18. package/dist/channels/github/state.d.ts.map +1 -1
  19. package/dist/channels/github/state.js +1 -1
  20. package/dist/channels/github/types.d.ts +8 -4
  21. package/dist/channels/github/types.d.ts.map +1 -1
  22. package/dist/channels/slack/slack-channel.d.ts +4 -0
  23. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  24. package/dist/channels/slack/slack-channel.js +4 -0
  25. package/dist/docs/404.html +2 -2
  26. package/dist/docs/ab.html +4 -4
  27. package/dist/docs/assets/{app.C4-Gwi7g.js → app.DsTLo2j1.js} +1 -1
  28. package/dist/docs/assets/chunks/@localSearchIndexroot.BZx4pmZL.js +1 -0
  29. package/dist/docs/assets/chunks/{VPLocalSearchBox.DDoLm843.js → VPLocalSearchBox.DoVfutcV.js} +1 -1
  30. package/dist/docs/assets/chunks/{theme.SbjGIiM0.js → theme.DtuVtKkc.js} +2 -2
  31. package/dist/docs/assets/{deployment.md.BHVjVqRa.js → deployment.md.Cdp4rTE4.js} +1 -1
  32. package/dist/docs/assets/{guides_github.md.R2QlpR75.js → guides_github.md.DSg0j9qj.js} +29 -3
  33. package/dist/docs/assets/{guides_github.md.R2QlpR75.lean.js → guides_github.md.DSg0j9qj.lean.js} +1 -1
  34. package/dist/docs/assets/guides_opentelemetry.md.DmyUwC5R.js +20 -0
  35. package/dist/docs/assets/guides_opentelemetry.md.DmyUwC5R.lean.js +1 -0
  36. package/dist/docs/assets/{index.md.BKpbkCa6.js → index.md.CMc5FP7E.js} +2 -1
  37. package/dist/docs/assets/{reference_channels.md.BIabFUAI.js → reference_channels.md.MN8iDy8V.js} +1 -1
  38. package/dist/docs/assets/{reference_hooks.md.B40QAG6m.js → reference_hooks.md.4cbRRIIu.js} +2 -2
  39. package/dist/docs/assets/{reference_hooks.md.B40QAG6m.lean.js → reference_hooks.md.4cbRRIIu.lean.js} +1 -1
  40. package/dist/docs/assets/{reference_project-layout.md._XdeMahr.js → reference_project-layout.md.D3MdHM2z.js} +2 -1
  41. package/dist/docs/assets/templates_triage.md.CConZt1z.js +11 -0
  42. package/dist/docs/assets/templates_triage.md.CConZt1z.lean.js +1 -0
  43. package/dist/docs/building-with-agents.html +5 -5
  44. package/dist/docs/concepts.html +5 -5
  45. package/dist/docs/deployment.html +6 -6
  46. package/dist/docs/evals.html +4 -4
  47. package/dist/docs/example-agents/approval-buddy.html +4 -4
  48. package/dist/docs/example-agents/benny.html +4 -4
  49. package/dist/docs/example-agents/bugbot.html +4 -4
  50. package/dist/docs/example-agents/codebase-wiki.html +4 -4
  51. package/dist/docs/example-agents/codeowners-review.html +4 -4
  52. package/dist/docs/example-agents/concierge.html +4 -4
  53. package/dist/docs/example-agents/fsd.html +4 -4
  54. package/dist/docs/example-agents/index.html +5 -5
  55. package/dist/docs/example-agents/knowledge-base.html +4 -4
  56. package/dist/docs/example-agents/oncall.html +4 -4
  57. package/dist/docs/example-agents/security-reviewer.html +4 -4
  58. package/dist/docs/example-agents/slack-agent.html +4 -4
  59. package/dist/docs/example-agents/weather-agent.html +4 -4
  60. package/dist/docs/guides/agent-to-agent.html +4 -4
  61. package/dist/docs/guides/cloud-runtime.html +5 -5
  62. package/dist/docs/guides/github.html +33 -7
  63. package/dist/docs/guides/human-in-the-loop.html +4 -4
  64. package/dist/docs/guides/mcp-oauth.html +4 -4
  65. package/dist/docs/guides/opentelemetry.html +44 -0
  66. package/dist/docs/guides/slack.html +4 -4
  67. package/dist/docs/guides/webhooks.html +4 -4
  68. package/dist/docs/hashmap.json +1 -1
  69. package/dist/docs/hillclimbing.html +4 -4
  70. package/dist/docs/index.html +7 -6
  71. package/dist/docs/quickstart.html +4 -4
  72. package/dist/docs/reference/agent-config.html +4 -4
  73. package/dist/docs/reference/artifacts.html +4 -4
  74. package/dist/docs/reference/channels.html +6 -6
  75. package/dist/docs/reference/cli.html +4 -4
  76. package/dist/docs/reference/connections.html +4 -4
  77. package/dist/docs/reference/hooks.html +6 -6
  78. package/dist/docs/reference/http-api.html +4 -4
  79. package/dist/docs/reference/instructions.html +4 -4
  80. package/dist/docs/reference/playground.html +4 -4
  81. package/dist/docs/reference/project-layout.html +7 -6
  82. package/dist/docs/reference/prompt.html +4 -4
  83. package/dist/docs/reference/schedules.html +4 -4
  84. package/dist/docs/reference/sessions.html +4 -4
  85. package/dist/docs/reference/skills.html +4 -4
  86. package/dist/docs/reference/subagents.html +4 -4
  87. package/dist/docs/reference/tools.html +4 -4
  88. package/dist/docs/scaffolding-agents.html +4 -4
  89. package/dist/docs/storage.html +4 -4
  90. package/dist/docs/templates/triage.html +35 -0
  91. package/dist/docs/troubleshooting.html +4 -4
  92. package/dist/index.d.ts +2 -0
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +1 -0
  95. package/dist/internal/cli-ax.d.ts +1 -0
  96. package/dist/internal/cli-ax.d.ts.map +1 -1
  97. package/dist/internal/cli-ax.js +18 -3
  98. package/dist/internal/discovery.d.ts.map +1 -1
  99. package/dist/internal/discovery.js +36 -4
  100. package/dist/internal/distribution.d.ts.map +1 -1
  101. package/dist/internal/distribution.js +1 -0
  102. package/dist/internal/init-project.d.ts +24 -0
  103. package/dist/internal/init-project.d.ts.map +1 -1
  104. package/dist/internal/init-project.js +126 -7
  105. package/dist/internal/otel/attrs.d.ts +7 -0
  106. package/dist/internal/otel/attrs.d.ts.map +1 -0
  107. package/dist/internal/otel/attrs.js +13 -0
  108. package/dist/internal/otel/collector.d.ts +16 -0
  109. package/dist/internal/otel/collector.d.ts.map +1 -0
  110. package/dist/internal/otel/collector.js +564 -0
  111. package/dist/internal/otel/config.d.ts +42 -0
  112. package/dist/internal/otel/config.d.ts.map +1 -0
  113. package/dist/internal/otel/config.js +236 -0
  114. package/dist/internal/otel/http.d.ts +11 -0
  115. package/dist/internal/otel/http.d.ts.map +1 -0
  116. package/dist/internal/otel/http.js +97 -0
  117. package/dist/internal/otel/runtime.d.ts +21 -0
  118. package/dist/internal/otel/runtime.d.ts.map +1 -0
  119. package/dist/internal/otel/runtime.js +188 -0
  120. package/dist/internal/server.d.ts.map +1 -1
  121. package/dist/internal/server.js +25 -1
  122. package/dist/internal/session-engine.d.ts +10 -1
  123. package/dist/internal/session-engine.d.ts.map +1 -1
  124. package/dist/internal/session-engine.js +35 -2
  125. package/dist/memory.d.ts +4 -0
  126. package/dist/memory.d.ts.map +1 -1
  127. package/dist/memory.js +4 -0
  128. package/dist/otel.d.ts +88 -0
  129. package/dist/otel.d.ts.map +1 -0
  130. package/dist/otel.js +64 -0
  131. package/dist/playground/assets/{index-B3HBneZZ.js → index-D-DIYQzw.js} +31 -31
  132. package/dist/playground/assets/index-DQTH622f.css +1 -0
  133. package/dist/playground/index.html +2 -2
  134. package/dist/types.d.ts +22 -1
  135. package/dist/types.d.ts.map +1 -1
  136. package/docs/README.md +3 -0
  137. package/docs/deployment.md +2 -1
  138. package/docs/guides/github.md +79 -6
  139. package/docs/guides/opentelemetry.md +184 -0
  140. package/docs/reference/channels.md +3 -1
  141. package/docs/reference/hooks.md +21 -4
  142. package/docs/reference/project-layout.md +2 -0
  143. package/docs/templates/triage.md +147 -0
  144. package/package.json +23 -1
  145. package/skills/create-agent/SKILL.md +2 -2
  146. package/skills/framework-map/SKILL.md +2 -0
  147. package/skills/otel/SKILL.md +80 -0
  148. package/src/bin/agent-serve.ts +3 -1
  149. package/src/channels/github/api.ts +22 -0
  150. package/src/channels/github/defaults.ts +27 -6
  151. package/src/channels/github/github-channel.ts +27 -1
  152. package/src/channels/github/index.ts +1 -0
  153. package/src/channels/github/progress.ts +243 -0
  154. package/src/channels/github/state.ts +3 -0
  155. package/src/channels/github/types.ts +8 -4
  156. package/src/channels/slack/slack-channel.ts +4 -0
  157. package/src/index.ts +6 -0
  158. package/src/internal/cli-ax.ts +19 -1
  159. package/src/internal/discovery.ts +59 -4
  160. package/src/internal/distribution.ts +1 -0
  161. package/src/internal/init-project.ts +150 -7
  162. package/src/internal/otel/attrs.ts +18 -0
  163. package/src/internal/otel/collector.ts +796 -0
  164. package/src/internal/otel/config.ts +307 -0
  165. package/src/internal/otel/http.ts +126 -0
  166. package/src/internal/otel/runtime.ts +271 -0
  167. package/src/internal/server.ts +38 -1
  168. package/src/internal/session-engine.ts +51 -0
  169. package/src/memory.ts +4 -0
  170. package/src/otel.ts +155 -0
  171. package/src/types.ts +20 -1
  172. package/templates/triage/README.md +48 -0
  173. package/templates/triage/agent/agent.ts +14 -0
  174. package/templates/triage/agent/channels/intake.ts +20 -0
  175. package/templates/triage/agent/channels/slack.ts +3 -0
  176. package/templates/triage/agent/hooks/memory.ts +3 -0
  177. package/templates/triage/agent/instructions.md +27 -0
  178. package/templates/triage/agent/skills/triage-rubric.md +43 -0
  179. package/templates/triage/agent/tools/record_triage.ts +23 -0
  180. package/templates/triage/evals/evals.config.ts +5 -0
  181. package/templates/triage/evals/triage.eval.ts +43 -0
  182. package/templates/triage/package.json +18 -0
  183. package/templates/triage/tsconfig.json +12 -0
  184. package/dist/docs/assets/chunks/@localSearchIndexroot.BlU3A8EB.js +0 -1
  185. package/dist/playground/assets/index-Bqk9nplh.css +0 -1
  186. /package/dist/docs/assets/{deployment.md.BHVjVqRa.lean.js → deployment.md.Cdp4rTE4.lean.js} +0 -0
  187. /package/dist/docs/assets/{index.md.BKpbkCa6.lean.js → index.md.CMc5FP7E.lean.js} +0 -0
  188. /package/dist/docs/assets/{reference_channels.md.BIabFUAI.lean.js → reference_channels.md.MN8iDy8V.lean.js} +0 -0
  189. /package/dist/docs/assets/{reference_project-layout.md._XdeMahr.lean.js → reference_project-layout.md.D3MdHM2z.lean.js} +0 -0
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Opt-in PR progress surfaces: commit status + sticky banner comment.
3
+ */
4
+
5
+ import {
6
+ createGitHubCommitStatus,
7
+ createGitHubIssueComment,
8
+ GitHubApiError,
9
+ updateGitHubIssueComment,
10
+ } from "./api.js";
11
+ import type { GitHubBindingConfig } from "./binding.js";
12
+ import { formatGitHubOutboundComment } from "./binding.js";
13
+ import type { GitHubChannelState } from "./state.js";
14
+
15
+ /** GitHub commit-status descriptions are capped at 140 characters. */
16
+ const STATUS_DESCRIPTION_MAX = 140;
17
+
18
+ export type GitHubProgressPhase = "pending" | "success" | "failure";
19
+
20
+ export interface GitHubProgressPhaseCopy {
21
+ pending?: string;
22
+ success?: string;
23
+ failure?: string;
24
+ }
25
+
26
+ export interface GitHubCommitStatusProgress extends GitHubProgressPhaseCopy {
27
+ /** Commit status context (unique per check in the merge box). */
28
+ context: string;
29
+ }
30
+
31
+ export type GitHubBannerProgress = GitHubProgressPhaseCopy;
32
+
33
+ export interface GitHubProgressConfig {
34
+ /** When false, skip the eyes reaction on turn.started. Defaults to true. */
35
+ reactions?: boolean;
36
+ /**
37
+ * Opt-in commit status on the PR head. Omit or `false` keeps today's
38
+ * behavior (no statuses from default events). With `cursorAccount`,
39
+ * needs `permissions: "contents-write"` (push-equivalent).
40
+ */
41
+ commitStatus?: false | GitHubCommitStatusProgress;
42
+ /**
43
+ * Opt-in sticky PR/issue timeline comment. Created on first pending,
44
+ * PATCHed on later phases. Omit or `false` disables.
45
+ */
46
+ banner?: false | GitHubBannerProgress;
47
+ }
48
+
49
+ export interface GitHubProgressOptions extends GitHubBindingConfig {
50
+ botName?: string;
51
+ progress?: GitHubProgressConfig;
52
+ }
53
+
54
+ export function resolveCommitStatusProgress(
55
+ progress: GitHubProgressConfig | undefined
56
+ ): GitHubCommitStatusProgress | null {
57
+ if (progress?.commitStatus === undefined || progress.commitStatus === false) {
58
+ return null;
59
+ }
60
+ return progress.commitStatus;
61
+ }
62
+
63
+ export function resolveBannerProgress(
64
+ progress: GitHubProgressConfig | undefined
65
+ ): GitHubBannerProgress | null {
66
+ if (progress?.banner === undefined || progress.banner === false) {
67
+ return null;
68
+ }
69
+ return progress.banner;
70
+ }
71
+
72
+ export function progressPhaseCopy(input: {
73
+ copy: GitHubProgressPhaseCopy | undefined;
74
+ phase: GitHubProgressPhase;
75
+ label: string;
76
+ }): string {
77
+ const custom = input.copy?.[input.phase];
78
+ if (custom !== undefined && custom.trim() !== "") {
79
+ return custom;
80
+ }
81
+ switch (input.phase) {
82
+ case "pending":
83
+ return `${input.label} running`;
84
+ case "success":
85
+ return `${input.label} finished`;
86
+ case "failure":
87
+ return `${input.label} failed`;
88
+ }
89
+ }
90
+
91
+ function clipStatusDescription(text: string): string {
92
+ if (text.length <= STATUS_DESCRIPTION_MAX) {
93
+ return text;
94
+ }
95
+ return `${text.slice(0, STATUS_DESCRIPTION_MAX - 1)}…`;
96
+ }
97
+
98
+ function progressLabel(
99
+ options: GitHubProgressOptions,
100
+ context?: string
101
+ ): string {
102
+ const bot = options.botName?.trim();
103
+ if (bot !== undefined && bot !== "") {
104
+ return bot;
105
+ }
106
+ if (context !== undefined && context.trim() !== "") {
107
+ return context;
108
+ }
109
+ return "Agent";
110
+ }
111
+
112
+ /**
113
+ * Post or update opt-in progress surfaces for a turn phase.
114
+ * Soft-fails on API errors (same posture as eyes / reply delivery).
115
+ */
116
+ export async function applyGitHubProgress(input: {
117
+ phase: GitHubProgressPhase;
118
+ channel: { state: GitHubChannelState };
119
+ options: GitHubProgressOptions;
120
+ }): Promise<void> {
121
+ const commitStatus = resolveCommitStatusProgress(input.options.progress);
122
+ const banner = resolveBannerProgress(input.options.progress);
123
+ if (commitStatus === null && banner === null) {
124
+ return;
125
+ }
126
+
127
+ const tasks: Array<Promise<void>> = [];
128
+ if (commitStatus !== null) {
129
+ tasks.push(
130
+ postCommitStatus({
131
+ phase: input.phase,
132
+ channel: input.channel,
133
+ options: input.options,
134
+ commitStatus,
135
+ })
136
+ );
137
+ }
138
+ if (banner !== null) {
139
+ tasks.push(
140
+ upsertBanner({
141
+ phase: input.phase,
142
+ channel: input.channel,
143
+ options: input.options,
144
+ banner,
145
+ context: commitStatus?.context,
146
+ })
147
+ );
148
+ }
149
+ await Promise.all(tasks);
150
+ }
151
+
152
+ async function postCommitStatus(input: {
153
+ phase: GitHubProgressPhase;
154
+ channel: { state: GitHubChannelState };
155
+ options: GitHubProgressOptions;
156
+ commitStatus: GitHubCommitStatusProgress;
157
+ }): Promise<void> {
158
+ const state = input.channel.state;
159
+ if (
160
+ state.owner === "" ||
161
+ state.repo === "" ||
162
+ state.headSha === null ||
163
+ state.headSha === ""
164
+ ) {
165
+ return;
166
+ }
167
+ const description = clipStatusDescription(
168
+ progressPhaseCopy({
169
+ copy: input.commitStatus,
170
+ phase: input.phase,
171
+ label: progressLabel(input.options, input.commitStatus.context),
172
+ })
173
+ );
174
+ try {
175
+ await createGitHubCommitStatus({
176
+ api: input.options.api,
177
+ credentials: input.options.credentials,
178
+ installationId: state.installationId ?? undefined,
179
+ owner: state.owner,
180
+ repo: state.repo,
181
+ sha: state.headSha,
182
+ state: input.phase,
183
+ context: input.commitStatus.context,
184
+ description,
185
+ });
186
+ } catch {
187
+ // Soft-fail: missing token / permission is fine.
188
+ }
189
+ }
190
+
191
+ async function upsertBanner(input: {
192
+ phase: GitHubProgressPhase;
193
+ channel: { state: GitHubChannelState };
194
+ options: GitHubProgressOptions;
195
+ banner: GitHubBannerProgress;
196
+ context?: string;
197
+ }): Promise<void> {
198
+ const state = input.channel.state;
199
+ const issueNumber = state.issueNumber ?? state.pullRequestNumber;
200
+ if (state.owner === "" || state.repo === "" || issueNumber === null) {
201
+ return;
202
+ }
203
+ const body = formatGitHubOutboundComment(
204
+ progressPhaseCopy({
205
+ copy: input.banner,
206
+ phase: input.phase,
207
+ label: progressLabel(input.options, input.context),
208
+ })
209
+ );
210
+ const resource = {
211
+ api: input.options.api,
212
+ credentials: input.options.credentials,
213
+ installationId: state.installationId ?? undefined,
214
+ owner: state.owner,
215
+ repo: state.repo,
216
+ };
217
+ try {
218
+ if (state.progressBannerCommentId !== null) {
219
+ try {
220
+ await updateGitHubIssueComment({
221
+ ...resource,
222
+ body,
223
+ commentId: state.progressBannerCommentId,
224
+ });
225
+ return;
226
+ } catch (error) {
227
+ if (!(error instanceof GitHubApiError) || error.status !== 404) {
228
+ return;
229
+ }
230
+ // Comment gone; clear sticky id and recreate below.
231
+ state.progressBannerCommentId = null;
232
+ }
233
+ }
234
+ const posted = await createGitHubIssueComment({
235
+ ...resource,
236
+ body,
237
+ issueNumber,
238
+ });
239
+ state.progressBannerCommentId = posted.id;
240
+ } catch {
241
+ // Soft-fail.
242
+ }
243
+ }
@@ -11,6 +11,8 @@ export interface GitHubChannelState extends GitHubBindingState {
11
11
  headSha: string | null;
12
12
  baseRef: string | null;
13
13
  headRef: string | null;
14
+ /** Sticky progress banner comment id (issue/PR timeline). */
15
+ progressBannerCommentId: number | null;
14
16
  }
15
17
 
16
18
  export function emptyGitHubChannelState(
@@ -32,6 +34,7 @@ export function emptyGitHubChannelState(
32
34
  headSha: null,
33
35
  baseRef: null,
34
36
  headRef: null,
37
+ progressBannerCommentId: null,
35
38
  ...overrides,
36
39
  };
37
40
  }
@@ -9,7 +9,7 @@ import type {
9
9
  } from "../../types.js";
10
10
  import type { GitHubApiOptions } from "./api.js";
11
11
  import type { GitHubHandle, GitHubThread } from "./binding.js";
12
- import type { GitHubProgressConfig } from "./defaults.js";
12
+ import type { GitHubProgressConfig } from "./progress.js";
13
13
  import type { GitHubChannelState } from "./state.js";
14
14
 
15
15
  /** A credential value: a literal or a lazy resolver fetched on demand. */
@@ -448,7 +448,7 @@ export interface GitHubChannelOptions {
448
448
  * Token capability tier:
449
449
  * - `"read"` — PR/issue/status read
450
450
  * - `"pr-write"` (default) — comments / PR+issue write, no `contents:write`
451
- * - `"contents-write"` — also push code (host-held; prefer only when needed)
451
+ * - `"contents-write"` — push code and create commit statuses (host-held)
452
452
  */
453
453
  permissions?: "read" | "pr-write" | "contents-write";
454
454
  };
@@ -500,10 +500,14 @@ export interface GitHubChannelOptions {
500
500
  onEvent?: GitHubEventHook;
501
501
  /**
502
502
  * Override / extend default stream-event handlers (eyes reaction, reply
503
- * posting). Handlers you provide replace the matching defaults.
503
+ * posting, opt-in commit status / banner). Handlers you provide replace
504
+ * the matching defaults.
504
505
  */
505
506
  events?: ChannelEventHandlers<GitHubChannelState>;
506
- /** Acknowledgement progress surfaces (reactions). */
507
+ /**
508
+ * Acknowledgement progress surfaces. Reactions default on; commit status
509
+ * and sticky banner are opt-in via `commitStatus` / `banner`.
510
+ */
507
511
  progress?: GitHubProgressConfig;
508
512
  /**
509
513
  * When false, skip posting assistant / error comments back to GitHub.
@@ -117,6 +117,10 @@ export function resolveDedicatedSlackHostBinding(
117
117
  /**
118
118
  * Create a Slack channel. Author as `agent/channels/slack.ts` default export.
119
119
  *
120
+ * Missing credentials are not an error: without a token pair (or a
121
+ * signed-in host for `cursorAccount`) the channel mounts idle and logs
122
+ * `channel idle`, so serving an agent never blocks on Slack setup.
123
+ *
120
124
  * When `cursorAccount` is on, `agentName` must be a single token (no
121
125
  * whitespace) — string literals with spaces fail at the type level;
122
126
  * runtime values are still checked by {@link assertSlackCursorAgentName}.
package/src/index.ts CHANGED
@@ -104,6 +104,12 @@ export {
104
104
  fileMemoryBackend,
105
105
  memoryHook,
106
106
  } from "./memory.js";
107
+ export type {
108
+ OtelConfig,
109
+ OtelDefinition,
110
+ OtelExporterConfig,
111
+ } from "./otel.js";
112
+ export { defineOtel } from "./otel.js";
107
113
  export type { PromptTag } from "./prompt.js";
108
114
  export { prompt } from "./prompt.js";
109
115
  export type {
@@ -41,6 +41,7 @@ import {
41
41
  startRemoteEvalRun,
42
42
  } from "./evals-client.js";
43
43
  import {
44
+ checkInitTarget,
44
45
  formatInitNextSteps,
45
46
  formatInitScaffoldSummary,
46
47
  initNextCommands,
@@ -48,6 +49,7 @@ import {
48
49
  installScaffoldDependencies,
49
50
  linkCliOntoPath,
50
51
  printInitGuide,
52
+ resolveTemplate,
51
53
  } from "./init-project.js";
52
54
  import { offerInstallCursorSkills } from "./install-cursor-skills.js";
53
55
  import { runLogsTail, sanitizeCustomerError } from "./logs-client.js";
@@ -131,6 +133,7 @@ export interface AxCliOptions {
131
133
  out?: string;
132
134
  /** Scaffold target directory for `init`. */
133
135
  initTarget?: string;
136
+ template?: string;
134
137
  /** Tool name for `call`. */
135
138
  toolName?: string;
136
139
  /** JSON input for `call`. */
@@ -288,9 +291,23 @@ export async function cmdInit(options: AxCliOptions): Promise<number> {
288
291
  printInitGuide();
289
292
  return 0;
290
293
  }
294
+ let templateDir: string | undefined;
295
+ if (options.template !== undefined) {
296
+ const template = resolveTemplate(options.template);
297
+ if (!template.ok) {
298
+ process.stderr.write(`${template.message}\n`);
299
+ return 1;
300
+ }
301
+ templateDir = template.dir;
302
+ }
291
303
  const cwd = options.cwd ?? process.cwd();
292
304
  const dir = resolve(cwd, target);
293
- const result = await initProject({ dir });
305
+ const targetCheck = checkInitTarget(dir, options.template);
306
+ if (!targetCheck.ok) {
307
+ process.stderr.write(`${targetCheck.message}\n`);
308
+ return 1;
309
+ }
310
+ const result = await initProject({ dir, templateDir });
294
311
  let signedIn = (await resolveApiKey()) !== undefined;
295
312
 
296
313
  // Machine-readable path: install deps (piped), never block on browser login.
@@ -307,6 +324,7 @@ export async function cmdInit(options: AxCliOptions): Promise<number> {
307
324
  {
308
325
  ok: install.ok,
309
326
  directory: result.rootDir,
327
+ template: options.template ?? null,
310
328
  created: result.created,
311
329
  skipped: result.skipped,
312
330
  installed: install.ok,
@@ -20,6 +20,7 @@ import { pathToFileURL } from "node:url";
20
20
  import { type ABConfigFile, resolveABMaxPlaygroundSessions } from "../ab.js";
21
21
  import { resolveArtifactsMax } from "../artifacts.js";
22
22
  import { httpChannel } from "../channels.js";
23
+ import type { OtelDefinition } from "../otel.js";
23
24
  import type { StorageDefinition } from "../storage.js";
24
25
  import {
25
26
  type AgentConcurrencyOptions,
@@ -300,6 +301,7 @@ export async function loadAgentProject(
300
301
  const abConfig = await loadABConfig(ctx, agentDir);
301
302
  const storage = await loadStorage(ctx, agentDir);
302
303
  const artifacts = await loadArtifacts(ctx, agentDir);
304
+ const otel = await loadOtel(ctx, agentDir);
303
305
  await appendArtifactTool(ctx, agentDir, agent, artifacts);
304
306
 
305
307
  if (agentDir !== rootDir) {
@@ -319,6 +321,7 @@ export async function loadAgentProject(
319
321
  abConfig,
320
322
  storage,
321
323
  artifacts,
324
+ otel,
322
325
  diagnostics,
323
326
  };
324
327
  }
@@ -1718,6 +1721,22 @@ async function loadStorage(
1718
1721
  return definition as StorageDefinition | undefined;
1719
1722
  }
1720
1723
 
1724
+ // ============================================================================
1725
+ // OpenTelemetry (agent/otel.ts)
1726
+ // ============================================================================
1727
+
1728
+ async function loadOtel(
1729
+ ctx: DiscoveryContext,
1730
+ agentDir: string
1731
+ ): Promise<OtelDefinition | undefined> {
1732
+ const path = await findModuleFile(agentDir, "otel");
1733
+ if (path === undefined) {
1734
+ return undefined;
1735
+ }
1736
+ const definition = await importDefault(ctx, path, "otel");
1737
+ return definition as OtelDefinition | undefined;
1738
+ }
1739
+
1721
1740
  // ============================================================================
1722
1741
  // Artifacts (agent/artifacts.ts)
1723
1742
  // ============================================================================
@@ -1973,6 +1992,13 @@ export function projectInfo(project: AgentProject): AgentProjectInfo {
1973
1992
  agentTool: project.artifacts.agentTool === true,
1974
1993
  max: resolveArtifactsMax(project.artifacts),
1975
1994
  },
1995
+ otel:
1996
+ project.otel === undefined
1997
+ ? undefined
1998
+ : {
1999
+ enabled: true as const,
2000
+ serviceName: project.otel.serviceName,
2001
+ },
1976
2002
  diagnostics: project.diagnostics,
1977
2003
  };
1978
2004
  }
@@ -1994,6 +2020,7 @@ async function importDefault(
1994
2020
  | "ab"
1995
2021
  | "storage"
1996
2022
  | "artifacts"
2023
+ | "otel"
1997
2024
  ): Promise<unknown> {
1998
2025
  let mod: Record<string, unknown>;
1999
2026
  try {
@@ -2008,10 +2035,7 @@ async function importDefault(
2008
2035
  }
2009
2036
  const kind = getDefinitionKind(mod.default);
2010
2037
  if (kind !== expectedKind) {
2011
- const helper =
2012
- expectedKind === "ab"
2013
- ? "defineAB"
2014
- : `define${expectedKind[0]?.toUpperCase()}${expectedKind.slice(1)}`;
2038
+ const helper = DEFINE_HELPER_NAME[expectedKind];
2015
2039
  ctx.diagnostics.push({
2016
2040
  severity: "error",
2017
2041
  path: displayPath(ctx, modulePath),
@@ -2025,6 +2049,37 @@ async function importDefault(
2025
2049
  return mod.default;
2026
2050
  }
2027
2051
 
2052
+ const DEFINE_HELPER_NAME: Record<
2053
+ | "agent"
2054
+ | "instructions"
2055
+ | "tool"
2056
+ | "skill"
2057
+ | "connection"
2058
+ | "channel"
2059
+ | "http-channel"
2060
+ | "schedule"
2061
+ | "hook"
2062
+ | "ab"
2063
+ | "storage"
2064
+ | "artifacts"
2065
+ | "otel",
2066
+ string
2067
+ > = {
2068
+ agent: "defineAgent",
2069
+ instructions: "defineInstructions",
2070
+ tool: "defineTool",
2071
+ skill: "defineSkill",
2072
+ connection: "defineConnection",
2073
+ channel: "defineChannel",
2074
+ "http-channel": "httpChannel",
2075
+ schedule: "defineSchedule",
2076
+ hook: "defineHook",
2077
+ ab: "defineAB",
2078
+ storage: "defineStorage",
2079
+ artifacts: "defineArtifacts",
2080
+ otel: "defineOtel",
2081
+ };
2082
+
2028
2083
  async function warnUnknownSlots(
2029
2084
  ctx: DiscoveryContext,
2030
2085
  agentDir: string
@@ -114,4 +114,5 @@ export const AUTHORING_ENTRY_FILES: ReadonlyArray<
114
114
  ["storage", "storage.js"],
115
115
  ["storage/file-kv", "storage-backends/file-kv.js"],
116
116
  ["storage/cursor-hosted", "storage-backends/cursor-hosted.js"],
117
+ ["otel", "otel.js"],
117
118
  ];