@jive-ai/cli 0.0.47 → 0.0.49

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 (2) hide show
  1. package/dist/index.mjs +115 -18
  2. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -774,6 +774,7 @@ const queries = {
774
774
  gitBranch
775
775
  previewUrl
776
776
  autoApprove
777
+ linkedIssueNumber
777
778
  project {
778
779
  id
779
780
  name
@@ -1072,6 +1073,22 @@ const mutations = {
1072
1073
  }
1073
1074
  }
1074
1075
  }
1076
+ `),
1077
+ CommentCreate: graphql(`
1078
+ mutation CommentCreate($input: CreateCommentInput!) {
1079
+ commentCreate(input: $input) {
1080
+ success
1081
+ comment {
1082
+ id
1083
+ body
1084
+ htmlUrl
1085
+ }
1086
+ errors {
1087
+ message
1088
+ code
1089
+ }
1090
+ }
1091
+ }
1075
1092
  `),
1076
1093
  RegisterRunner: graphql(`
1077
1094
  mutation RegisterRunner($input: RegisterRunnerInput!) {
@@ -1539,7 +1556,8 @@ var ApiClient = class {
1539
1556
  description: data.task.description || "",
1540
1557
  status: data.task.status.toLowerCase().replace("_", "-"),
1541
1558
  gitBranch: data.task.gitBranch || "",
1542
- previewUrl: data.task.previewUrl || void 0
1559
+ previewUrl: data.task.previewUrl || void 0,
1560
+ linkedIssueNumber: data.task.linkedIssueNumber ?? null
1543
1561
  },
1544
1562
  plan: data.task.currentPlan ? {
1545
1563
  id: parseInt(data.task.currentPlan.id, 10),
@@ -1652,6 +1670,22 @@ var ApiClient = class {
1652
1670
  }
1653
1671
  };
1654
1672
  }
1673
+ async createComment(projectId, data) {
1674
+ const result = await (await getGraphQLClient()).request(mutations.CommentCreate, { input: {
1675
+ projectId: String(projectId),
1676
+ issueNumber: data.issueNumber,
1677
+ content: data.content
1678
+ } });
1679
+ if (result.commentCreate.errors?.length) throw this.formatError({ message: result.commentCreate.errors[0].message });
1680
+ return {
1681
+ success: result.commentCreate.success,
1682
+ comment: {
1683
+ id: result.commentCreate.comment.id,
1684
+ body: result.commentCreate.comment.body,
1685
+ htmlUrl: result.commentCreate.comment.htmlUrl
1686
+ }
1687
+ };
1688
+ }
1655
1689
  async getTaskSteps(id) {
1656
1690
  const data = await (await getGraphQLClient()).request(queries.GetPlan, { id: String(id) });
1657
1691
  if (!data.plan?.steps) return [];
@@ -2050,7 +2084,7 @@ async function createGraphQLClient() {
2050
2084
 
2051
2085
  //#endregion
2052
2086
  //#region package.json
2053
- var version = "0.0.47";
2087
+ var version = "0.0.49";
2054
2088
 
2055
2089
  //#endregion
2056
2090
  //#region src/runner/index.ts
@@ -2210,37 +2244,41 @@ var TaskRunner = class {
2210
2244
  }
2211
2245
  }
2212
2246
  async fetchTaskProcess(taskId) {
2213
- const existingProcess = this.taskProcesses[taskId.toString()];
2214
- if (existingProcess) return existingProcess;
2247
+ const key = taskId.toString();
2248
+ const existing = this.taskProcesses[key];
2249
+ if (existing) return existing;
2215
2250
  if (Object.values(this.taskProcesses).filter((p) => p !== null).length >= this.maxConcurrentTasks) {
2216
2251
  console.warn(chalk.yellow(`Maximum concurrent tasks reached (${this.maxConcurrentTasks})`));
2217
2252
  return null;
2218
2253
  }
2254
+ const initPromise = this.initTaskProcess(taskId);
2255
+ this.taskProcesses[key] = initPromise;
2256
+ const result = await initPromise;
2257
+ if (!result && this.taskProcesses[key] === initPromise) this.taskProcesses[key] = null;
2258
+ return result;
2259
+ }
2260
+ async initTaskProcess(taskId) {
2219
2261
  const ctx = await this.fetchTaskContext(taskId);
2220
2262
  if (!ctx) {
2221
2263
  console.error(chalk.red(`Failed to fetch context for task ${taskId}`));
2222
2264
  return null;
2223
2265
  }
2224
- return this.taskProcesses[taskId.toString()] = new Promise((resolve) => {
2225
- (this.config.type === "docker" ? spawnTaskDocker(ctx, this.config, {
2266
+ return {
2267
+ process: this.config.type === "docker" ? await spawnTaskDocker(ctx, this.config, {
2226
2268
  onMessage: (message) => this.onTaskMessage(ctx.taskId, message),
2227
2269
  onError: () => {},
2228
2270
  onClose: () => {
2229
2271
  this.taskProcesses[ctx.taskId.toString()] = null;
2230
2272
  }
2231
- }) : Promise.resolve(spawnTask(ctx, {
2273
+ }) : spawnTask(ctx, {
2232
2274
  onMessage: (message) => this.onTaskMessage(ctx.taskId, message),
2233
2275
  onError: () => {},
2234
2276
  onClose: () => {
2235
2277
  this.taskProcesses[ctx.taskId.toString()] = null;
2236
2278
  }
2237
- }))).then((process$1) => {
2238
- resolve({
2239
- process: process$1,
2240
- ctx
2241
- });
2242
- });
2243
- });
2279
+ }),
2280
+ ctx
2281
+ };
2244
2282
  }
2245
2283
  async sendToTask(taskId, message) {
2246
2284
  const result = await this.fetchTaskProcess(taskId);
@@ -2435,7 +2473,13 @@ var TaskRunner = class {
2435
2473
  `);
2436
2474
  const pendingTasks = (await client.request(query$1, { limit: availableSlots })).tasks.edges.map((e$2) => e$2.node);
2437
2475
  if (pendingTasks.length > 0) console.log(chalk.yellow(`Found ${pendingTasks.length} pending task(s) to pick up`));
2438
- for (const task of pendingTasks) await this.pickupPendingTask(parseInt(task.id));
2476
+ for (const task of pendingTasks) {
2477
+ if (this.taskProcesses[task.id]) {
2478
+ console.log(chalk.dim(`Task ${task.id} already managed, skipping`));
2479
+ continue;
2480
+ }
2481
+ await this.pickupPendingTask(parseInt(task.id));
2482
+ }
2439
2483
  } catch (error$1) {
2440
2484
  if (!error$1.message?.includes("Unable to connect")) console.error(chalk.red(`Failed to poll for pending tasks: ${error$1.message}`));
2441
2485
  }
@@ -2736,8 +2780,13 @@ function createTasksSdkServer(task) {
2736
2780
 
2737
2781
  If the next step contains a subagent, you must invoke the subagent for the next step.
2738
2782
 
2739
- If result contains \`isComplete: true\`, then the task is complete and you MUST create a pull request using the \`create_pull_request\` tool.
2740
- The user is expecting pull requests to be automatically created when the task is complete.
2783
+ If result contains \`isComplete: true\`, then the task is complete and you MUST add an issue comment using the \`add_issue_comment\` tool.
2784
+ The comment MUST include:
2785
+ - A very concise (1-2 sentence) description of the changes
2786
+ - A reference to the branch: ${task.branch}
2787
+ - A link to the task: https://getjive.app/app/tasks/${task.id}
2788
+
2789
+ The user is expecting issue comments to be automatically created when the task is complete.
2741
2790
  `, {
2742
2791
  stepId: z.number(),
2743
2792
  commitMessage: z.string().describe("Concise commit message describing changes"),
@@ -2801,6 +2850,51 @@ function createTasksSdkServer(task) {
2801
2850
  };
2802
2851
  }
2803
2852
  }),
2853
+ tool("add_issue_comment", "Add a comment to the linked issue on GitHub or GitLab. Use this to post updates, summaries, or task completion notices on the issue.", { content: z.string().describe("The comment body to post on the issue (supports markdown)") }, async (args) => {
2854
+ if (!context) return {
2855
+ content: [{
2856
+ type: "text",
2857
+ text: "Error: Task context not initialized"
2858
+ }],
2859
+ isError: true
2860
+ };
2861
+ try {
2862
+ const apiClient$1 = getApiClient();
2863
+ const { task: taskData, project } = await apiClient$1.getTask(context.taskId);
2864
+ if (!project) return {
2865
+ content: [{
2866
+ type: "text",
2867
+ text: "Error: Project not found for this task"
2868
+ }],
2869
+ isError: true
2870
+ };
2871
+ if (!taskData.linkedIssueNumber) return {
2872
+ content: [{
2873
+ type: "text",
2874
+ text: "Error: No linked issue found for this task. Cannot add comment."
2875
+ }],
2876
+ isError: true
2877
+ };
2878
+ task.debugLog(`Adding comment to issue #${taskData.linkedIssueNumber}`);
2879
+ const result = await apiClient$1.createComment(project.id, {
2880
+ issueNumber: taskData.linkedIssueNumber,
2881
+ content: args.content
2882
+ });
2883
+ task.debugLog(`Comment created: ${JSON.stringify(result, null, 2)}`);
2884
+ return { content: [{
2885
+ type: "text",
2886
+ text: `Comment posted successfully on issue #${taskData.linkedIssueNumber}!\n\nURL: ${result.comment.htmlUrl}`
2887
+ }] };
2888
+ } catch (error$1) {
2889
+ return {
2890
+ content: [{
2891
+ type: "text",
2892
+ text: `Error adding issue comment: ${error$1.message}`
2893
+ }],
2894
+ isError: true
2895
+ };
2896
+ }
2897
+ }),
2804
2898
  tool("create_issue", "Create an issue on GitHub or GitLab for the current project. Use this to track bugs, feature requests, or other work items.", {
2805
2899
  title: z.string().describe("Issue title - a concise summary of the issue"),
2806
2900
  body: z.string().describe("Issue body/description - detailed explanation of the issue"),
@@ -2899,7 +2993,7 @@ function createTasksSdkServer(task) {
2899
2993
  };
2900
2994
  }
2901
2995
  }),
2902
- tool("ask_user_question", "Ask the user clarifying questions. Returns immediately - answers will be provided in a follow-up message.", { questions: z.array(z.object({
2996
+ tool("ask_user_question", "USE THIS INSTEAD OF AskUserQuestion. Ask the user clarifying questions. Returns immediately - answers will be provided in a follow-up message.", { questions: z.array(z.object({
2903
2997
  question: z.string().describe("The question to ask"),
2904
2998
  header: z.string().describe("Short header/label for the question"),
2905
2999
  options: z.array(z.object({
@@ -3117,6 +3211,9 @@ var Task = class {
3117
3211
  }
3118
3212
  return tasksConfig.git.default_branch;
3119
3213
  }
3214
+ get branch() {
3215
+ return this.ctx.branch;
3216
+ }
3120
3217
  get projectId() {
3121
3218
  return this.ctx.projectId;
3122
3219
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@jive-ai/cli",
4
- "version": "0.0.47",
4
+ "version": "0.0.49",
5
5
  "main": "index.js",
6
6
  "files": [
7
7
  "dist",
@@ -15,7 +15,7 @@
15
15
  "test": "echo \"Error: no test specified\" && exit 1",
16
16
  "typecheck": "tsc --noEmit",
17
17
  "build": "tsdown && npm pack && npm install -g jive-ai-cli-*.tgz",
18
- "docker:clean": "docker rmi jiveai/task:latest jiveai/task:$npm_package_version",
18
+ "docker:clean": "docker rmi jiveai/task:latest jiveai/task:$npm_package_version || true",
19
19
  "docker:build": "bun run build && npm run docker:clean && .docker/build.sh",
20
20
  "docker:push": ".docker/build.sh --push",
21
21
  "prepublishOnly": "npm run typecheck && npm run build"
@@ -34,7 +34,7 @@
34
34
  "tsx": "^4.20.6"
35
35
  },
36
36
  "dependencies": {
37
- "@anthropic-ai/claude-agent-sdk": "^0.2.7",
37
+ "@anthropic-ai/claude-agent-sdk": "^0.2.39",
38
38
  "@modelcontextprotocol/sdk": "^1.22.0",
39
39
  "chalk": "^5.6.2",
40
40
  "change-case": "^5.4.4",