@sireai/optimus 0.1.40 → 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.
- package/dist/cli/optimus.js +425 -58
- package/dist/cli/optimus.js.map +1 -1
- package/dist/config/load-config.js +8 -1
- package/dist/config/load-config.js.map +1 -1
- package/dist/integrations/feishu/feishu-doc-service.d.ts +14 -2
- package/dist/integrations/feishu/feishu-doc-service.js +33 -12
- package/dist/integrations/feishu/feishu-doc-service.js.map +1 -1
- package/dist/integrations/feishu/feishu-document-reader.d.ts +33 -0
- package/dist/integrations/feishu/feishu-document-reader.js +597 -0
- package/dist/integrations/feishu/feishu-document-reader.js.map +1 -0
- package/dist/integrations/jira/jira-access-manager.d.ts +1 -0
- package/dist/integrations/jira/jira-access-manager.js +24 -0
- package/dist/integrations/jira/jira-access-manager.js.map +1 -1
- package/dist/integrations/jira/jira-cli.js +19 -3
- package/dist/integrations/jira/jira-cli.js.map +1 -1
- package/dist/integrations/jira/jira-submit.js +5 -18
- package/dist/integrations/jira/jira-submit.js.map +1 -1
- package/dist/integrations/sentry/sentry-cli.js +18 -2
- package/dist/integrations/sentry/sentry-cli.js.map +1 -1
- package/dist/problem-solving-core/codex/codex-runner.d.ts +2 -0
- package/dist/problem-solving-core/codex/codex-runner.js +46 -36
- package/dist/problem-solving-core/codex/codex-runner.js.map +1 -1
- package/dist/task-environment/delivery/delivery-warning-copy.d.ts +2 -0
- package/dist/task-environment/delivery/delivery-warning-copy.js +24 -0
- package/dist/task-environment/delivery/delivery-warning-copy.js.map +1 -0
- package/dist/task-environment/delivery/feishu-analysis-doc-service.d.ts +32 -1
- package/dist/task-environment/delivery/feishu-analysis-doc-service.js +351 -7
- package/dist/task-environment/delivery/feishu-analysis-doc-service.js.map +1 -1
- package/dist/task-environment/delivery/feishu-card-primitives.d.ts +33 -0
- package/dist/task-environment/delivery/feishu-card-primitives.js +95 -0
- package/dist/task-environment/delivery/feishu-card-primitives.js.map +1 -0
- package/dist/task-environment/delivery/feishu-card-renderer.d.ts +1 -0
- package/dist/task-environment/delivery/feishu-card-renderer.js +38 -73
- package/dist/task-environment/delivery/feishu-card-renderer.js.map +1 -1
- package/dist/task-environment/delivery/feishu-content/feishu-copy-config.js +1 -0
- package/dist/task-environment/delivery/feishu-content/feishu-copy-config.js.map +1 -1
- package/dist/task-environment/delivery/feishu-notifier.d.ts +5 -0
- package/dist/task-environment/delivery/feishu-notifier.js +107 -38
- package/dist/task-environment/delivery/feishu-notifier.js.map +1 -1
- package/dist/task-environment/delivery/feishu-templates/analysis-message-template.js +3 -0
- package/dist/task-environment/delivery/feishu-templates/analysis-message-template.js.map +1 -1
- package/dist/task-environment/delivery/pm-feishu-card-renderer.d.ts +19 -0
- package/dist/task-environment/delivery/pm-feishu-card-renderer.js +177 -0
- package/dist/task-environment/delivery/pm-feishu-card-renderer.js.map +1 -0
- package/dist/task-environment/delivery/sentry-feishu-card-renderer.d.ts +1 -0
- package/dist/task-environment/delivery/sentry-feishu-card-renderer.js +33 -70
- package/dist/task-environment/delivery/sentry-feishu-card-renderer.js.map +1 -1
- package/dist/task-environment/delivery/task-delivery-service.d.ts +6 -1
- package/dist/task-environment/delivery/task-delivery-service.js +142 -10
- package/dist/task-environment/delivery/task-delivery-service.js.map +1 -1
- package/dist/task-environment/delivery/task-publication-service.d.ts +1 -0
- package/dist/task-environment/delivery/task-publication-service.js +22 -0
- package/dist/task-environment/delivery/task-publication-service.js.map +1 -1
- package/dist/task-environment/intake/manual-problem-intake.js +54 -0
- package/dist/task-environment/intake/manual-problem-intake.js.map +1 -1
- package/dist/task-environment/orchestration/execution-context-assembler.d.ts +1 -0
- package/dist/task-environment/orchestration/execution-context-assembler.js +58 -3
- package/dist/task-environment/orchestration/execution-context-assembler.js.map +1 -1
- package/dist/task-environment/orchestration/task-orchestrator.d.ts +1 -0
- package/dist/task-environment/orchestration/task-orchestrator.js +41 -5
- package/dist/task-environment/orchestration/task-orchestrator.js.map +1 -1
- package/dist/task-environment/orchestration/task-package-inputs.d.ts +2 -0
- package/dist/task-environment/orchestration/task-package-inputs.js +83 -0
- package/dist/task-environment/orchestration/task-package-inputs.js.map +1 -0
- package/dist/task-environment/orchestration/task-runtime-policy.d.ts +4 -0
- package/dist/task-environment/orchestration/task-runtime-policy.js +38 -0
- package/dist/task-environment/orchestration/task-runtime-policy.js.map +1 -0
- package/dist/task-environment/result-paths.d.ts +9 -0
- package/dist/task-environment/result-paths.js +36 -0
- package/dist/task-environment/result-paths.js.map +1 -0
- package/dist/types.d.ts +45 -1
- package/package.json +1 -1
- package/task-harnesses/bugfix/ACCEPT.md +3 -2
- package/task-harnesses/bugfix/CONSTRAINTS.md +10 -4
- package/task-harnesses/bugfix/EVOLUTION.md +2 -8
- package/task-harnesses/bugfix/ROLE.md +7 -11
- package/task-harnesses/bugfix/STANDARD.md +81 -0
- package/task-harnesses/pm/ACCEPT.md +66 -0
- package/task-harnesses/pm/CONSTRAINTS.md +60 -0
- package/task-harnesses/pm/CONTEXT.md +50 -0
- package/task-harnesses/pm/EVOLUTION.md +77 -0
- package/task-harnesses/pm/ROLE.md +44 -0
- package/task-harnesses/pm/STANDARD.md +483 -0
- package/task-harnesses/pm/manifest.json +13 -0
- package/task-harnesses/registry.json +4 -0
package/dist/cli/optimus.js
CHANGED
|
@@ -17,6 +17,7 @@ import { classifyCodexFailureCategory } from "../problem-solving-core/codex/code
|
|
|
17
17
|
import { createManualEventContent, createManualProblemEvent } from "../task-environment/intake/manual-problem-intake.js";
|
|
18
18
|
import { OptimusLogger } from "../task-environment/observability/logger.js";
|
|
19
19
|
import { TaskOrchestrator } from "../task-environment/orchestration/task-orchestrator.js";
|
|
20
|
+
import { getTaskRuntimePolicy } from "../task-environment/orchestration/task-runtime-policy.js";
|
|
20
21
|
import { TriageRunner } from "../task-environment/orchestration/triage-runner.js";
|
|
21
22
|
import { OptimusRuntime } from "../task-environment/runtime/optimus-runtime.js";
|
|
22
23
|
import { SQLiteTaskStore } from "../task-environment/storage/sqlite-task-store.js";
|
|
@@ -25,9 +26,11 @@ import { buildTaskExecutionMetrics, formatExecutionMetricsCompact } from "../tas
|
|
|
25
26
|
import { FeishuNotifier } from "../task-environment/delivery/feishu-notifier.js";
|
|
26
27
|
import { TaskDeliveryDispatcher } from "../task-environment/delivery/task-delivery-dispatcher.js";
|
|
27
28
|
import { TaskDeliveryService } from "../task-environment/delivery/task-delivery-service.js";
|
|
29
|
+
import { formatDeliveryWarningsWithDescriptions } from "../task-environment/delivery/delivery-warning-copy.js";
|
|
28
30
|
import { FeishuAnalysisDocService } from "../task-environment/delivery/feishu-analysis-doc-service.js";
|
|
29
31
|
import { TaskPublicationService } from "../task-environment/delivery/task-publication-service.js";
|
|
30
32
|
import { FeishuClient } from "../integrations/feishu/feishu-client.js";
|
|
33
|
+
import { FeishuDocumentReader, mergeFeishuReferenceMaterials } from "../integrations/feishu/feishu-document-reader.js";
|
|
31
34
|
import { FeishuUserService } from "../integrations/feishu/feishu-user-service.js";
|
|
32
35
|
import { createFeedbackReport } from "./feedback.js";
|
|
33
36
|
import { DEFAULT_FEEDBACK_RECIPIENT_EMAIL, FeishuFeedbackDeliveryService, persistFeedbackDeliveryResult, resolveDefaultFeedbackRecipientFallbackOpenId } from "./feedback-delivery.js";
|
|
@@ -63,6 +66,9 @@ function renderSetupResult(result) {
|
|
|
63
66
|
lines.push("Repository: not configured");
|
|
64
67
|
}
|
|
65
68
|
lines.push(`Delivery: ${result.deliveryChannels.join(", ")}`);
|
|
69
|
+
if (result.feishuDefaultRecipientEmail) {
|
|
70
|
+
lines.push(`Feishu Recipient: ${result.feishuDefaultRecipientEmail}`);
|
|
71
|
+
}
|
|
66
72
|
lines.push(`Jira: ${result.jiraEnabled ? "enabled" : "disabled"}`);
|
|
67
73
|
lines.push(`Sentry: ${result.sentryEnabled ? "enabled" : "disabled"}`);
|
|
68
74
|
const providerLabel = result.codexAuth.provider ? ` | Provider: ${result.codexAuth.provider.displayName} (${result.codexAuth.provider.id})` : "";
|
|
@@ -316,23 +322,26 @@ function renderCommandHelp(command) {
|
|
|
316
322
|
"",
|
|
317
323
|
"Usage:",
|
|
318
324
|
" optimus submit --title <title> --description <text> [options]",
|
|
319
|
-
" optimus submit --title <title> --
|
|
320
|
-
"
|
|
325
|
+
" optimus submit --title <title> --file <path> [options]",
|
|
326
|
+
" optimus submit --url <url> [--title <title>] [options]",
|
|
321
327
|
"",
|
|
322
328
|
"Required:",
|
|
323
|
-
"
|
|
324
|
-
"
|
|
329
|
+
" exactly one of:",
|
|
330
|
+
" --description <text> Task text",
|
|
331
|
+
" --file <path> Read task text from a file",
|
|
332
|
+
" --url <url> Read task text from a remote document URL",
|
|
333
|
+
" --title <title> Task title; optional only when --url resolves a document title",
|
|
325
334
|
"",
|
|
326
335
|
"Common options:",
|
|
327
|
-
" --description-file <path> Read task description from a file",
|
|
328
|
-
" --description-stdin Read task description from stdin",
|
|
329
336
|
" --repo <alias> Target registered repository alias",
|
|
330
337
|
" --task-type <type> Task type, default bugfix",
|
|
331
338
|
" --source-ref <id> External issue key or source reference",
|
|
332
339
|
" --allow-duplicate Allow duplicate submission",
|
|
333
340
|
"",
|
|
334
341
|
"Example:",
|
|
335
|
-
" optimus submit --title \"Login crash\" --description \"Crash on startup\" --repo ohos-pre"
|
|
342
|
+
" optimus submit --title \"Login crash\" --description \"Crash on startup\" --repo ohos-pre",
|
|
343
|
+
" optimus submit --title \"Onboarding prototype\" --file ./docs/onboarding-prd.md --task-type pm",
|
|
344
|
+
" optimus submit --url https://mi.feishu.cn/docx/ABC123 --task-type pm"
|
|
336
345
|
].join("\n"),
|
|
337
346
|
feedback: [
|
|
338
347
|
"optimus feedback",
|
|
@@ -830,6 +839,7 @@ async function promptForStartupSelfUpdate(currentVersion, latestVersion) {
|
|
|
830
839
|
}
|
|
831
840
|
}
|
|
832
841
|
async function maybeHandleStartupSelfUpdate(input) {
|
|
842
|
+
const suppressSubmitOutput = input.command === "submit";
|
|
833
843
|
const check = await checkForSelfUpdate({
|
|
834
844
|
command: input.command,
|
|
835
845
|
config: input.config,
|
|
@@ -846,47 +856,54 @@ async function maybeHandleStartupSelfUpdate(input) {
|
|
|
846
856
|
const nextCheckAt = Number.isFinite(lastCheckedAtMs)
|
|
847
857
|
? new Date(lastCheckedAtMs + intervalHours * 60 * 60 * 1000).toISOString()
|
|
848
858
|
: null;
|
|
849
|
-
|
|
859
|
+
if (!suppressSubmitOutput) {
|
|
860
|
+
await input.logger.info("self_update.cached", {
|
|
861
|
+
command: input.command,
|
|
862
|
+
currentVersion: check.currentVersion,
|
|
863
|
+
latestVersion: check.latestVersion ?? null,
|
|
864
|
+
channel: check.channel,
|
|
865
|
+
installSource: check.installSource,
|
|
866
|
+
intervalHours,
|
|
867
|
+
lastCheckedAt,
|
|
868
|
+
nextCheckAt,
|
|
869
|
+
realtimeCheckSkipped: true
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
return { handled: false };
|
|
874
|
+
}
|
|
875
|
+
if (check.reason === "check_failed") {
|
|
876
|
+
if (!suppressSubmitOutput) {
|
|
877
|
+
await input.logger.warn("self_update.check_failed", {
|
|
850
878
|
command: input.command,
|
|
851
|
-
|
|
852
|
-
latestVersion: check.latestVersion ?? null,
|
|
853
|
-
channel: check.channel,
|
|
854
|
-
installSource: check.installSource,
|
|
855
|
-
intervalHours,
|
|
856
|
-
lastCheckedAt,
|
|
857
|
-
nextCheckAt,
|
|
858
|
-
realtimeCheckSkipped: true
|
|
879
|
+
reason: check.state.lastError ?? "unknown"
|
|
859
880
|
});
|
|
860
881
|
}
|
|
861
882
|
return { handled: false };
|
|
862
883
|
}
|
|
863
|
-
if (
|
|
864
|
-
await input.logger.
|
|
884
|
+
if (!suppressSubmitOutput) {
|
|
885
|
+
await input.logger.info(check.updateAvailable ? "self_update.available" : "self_update.current", {
|
|
865
886
|
command: input.command,
|
|
866
|
-
|
|
887
|
+
currentVersion: check.currentVersion,
|
|
888
|
+
latestVersion: check.latestVersion ?? null,
|
|
889
|
+
channel: check.channel,
|
|
890
|
+
installSource: check.installSource
|
|
867
891
|
});
|
|
868
|
-
return { handled: false };
|
|
869
892
|
}
|
|
870
|
-
await input.logger.info(check.updateAvailable ? "self_update.available" : "self_update.current", {
|
|
871
|
-
command: input.command,
|
|
872
|
-
currentVersion: check.currentVersion,
|
|
873
|
-
latestVersion: check.latestVersion ?? null,
|
|
874
|
-
channel: check.channel,
|
|
875
|
-
installSource: check.installSource
|
|
876
|
-
});
|
|
877
893
|
if (!check.updateAvailable || !check.latestVersion) {
|
|
878
894
|
return { handled: false };
|
|
879
895
|
}
|
|
880
896
|
if (check.reason === "skipped_version") {
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
897
|
+
if (!suppressSubmitOutput) {
|
|
898
|
+
await input.logger.info("self_update.skipped_version", {
|
|
899
|
+
command: input.command,
|
|
900
|
+
currentVersion: check.currentVersion,
|
|
901
|
+
latestVersion: check.latestVersion
|
|
902
|
+
});
|
|
903
|
+
}
|
|
886
904
|
return { handled: false };
|
|
887
905
|
}
|
|
888
906
|
if (input.command !== "start") {
|
|
889
|
-
console.log(`[optimus] update available ${check.currentVersion} -> ${check.latestVersion}. Run \`optimus upgrade\`.`);
|
|
890
907
|
return { handled: false };
|
|
891
908
|
}
|
|
892
909
|
if (selfUpdateConfig.mode === "prompt") {
|
|
@@ -1197,6 +1214,8 @@ async function promptSetupAnswers(defaults) {
|
|
|
1197
1214
|
printSetupSection("Feishu", "Built-in Feishu app delivery is already available. Add a webhook only if group notifications should go to a chat first. Type \"\" to clear an existing optional value.");
|
|
1198
1215
|
printSetupHint("Feishu webhook: optional; leave empty to use direct Feishu app delivery only.");
|
|
1199
1216
|
const feishuWebhook = resolveOptionalTextAnswer(await ask(renderSetupPrompt("Optional", "Feishu webhook", defaults.feishuWebhook ? "configured" : "")), defaults.feishuWebhook ?? undefined);
|
|
1217
|
+
printSetupHint("Feishu default recipient email: optional; used as a fallback for direct Feishu app delivery when no webhook and no task assignee are available.");
|
|
1218
|
+
const feishuRecipientEmail = resolveOptionalTextAnswer(await ask(renderSetupPrompt("Optional", "Feishu default recipient email", defaults.feishuRecipientEmail ?? "")), defaults.feishuRecipientEmail ?? undefined);
|
|
1200
1219
|
printSetupSection("Jira", "Optional. Turn this on only if you want this machine to read Jira issues or write Jira comments.");
|
|
1201
1220
|
printSetupHint("If disabled, Optimus still works; Jira commands just stay unavailable on this machine.");
|
|
1202
1221
|
const enableJiraInput = (await ask(renderSetupPrompt("Optional integration", "Enable Jira integration", defaults.enableJira ? "Y/n" : "y/N"))).trim().toLowerCase();
|
|
@@ -1235,6 +1254,7 @@ async function promptSetupAnswers(defaults) {
|
|
|
1235
1254
|
...(codexProviderBaseUrl ? { codexProviderBaseUrl } : {}),
|
|
1236
1255
|
...(codexProviderApiKeyEnvName ? { codexProviderApiKeyEnvName } : {}),
|
|
1237
1256
|
...(feishuWebhook !== undefined ? { feishuWebhook } : {}),
|
|
1257
|
+
...(feishuRecipientEmail !== undefined ? { feishuRecipientEmail } : {}),
|
|
1238
1258
|
enableJira,
|
|
1239
1259
|
...(jiraBaseUrl ? { jiraBaseUrl } : {}),
|
|
1240
1260
|
...(jiraPersonalToken ? { jiraPersonalToken } : {}),
|
|
@@ -1286,6 +1306,7 @@ async function resolveDefaultSetupAnswers() {
|
|
|
1286
1306
|
...(provider?.baseUrl ? { codexProviderBaseUrl: provider.baseUrl } : {}),
|
|
1287
1307
|
...(provider?.apiKeyEnvName ? { codexProviderApiKeyEnvName: provider.apiKeyEnvName } : {}),
|
|
1288
1308
|
...(config.delivery.feishu.webhook ? { feishuWebhook: config.delivery.feishu.webhook } : {}),
|
|
1309
|
+
...(config.delivery.feishu.defaultRecipient?.email ? { feishuRecipientEmail: config.delivery.feishu.defaultRecipient.email } : {}),
|
|
1289
1310
|
enableJira: config.jira.enabled,
|
|
1290
1311
|
...(config.jira.baseUrl ? { jiraBaseUrl: config.jira.baseUrl } : {}),
|
|
1291
1312
|
...(config.jira.personalToken ? { jiraPersonalToken: config.jira.personalToken } : {}),
|
|
@@ -1487,6 +1508,19 @@ function buildSetupConfig(answers, rawConfig) {
|
|
|
1487
1508
|
delete config.delivery.feishu.webhook;
|
|
1488
1509
|
delete config.delivery.feishu.webhooks;
|
|
1489
1510
|
}
|
|
1511
|
+
if (typeof answers.feishuRecipientEmail === "string") {
|
|
1512
|
+
config.delivery.feishu.defaultRecipient = {
|
|
1513
|
+
email: answers.feishuRecipientEmail
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
else if (answers.feishuRecipientEmail === null) {
|
|
1517
|
+
delete config.delivery.feishu.defaultRecipient;
|
|
1518
|
+
}
|
|
1519
|
+
else if (rawConfig?.delivery?.feishu?.defaultRecipient) {
|
|
1520
|
+
config.delivery.feishu.defaultRecipient = {
|
|
1521
|
+
...rawConfig.delivery.feishu.defaultRecipient
|
|
1522
|
+
};
|
|
1523
|
+
}
|
|
1490
1524
|
config.jira.enabled = answers.enableJira;
|
|
1491
1525
|
if (answers.enableJira) {
|
|
1492
1526
|
config.jira.baseUrl = answers.jiraBaseUrl ?? config.jira.baseUrl;
|
|
@@ -2044,6 +2078,7 @@ async function runSetup(args) {
|
|
|
2044
2078
|
}
|
|
2045
2079
|
} : {}),
|
|
2046
2080
|
deliveryChannels: config.delivery.channels,
|
|
2081
|
+
...(config.delivery.feishu.defaultRecipient?.email ? { feishuDefaultRecipientEmail: config.delivery.feishu.defaultRecipient.email } : {}),
|
|
2047
2082
|
jiraEnabled: config.jira.enabled,
|
|
2048
2083
|
sentryEnabled: config.sentry.enabled,
|
|
2049
2084
|
codexAuth: {
|
|
@@ -2065,6 +2100,7 @@ function inferArtifactDir(artifacts, bundle) {
|
|
|
2065
2100
|
const candidates = [
|
|
2066
2101
|
bundle?.artifacts.resultMd,
|
|
2067
2102
|
bundle?.artifacts.patchDiff,
|
|
2103
|
+
bundle?.artifacts.prototypeHtml,
|
|
2068
2104
|
...artifacts.map((artifact) => artifact.path)
|
|
2069
2105
|
].filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
2070
2106
|
const artifactPath = candidates.find((candidate) => candidate.includes(`${join(".optimus", "artifacts")}${candidate.includes("\\") ? "\\" : "/"}`))
|
|
@@ -2110,6 +2146,7 @@ async function buildReplayExecutionContext(input) {
|
|
|
2110
2146
|
: undefined;
|
|
2111
2147
|
return {
|
|
2112
2148
|
taskRootDir,
|
|
2149
|
+
runtimePolicy: getTaskRuntimePolicy(input.taskType),
|
|
2113
2150
|
addresses: {
|
|
2114
2151
|
mode,
|
|
2115
2152
|
workspaceDir,
|
|
@@ -2137,6 +2174,8 @@ function mergeReplayBundle(rebuilt, existing) {
|
|
|
2137
2174
|
...existing.summary,
|
|
2138
2175
|
...rebuilt.summary,
|
|
2139
2176
|
...(rebuilt.summary.analysisDocUrl ? {} : existing.summary.analysisDocUrl ? { analysisDocUrl: existing.summary.analysisDocUrl } : {}),
|
|
2177
|
+
...(rebuilt.summary.prototypePreviewUrl ? {} : existing.summary.prototypePreviewUrl ? { prototypePreviewUrl: existing.summary.prototypePreviewUrl } : {}),
|
|
2178
|
+
...(rebuilt.summary.prototypeDownloadUrl ? {} : existing.summary.prototypeDownloadUrl ? { prototypeDownloadUrl: existing.summary.prototypeDownloadUrl } : {}),
|
|
2140
2179
|
...(rebuilt.summary.repo ? {} : existing.summary.repo ? { repo: existing.summary.repo } : {}),
|
|
2141
2180
|
...(rebuilt.summary.sourceSystem ? {} : existing.summary.sourceSystem ? { sourceSystem: existing.summary.sourceSystem } : {}),
|
|
2142
2181
|
...(rebuilt.summary.sourceRef ? {} : existing.summary.sourceRef ? { sourceRef: existing.summary.sourceRef } : {}),
|
|
@@ -2260,30 +2299,309 @@ async function resolveLongTextArg(args, keys) {
|
|
|
2260
2299
|
return value;
|
|
2261
2300
|
}
|
|
2262
2301
|
}
|
|
2263
|
-
const
|
|
2264
|
-
|
|
2265
|
-
const
|
|
2266
|
-
if (
|
|
2267
|
-
|
|
2302
|
+
const fileKeys = typeof keys.file === "string" ? [keys.file] : (keys.file ?? []);
|
|
2303
|
+
for (const key of fileKeys) {
|
|
2304
|
+
const filePath = args[key]?.trim();
|
|
2305
|
+
if (filePath) {
|
|
2306
|
+
const content = (await readFile(filePath, "utf8")).trim();
|
|
2307
|
+
if (content) {
|
|
2308
|
+
return content;
|
|
2309
|
+
}
|
|
2268
2310
|
}
|
|
2269
2311
|
}
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
if (
|
|
2273
|
-
|
|
2312
|
+
const stdinKeys = typeof keys.stdin === "string" ? [keys.stdin] : (keys.stdin ?? []);
|
|
2313
|
+
for (const key of stdinKeys) {
|
|
2314
|
+
if (args[key] === "true") {
|
|
2315
|
+
const content = (await readTextFromStdin()).trim();
|
|
2316
|
+
if (content) {
|
|
2317
|
+
return content;
|
|
2318
|
+
}
|
|
2274
2319
|
}
|
|
2275
2320
|
}
|
|
2276
2321
|
return undefined;
|
|
2277
2322
|
}
|
|
2278
2323
|
function renderShellQuotingHint(command) {
|
|
2324
|
+
const requirementHint = command === "submit"
|
|
2325
|
+
? "Provide exactly one of --description, --file, or --url. --title is optional only when --url resolves a document title."
|
|
2326
|
+
: "Use single quotes, or pass the text with --description-file / --description-stdin.";
|
|
2279
2327
|
return [
|
|
2280
|
-
|
|
2328
|
+
command === "submit"
|
|
2329
|
+
? "submit requires exactly one of --description, --file, or --url, plus --title unless --url resolves a document title."
|
|
2330
|
+
: "feedback requires both --title and --description.",
|
|
2281
2331
|
"Tip: shell metacharacters like `...`, $(...), and $VAR may be expanded before Optimus starts.",
|
|
2282
|
-
|
|
2332
|
+
requirementHint,
|
|
2283
2333
|
`Example: optimus ${command} --title "..." --description 'literal text with \`optimus setup\` inside'`,
|
|
2284
|
-
|
|
2334
|
+
...(command === "submit"
|
|
2335
|
+
? [
|
|
2336
|
+
`Example: optimus submit --title "..." --file ./task.md`,
|
|
2337
|
+
`Example: optimus submit --url https://mi.feishu.cn/docx/ABC123`
|
|
2338
|
+
]
|
|
2339
|
+
: [`Example: printf '%s' 'literal text with \`optimus setup\` inside' | optimus feedback --title "..." --description-stdin`])
|
|
2285
2340
|
].join("\n");
|
|
2286
2341
|
}
|
|
2342
|
+
function isFeishuDocumentUrl(value) {
|
|
2343
|
+
return /^https?:\/\/(?:[\w-]+\.)?feishu\.cn\//iu.test(value.trim())
|
|
2344
|
+
|| /^https?:\/\/(?:[\w-]+\.)?larksuite\.com\//iu.test(value.trim());
|
|
2345
|
+
}
|
|
2346
|
+
function extractTitleFromMarkdown(markdown) {
|
|
2347
|
+
const match = markdown.match(/<title>([\s\S]*?)<\/title>/iu);
|
|
2348
|
+
const title = match?.[1]?.trim();
|
|
2349
|
+
return title ? title : undefined;
|
|
2350
|
+
}
|
|
2351
|
+
function parseHtmlAttributeMap(fragment) {
|
|
2352
|
+
const attributes = {};
|
|
2353
|
+
const pattern = /([\w:-]+)="([^"]*)"/gu;
|
|
2354
|
+
let match;
|
|
2355
|
+
while ((match = pattern.exec(fragment)) !== null) {
|
|
2356
|
+
const key = match[1];
|
|
2357
|
+
const value = match[2];
|
|
2358
|
+
if (key !== undefined && value !== undefined) {
|
|
2359
|
+
attributes[key] = value;
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
return attributes;
|
|
2363
|
+
}
|
|
2364
|
+
function extractFeishuReferenceMaterials(markdown, media, sourceUrl) {
|
|
2365
|
+
const references = [];
|
|
2366
|
+
const seen = new Set();
|
|
2367
|
+
let embeddedImageCount = 0;
|
|
2368
|
+
let embeddedWhiteboardCount = 0;
|
|
2369
|
+
let embeddedDocCount = 0;
|
|
2370
|
+
let embeddedSheetCount = 0;
|
|
2371
|
+
let embeddedBitableCount = 0;
|
|
2372
|
+
let embeddedFileCount = 0;
|
|
2373
|
+
let rawLinkCount = 0;
|
|
2374
|
+
const pushReference = (reference) => {
|
|
2375
|
+
const identityParts = [
|
|
2376
|
+
reference.type,
|
|
2377
|
+
reference.url ?? "",
|
|
2378
|
+
reference.token ?? "",
|
|
2379
|
+
reference.content ?? ""
|
|
2380
|
+
];
|
|
2381
|
+
const key = identityParts.some((part) => part.length > 0)
|
|
2382
|
+
? identityParts.join("|")
|
|
2383
|
+
: [reference.type, reference.title].join("|");
|
|
2384
|
+
if (seen.has(key)) {
|
|
2385
|
+
return;
|
|
2386
|
+
}
|
|
2387
|
+
seen.add(key);
|
|
2388
|
+
references.push(reference);
|
|
2389
|
+
};
|
|
2390
|
+
if (Array.isArray(media)) {
|
|
2391
|
+
for (const entry of media) {
|
|
2392
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
2393
|
+
continue;
|
|
2394
|
+
}
|
|
2395
|
+
const record = entry;
|
|
2396
|
+
const token = typeof record.token === "string" ? record.token.trim() : "";
|
|
2397
|
+
const type = typeof record.type === "string" ? record.type.trim() : "";
|
|
2398
|
+
if (!token || !type) {
|
|
2399
|
+
continue;
|
|
2400
|
+
}
|
|
2401
|
+
if (type === "whiteboard") {
|
|
2402
|
+
embeddedWhiteboardCount += 1;
|
|
2403
|
+
pushReference({
|
|
2404
|
+
type: "whiteboard",
|
|
2405
|
+
title: `Embedded whiteboard ${embeddedWhiteboardCount}`,
|
|
2406
|
+
token,
|
|
2407
|
+
sourceType: "feishu_media"
|
|
2408
|
+
});
|
|
2409
|
+
continue;
|
|
2410
|
+
}
|
|
2411
|
+
embeddedFileCount += 1;
|
|
2412
|
+
pushReference({
|
|
2413
|
+
type: "file",
|
|
2414
|
+
title: `Embedded ${type} ${embeddedFileCount}`,
|
|
2415
|
+
token,
|
|
2416
|
+
sourceType: "feishu_media"
|
|
2417
|
+
});
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
const markdownImagePattern = /!\[(.*?)\]\((https?:\/\/[^)\s]+)\)/gu;
|
|
2421
|
+
let imageMatch;
|
|
2422
|
+
while ((imageMatch = markdownImagePattern.exec(markdown)) !== null) {
|
|
2423
|
+
embeddedImageCount += 1;
|
|
2424
|
+
const alt = imageMatch[1]?.trim();
|
|
2425
|
+
const imageUrl = imageMatch[2]?.trim();
|
|
2426
|
+
if (!imageUrl) {
|
|
2427
|
+
continue;
|
|
2428
|
+
}
|
|
2429
|
+
pushReference({
|
|
2430
|
+
type: "image",
|
|
2431
|
+
title: alt || `Embedded image ${embeddedImageCount}`,
|
|
2432
|
+
url: imageUrl,
|
|
2433
|
+
sourceType: "feishu_markdown"
|
|
2434
|
+
});
|
|
2435
|
+
}
|
|
2436
|
+
const htmlImagePattern = /<img\b([^>]*)\/?>/gu;
|
|
2437
|
+
let htmlImageMatch;
|
|
2438
|
+
while ((htmlImageMatch = htmlImagePattern.exec(markdown)) !== null) {
|
|
2439
|
+
embeddedImageCount += 1;
|
|
2440
|
+
const attrs = parseHtmlAttributeMap(htmlImageMatch[1] ?? "");
|
|
2441
|
+
pushReference({
|
|
2442
|
+
type: "image",
|
|
2443
|
+
title: attrs.name?.trim() || `Embedded image ${embeddedImageCount}`,
|
|
2444
|
+
...(attrs.src?.trim() ? { token: attrs.src.trim() } : {}),
|
|
2445
|
+
...(attrs.mime?.trim() ? { mimeType: attrs.mime.trim() } : {}),
|
|
2446
|
+
sourceType: "feishu_markdown"
|
|
2447
|
+
});
|
|
2448
|
+
}
|
|
2449
|
+
const whiteboardPattern = /<whiteboard\b([^>]*)>(?:<\/whiteboard>)?/gu;
|
|
2450
|
+
let whiteboardMatch;
|
|
2451
|
+
while ((whiteboardMatch = whiteboardPattern.exec(markdown)) !== null) {
|
|
2452
|
+
embeddedWhiteboardCount += 1;
|
|
2453
|
+
const attrs = parseHtmlAttributeMap(whiteboardMatch[1] ?? "");
|
|
2454
|
+
pushReference({
|
|
2455
|
+
type: "whiteboard",
|
|
2456
|
+
title: `Embedded whiteboard ${embeddedWhiteboardCount}`,
|
|
2457
|
+
...(attrs.token?.trim() ? { token: attrs.token.trim() } : {}),
|
|
2458
|
+
sourceType: "feishu_markdown"
|
|
2459
|
+
});
|
|
2460
|
+
}
|
|
2461
|
+
const citeDocPattern = /<cite\b([^>]*)><\/cite>/gu;
|
|
2462
|
+
let citeMatch;
|
|
2463
|
+
while ((citeMatch = citeDocPattern.exec(markdown)) !== null) {
|
|
2464
|
+
const attrs = parseHtmlAttributeMap(citeMatch[1] ?? "");
|
|
2465
|
+
if (attrs.type !== "doc") {
|
|
2466
|
+
continue;
|
|
2467
|
+
}
|
|
2468
|
+
const fileType = attrs["file-type"]?.trim();
|
|
2469
|
+
const title = attrs.title?.trim();
|
|
2470
|
+
const token = attrs["doc-id"]?.trim();
|
|
2471
|
+
const referenceType = fileType === "wiki" || fileType === "docx"
|
|
2472
|
+
? "doc"
|
|
2473
|
+
: fileType === "sheet"
|
|
2474
|
+
? "sheet"
|
|
2475
|
+
: "doc";
|
|
2476
|
+
if (referenceType === "sheet") {
|
|
2477
|
+
embeddedSheetCount += 1;
|
|
2478
|
+
}
|
|
2479
|
+
else {
|
|
2480
|
+
embeddedDocCount += 1;
|
|
2481
|
+
}
|
|
2482
|
+
pushReference({
|
|
2483
|
+
type: referenceType,
|
|
2484
|
+
title: title || (referenceType === "sheet" ? `Referenced sheet ${embeddedSheetCount}` : `Referenced document ${embeddedDocCount}`),
|
|
2485
|
+
...(token ? { token } : {}),
|
|
2486
|
+
sourceType: "feishu_cite"
|
|
2487
|
+
});
|
|
2488
|
+
}
|
|
2489
|
+
const sheetPattern = /<sheet\b([^>]*)\/?>/gu;
|
|
2490
|
+
let sheetMatch;
|
|
2491
|
+
while ((sheetMatch = sheetPattern.exec(markdown)) !== null) {
|
|
2492
|
+
embeddedSheetCount += 1;
|
|
2493
|
+
const attrs = parseHtmlAttributeMap(sheetMatch[1] ?? "");
|
|
2494
|
+
pushReference({
|
|
2495
|
+
type: "sheet",
|
|
2496
|
+
title: `Embedded sheet ${embeddedSheetCount}`,
|
|
2497
|
+
...(attrs.token?.trim() ? { token: attrs.token.trim() } : {}),
|
|
2498
|
+
sourceType: "feishu_markdown"
|
|
2499
|
+
});
|
|
2500
|
+
}
|
|
2501
|
+
const bitablePattern = /<bitable\b([^>]*)\/?>/gu;
|
|
2502
|
+
let bitableMatch;
|
|
2503
|
+
while ((bitableMatch = bitablePattern.exec(markdown)) !== null) {
|
|
2504
|
+
embeddedBitableCount += 1;
|
|
2505
|
+
const attrs = parseHtmlAttributeMap(bitableMatch[1] ?? "");
|
|
2506
|
+
pushReference({
|
|
2507
|
+
type: "bitable",
|
|
2508
|
+
title: `Embedded bitable ${embeddedBitableCount}`,
|
|
2509
|
+
...(attrs.token?.trim() ? { token: attrs.token.trim() } : {}),
|
|
2510
|
+
sourceType: "feishu_markdown"
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
const filePattern = /<file\b([^>]*)\/?>/gu;
|
|
2514
|
+
let fileMatch;
|
|
2515
|
+
while ((fileMatch = filePattern.exec(markdown)) !== null) {
|
|
2516
|
+
embeddedFileCount += 1;
|
|
2517
|
+
const attrs = parseHtmlAttributeMap(fileMatch[1] ?? "");
|
|
2518
|
+
pushReference({
|
|
2519
|
+
type: "file",
|
|
2520
|
+
title: attrs.name?.trim() || `Embedded file ${embeddedFileCount}`,
|
|
2521
|
+
...(attrs.token?.trim() ? { token: attrs.token.trim() } : {}),
|
|
2522
|
+
sourceType: "feishu_markdown"
|
|
2523
|
+
});
|
|
2524
|
+
}
|
|
2525
|
+
const rawUrlPattern = /https?:\/\/[^\s<>"')]+/gu;
|
|
2526
|
+
let urlMatch;
|
|
2527
|
+
while ((urlMatch = rawUrlPattern.exec(markdown)) !== null) {
|
|
2528
|
+
const link = urlMatch[0];
|
|
2529
|
+
if (link === sourceUrl || /https?:\/\/(?:[\w-]+\.)?feishu\.cn\/file\//iu.test(link)) {
|
|
2530
|
+
continue;
|
|
2531
|
+
}
|
|
2532
|
+
rawLinkCount += 1;
|
|
2533
|
+
pushReference({
|
|
2534
|
+
type: "link",
|
|
2535
|
+
title: rawLinkCount === 1 ? "Referenced link" : `Referenced link ${rawLinkCount}`,
|
|
2536
|
+
url: link,
|
|
2537
|
+
sourceType: "feishu_markdown"
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
return references.length > 0 ? references : undefined;
|
|
2541
|
+
}
|
|
2542
|
+
async function resolveTaskTextFromUrl(url) {
|
|
2543
|
+
const trimmedUrl = url.trim();
|
|
2544
|
+
if (!trimmedUrl) {
|
|
2545
|
+
throw new Error("Task document URL is empty.");
|
|
2546
|
+
}
|
|
2547
|
+
if (!isFeishuDocumentUrl(trimmedUrl)) {
|
|
2548
|
+
throw new Error("submit currently supports document URLs from Feishu/Lark only.");
|
|
2549
|
+
}
|
|
2550
|
+
const reader = new FeishuDocumentReader();
|
|
2551
|
+
try {
|
|
2552
|
+
const resolved = await reader.readFromUrl(trimmedUrl);
|
|
2553
|
+
const referenceMaterials = mergeFeishuReferenceMaterials(extractFeishuReferenceMaterials(resolved.content, undefined, trimmedUrl), resolved.referenceMaterials);
|
|
2554
|
+
return {
|
|
2555
|
+
content: resolved.content,
|
|
2556
|
+
...(resolved.title ? { title: resolved.title } : {}),
|
|
2557
|
+
sourceType: resolved.sourceType,
|
|
2558
|
+
...(resolved.sourceDocumentType ? { sourceDocumentType: resolved.sourceDocumentType } : {}),
|
|
2559
|
+
...(referenceMaterials ? { referenceMaterials } : {})
|
|
2560
|
+
};
|
|
2561
|
+
}
|
|
2562
|
+
catch (builtinError) {
|
|
2563
|
+
let stdout;
|
|
2564
|
+
try {
|
|
2565
|
+
const result = await execFileAsync("feishu", ["fetch", trimmedUrl], {
|
|
2566
|
+
maxBuffer: 10 * 1024 * 1024
|
|
2567
|
+
});
|
|
2568
|
+
stdout = result.stdout;
|
|
2569
|
+
}
|
|
2570
|
+
catch (error) {
|
|
2571
|
+
const execError = error;
|
|
2572
|
+
const cliDetail = execError?.code === "ENOENT"
|
|
2573
|
+
? "the `feishu` CLI is not installed or not on PATH"
|
|
2574
|
+
: execError?.stderr?.trim() || execError?.stdout?.trim() || execError?.message || "unknown error";
|
|
2575
|
+
const builtinDetail = builtinError instanceof Error ? builtinError.message : String(builtinError);
|
|
2576
|
+
throw new Error(`submit could not fetch the Feishu document via built-in app (${builtinDetail}) or via \`feishu fetch\` (${cliDetail}).`);
|
|
2577
|
+
}
|
|
2578
|
+
let payload;
|
|
2579
|
+
try {
|
|
2580
|
+
payload = JSON.parse(stdout);
|
|
2581
|
+
}
|
|
2582
|
+
catch {
|
|
2583
|
+
throw new Error("submit received non-JSON output from `feishu fetch`.");
|
|
2584
|
+
}
|
|
2585
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
2586
|
+
throw new Error("submit received an invalid response from `feishu fetch`.");
|
|
2587
|
+
}
|
|
2588
|
+
const record = payload;
|
|
2589
|
+
const markdown = typeof record.markdown === "string" ? record.markdown.trim() : "";
|
|
2590
|
+
const title = (typeof record.title === "string" ? record.title.trim() : "") || extractTitleFromMarkdown(markdown);
|
|
2591
|
+
const sourceDocumentType = typeof record.type === "string" ? record.type.trim() : undefined;
|
|
2592
|
+
const referenceMaterials = extractFeishuReferenceMaterials(markdown, record.media, trimmedUrl);
|
|
2593
|
+
if (!markdown) {
|
|
2594
|
+
throw new Error("submit fetched the document URL, but it did not return readable markdown content.");
|
|
2595
|
+
}
|
|
2596
|
+
return {
|
|
2597
|
+
content: markdown,
|
|
2598
|
+
...(title ? { title } : {}),
|
|
2599
|
+
sourceType: "feishu_doc",
|
|
2600
|
+
...(sourceDocumentType ? { sourceDocumentType } : {}),
|
|
2601
|
+
...(referenceMaterials ? { referenceMaterials } : {})
|
|
2602
|
+
};
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2287
2605
|
async function main() {
|
|
2288
2606
|
const argv = process.argv.slice(2);
|
|
2289
2607
|
const [firstArg, ...rest] = argv;
|
|
@@ -2474,19 +2792,57 @@ async function main() {
|
|
|
2474
2792
|
}
|
|
2475
2793
|
if (command === "submit") {
|
|
2476
2794
|
const args = parseArgs(commandArgs);
|
|
2477
|
-
const
|
|
2478
|
-
const
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
if (
|
|
2795
|
+
const explicitTitle = args.title?.trim();
|
|
2796
|
+
const taskType = args["task-type"]?.trim() || "bugfix";
|
|
2797
|
+
const inlineDescription = args.desc?.trim() || args.description?.trim();
|
|
2798
|
+
const filePath = args.file?.trim();
|
|
2799
|
+
const url = args.url?.trim();
|
|
2800
|
+
const inputSourceCount = [inlineDescription, filePath, url].filter(Boolean).length;
|
|
2801
|
+
if (inputSourceCount !== 1) {
|
|
2802
|
+
console.error(renderShellQuotingHint("submit"));
|
|
2803
|
+
process.exitCode = 1;
|
|
2804
|
+
return;
|
|
2805
|
+
}
|
|
2806
|
+
let description = "";
|
|
2807
|
+
let resolvedTitle = explicitTitle;
|
|
2808
|
+
let remoteSourceType;
|
|
2809
|
+
let remoteDocumentTitle;
|
|
2810
|
+
let remoteDocumentType;
|
|
2811
|
+
let referenceMaterials;
|
|
2812
|
+
if (inlineDescription) {
|
|
2813
|
+
description = inlineDescription;
|
|
2814
|
+
}
|
|
2815
|
+
else if (filePath) {
|
|
2816
|
+
description = (await readFile(filePath, "utf8")).trim();
|
|
2817
|
+
}
|
|
2818
|
+
else {
|
|
2819
|
+
try {
|
|
2820
|
+
const remote = await runWithTerminalLoading("Resolving remote requirement document", async () => await resolveTaskTextFromUrl(url));
|
|
2821
|
+
description = remote.content;
|
|
2822
|
+
resolvedTitle = resolvedTitle || remote.title;
|
|
2823
|
+
remoteSourceType = remote.sourceType;
|
|
2824
|
+
remoteDocumentTitle = remote.title;
|
|
2825
|
+
remoteDocumentType = remote.sourceDocumentType;
|
|
2826
|
+
referenceMaterials = remote.referenceMaterials;
|
|
2827
|
+
}
|
|
2828
|
+
catch (error) {
|
|
2829
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
2830
|
+
process.exitCode = 1;
|
|
2831
|
+
return;
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
if (!resolvedTitle || !description) {
|
|
2835
|
+
console.error(renderShellQuotingHint("submit"));
|
|
2836
|
+
process.exitCode = 1;
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2839
|
+
if (!description) {
|
|
2484
2840
|
console.error(renderShellQuotingHint("submit"));
|
|
2485
2841
|
process.exitCode = 1;
|
|
2486
2842
|
return;
|
|
2487
2843
|
}
|
|
2488
2844
|
await store.init();
|
|
2489
|
-
const repositorySelection = await resolveSubmissionRepositorySelector(args, store, config);
|
|
2845
|
+
const repositorySelection = await resolveSubmissionRepositorySelector(taskType, args, store, config);
|
|
2490
2846
|
if (!repositorySelection.ok) {
|
|
2491
2847
|
console.error(repositorySelection.reason);
|
|
2492
2848
|
process.exitCode = 1;
|
|
@@ -2494,11 +2850,18 @@ async function main() {
|
|
|
2494
2850
|
}
|
|
2495
2851
|
const event = createManualProblemEvent({
|
|
2496
2852
|
...args,
|
|
2853
|
+
title: resolvedTitle,
|
|
2854
|
+
description,
|
|
2855
|
+
...(url ? { sourceUrl: url } : {}),
|
|
2856
|
+
...(remoteSourceType ? { "source-type": remoteSourceType } : {}),
|
|
2857
|
+
...(remoteDocumentTitle ? { "source-document-title": remoteDocumentTitle } : {}),
|
|
2858
|
+
...(remoteDocumentType ? { "source-document-type": remoteDocumentType } : {}),
|
|
2859
|
+
...(referenceMaterials ? { "reference-materials-json": JSON.stringify(referenceMaterials) } : {}),
|
|
2497
2860
|
...(repositorySelection.repoSelector ? { repo: repositorySelection.repoSelector } : {}),
|
|
2498
2861
|
...(args["allow-duplicate"] === "true" ? { "allow-duplicate": "true" } : {})
|
|
2499
2862
|
});
|
|
2500
|
-
|
|
2501
|
-
console.log(
|
|
2863
|
+
await runtime.writeManualSubmission(event);
|
|
2864
|
+
console.log("[optimus] submit succeeded");
|
|
2502
2865
|
return;
|
|
2503
2866
|
}
|
|
2504
2867
|
if (command === "feedback") {
|
|
@@ -3405,7 +3768,11 @@ async function inspectBuiltinSkills(config, skillSyncService) {
|
|
|
3405
3768
|
evolutionTaskLevelSkills
|
|
3406
3769
|
};
|
|
3407
3770
|
}
|
|
3408
|
-
async function resolveSubmissionRepositorySelector(args, store, config) {
|
|
3771
|
+
async function resolveSubmissionRepositorySelector(taskType, args, store, config) {
|
|
3772
|
+
const runtimePolicy = getTaskRuntimePolicy(taskType);
|
|
3773
|
+
if (!runtimePolicy.requiresRepository) {
|
|
3774
|
+
return { ok: true };
|
|
3775
|
+
}
|
|
3409
3776
|
const candidates = await listCliRepositoryCandidates(store, config);
|
|
3410
3777
|
const requestedRepo = args.repo?.trim();
|
|
3411
3778
|
if (requestedRepo) {
|
|
@@ -3682,7 +4049,7 @@ function renderTaskResultReport(input) {
|
|
|
3682
4049
|
lines.push(`Metrics: ${metrics}`);
|
|
3683
4050
|
}
|
|
3684
4051
|
if (input.deliveryBundle.warnings?.length) {
|
|
3685
|
-
lines.push(`Warnings: ${input.deliveryBundle.warnings
|
|
4052
|
+
lines.push(`Warnings: ${formatDeliveryWarningsWithDescriptions(input.deliveryBundle.warnings)}`);
|
|
3686
4053
|
}
|
|
3687
4054
|
if (input.deliveryBundle.publication) {
|
|
3688
4055
|
lines.push(`Publication: ${input.deliveryBundle.publication.action}${input.deliveryBundle.publication.reason ? ` (${input.deliveryBundle.publication.reason})` : ""}`);
|
|
@@ -3795,7 +4162,7 @@ function renderDeliveryStatusReport(input) {
|
|
|
3795
4162
|
lines.push(`Decision: ${input.deliveryBundle.summary.decision}`);
|
|
3796
4163
|
lines.push(`Created At: ${input.deliveryBundle.createdAt}`);
|
|
3797
4164
|
if (input.deliveryBundle.warnings?.length) {
|
|
3798
|
-
lines.push(`Warnings: ${input.deliveryBundle.warnings
|
|
4165
|
+
lines.push(`Warnings: ${formatDeliveryWarningsWithDescriptions(input.deliveryBundle.warnings)}`);
|
|
3799
4166
|
}
|
|
3800
4167
|
}
|
|
3801
4168
|
else {
|