spets 0.1.5 → 0.1.7

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.js +109 -61
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1069,6 +1069,7 @@ var GitHubPlatform = class extends BasePlatform {
1069
1069
  config;
1070
1070
  currentTaskId;
1071
1071
  currentOutputPath;
1072
+ lastQuestions;
1072
1073
  constructor(config) {
1073
1074
  super();
1074
1075
  this.config = config;
@@ -1076,12 +1077,16 @@ var GitHubPlatform = class extends BasePlatform {
1076
1077
  setTaskId(taskId) {
1077
1078
  this.currentTaskId = taskId;
1078
1079
  }
1080
+ setBranch(branch) {
1081
+ this.config.branch = branch;
1082
+ }
1079
1083
  async generateDocument(context) {
1080
1084
  this.currentTaskId = context.taskId;
1081
1085
  this.currentOutputPath = context.outputPath;
1082
1086
  const prompt = this.buildPrompt(context);
1083
1087
  const response = await this.callClaude(prompt);
1084
1088
  const { document, questions } = this.parseResponse(response);
1089
+ this.lastQuestions = questions;
1085
1090
  return { document, questions };
1086
1091
  }
1087
1092
  async askUser(questions) {
@@ -1092,7 +1097,7 @@ var GitHubPlatform = class extends BasePlatform {
1092
1097
  throw new PauseForInputError("questions", questions);
1093
1098
  }
1094
1099
  async requestApproval(doc, stepName) {
1095
- const comment = this.formatApprovalComment(doc, stepName, this.currentTaskId, this.currentOutputPath);
1100
+ const comment = this.formatApprovalComment(doc, stepName, this.currentTaskId, this.currentOutputPath, this.lastQuestions);
1096
1101
  await this.postComment(comment);
1097
1102
  console.log("\n\u23F8\uFE0F Waiting for approval on GitHub...");
1098
1103
  console.log(" Comment /approve, /revise <feedback>, or /reject on the PR/Issue.");
@@ -1143,36 +1148,59 @@ var GitHubPlatform = class extends BasePlatform {
1143
1148
  lines.push("```");
1144
1149
  return lines.join("\n");
1145
1150
  }
1146
- formatApprovalComment(doc, stepName, taskId, outputPath) {
1151
+ formatApprovalComment(doc, stepName, taskId, outputPath, openQuestions) {
1147
1152
  const relativePath = outputPath ? outputPath.replace(process.cwd() + "/", "") : `.spets/outputs/${taskId}/${stepName}.md`;
1153
+ const { owner, repo, branch } = this.config;
1154
+ const fileLink = branch ? `[\`${relativePath}\`](https://github.com/${owner}/${repo}/blob/${branch}/${relativePath})` : `\`${relativePath}\``;
1155
+ const escapedDoc = doc.replace(/```/g, "\\`\\`\\`");
1148
1156
  const lines = [
1149
1157
  `## \u{1F4C4} Spets: ${stepName} - Review Required`,
1150
1158
  "",
1151
1159
  `> Task ID: \`${taskId}\``,
1152
- `> Output: \`${relativePath}\``,
1160
+ `> Output: ${fileLink}`,
1153
1161
  "",
1154
1162
  "<details>",
1155
1163
  "<summary>\u{1F4DD} View Document</summary>",
1156
1164
  "",
1157
- "```markdown",
1158
- doc,
1159
- "```",
1160
- "",
1161
- "</details>",
1162
- "",
1163
- "---",
1164
- "",
1165
- "**Commands:**",
1166
- "| Command | Description |",
1167
- "|---------|-------------|",
1168
- "| `/approve` | Approve and continue to next step |",
1169
- "| `/approve --pr` | Approve and create a Pull Request |",
1170
- "| `/approve --issue` | Approve and create/update an Issue |",
1171
- "| `/revise <feedback>` | Request changes with feedback |",
1172
- "| `/reject` | Reject and stop workflow |",
1165
+ escapedDoc,
1173
1166
  "",
1174
- "Example: `/revise Please add more details about error handling`"
1167
+ "</details>"
1175
1168
  ];
1169
+ if (openQuestions && openQuestions.length > 0) {
1170
+ lines.push("");
1171
+ lines.push("---");
1172
+ lines.push("");
1173
+ lines.push("### \u2753 Open Questions");
1174
+ lines.push("");
1175
+ for (let i = 0; i < openQuestions.length; i++) {
1176
+ const q = openQuestions[i];
1177
+ lines.push(`**Q${i + 1}:** ${q.question}`);
1178
+ if (q.context) {
1179
+ lines.push(`> ${q.context}`);
1180
+ }
1181
+ lines.push("");
1182
+ }
1183
+ lines.push("**To answer questions:**");
1184
+ lines.push("```");
1185
+ lines.push("/answer");
1186
+ for (let i = 0; i < openQuestions.length; i++) {
1187
+ lines.push(`Q${i + 1}: <your answer>`);
1188
+ }
1189
+ lines.push("```");
1190
+ }
1191
+ lines.push("");
1192
+ lines.push("---");
1193
+ lines.push("");
1194
+ lines.push("**Commands:**");
1195
+ lines.push("| Command | Description |");
1196
+ lines.push("|---------|-------------|");
1197
+ lines.push("| `/approve` | Approve and continue to next step |");
1198
+ lines.push("| `/approve --pr` | Approve and create a Pull Request |");
1199
+ lines.push("| `/approve --issue` | Approve and create/update an Issue |");
1200
+ lines.push("| `/revise <feedback>` | Request changes with feedback |");
1201
+ lines.push("| `/reject` | Reject and stop workflow |");
1202
+ lines.push("");
1203
+ lines.push("Example: `/revise Please add more details about error handling`");
1176
1204
  return lines.join("\n");
1177
1205
  }
1178
1206
  async postPRComment(body) {
@@ -1346,6 +1374,13 @@ _Managed by [Spets](https://github.com/eatnug/spets)_`;
1346
1374
  }
1347
1375
  return parseInt(match[1], 10);
1348
1376
  }
1377
+ function getCurrentBranch() {
1378
+ try {
1379
+ return execSync3("git branch --show-current", { encoding: "utf-8" }).trim() || void 0;
1380
+ } catch {
1381
+ return void 0;
1382
+ }
1383
+ }
1349
1384
  function findLinkedIssueOrPR(info) {
1350
1385
  try {
1351
1386
  const result = execSync3(
@@ -1415,7 +1450,8 @@ async function startCommand(query, options) {
1415
1450
  owner: githubInfo.owner,
1416
1451
  repo: githubInfo.repo,
1417
1452
  prNumber,
1418
- issueNumber
1453
+ issueNumber,
1454
+ branch: getCurrentBranch()
1419
1455
  });
1420
1456
  console.log(`Starting workflow: ${taskId}`);
1421
1457
  console.log(`Query: ${query}`);
@@ -1807,6 +1843,13 @@ function getGitHubInfo2(cwd) {
1807
1843
  }
1808
1844
  return null;
1809
1845
  }
1846
+ function getCurrentBranch2(cwd) {
1847
+ try {
1848
+ return execSync4("git branch --show-current", { encoding: "utf-8", cwd }).trim();
1849
+ } catch {
1850
+ return void 0;
1851
+ }
1852
+ }
1810
1853
  async function githubCommand(options) {
1811
1854
  const cwd = process.cwd();
1812
1855
  if (!spetsExists(cwd)) {
@@ -1832,9 +1875,20 @@ async function githubCommand(options) {
1832
1875
  console.log(`Received command: ${parsed.command}`);
1833
1876
  let taskId = task;
1834
1877
  if (!taskId) {
1835
- const taskMatch = comment.match(/Task ID: `([^`]+)`/);
1836
- if (taskMatch) {
1837
- taskId = taskMatch[1];
1878
+ try {
1879
+ const issueNum = issue || pr;
1880
+ if (issueNum) {
1881
+ const commentsJson = execSync4(
1882
+ `gh api repos/${owner}/${repo}/issues/${issueNum}/comments --jq '.[].body'`,
1883
+ { encoding: "utf-8" }
1884
+ );
1885
+ const taskMatch = commentsJson.match(/Task ID: `([^`]+)`/);
1886
+ if (taskMatch) {
1887
+ taskId = taskMatch[1];
1888
+ console.log(`Found Task ID from Issue comments: ${taskId}`);
1889
+ }
1890
+ }
1891
+ } catch {
1838
1892
  }
1839
1893
  }
1840
1894
  if (!taskId) {
@@ -1866,16 +1920,15 @@ async function githubCommand(options) {
1866
1920
  owner,
1867
1921
  repo,
1868
1922
  prNumber: pr ? parseInt(pr, 10) : void 0,
1869
- issueNumber: issue ? parseInt(issue, 10) : void 0
1923
+ issueNumber: issue ? parseInt(issue, 10) : void 0,
1924
+ branch: getCurrentBranch2(cwd)
1870
1925
  };
1871
1926
  switch (parsed.command) {
1872
1927
  case "approve": {
1873
1928
  console.log(`Approving step: ${state.currentStepName}`);
1874
1929
  updateDocumentStatus(outputPath, "approved");
1875
1930
  if (parsed.createPR) {
1876
- console.log("Creating Pull Request...");
1877
- const prNumber = await createPullRequest(githubConfig, taskId, userQuery, state.currentStepName);
1878
- console.log(`Created PR #${prNumber}`);
1931
+ console.log("PR will be created after changes are committed.");
1879
1932
  }
1880
1933
  if (parsed.createIssue) {
1881
1934
  console.log("Creating/Updating Issue...");
@@ -1972,32 +2025,8 @@ async function postComment(config, body) {
1972
2025
  proc.on("error", reject);
1973
2026
  });
1974
2027
  }
1975
- async function createPullRequest(config, taskId, userQuery, stepName) {
1976
- const { execSync: execSync5 } = await import("child_process");
1977
- const { owner, repo } = config;
1978
- const title = userQuery.slice(0, 50) + (userQuery.length > 50 ? "..." : "");
1979
- const body = `## Spets Workflow
1980
-
1981
- - Task ID: \`${taskId}\`
1982
- - Current Step: **${stepName}**
1983
-
1984
- ### Description
1985
- ${userQuery}
1986
-
1987
- ---
1988
- _Created by [Spets](https://github.com/eatnug/spets)_`;
1989
- const result = execSync5(
1990
- `gh pr create --repo ${owner}/${repo} --title "${title.replace(/"/g, '\\"')}" --body "${body.replace(/"/g, '\\"')}"`,
1991
- { encoding: "utf-8" }
1992
- );
1993
- const match = result.match(/\/pull\/(\d+)/);
1994
- if (!match) {
1995
- throw new Error("Failed to parse PR number from gh output");
1996
- }
1997
- return parseInt(match[1], 10);
1998
- }
1999
2028
  async function createOrUpdateIssue(config, taskId, userQuery, stepName) {
2000
- const { execSync: execSync5 } = await import("child_process");
2029
+ const { spawnSync } = await import("child_process");
2001
2030
  const { owner, repo, issueNumber } = config;
2002
2031
  const body = `## Spets Workflow Update
2003
2032
 
@@ -2010,16 +2039,35 @@ ${userQuery}
2010
2039
  ---
2011
2040
  _Updated by [Spets](https://github.com/eatnug/spets)_`;
2012
2041
  if (issueNumber) {
2013
- execSync5(
2014
- `gh issue comment ${issueNumber} --repo ${owner}/${repo} --body "${body.replace(/"/g, '\\"')}"`,
2015
- { encoding: "utf-8" }
2016
- );
2042
+ const result = spawnSync("gh", [
2043
+ "issue",
2044
+ "comment",
2045
+ String(issueNumber),
2046
+ "--repo",
2047
+ `${owner}/${repo}`,
2048
+ "--body",
2049
+ body
2050
+ ], { encoding: "utf-8" });
2051
+ if (result.status !== 0) {
2052
+ throw new Error(`Failed to comment on issue: ${result.stderr}`);
2053
+ }
2017
2054
  } else {
2018
2055
  const title = userQuery.slice(0, 50) + (userQuery.length > 50 ? "..." : "");
2019
- execSync5(
2020
- `gh issue create --repo ${owner}/${repo} --title "${title.replace(/"/g, '\\"')}" --body "${body.replace(/"/g, '\\"')}" --label spets`,
2021
- { encoding: "utf-8" }
2022
- );
2056
+ const result = spawnSync("gh", [
2057
+ "issue",
2058
+ "create",
2059
+ "--repo",
2060
+ `${owner}/${repo}`,
2061
+ "--title",
2062
+ title,
2063
+ "--body",
2064
+ body,
2065
+ "--label",
2066
+ "spets"
2067
+ ], { encoding: "utf-8" });
2068
+ if (result.status !== 0) {
2069
+ throw new Error(`Failed to create issue: ${result.stderr}`);
2070
+ }
2023
2071
  }
2024
2072
  }
2025
2073
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spets",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Spec Driven Development Execution Framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",