@sireai/optimus 0.1.1 → 0.1.2
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/cli/optimus.js +166 -40
- package/dist/cli/optimus.js.map +1 -1
- package/dist/cli/self-update.js +1 -1
- package/dist/config/load-config.js +1 -1
- package/dist/integrations/jira/jira-cli.js +49 -0
- package/dist/integrations/jira/jira-cli.js.map +1 -1
- package/dist/integrations/jira/jira-client.d.ts +16 -3
- package/dist/integrations/jira/jira-client.js +53 -14
- package/dist/integrations/jira/jira-client.js.map +1 -1
- package/dist/integrations/jira/jira-submit.js +2 -0
- package/dist/integrations/jira/jira-submit.js.map +1 -1
- package/dist/task-environment/intake/manual-problem-intake.js +3 -0
- package/dist/task-environment/intake/manual-problem-intake.js.map +1 -1
- package/dist/task-environment/intake/triage-rejection-feedback-service.d.ts +21 -0
- package/dist/task-environment/intake/triage-rejection-feedback-service.js +154 -0
- package/dist/task-environment/intake/triage-rejection-feedback-service.js.map +1 -0
- package/dist/task-environment/runtime/optimus-runtime.d.ts +3 -0
- package/dist/task-environment/runtime/optimus-runtime.js +5 -0
- package/dist/task-environment/runtime/optimus-runtime.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +3 -3
- package/task-harnesses/bugfix/ACCEPT.md +13 -0
package/dist/cli/optimus.js
CHANGED
|
@@ -33,6 +33,7 @@ const CLI_ROOT_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..", ".."
|
|
|
33
33
|
const PACKAGE_JSON_PATH = join(CLI_ROOT_DIR, "package.json");
|
|
34
34
|
const execFileAsync = promisify(execFile);
|
|
35
35
|
const PACKAGE_NAME = "@sireai/optimus";
|
|
36
|
+
const JIRA_CLI_ENTRY = join(CLI_ROOT_DIR, "dist", "integrations", "jira", "jira-cli.js");
|
|
36
37
|
function renderSetupResult(result) {
|
|
37
38
|
const lines = [];
|
|
38
39
|
lines.push("Setup Complete");
|
|
@@ -162,7 +163,7 @@ function renderCliHelp() {
|
|
|
162
163
|
"",
|
|
163
164
|
"Integration commands:",
|
|
164
165
|
" intake-status|intake-run|intake-disable|intake-enable|intake-reset-checkpoint",
|
|
165
|
-
" jira-search|jira-get-issue|jira-search-assigned-open|jira-submit-issue|jira-submit-assigned-open|jira-poll-once|jira-poll-daemon",
|
|
166
|
+
" jira-search|jira-get-issue|jira-search-assigned-open|jira-submit-issue|jira-submit-assigned-open|jira-add-comment|jira-poll-once|jira-poll-daemon",
|
|
166
167
|
"",
|
|
167
168
|
"Global options:",
|
|
168
169
|
" -h, --help Show this help",
|
|
@@ -173,24 +174,125 @@ function renderCliHelp() {
|
|
|
173
174
|
` - Run \`optimus setup\` once; Optimus stores config and runtime data under ${resolveOptimusHomeDir()}.`
|
|
174
175
|
].join("\n");
|
|
175
176
|
}
|
|
177
|
+
function mapJiraCommand(command) {
|
|
178
|
+
switch (command) {
|
|
179
|
+
case "jira-search":
|
|
180
|
+
return "search";
|
|
181
|
+
case "jira-get-issue":
|
|
182
|
+
return "get-issue";
|
|
183
|
+
case "jira-search-assigned-open":
|
|
184
|
+
return "search-assigned-open";
|
|
185
|
+
case "jira-submit-issue":
|
|
186
|
+
return "submit-issue";
|
|
187
|
+
case "jira-submit-assigned-open":
|
|
188
|
+
return "submit-assigned-open";
|
|
189
|
+
case "jira-add-comment":
|
|
190
|
+
return "add-comment";
|
|
191
|
+
case "jira-poll-once":
|
|
192
|
+
return "poll-once";
|
|
193
|
+
case "jira-poll-daemon":
|
|
194
|
+
return "poll-daemon";
|
|
195
|
+
default:
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function resolveJiraQuickDoctorIssues(config) {
|
|
200
|
+
const issues = [];
|
|
201
|
+
if (!config.baseUrl?.trim() || /jira\.example\.com/i.test(config.baseUrl)) {
|
|
202
|
+
issues.push({
|
|
203
|
+
code: "jira_base_url_missing",
|
|
204
|
+
message: "Jira integration is enabled, but Jira base URL is missing or still using the placeholder value.",
|
|
205
|
+
fix: "Rerun `optimus setup` and provide a real Jira base URL."
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
if (config.authType === "bearer") {
|
|
209
|
+
if (!config.bearerToken?.trim()) {
|
|
210
|
+
issues.push({
|
|
211
|
+
code: "jira_token_missing",
|
|
212
|
+
message: "Jira integration is enabled, but Jira bearer token is missing.",
|
|
213
|
+
fix: "Rerun `optimus setup` and provide a Jira token."
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return issues;
|
|
217
|
+
}
|
|
218
|
+
if (config.authType === "basic") {
|
|
219
|
+
if (!config.username?.trim() || !(config.apiToken?.trim() || config.password?.trim())) {
|
|
220
|
+
issues.push({
|
|
221
|
+
code: "jira_basic_auth_missing",
|
|
222
|
+
message: "Jira integration is enabled, but Jira basic auth credentials are incomplete.",
|
|
223
|
+
fix: "Provide Jira username plus api token or password, then rerun `optimus doctor --quick`."
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return issues;
|
|
227
|
+
}
|
|
228
|
+
if (!config.mcpUrl?.trim() || /jira-mcp\.example\.com/i.test(config.mcpUrl)) {
|
|
229
|
+
issues.push({
|
|
230
|
+
code: "jira_mcp_url_missing",
|
|
231
|
+
message: "Jira integration is enabled, but Jira MCP URL is missing or still using the placeholder value.",
|
|
232
|
+
fix: "Provide a real Jira MCP URL, then rerun `optimus doctor --quick`."
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
const requiredHeaders = [
|
|
236
|
+
"X-Atlassian-Jira-Url",
|
|
237
|
+
"X-Atlassian-Username",
|
|
238
|
+
"X-Atlassian-Jira-Personal-Token"
|
|
239
|
+
];
|
|
240
|
+
const missingHeaders = requiredHeaders.filter((name) => !config.httpHeaders[name]?.trim());
|
|
241
|
+
if (missingHeaders.length > 0) {
|
|
242
|
+
issues.push({
|
|
243
|
+
code: "jira_mcp_headers_missing",
|
|
244
|
+
message: `Jira integration is enabled, but Jira MCP headers are incomplete: ${missingHeaders.join(", ")}.`,
|
|
245
|
+
fix: "Provide the required Jira MCP headers, then rerun `optimus doctor --quick`."
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
return issues;
|
|
249
|
+
}
|
|
250
|
+
async function forwardJiraCliCommand(command, commandArgs) {
|
|
251
|
+
const mappedCommand = mapJiraCommand(command);
|
|
252
|
+
if (!mappedCommand) {
|
|
253
|
+
throw new Error(`Unsupported Jira command forwarding target: ${command}`);
|
|
254
|
+
}
|
|
255
|
+
const jiraCliEntry = process.env.OPTIMUS_JIRA_CLI_ENTRY?.trim() || JIRA_CLI_ENTRY;
|
|
256
|
+
return await new Promise((resolvePromise, rejectPromise) => {
|
|
257
|
+
const child = spawn(process.execPath, [jiraCliEntry, mappedCommand, ...commandArgs], {
|
|
258
|
+
cwd: process.cwd(),
|
|
259
|
+
env: process.env,
|
|
260
|
+
stdio: "inherit"
|
|
261
|
+
});
|
|
262
|
+
child.on("error", rejectPromise);
|
|
263
|
+
child.on("close", (code) => {
|
|
264
|
+
resolvePromise(code ?? 1);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
}
|
|
176
268
|
async function readPackageVersion() {
|
|
177
269
|
const raw = await readFile(PACKAGE_JSON_PATH, "utf8");
|
|
178
270
|
const parsed = JSON.parse(raw);
|
|
179
271
|
return parsed.version?.trim() || "0.0.0";
|
|
180
272
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
273
|
+
function isInteractiveSelfUpdatePromptAllowed() {
|
|
274
|
+
return Boolean(input.isTTY && output.isTTY);
|
|
275
|
+
}
|
|
276
|
+
async function promptForStartupSelfUpdate(currentVersion, latestVersion) {
|
|
277
|
+
const rl = createInterface({ input, output });
|
|
278
|
+
try {
|
|
279
|
+
console.log(`[optimus] update available ${currentVersion} -> ${latestVersion}.`);
|
|
280
|
+
console.log("1. Upgrade now and exit");
|
|
281
|
+
console.log("2. Continue with current version");
|
|
282
|
+
while (true) {
|
|
283
|
+
const answer = (await rl.question("Select [1/2] (default 2): ")).trim().toLowerCase();
|
|
284
|
+
if (!answer || answer === "2" || answer === "c" || answer === "continue") {
|
|
285
|
+
return "continue";
|
|
286
|
+
}
|
|
287
|
+
if (answer === "1" || answer === "u" || answer === "upgrade") {
|
|
288
|
+
return "upgrade";
|
|
289
|
+
}
|
|
290
|
+
console.log("Invalid selection. Enter 1 to upgrade or 2 to continue.");
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
finally {
|
|
294
|
+
rl.close();
|
|
295
|
+
}
|
|
194
296
|
}
|
|
195
297
|
async function maybeHandleStartupSelfUpdate(input) {
|
|
196
298
|
const check = await checkForSelfUpdate({
|
|
@@ -222,7 +324,28 @@ async function maybeHandleStartupSelfUpdate(input) {
|
|
|
222
324
|
if (!check.updateAvailable || !check.latestVersion) {
|
|
223
325
|
return { handled: false };
|
|
224
326
|
}
|
|
225
|
-
|
|
327
|
+
const selfUpdateConfig = input.config.selfUpdate ?? buildDefaultConfig().selfUpdate;
|
|
328
|
+
if (input.command !== "start") {
|
|
329
|
+
console.log(`[optimus] update available ${check.currentVersion} -> ${check.latestVersion}. Run \`optimus upgrade\`.`);
|
|
330
|
+
return { handled: false };
|
|
331
|
+
}
|
|
332
|
+
if (selfUpdateConfig.mode === "prompt") {
|
|
333
|
+
if (!isInteractiveSelfUpdatePromptAllowed()) {
|
|
334
|
+
console.log(`[optimus] update available ${check.currentVersion} -> ${check.latestVersion}. Run \`optimus upgrade\`.`);
|
|
335
|
+
return { handled: false };
|
|
336
|
+
}
|
|
337
|
+
const choice = await promptForStartupSelfUpdate(check.currentVersion, check.latestVersion);
|
|
338
|
+
await input.logger.info("self_update.prompt_resolved", {
|
|
339
|
+
command: input.command,
|
|
340
|
+
currentVersion: check.currentVersion,
|
|
341
|
+
latestVersion: check.latestVersion,
|
|
342
|
+
choice
|
|
343
|
+
});
|
|
344
|
+
if (choice === "continue") {
|
|
345
|
+
return { handled: false };
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
else if (selfUpdateConfig.mode !== "auto") {
|
|
226
349
|
console.log(`[optimus] update available ${check.currentVersion} -> ${check.latestVersion}. Run \`optimus upgrade\`.`);
|
|
227
350
|
return { handled: false };
|
|
228
351
|
}
|
|
@@ -245,7 +368,10 @@ async function maybeHandleStartupSelfUpdate(input) {
|
|
|
245
368
|
latestVersion: check.latestVersion,
|
|
246
369
|
reason: install.state.lastError ?? install.reason ?? "unknown"
|
|
247
370
|
});
|
|
248
|
-
console.log(`[optimus] upgrade failed
|
|
371
|
+
console.log(`[optimus] upgrade failed. Continue with ${check.currentVersion}, or run \`optimus upgrade\` after fixing npm access.`);
|
|
372
|
+
if (selfUpdateConfig.mode === "auto") {
|
|
373
|
+
return { handled: true, exitCode: 1 };
|
|
374
|
+
}
|
|
249
375
|
return { handled: false };
|
|
250
376
|
}
|
|
251
377
|
await input.logger.info("self_update.install_succeeded", {
|
|
@@ -253,10 +379,10 @@ async function maybeHandleStartupSelfUpdate(input) {
|
|
|
253
379
|
currentVersion: check.currentVersion,
|
|
254
380
|
latestVersion: check.latestVersion
|
|
255
381
|
});
|
|
256
|
-
console.log(`[optimus] upgrade succeeded
|
|
382
|
+
console.log(`[optimus] upgrade succeeded. Restart with \`optimus ${input.command}\`.`);
|
|
257
383
|
return {
|
|
258
384
|
handled: true,
|
|
259
|
-
exitCode:
|
|
385
|
+
exitCode: 0
|
|
260
386
|
};
|
|
261
387
|
}
|
|
262
388
|
async function pathExists(path) {
|
|
@@ -839,20 +965,9 @@ async function runQuickDoctor(configPath = resolveDefaultConfigPath()) {
|
|
|
839
965
|
});
|
|
840
966
|
}
|
|
841
967
|
if (config.jira.enabled) {
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
message: "Jira integration is enabled, but Jira base URL is missing or still using the placeholder value.",
|
|
846
|
-
fix: "Rerun `optimus setup` and provide a real Jira base URL."
|
|
847
|
-
});
|
|
848
|
-
next.add("optimus setup");
|
|
849
|
-
}
|
|
850
|
-
if (!config.jira.bearerToken?.trim()) {
|
|
851
|
-
blocking.push({
|
|
852
|
-
code: "jira_token_missing",
|
|
853
|
-
message: "Jira integration is enabled, but Jira token is missing.",
|
|
854
|
-
fix: "Rerun `optimus setup` and provide a Jira token."
|
|
855
|
-
});
|
|
968
|
+
const jiraIssues = resolveJiraQuickDoctorIssues(config.jira);
|
|
969
|
+
blocking.push(...jiraIssues);
|
|
970
|
+
if (jiraIssues.length > 0) {
|
|
856
971
|
next.add("optimus setup");
|
|
857
972
|
}
|
|
858
973
|
}
|
|
@@ -890,7 +1005,18 @@ async function runSetup(args) {
|
|
|
890
1005
|
if (!inspection.ok) {
|
|
891
1006
|
throw new Error(`Repository path is not usable: ${normalizedRepoPath} (${inspection.reason ?? "unknown"})`);
|
|
892
1007
|
}
|
|
893
|
-
const
|
|
1008
|
+
const preflightConfig = configExists ? await loadConfig(configPath) : buildDefaultConfig();
|
|
1009
|
+
const preflightStore = new SQLiteTaskStore(preflightConfig.storage.rootDir);
|
|
1010
|
+
await preflightStore.init();
|
|
1011
|
+
const existingRepositories = await preflightStore.listRepositoryRoots();
|
|
1012
|
+
const aliasConflict = existingRepositories.find((repository) => repository.alias === answers.repoAlias && repository.path !== normalizedRepoPath);
|
|
1013
|
+
if (aliasConflict) {
|
|
1014
|
+
throw new Error(`Repository alias already exists for another path: ${answers.repoAlias} -> ${aliasConflict.path}. `
|
|
1015
|
+
+ "Use `optimus repo update` or `optimus repo remove` before re-running setup.");
|
|
1016
|
+
}
|
|
1017
|
+
const existingRepository = existingRepositories.find((repository) => repository.path === normalizedRepoPath);
|
|
1018
|
+
const resolvedExecutionMode = existingRepository?.executionMode ?? describeRepositoryExecutionPlan({ executionMode: "copy" }, inspection).resolvedDefaultMode;
|
|
1019
|
+
const previewExecutionPlan = describeRepositoryExecutionPlan({ executionMode: resolvedExecutionMode }, inspection);
|
|
894
1020
|
const reviewSystem = await detectRepositoryReviewSystem(normalizedRepoPath, inspection);
|
|
895
1021
|
await mkdir(dirname(configPath), { recursive: true });
|
|
896
1022
|
await writeFile(configPath, `${buildSetupConfig({ ...answers, repoPath: normalizedRepoPath })}\n`, "utf8");
|
|
@@ -902,14 +1028,10 @@ async function runSetup(args) {
|
|
|
902
1028
|
const config = await loadConfig(configPath);
|
|
903
1029
|
const store = new SQLiteTaskStore(config.storage.rootDir);
|
|
904
1030
|
await store.init();
|
|
905
|
-
const existingRepositories = await store.listRepositoryRoots();
|
|
906
|
-
for (const repository of existingRepositories) {
|
|
907
|
-
await store.removeRepositoryRoot(repository.path);
|
|
908
|
-
}
|
|
909
1031
|
await store.addRepositoryRoot({
|
|
910
1032
|
path: normalizedRepoPath,
|
|
911
1033
|
alias: answers.repoAlias,
|
|
912
|
-
executionMode:
|
|
1034
|
+
executionMode: resolvedExecutionMode
|
|
913
1035
|
});
|
|
914
1036
|
const doctorQuick = await runQuickDoctor(configPath);
|
|
915
1037
|
const codexAuth = new CodexAuthResolver(config).resolve().diagnostics;
|
|
@@ -922,7 +1044,7 @@ async function runSetup(args) {
|
|
|
922
1044
|
path: normalizedRepoPath,
|
|
923
1045
|
alias: answers.repoAlias,
|
|
924
1046
|
workspaceKind: previewExecutionPlan.workspaceKind,
|
|
925
|
-
executionMode:
|
|
1047
|
+
executionMode: resolvedExecutionMode,
|
|
926
1048
|
reviewSystem
|
|
927
1049
|
},
|
|
928
1050
|
deliveryChannels: config.delivery.channels,
|
|
@@ -1187,6 +1309,10 @@ async function main() {
|
|
|
1187
1309
|
process.exitCode = result.doctorQuick.summary === "blocked" ? 1 : 0;
|
|
1188
1310
|
return;
|
|
1189
1311
|
}
|
|
1312
|
+
if (mapJiraCommand(command)) {
|
|
1313
|
+
process.exitCode = await forwardJiraCliCommand(command, commandArgs);
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1190
1316
|
const parsedCommandArgs = parseArgs(commandArgs);
|
|
1191
1317
|
if (command === "doctor" && parsedCommandArgs.quick === "true") {
|
|
1192
1318
|
const result = await runQuickDoctor();
|
|
@@ -1205,7 +1331,7 @@ async function main() {
|
|
|
1205
1331
|
}
|
|
1206
1332
|
catch (error) {
|
|
1207
1333
|
if (error?.code === "ENOENT") {
|
|
1208
|
-
console.error(
|
|
1334
|
+
console.error("Configuration is missing. Run `optimus setup` first.");
|
|
1209
1335
|
process.exitCode = 1;
|
|
1210
1336
|
return;
|
|
1211
1337
|
}
|