spets 0.1.65 → 0.1.67
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/index.js +101 -96
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -943,50 +943,32 @@ function buildClarifyPrompt(params) {
|
|
|
943
943
|
parts.push("");
|
|
944
944
|
parts.push(params.gatheredContext);
|
|
945
945
|
parts.push("");
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
parts.push(
|
|
952
|
-
parts.push(
|
|
953
|
-
parts.push("");
|
|
954
|
-
for (const entry of unresolvedEntries) {
|
|
955
|
-
parts.push(`**Original Question:** ${entry.question.question}`);
|
|
956
|
-
if (entry.question.context) {
|
|
957
|
-
parts.push(`Context: ${entry.question.context}`);
|
|
958
|
-
}
|
|
959
|
-
parts.push(`**User Response:** "${entry.answer.answer}"`);
|
|
960
|
-
parts.push("");
|
|
961
|
-
parts.push("\u2192 Re-ask this question with simpler language, concrete examples, or more context.");
|
|
962
|
-
parts.push("");
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
if (resolvedEntries.length > 0) {
|
|
966
|
-
parts.push("## Previous Questions & Answers");
|
|
967
|
-
parts.push("");
|
|
968
|
-
parts.push("The following questions have been resolved:");
|
|
969
|
-
parts.push("");
|
|
970
|
-
for (const entry of resolvedEntries) {
|
|
971
|
-
parts.push(`**Q: ${entry.question.question}**`);
|
|
972
|
-
if (entry.question.context) {
|
|
973
|
-
parts.push(`Context: ${entry.question.context}`);
|
|
974
|
-
}
|
|
975
|
-
parts.push(`A: ${entry.answer.answer}`);
|
|
976
|
-
parts.push("");
|
|
977
|
-
}
|
|
978
|
-
parts.push("Based on these answers, determine if there are still ambiguities that need clarification.");
|
|
979
|
-
parts.push("Do NOT repeat questions that have already been resolved.");
|
|
946
|
+
const hasQAHistory = params.previousQA && params.previousQA.length > 0;
|
|
947
|
+
if (hasQAHistory) {
|
|
948
|
+
parts.push("## Previous Q&A");
|
|
949
|
+
parts.push("");
|
|
950
|
+
for (const entry of params.previousQA) {
|
|
951
|
+
parts.push(`**Q:** ${entry.question.question}`);
|
|
952
|
+
parts.push(`**A:** ${entry.answer.answer}`);
|
|
980
953
|
parts.push("");
|
|
981
954
|
}
|
|
955
|
+
parts.push("## Your Task");
|
|
956
|
+
parts.push("");
|
|
957
|
+
parts.push("For each Q&A above, judge if the question is resolved:");
|
|
958
|
+
parts.push("- Clear answer \u2192 resolved, do NOT re-ask");
|
|
959
|
+
parts.push('- "you decide" / "\uC54C\uC544\uC11C \uD574" \u2192 resolved, use your judgment');
|
|
960
|
+
parts.push('- "give options" / "\uC635\uC158 \uC918" \u2192 NOT resolved, re-ask WITH concrete options');
|
|
961
|
+
parts.push("- Confused / unclear \u2192 NOT resolved, re-ask simpler");
|
|
962
|
+
parts.push("");
|
|
963
|
+
parts.push("Only output questions that are NOT resolved. Do NOT ask new questions.");
|
|
964
|
+
parts.push("");
|
|
965
|
+
} else {
|
|
966
|
+
parts.push("## Consider");
|
|
967
|
+
parts.push("");
|
|
968
|
+
parts.push("1. Is the task clear enough to proceed?");
|
|
969
|
+
parts.push("2. Are there ambiguities that need user decision?");
|
|
970
|
+
parts.push("");
|
|
982
971
|
}
|
|
983
|
-
parts.push("## Consider These Questions");
|
|
984
|
-
parts.push("");
|
|
985
|
-
parts.push("1. Is the task description clear enough to proceed?");
|
|
986
|
-
parts.push("2. Are there multiple valid approaches that need user decision?");
|
|
987
|
-
parts.push("3. Are there ambiguities that could lead to wrong implementation?");
|
|
988
|
-
parts.push("4. Are there missing requirements or constraints?");
|
|
989
|
-
parts.push("");
|
|
990
972
|
parts.push("## Output Format");
|
|
991
973
|
parts.push("");
|
|
992
974
|
parts.push("Output a JSON object with questions array:");
|
|
@@ -1655,30 +1637,10 @@ ${issues}`;
|
|
|
1655
1637
|
this.saveState(state);
|
|
1656
1638
|
return this.responsePhaseExecute(state);
|
|
1657
1639
|
}
|
|
1658
|
-
/**
|
|
1659
|
-
* Check if an answer indicates user confusion
|
|
1660
|
-
*/
|
|
1661
|
-
isConfusedAnswer(answer) {
|
|
1662
|
-
const confusionPatterns = [
|
|
1663
|
-
/don'?t understand/i,
|
|
1664
|
-
/not sure/i,
|
|
1665
|
-
/unclear/i,
|
|
1666
|
-
/what do you mean/i,
|
|
1667
|
-
/i'?m confused/i,
|
|
1668
|
-
/can you explain/i,
|
|
1669
|
-
/뭔 말/i,
|
|
1670
|
-
/이해가 안/i,
|
|
1671
|
-
/모르겠/i,
|
|
1672
|
-
/무슨 말/i,
|
|
1673
|
-
/잘 모르/i
|
|
1674
|
-
];
|
|
1675
|
-
return confusionPatterns.some((p) => p.test(answer));
|
|
1676
|
-
}
|
|
1677
1640
|
/**
|
|
1678
1641
|
* Human answered questions
|
|
1679
|
-
* -
|
|
1680
|
-
* -
|
|
1681
|
-
* - Re-ask unresolved questions until all are resolved
|
|
1642
|
+
* - Store Q&A in history
|
|
1643
|
+
* - Loop back to clarify phase - AI will judge if answers resolved the questions
|
|
1682
1644
|
*/
|
|
1683
1645
|
cmdClarified(taskId, answers) {
|
|
1684
1646
|
const state = this.loadState(taskId);
|
|
@@ -1686,23 +1648,11 @@ ${issues}`;
|
|
|
1686
1648
|
return this.responseError(`No workflow found: ${taskId}`, taskId);
|
|
1687
1649
|
}
|
|
1688
1650
|
const questions = state.questions || [];
|
|
1689
|
-
for (const answer of answers) {
|
|
1690
|
-
const question = questions.find((q) => q.id === answer.questionId);
|
|
1691
|
-
if (question) {
|
|
1692
|
-
question.resolved = !this.isConfusedAnswer(answer.answer);
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
1651
|
const newEntries = questions.map((q, i) => ({
|
|
1696
1652
|
question: q,
|
|
1697
1653
|
answer: answers[i] || { questionId: q.id, answer: "" }
|
|
1698
1654
|
}));
|
|
1699
1655
|
state.qaHistory = [...state.qaHistory || [], ...newEntries];
|
|
1700
|
-
const unresolvedQuestions = questions.filter((q) => !q.resolved);
|
|
1701
|
-
if (unresolvedQuestions.length > 0) {
|
|
1702
|
-
state.questions = unresolvedQuestions;
|
|
1703
|
-
this.saveState(state);
|
|
1704
|
-
return this.responseCheckpointClarify(state);
|
|
1705
|
-
}
|
|
1706
1656
|
state.questions = void 0;
|
|
1707
1657
|
state.answers = void 0;
|
|
1708
1658
|
state.status = "phase_clarify";
|
|
@@ -4146,6 +4096,54 @@ function outputError(error) {
|
|
|
4146
4096
|
console.log(JSON.stringify({ type: "error", error }, null, 2));
|
|
4147
4097
|
process.exit(1);
|
|
4148
4098
|
}
|
|
4099
|
+
function parseFlexibleJSON(json, options = {}) {
|
|
4100
|
+
const { expectArray = false, arrayKeys = [], defaultValue, allowStringFallback = false } = options;
|
|
4101
|
+
try {
|
|
4102
|
+
const parsed = JSON.parse(json);
|
|
4103
|
+
if (expectArray) {
|
|
4104
|
+
if (Array.isArray(parsed)) {
|
|
4105
|
+
return { success: true, data: parsed };
|
|
4106
|
+
}
|
|
4107
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
4108
|
+
for (const key of arrayKeys) {
|
|
4109
|
+
if (Array.isArray(parsed[key])) {
|
|
4110
|
+
return { success: true, data: parsed[key] };
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
for (const key of ["data", "items", "results", "list"]) {
|
|
4114
|
+
if (Array.isArray(parsed[key])) {
|
|
4115
|
+
return { success: true, data: parsed[key] };
|
|
4116
|
+
}
|
|
4117
|
+
}
|
|
4118
|
+
const values = Object.values(parsed);
|
|
4119
|
+
const arrays = values.filter(Array.isArray);
|
|
4120
|
+
if (arrays.length === 1) {
|
|
4121
|
+
return { success: true, data: arrays[0] };
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
return { success: true, data: [] };
|
|
4125
|
+
}
|
|
4126
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
4127
|
+
const keys = Object.keys(parsed);
|
|
4128
|
+
if (keys.length === 1) {
|
|
4129
|
+
const innerValue = parsed[keys[0]];
|
|
4130
|
+
if (typeof innerValue === "object" && innerValue !== null && !Array.isArray(innerValue)) {
|
|
4131
|
+
const innerKeys = Object.keys(innerValue);
|
|
4132
|
+
if (innerKeys.length > 1) {
|
|
4133
|
+
return { success: true, data: innerValue };
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
}
|
|
4137
|
+
return { success: true, data: parsed };
|
|
4138
|
+
}
|
|
4139
|
+
return { success: true, data: parsed };
|
|
4140
|
+
} catch {
|
|
4141
|
+
if (allowStringFallback && defaultValue !== void 0) {
|
|
4142
|
+
return { success: true, data: defaultValue };
|
|
4143
|
+
}
|
|
4144
|
+
return { success: false, error: "Invalid JSON format" };
|
|
4145
|
+
}
|
|
4146
|
+
}
|
|
4149
4147
|
async function orchestrateCommand(action, args) {
|
|
4150
4148
|
try {
|
|
4151
4149
|
const orchestrator = new Orchestrator();
|
|
@@ -4167,18 +4165,21 @@ async function orchestrateCommand(action, args) {
|
|
|
4167
4165
|
outputError("Task ID is required for explore-done");
|
|
4168
4166
|
return;
|
|
4169
4167
|
}
|
|
4170
|
-
|
|
4168
|
+
const defaultExplore = {
|
|
4171
4169
|
summary: "",
|
|
4172
4170
|
relevantFiles: [],
|
|
4173
4171
|
patterns: [],
|
|
4174
4172
|
constraints: [],
|
|
4175
4173
|
dependencies: []
|
|
4176
4174
|
};
|
|
4175
|
+
let exploreOutput = defaultExplore;
|
|
4177
4176
|
if (exploreJson) {
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4177
|
+
const parsed = parseFlexibleJSON(exploreJson, {
|
|
4178
|
+
allowStringFallback: true,
|
|
4179
|
+
defaultValue: { ...defaultExplore, summary: exploreJson }
|
|
4180
|
+
});
|
|
4181
|
+
if (parsed.success) {
|
|
4182
|
+
exploreOutput = { ...defaultExplore, ...parsed.data };
|
|
4182
4183
|
}
|
|
4183
4184
|
}
|
|
4184
4185
|
const result = orchestrator.cmdExploreDone(taskId, exploreOutput);
|
|
@@ -4194,13 +4195,15 @@ async function orchestrateCommand(action, args) {
|
|
|
4194
4195
|
}
|
|
4195
4196
|
let questions = [];
|
|
4196
4197
|
if (questionsJson) {
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
}
|
|
4201
|
-
|
|
4198
|
+
const parsed = parseFlexibleJSON(questionsJson, {
|
|
4199
|
+
expectArray: true,
|
|
4200
|
+
arrayKeys: ["questions"]
|
|
4201
|
+
});
|
|
4202
|
+
if (!parsed.success) {
|
|
4203
|
+
outputError(parsed.error);
|
|
4202
4204
|
return;
|
|
4203
4205
|
}
|
|
4206
|
+
questions = parsed.data;
|
|
4204
4207
|
}
|
|
4205
4208
|
const result = orchestrator.cmdClarifyDone(taskId, questions);
|
|
4206
4209
|
outputJSON(result);
|
|
@@ -4223,7 +4226,7 @@ async function orchestrateCommand(action, args) {
|
|
|
4223
4226
|
outputError("Task ID is required for verify-done");
|
|
4224
4227
|
return;
|
|
4225
4228
|
}
|
|
4226
|
-
|
|
4229
|
+
const defaultVerify = {
|
|
4227
4230
|
passed: false,
|
|
4228
4231
|
score: {
|
|
4229
4232
|
requirementsCoverage: 0,
|
|
@@ -4234,13 +4237,14 @@ async function orchestrateCommand(action, args) {
|
|
|
4234
4237
|
issues: [],
|
|
4235
4238
|
summary: ""
|
|
4236
4239
|
};
|
|
4240
|
+
let verifyOutput = defaultVerify;
|
|
4237
4241
|
if (verifyJson) {
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
outputError("Invalid JSON for verify output");
|
|
4242
|
+
const parsed = parseFlexibleJSON(verifyJson, {});
|
|
4243
|
+
if (!parsed.success) {
|
|
4244
|
+
outputError(parsed.error);
|
|
4242
4245
|
return;
|
|
4243
4246
|
}
|
|
4247
|
+
verifyOutput = { ...defaultVerify, ...parsed.data };
|
|
4244
4248
|
}
|
|
4245
4249
|
const result = orchestrator.cmdVerifyDone(taskId, verifyOutput);
|
|
4246
4250
|
outputJSON(result);
|
|
@@ -4253,14 +4257,15 @@ async function orchestrateCommand(action, args) {
|
|
|
4253
4257
|
outputError("Task ID and answers JSON are required for clarified");
|
|
4254
4258
|
return;
|
|
4255
4259
|
}
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
answers
|
|
4259
|
-
}
|
|
4260
|
-
|
|
4260
|
+
const parsed = parseFlexibleJSON(answersJson, {
|
|
4261
|
+
expectArray: true,
|
|
4262
|
+
arrayKeys: ["answers"]
|
|
4263
|
+
});
|
|
4264
|
+
if (!parsed.success) {
|
|
4265
|
+
outputError(parsed.error);
|
|
4261
4266
|
return;
|
|
4262
4267
|
}
|
|
4263
|
-
const result = orchestrator.cmdClarified(taskId,
|
|
4268
|
+
const result = orchestrator.cmdClarified(taskId, parsed.data);
|
|
4264
4269
|
outputJSON(result);
|
|
4265
4270
|
break;
|
|
4266
4271
|
}
|