@kw-yeh/vibeflow 4.9.0 → 4.10.0
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/README.md +2 -0
- package/dist/vibeflow.mjs +440 -39
- package/dist/web/404/index.html +1 -1
- package/dist/web/404.html +1 -1
- package/dist/web/_next/static/{zd9N4vIppSGgwT--n88P6 → BitLlFC-3hSS2mIvjdaGE}/_buildManifest.js +1 -1
- package/dist/web/_next/static/chunks/{02e71eac.0250f42685eae210.js → 02e71eac.a73ad9a7a96ae1e3.js} +1 -1
- package/dist/web/_next/static/chunks/5695.b97c93788c76800e.js +1 -0
- package/dist/web/_next/static/chunks/pages/{_app-496c474d7f14dd07.js → _app-ab090e0b95efc7ae.js} +1 -1
- package/dist/web/_next/static/chunks/pages/home-b06aaed2bc1f9020.js +12 -0
- package/dist/web/_next/static/chunks/{webpack-c8aa5df0425f6b7b.js → webpack-0eacf76ebd7d56d5.js} +1 -1
- package/dist/web/_next/static/css/69a4a772468eeb68.css +2 -0
- package/dist/web/home/index.html +1 -1
- package/package.json +1 -1
- package/dist/web/_next/static/chunks/5695.45dd981e66074a89.js +0 -1
- package/dist/web/_next/static/chunks/pages/home-8775f5b8256ee371.js +0 -12
- package/dist/web/_next/static/css/c1491b2feaf90c67.css +0 -2
- /package/dist/web/_next/static/{zd9N4vIppSGgwT--n88P6 → BitLlFC-3hSS2mIvjdaGE}/_ssgManifest.js +0 -0
package/dist/vibeflow.mjs
CHANGED
|
@@ -1103,7 +1103,7 @@ import fs22 from "fs";
|
|
|
1103
1103
|
import os9 from "os";
|
|
1104
1104
|
import path26 from "path";
|
|
1105
1105
|
import React, { useEffect, useRef, useState } from "react";
|
|
1106
|
-
import { Box, Text, render, useApp, useInput } from "ink";
|
|
1106
|
+
import { Box, Text, render as render2, useApp, useInput } from "ink";
|
|
1107
1107
|
function newFormState(defaultAutoMode, agents) {
|
|
1108
1108
|
const agentCli = agents && agents.length > 0 && !agents.some((a) => a.id === "claude") ? agents[0].id : "claude";
|
|
1109
1109
|
return {
|
|
@@ -1477,7 +1477,7 @@ function FormView({ api, ctx, initial, initialFocus, initialMessage, pristine, o
|
|
|
1477
1477
|
function showForm(api, ctx, initial, pristine, initialFocus = 0, initialMessage) {
|
|
1478
1478
|
return new Promise((resolve) => {
|
|
1479
1479
|
let result = { type: "cancel" };
|
|
1480
|
-
const instance =
|
|
1480
|
+
const instance = render2(
|
|
1481
1481
|
h(FormView, { api, ctx, initial, initialFocus, initialMessage, pristine, onResult: (r) => result = r }),
|
|
1482
1482
|
{ exitOnCtrlC: false }
|
|
1483
1483
|
);
|
|
@@ -1560,7 +1560,7 @@ __export(src_exports, {
|
|
|
1560
1560
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
1561
1561
|
import path27 from "path";
|
|
1562
1562
|
import React2, { useEffect as useEffect2, useState as useState2 } from "react";
|
|
1563
|
-
import { Box as Box2, Text as Text2, render as
|
|
1563
|
+
import { Box as Box2, Text as Text2, render as render3, useApp as useApp2, useInput as useInput2, useStdout } from "ink";
|
|
1564
1564
|
function findDetachKey(text) {
|
|
1565
1565
|
const plain = text.indexOf(DETACH_KEY);
|
|
1566
1566
|
const m = /\x1b\[\d+;\d+;29;1;\d+;\d+_/.exec(text);
|
|
@@ -1828,7 +1828,7 @@ function BoardView({ opts, initial, initialMessage, onAction }) {
|
|
|
1828
1828
|
function showBoard(opts, initial, initialMessage) {
|
|
1829
1829
|
return new Promise((resolve) => {
|
|
1830
1830
|
let result = { action: { type: "quit" }, sel: initial };
|
|
1831
|
-
const instance =
|
|
1831
|
+
const instance = render3(
|
|
1832
1832
|
h2(BoardView, {
|
|
1833
1833
|
opts,
|
|
1834
1834
|
initial,
|
|
@@ -2464,6 +2464,13 @@ function createBridge(t) {
|
|
|
2464
2464
|
logoutGithubAuth: () => t.invoke("settings:logoutGithubAuth"),
|
|
2465
2465
|
/** Open Issues/PRs of the board's GitHub repos that involve me; cached unless `force`. */
|
|
2466
2466
|
getGithubInbox: (opts) => t.invoke("github:inbox", opts ?? {}),
|
|
2467
|
+
getJiraAuthStatus: () => t.invoke("jira:authStatus"),
|
|
2468
|
+
startJiraAuthLogin: () => t.invoke("settings:startJiraAuthLogin"),
|
|
2469
|
+
cancelJiraAuthLogin: () => t.invoke("settings:cancelJiraAuthLogin"),
|
|
2470
|
+
inputJiraAuthLogin: (input) => t.invoke("settings:inputJiraAuthLogin", input),
|
|
2471
|
+
logoutJiraAuth: () => t.invoke("settings:logoutJiraAuth"),
|
|
2472
|
+
onJiraAuthEvent: (callback) => t.on("jira-auth:event", (event) => callback(event)),
|
|
2473
|
+
getJiraInbox: (opts) => t.invoke("jira:inbox", opts ?? {}),
|
|
2467
2474
|
/** The Issue/PR each card belongs to, keyed by task id. */
|
|
2468
2475
|
getGithubTaskLinks: (opts) => t.invoke("github:taskLinks", opts ?? {}),
|
|
2469
2476
|
onGithubAuthEvent: (callback) => {
|
|
@@ -2963,10 +2970,11 @@ function parseGithubRepo(remoteUrl) {
|
|
|
2963
2970
|
return match ? `${match[1]}/${match[2]}` : null;
|
|
2964
2971
|
}
|
|
2965
2972
|
var REPO_RE = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
2973
|
+
var isRepoName = (repo) => REPO_RE.test(repo) && repo.split("/").every((part) => part !== "." && part !== "..");
|
|
2966
2974
|
function isGithubRef(value) {
|
|
2967
2975
|
if (!value || typeof value !== "object") return false;
|
|
2968
2976
|
const v = value;
|
|
2969
|
-
return (v.kind === "issue" || v.kind === "pr") && typeof v.repo === "string" &&
|
|
2977
|
+
return (v.kind === "issue" || v.kind === "pr") && typeof v.repo === "string" && isRepoName(v.repo) && typeof v.number === "number" && Number.isInteger(v.number) && v.number > 0 && typeof v.url === "string" && v.url.startsWith(`https://github.com/${v.repo}/`);
|
|
2970
2978
|
}
|
|
2971
2979
|
var ITEM_FIELDS = "number,title,url,body,author,assignees,labels,milestone,createdAt";
|
|
2972
2980
|
var ISSUE_FIELDS = `${ITEM_FIELDS},issueType`;
|
|
@@ -2974,6 +2982,7 @@ var PR_FIELDS = `${ITEM_FIELDS},state,isDraft,reviewDecision,headRefName,baseRef
|
|
|
2974
2982
|
var PR_INDEX_FIELDS = "number,url,state,isDraft,headRefName,closingIssuesReferences";
|
|
2975
2983
|
var LIST_LIMIT = "50";
|
|
2976
2984
|
var PR_INDEX_LIMIT = "100";
|
|
2985
|
+
var SEARCH_LIMIT = "1000";
|
|
2977
2986
|
async function runJson(run3, args) {
|
|
2978
2987
|
const out = await run3(args);
|
|
2979
2988
|
const parsed = JSON.parse(out || "[]");
|
|
@@ -3070,6 +3079,34 @@ async function fetchRepoItems(run3, repo) {
|
|
|
3070
3079
|
prs: mergeItems([assignedPrs, authoredPrs, reviewPrs, reviewedPrs])
|
|
3071
3080
|
};
|
|
3072
3081
|
}
|
|
3082
|
+
async function findRelatedRepos(run3) {
|
|
3083
|
+
const searches = [
|
|
3084
|
+
["issues", ["--assignee", "@me"]],
|
|
3085
|
+
["issues", ["--author", "@me"]],
|
|
3086
|
+
["prs", ["--assignee", "@me"]],
|
|
3087
|
+
["prs", ["--author", "@me"]],
|
|
3088
|
+
["prs", ["--review-requested", "@me"]],
|
|
3089
|
+
["prs", ["--reviewed-by", "@me"]]
|
|
3090
|
+
];
|
|
3091
|
+
const results = await Promise.all(searches.map(([kind, filter]) => runJson(run3, [
|
|
3092
|
+
"search",
|
|
3093
|
+
kind,
|
|
3094
|
+
"--state",
|
|
3095
|
+
"open",
|
|
3096
|
+
"--limit",
|
|
3097
|
+
SEARCH_LIMIT,
|
|
3098
|
+
...filter,
|
|
3099
|
+
"--json",
|
|
3100
|
+
"repository"
|
|
3101
|
+
])));
|
|
3102
|
+
const found2 = /* @__PURE__ */ new Set();
|
|
3103
|
+
for (const rows of results) for (const row of rows) {
|
|
3104
|
+
const repository = row.repository;
|
|
3105
|
+
const name = repository?.nameWithOwner;
|
|
3106
|
+
if (typeof name === "string" && isRepoName(name)) found2.add(name);
|
|
3107
|
+
}
|
|
3108
|
+
return Array.from(found2).sort();
|
|
3109
|
+
}
|
|
3073
3110
|
async function fetchPrIndex(run3, repo) {
|
|
3074
3111
|
const rows = await runJson(run3, [
|
|
3075
3112
|
"pr",
|
|
@@ -3166,6 +3203,7 @@ function createGithubService(options) {
|
|
|
3166
3203
|
const items = /* @__PURE__ */ new Map();
|
|
3167
3204
|
const indexes = /* @__PURE__ */ new Map();
|
|
3168
3205
|
const repos = /* @__PURE__ */ new Map();
|
|
3206
|
+
const discovery = /* @__PURE__ */ new Map();
|
|
3169
3207
|
function cached2(map, key, force, load) {
|
|
3170
3208
|
const hit = map.get(key);
|
|
3171
3209
|
if (hit && !force && now() - hit.at < GITHUB_CACHE_TTL_MS) return hit;
|
|
@@ -3196,11 +3234,12 @@ function createGithubService(options) {
|
|
|
3196
3234
|
const byProject = await projectRepos(board, force);
|
|
3197
3235
|
const repoProject = /* @__PURE__ */ new Map();
|
|
3198
3236
|
for (const [project, repo] of byProject) if (!repoProject.has(repo)) repoProject.set(repo, project);
|
|
3199
|
-
const
|
|
3237
|
+
const discovered = cached2(discovery, "related", force, () => findRelatedRepos(run3));
|
|
3238
|
+
const entries = (await discovered.value).map((repo) => [repo, repoProject.get(repo) ?? null]);
|
|
3200
3239
|
const results = await Promise.all(
|
|
3201
3240
|
entries.map(async ([repo, projectPath]) => {
|
|
3202
3241
|
const entry = cached2(items, repo, force, () => fetchRepoItems(run3, repo));
|
|
3203
|
-
const head = { repo, projectPath, projectName: basename(projectPath) };
|
|
3242
|
+
const head = { repo, projectPath, projectName: projectPath ? basename(projectPath) : repo };
|
|
3204
3243
|
try {
|
|
3205
3244
|
return { at: entry.at, inbox: { ...head, ...await entry.value } };
|
|
3206
3245
|
} catch (err) {
|
|
@@ -3211,7 +3250,7 @@ function createGithubService(options) {
|
|
|
3211
3250
|
return {
|
|
3212
3251
|
status: "ok",
|
|
3213
3252
|
...auth.login ? { login: auth.login } : {},
|
|
3214
|
-
fetchedAt:
|
|
3253
|
+
fetchedAt: Math.min(discovered.at, ...results.map((r) => r.at)),
|
|
3215
3254
|
repos: results.map((r) => r.inbox).sort((a, b) => a.repo.localeCompare(b.repo))
|
|
3216
3255
|
};
|
|
3217
3256
|
},
|
|
@@ -3654,10 +3693,10 @@ async function ignoredEntryFitsCopyBudget(src) {
|
|
|
3654
3693
|
const stat = await fs8.lstat(current);
|
|
3655
3694
|
if (stat.isSymbolicLink()) continue;
|
|
3656
3695
|
if (stat.isDirectory()) {
|
|
3657
|
-
const
|
|
3658
|
-
files +=
|
|
3696
|
+
const children2 = await fs8.readdir(current, { withFileTypes: true });
|
|
3697
|
+
files += children2.length;
|
|
3659
3698
|
if (files > MAX_IGNORED_COPY_FILES) return false;
|
|
3660
|
-
for (const child of
|
|
3699
|
+
for (const child of children2) stack.push(path12.join(current, child.name));
|
|
3661
3700
|
continue;
|
|
3662
3701
|
}
|
|
3663
3702
|
files += 1;
|
|
@@ -4305,7 +4344,8 @@ async function createTaskFromInput(input) {
|
|
|
4305
4344
|
model: input.model || void 0,
|
|
4306
4345
|
effort: input.effort ?? DEFAULT_TASK_EFFORT,
|
|
4307
4346
|
autoMode: input.autoMode,
|
|
4308
|
-
...input.github ? { github: input.github } : {}
|
|
4347
|
+
...input.github ? { github: input.github } : {},
|
|
4348
|
+
...input.jira ? { jira: input.jira } : {}
|
|
4309
4349
|
};
|
|
4310
4350
|
try {
|
|
4311
4351
|
const board = store.get("board");
|
|
@@ -4789,17 +4829,17 @@ function listLibrary(root, builtinDir) {
|
|
|
4789
4829
|
const full = path14.join(dir, name);
|
|
4790
4830
|
if (wantsDirectory && !fs10.existsSync(path14.join(full, "SKILL.md"))) continue;
|
|
4791
4831
|
const key = entryKey(kind, name);
|
|
4792
|
-
const
|
|
4832
|
+
const record2 = index.entries[key] ?? {};
|
|
4793
4833
|
entries.push({
|
|
4794
4834
|
key,
|
|
4795
4835
|
kind,
|
|
4796
4836
|
name,
|
|
4797
4837
|
path: full,
|
|
4798
|
-
description: wantsDirectory ? readSkillDescription(path14.join(full, "SKILL.md")) :
|
|
4799
|
-
sourcePath:
|
|
4800
|
-
importedAt:
|
|
4801
|
-
enabled:
|
|
4802
|
-
builtin: wantsDirectory &&
|
|
4838
|
+
description: wantsDirectory ? readSkillDescription(path14.join(full, "SKILL.md")) : record2.description,
|
|
4839
|
+
sourcePath: record2.sourcePath,
|
|
4840
|
+
importedAt: record2.importedAt,
|
|
4841
|
+
enabled: record2.enabled !== false,
|
|
4842
|
+
builtin: wantsDirectory && record2.builtinHash && builtinDir !== void 0 ? builtinStatus(full, name, record2.builtinHash, builtinDir) : void 0
|
|
4803
4843
|
});
|
|
4804
4844
|
}
|
|
4805
4845
|
}
|
|
@@ -4874,8 +4914,8 @@ function markBuiltinDeleted(root, key) {
|
|
|
4874
4914
|
function deleteEntry(root, kind, name) {
|
|
4875
4915
|
fs10.rmSync(entryPath(root, kind, name), { recursive: true, force: true });
|
|
4876
4916
|
const key = entryKey(kind, name);
|
|
4877
|
-
const
|
|
4878
|
-
if (
|
|
4917
|
+
const record2 = readIndex(root).entries[key];
|
|
4918
|
+
if (record2?.builtinHash || record2?.builtinDeleted) {
|
|
4879
4919
|
markBuiltinDeleted(root, key);
|
|
4880
4920
|
return;
|
|
4881
4921
|
}
|
|
@@ -5070,10 +5110,10 @@ function syncBuiltinSkills(root, builtinDir) {
|
|
|
5070
5110
|
}
|
|
5071
5111
|
function syncOne(root, builtinDir, name, result) {
|
|
5072
5112
|
const key = entryKey("skill", name);
|
|
5073
|
-
const
|
|
5074
|
-
if (
|
|
5113
|
+
const record2 = readIndex(root).entries[key] ?? {};
|
|
5114
|
+
if (record2.builtinDeleted) return;
|
|
5075
5115
|
const target = entryPath(root, "skill", name);
|
|
5076
|
-
if (!
|
|
5116
|
+
if (!record2.builtinHash) {
|
|
5077
5117
|
if (fs11.existsSync(target)) return;
|
|
5078
5118
|
annotate(root, key, {
|
|
5079
5119
|
builtinHash: installBuiltin(root, builtinDir, name),
|
|
@@ -5087,8 +5127,8 @@ function syncOne(root, builtinDir, name, result) {
|
|
|
5087
5127
|
markBuiltinDeleted(root, key);
|
|
5088
5128
|
return;
|
|
5089
5129
|
}
|
|
5090
|
-
if (hashSkillDir(path15.join(builtinDir, name)) ===
|
|
5091
|
-
if (hashSkillDir(target) !==
|
|
5130
|
+
if (hashSkillDir(path15.join(builtinDir, name)) === record2.builtinHash) return;
|
|
5131
|
+
if (hashSkillDir(target) !== record2.builtinHash) return;
|
|
5092
5132
|
annotate(root, key, { builtinHash: installBuiltin(root, builtinDir, name) });
|
|
5093
5133
|
result.updated.push(name);
|
|
5094
5134
|
}
|
|
@@ -5103,10 +5143,10 @@ function restoreBuiltinSkill(root, builtinDir, name) {
|
|
|
5103
5143
|
ensureLibrary(root);
|
|
5104
5144
|
const builtinHash = installBuiltin(root, builtinDir, name);
|
|
5105
5145
|
const index = readIndex(root);
|
|
5106
|
-
const
|
|
5107
|
-
delete
|
|
5108
|
-
delete
|
|
5109
|
-
index.entries[key] =
|
|
5146
|
+
const record2 = { ...index.entries[key], builtinHash, enabled: true, importedAt: Date.now() };
|
|
5147
|
+
delete record2.builtinDeleted;
|
|
5148
|
+
delete record2.sourcePath;
|
|
5149
|
+
index.entries[key] = record2;
|
|
5110
5150
|
writeIndex(root, index);
|
|
5111
5151
|
const entry = listLibrary(root, builtinDir).find((e) => e.key === key);
|
|
5112
5152
|
if (!entry) throw new Error(`\u9084\u539F\u5931\u6557\uFF1A${name}`);
|
|
@@ -5203,12 +5243,12 @@ function spawnJsonLines(bin, args, opts) {
|
|
|
5203
5243
|
}
|
|
5204
5244
|
});
|
|
5205
5245
|
proc.on("exit", (code2, signal) => {
|
|
5206
|
-
finished();
|
|
5207
5246
|
clearTimeout(timer);
|
|
5208
5247
|
clearTimeout(graceTimer);
|
|
5209
5248
|
const reason = signal ? `was killed (${signal})` : `exited with code ${code2}`;
|
|
5210
5249
|
fail2(new Error(`${bin} ${reason}${stderr.trim() ? `: ${stderr.trim()}` : ""}`));
|
|
5211
5250
|
});
|
|
5251
|
+
proc.on("close", finished);
|
|
5212
5252
|
proc.stdin.on("error", () => {
|
|
5213
5253
|
});
|
|
5214
5254
|
const kill = () => {
|
|
@@ -5644,6 +5684,334 @@ function startGitHubCliLogin(onEvent) {
|
|
|
5644
5684
|
});
|
|
5645
5685
|
}
|
|
5646
5686
|
|
|
5687
|
+
// packages/core/src/jira-adf.ts
|
|
5688
|
+
function record(value) {
|
|
5689
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
5690
|
+
}
|
|
5691
|
+
function children(node) {
|
|
5692
|
+
return Array.isArray(node.content) ? node.content : [];
|
|
5693
|
+
}
|
|
5694
|
+
function render(node, depth = 0) {
|
|
5695
|
+
if (typeof node === "string") return node;
|
|
5696
|
+
const item = record(node);
|
|
5697
|
+
if (!item) return "";
|
|
5698
|
+
const type = item.type;
|
|
5699
|
+
const body = () => children(item).map((child) => render(child, depth)).join("");
|
|
5700
|
+
const attrs = record(item.attrs);
|
|
5701
|
+
if (type === "text") {
|
|
5702
|
+
let value = typeof item.text === "string" ? item.text : "";
|
|
5703
|
+
for (const mark of Array.isArray(item.marks) ? item.marks : []) {
|
|
5704
|
+
const m = record(mark);
|
|
5705
|
+
if (m?.type === "strong") value = `**${value}**`;
|
|
5706
|
+
if (m?.type === "em") value = `*${value}*`;
|
|
5707
|
+
if (m?.type === "strike") value = `~~${value}~~`;
|
|
5708
|
+
if (m?.type === "code") value = `\`${value}\``;
|
|
5709
|
+
if (m?.type === "link" && typeof record(m.attrs)?.href === "string") value = `[${value}](${record(m.attrs)?.href})`;
|
|
5710
|
+
}
|
|
5711
|
+
return value;
|
|
5712
|
+
}
|
|
5713
|
+
if (type === "hardBreak") return " \n";
|
|
5714
|
+
if (type === "rule") return "\n---\n\n";
|
|
5715
|
+
if (type === "mention") return `@${String(attrs?.text ?? attrs?.id ?? "")}`;
|
|
5716
|
+
if (type === "emoji") return String(attrs?.shortName ?? "");
|
|
5717
|
+
if (type === "inlineCard" || type === "blockCard") return `[${String(attrs?.url ?? "\u9023\u7D50")}](${String(attrs?.url ?? "")})`;
|
|
5718
|
+
if (type === "media" || type === "mediaSingle") return "[\u9644\u4EF6]";
|
|
5719
|
+
if (type === "paragraph") return `${body()}
|
|
5720
|
+
|
|
5721
|
+
`;
|
|
5722
|
+
if (type === "heading") return `${"#".repeat(Math.min(6, Math.max(1, Number(attrs?.level) || 1)))} ${body()}
|
|
5723
|
+
|
|
5724
|
+
`;
|
|
5725
|
+
if (type === "blockquote") return body().trim().split("\n").map((line) => `> ${line}`).join("\n") + "\n\n";
|
|
5726
|
+
if (type === "codeBlock") return `
|
|
5727
|
+
\`\`\`${String(attrs?.language ?? "")}
|
|
5728
|
+
${children(item).map((child) => render(child)).join("").trimEnd()}
|
|
5729
|
+
\`\`\`
|
|
5730
|
+
|
|
5731
|
+
`;
|
|
5732
|
+
if (type === "bulletList" || type === "orderedList") {
|
|
5733
|
+
return children(item).map((child, index) => {
|
|
5734
|
+
const content = render(child, depth + 1).trim().replace(/\n\n/g, "\n");
|
|
5735
|
+
const prefix = type === "orderedList" ? `${index + 1}. ` : "- ";
|
|
5736
|
+
return `${" ".repeat(depth)}${prefix}${content}
|
|
5737
|
+
`;
|
|
5738
|
+
}).join("") + "\n";
|
|
5739
|
+
}
|
|
5740
|
+
if (type === "listItem") return body();
|
|
5741
|
+
if (type === "table") {
|
|
5742
|
+
const rows = children(item).map((row) => {
|
|
5743
|
+
const cells = children(record(row) ?? {}).map((cell) => render(cell).trim().replace(/\|/g, "\\|").replace(/\n+/g, " "));
|
|
5744
|
+
return `| ${cells.join(" | ")} |`;
|
|
5745
|
+
});
|
|
5746
|
+
if (rows.length === 0) return "";
|
|
5747
|
+
const width = children(record(children(item)[0]) ?? {}).length;
|
|
5748
|
+
rows.splice(1, 0, `| ${Array(width).fill("---").join(" | ")} |`);
|
|
5749
|
+
return rows.join("\n") + "\n\n";
|
|
5750
|
+
}
|
|
5751
|
+
return body();
|
|
5752
|
+
}
|
|
5753
|
+
function adfToMarkdown(value) {
|
|
5754
|
+
return render(value).trim();
|
|
5755
|
+
}
|
|
5756
|
+
|
|
5757
|
+
// packages/core/src/jira-auth.ts
|
|
5758
|
+
init_env();
|
|
5759
|
+
import { execFile as execFile8 } from "child_process";
|
|
5760
|
+
import { promisify as promisify5 } from "util";
|
|
5761
|
+
import * as nodePty4 from "node-pty";
|
|
5762
|
+
var pexec5 = promisify5(execFile8);
|
|
5763
|
+
var activeLogin2 = null;
|
|
5764
|
+
var activeCancel = null;
|
|
5765
|
+
function stripAnsi2(value) {
|
|
5766
|
+
return value.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/\x07/g, "");
|
|
5767
|
+
}
|
|
5768
|
+
function hasSingleSitePrompt(output) {
|
|
5769
|
+
const clean = stripAnsi2(output);
|
|
5770
|
+
if (!/select the site to login/i.test(clean) || !/enter submit/i.test(clean)) return false;
|
|
5771
|
+
const sites = new Set([...clean.matchAll(/https:\/\/([a-z0-9.-]+\.atlassian\.net)\b/gi)].map((match) => match[1].toLowerCase()));
|
|
5772
|
+
return sites.size === 1;
|
|
5773
|
+
}
|
|
5774
|
+
function parseAuthStatus(output) {
|
|
5775
|
+
const clean = stripAnsi2(output);
|
|
5776
|
+
const site = clean.match(/(?:site|host)\s*:\s*(?:https?:\/\/)?([a-z0-9.-]+\.atlassian\.net)/i)?.[1];
|
|
5777
|
+
const email = clean.match(/(?:email|user)\s*:\s*([^\s]+@[^\s]+)/i)?.[1];
|
|
5778
|
+
return {
|
|
5779
|
+
installed: true,
|
|
5780
|
+
authenticated: Boolean(site) && !/not (?:logged|authenticated)|unauthenticated/i.test(clean),
|
|
5781
|
+
...site ? { site } : {},
|
|
5782
|
+
...email ? { email } : {}
|
|
5783
|
+
};
|
|
5784
|
+
}
|
|
5785
|
+
var defaultAcliRunner = async (args) => {
|
|
5786
|
+
const { stdout } = await pexec5("acli", args, {
|
|
5787
|
+
env: execEnv(),
|
|
5788
|
+
timeout: 6e4,
|
|
5789
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
5790
|
+
windowsHide: true
|
|
5791
|
+
});
|
|
5792
|
+
return stdout.toString();
|
|
5793
|
+
};
|
|
5794
|
+
async function getJiraAuthStatus(run3 = defaultAcliRunner) {
|
|
5795
|
+
try {
|
|
5796
|
+
return parseAuthStatus(await run3(["jira", "auth", "status"]));
|
|
5797
|
+
} catch (err) {
|
|
5798
|
+
const error = err;
|
|
5799
|
+
if (error.code === "ENOENT") return { installed: false, authenticated: false };
|
|
5800
|
+
return { installed: true, authenticated: false, error: stripAnsi2(String(error.stderr || error.message || err)) };
|
|
5801
|
+
}
|
|
5802
|
+
}
|
|
5803
|
+
function cancelJiraLogin() {
|
|
5804
|
+
activeCancel?.();
|
|
5805
|
+
activeCancel = null;
|
|
5806
|
+
if (!activeLogin2) return;
|
|
5807
|
+
const process2 = activeLogin2;
|
|
5808
|
+
activeLogin2 = null;
|
|
5809
|
+
try {
|
|
5810
|
+
process2.kill();
|
|
5811
|
+
} catch {
|
|
5812
|
+
}
|
|
5813
|
+
}
|
|
5814
|
+
function inputJiraLogin(data) {
|
|
5815
|
+
activeLogin2?.write(data);
|
|
5816
|
+
}
|
|
5817
|
+
function startJiraLogin(onEvent, run3 = defaultAcliRunner) {
|
|
5818
|
+
cancelJiraLogin();
|
|
5819
|
+
onEvent({ type: "starting" });
|
|
5820
|
+
let process2;
|
|
5821
|
+
try {
|
|
5822
|
+
process2 = nodePty4.spawn("acli", ["jira", "auth", "login", "--web"], {
|
|
5823
|
+
name: "xterm-256color",
|
|
5824
|
+
cwd: processCwd(),
|
|
5825
|
+
env: { ...execEnv(), TERM: "xterm-256color" },
|
|
5826
|
+
cols: 100,
|
|
5827
|
+
rows: 24
|
|
5828
|
+
});
|
|
5829
|
+
} catch (err) {
|
|
5830
|
+
onEvent({ type: "error", error: String(err.message ?? err) });
|
|
5831
|
+
return;
|
|
5832
|
+
}
|
|
5833
|
+
activeLogin2 = process2;
|
|
5834
|
+
let output = "";
|
|
5835
|
+
let sentUrl = false;
|
|
5836
|
+
let autoSelectedSite = false;
|
|
5837
|
+
let cancelled = false;
|
|
5838
|
+
activeCancel = () => {
|
|
5839
|
+
cancelled = true;
|
|
5840
|
+
onEvent({ type: "cancelled" });
|
|
5841
|
+
};
|
|
5842
|
+
process2.onData((chunk) => {
|
|
5843
|
+
onEvent({ type: "output", data: chunk });
|
|
5844
|
+
output += chunk;
|
|
5845
|
+
if (output.length > 64e3) output = output.slice(-64e3);
|
|
5846
|
+
const clean = stripAnsi2(output);
|
|
5847
|
+
const url = clean.match(/https:\/\/[^\s<>"']+/)?.[0];
|
|
5848
|
+
if (url && !sentUrl) {
|
|
5849
|
+
sentUrl = true;
|
|
5850
|
+
onEvent({ type: "url", url });
|
|
5851
|
+
}
|
|
5852
|
+
if (!autoSelectedSite && hasSingleSitePrompt(clean)) {
|
|
5853
|
+
autoSelectedSite = true;
|
|
5854
|
+
process2.write("\r");
|
|
5855
|
+
}
|
|
5856
|
+
});
|
|
5857
|
+
process2.onExit(async ({ exitCode }) => {
|
|
5858
|
+
if (activeLogin2 !== process2) return;
|
|
5859
|
+
activeLogin2 = null;
|
|
5860
|
+
activeCancel = null;
|
|
5861
|
+
if (cancelled) return;
|
|
5862
|
+
if (exitCode === 0) {
|
|
5863
|
+
const status = await getJiraAuthStatus(run3);
|
|
5864
|
+
onEvent(status.authenticated ? { type: "success", status } : { type: "error", error: status.error ?? "\u767B\u5165\u5B8C\u6210\uFF0C\u4F46\u7121\u6CD5\u78BA\u8A8D Atlassian \u5E33\u865F\u3002" });
|
|
5865
|
+
} else {
|
|
5866
|
+
const clean = stripAnsi2(output);
|
|
5867
|
+
const error = clean.match(/(?:✗\s*)?Error:[^\r\n]*/g)?.at(-1) ?? clean.split(/[\r\n]+/).map((line) => line.trim()).filter(Boolean).at(-1);
|
|
5868
|
+
onEvent({ type: "error", error: error || `Atlassian \u767B\u5165\u5931\u6557\uFF08exit ${exitCode}\uFF09\u3002` });
|
|
5869
|
+
}
|
|
5870
|
+
});
|
|
5871
|
+
}
|
|
5872
|
+
function processCwd() {
|
|
5873
|
+
return process.cwd();
|
|
5874
|
+
}
|
|
5875
|
+
async function logoutJira(run3 = defaultAcliRunner) {
|
|
5876
|
+
await run3(["jira", "auth", "logout"]);
|
|
5877
|
+
return getJiraAuthStatus(run3);
|
|
5878
|
+
}
|
|
5879
|
+
|
|
5880
|
+
// packages/core/src/jira.ts
|
|
5881
|
+
var asRaw = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : {};
|
|
5882
|
+
var nameOf = (v) => typeof v === "string" ? v : String(asRaw(v).name ?? "");
|
|
5883
|
+
var JIRA_INBOX_JQL = "assignee = currentUser() AND (statusCategory != Done OR sprint in openSprints()) ORDER BY updated DESC";
|
|
5884
|
+
var DEFAULT_POINT_FIELDS = ["customfield_10033", "customfield_10016"];
|
|
5885
|
+
var JIRA_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
5886
|
+
function buildSearchArgs() {
|
|
5887
|
+
return [
|
|
5888
|
+
"jira",
|
|
5889
|
+
"workitem",
|
|
5890
|
+
"search",
|
|
5891
|
+
"--jql",
|
|
5892
|
+
JIRA_INBOX_JQL,
|
|
5893
|
+
"--fields",
|
|
5894
|
+
"key,summary,status,issuetype,priority,description",
|
|
5895
|
+
"--json",
|
|
5896
|
+
"--paginate",
|
|
5897
|
+
"--limit",
|
|
5898
|
+
"200"
|
|
5899
|
+
];
|
|
5900
|
+
}
|
|
5901
|
+
function buildViewArgs(key, pointFields = DEFAULT_POINT_FIELDS) {
|
|
5902
|
+
return [
|
|
5903
|
+
"jira",
|
|
5904
|
+
"workitem",
|
|
5905
|
+
"view",
|
|
5906
|
+
key,
|
|
5907
|
+
"--fields",
|
|
5908
|
+
[.../* @__PURE__ */ new Set(["duedate", "parent", "created", "updated", "project", "customfield_10020", ...pointFields])].join(","),
|
|
5909
|
+
"--json"
|
|
5910
|
+
];
|
|
5911
|
+
}
|
|
5912
|
+
function isJiraRef(value) {
|
|
5913
|
+
const v = asRaw(value);
|
|
5914
|
+
return typeof v.key === "string" && /^[A-Z][A-Z0-9_]+-\d+$/.test(v.key) && typeof v.site === "string" && /^[a-z0-9-]+(?:\.[a-z0-9-]+)*\.atlassian\.net$/.test(v.site) && v.url === `https://${v.site}/browse/${v.key}`;
|
|
5915
|
+
}
|
|
5916
|
+
function toTicket(raw, site, pointFields = DEFAULT_POINT_FIELDS) {
|
|
5917
|
+
const row = asRaw(raw);
|
|
5918
|
+
const fields = asRaw(row.fields);
|
|
5919
|
+
const source = Object.keys(fields).length ? fields : row;
|
|
5920
|
+
const key = row.key;
|
|
5921
|
+
if (typeof key !== "string" || !/^[A-Z][A-Z0-9_]+-\d+$/.test(key)) return null;
|
|
5922
|
+
const status = asRaw(source.status);
|
|
5923
|
+
const category = asRaw(status.statusCategory);
|
|
5924
|
+
const categoryKey = String(category.key ?? category.name ?? "").toLowerCase();
|
|
5925
|
+
const points = pointFields.map((field) => source[field]).find((v) => typeof v === "number" && Number.isFinite(v));
|
|
5926
|
+
const sprintValue = source.customfield_10020;
|
|
5927
|
+
const sprintList = Array.isArray(sprintValue) ? sprintValue : sprintValue ? [sprintValue] : [];
|
|
5928
|
+
const activeSprint = sprintList.map(asRaw).find((s) => String(s.state ?? "").toLowerCase() === "active");
|
|
5929
|
+
const parent = asRaw(source.parent);
|
|
5930
|
+
return {
|
|
5931
|
+
key,
|
|
5932
|
+
url: `https://${site}/browse/${key}`,
|
|
5933
|
+
projectKey: String(asRaw(source.project).key ?? key.split("-")[0]),
|
|
5934
|
+
summary: String(source.summary ?? ""),
|
|
5935
|
+
status: { name: nameOf(source.status), category: categoryKey === "done" ? "done" : categoryKey === "indeterminate" || categoryKey === "in progress" ? "indeterminate" : "new" },
|
|
5936
|
+
issueType: nameOf(source.issuetype),
|
|
5937
|
+
priority: nameOf(source.priority) || null,
|
|
5938
|
+
storyPoints: typeof points === "number" ? points : null,
|
|
5939
|
+
dueDate: typeof source.duedate === "string" ? source.duedate : null,
|
|
5940
|
+
sprint: typeof activeSprint?.name === "string" ? activeSprint.name : null,
|
|
5941
|
+
parentKey: typeof parent.key === "string" ? parent.key : null,
|
|
5942
|
+
description: adfToMarkdown(source.description),
|
|
5943
|
+
createdAt: String(source.created ?? ""),
|
|
5944
|
+
updatedAt: String(source.updated ?? "")
|
|
5945
|
+
};
|
|
5946
|
+
}
|
|
5947
|
+
function searchRows(output) {
|
|
5948
|
+
const parsed = JSON.parse(output);
|
|
5949
|
+
if (Array.isArray(parsed)) return parsed;
|
|
5950
|
+
const body = asRaw(parsed);
|
|
5951
|
+
if (Array.isArray(body.issues)) return body.issues;
|
|
5952
|
+
if (Array.isArray(body.values)) return body.values;
|
|
5953
|
+
throw new Error("\u7121\u6CD5\u8FA8\u8B58 acli Jira search \u7684 JSON \u683C\u5F0F");
|
|
5954
|
+
}
|
|
5955
|
+
async function enrichRows(rows, run3, pointFields) {
|
|
5956
|
+
const enriched = Array.from(rows);
|
|
5957
|
+
let next = 0;
|
|
5958
|
+
let failed = 0;
|
|
5959
|
+
async function worker() {
|
|
5960
|
+
while (next < rows.length) {
|
|
5961
|
+
const index = next++;
|
|
5962
|
+
const row = asRaw(rows[index]);
|
|
5963
|
+
if (typeof row.key !== "string") continue;
|
|
5964
|
+
try {
|
|
5965
|
+
const detail = asRaw(JSON.parse(await run3(buildViewArgs(row.key, pointFields))));
|
|
5966
|
+
enriched[index] = { ...row, fields: { ...asRaw(row.fields), ...asRaw(detail.fields) } };
|
|
5967
|
+
} catch {
|
|
5968
|
+
failed++;
|
|
5969
|
+
}
|
|
5970
|
+
}
|
|
5971
|
+
}
|
|
5972
|
+
await Promise.all(Array.from({ length: Math.min(6, rows.length) }, () => worker()));
|
|
5973
|
+
return { rows: enriched, failed };
|
|
5974
|
+
}
|
|
5975
|
+
function createJiraService(options) {
|
|
5976
|
+
const run3 = options.run ?? defaultAcliRunner;
|
|
5977
|
+
const authStatus = options.authStatus ?? (() => getJiraAuthStatus(run3));
|
|
5978
|
+
const now = options.now ?? Date.now;
|
|
5979
|
+
let cache = null;
|
|
5980
|
+
return {
|
|
5981
|
+
clear() {
|
|
5982
|
+
cache = null;
|
|
5983
|
+
},
|
|
5984
|
+
async inbox(opts = {}) {
|
|
5985
|
+
const auth = await authStatus();
|
|
5986
|
+
if (!auth.installed) return { status: "acli-missing", fetchedAt: 0, tickets: [] };
|
|
5987
|
+
if (!auth.authenticated || !auth.site) return { status: "unauthenticated", fetchedAt: 0, tickets: [] };
|
|
5988
|
+
if (cache && cache.site === auth.site && !opts.force && now() - cache.at < JIRA_CACHE_TTL_MS) return cache.value;
|
|
5989
|
+
const at = now();
|
|
5990
|
+
const pointFields = options.pointFields?.() ?? DEFAULT_POINT_FIELDS;
|
|
5991
|
+
const value = run3(buildSearchArgs()).then(async (output) => {
|
|
5992
|
+
const detail = await enrichRows(searchRows(output), run3, pointFields);
|
|
5993
|
+
return {
|
|
5994
|
+
status: "ok",
|
|
5995
|
+
site: auth.site,
|
|
5996
|
+
email: auth.email,
|
|
5997
|
+
fetchedAt: at,
|
|
5998
|
+
tickets: detail.rows.map((row) => toTicket(row, auth.site, pointFields)).filter((ticket) => ticket !== null),
|
|
5999
|
+
...detail.failed ? { error: `${detail.failed} \u5F35 Jira ticket \u7684\u8A73\u7D30\u6B04\u4F4D\u8B80\u53D6\u5931\u6557\uFF1B\u6E05\u55AE\u4ECD\u53EF\u67E5\u770B\u3002` } : {}
|
|
6000
|
+
};
|
|
6001
|
+
}).catch((err) => ({
|
|
6002
|
+
status: "ok",
|
|
6003
|
+
site: auth.site,
|
|
6004
|
+
email: auth.email,
|
|
6005
|
+
fetchedAt: at,
|
|
6006
|
+
tickets: [],
|
|
6007
|
+
error: String(err.stderr || err.message || err)
|
|
6008
|
+
}));
|
|
6009
|
+
cache = { at, site: auth.site, value };
|
|
6010
|
+
return value;
|
|
6011
|
+
}
|
|
6012
|
+
};
|
|
6013
|
+
}
|
|
6014
|
+
|
|
5647
6015
|
// packages/core/src/board-cli.ts
|
|
5648
6016
|
import fs14 from "fs";
|
|
5649
6017
|
import path18 from "path";
|
|
@@ -5766,7 +6134,7 @@ async function readSpecsAt(cwd, ref, paths) {
|
|
|
5766
6134
|
// packages/core/src/chat-session.ts
|
|
5767
6135
|
init_env();
|
|
5768
6136
|
init_git_bash();
|
|
5769
|
-
import { spawn as
|
|
6137
|
+
import { spawn as spawn7 } from "child_process";
|
|
5770
6138
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
5771
6139
|
|
|
5772
6140
|
// packages/core/src/chat-store.ts
|
|
@@ -5922,7 +6290,7 @@ ${attachmentLines.join("\n")}` : text;
|
|
|
5922
6290
|
`--append-system-prompt ${quote(systemPrompt)}`,
|
|
5923
6291
|
quote(fullText)
|
|
5924
6292
|
].filter(Boolean).join(" ") : buildRawAgentCommand(agentCli, model, fullText, systemPrompt, worktreePath, quote, workspacePath);
|
|
5925
|
-
const proc =
|
|
6293
|
+
const proc = spawn7(shell.command, shell.args(cmd), {
|
|
5926
6294
|
cwd: worktreePath,
|
|
5927
6295
|
env: execEnv()
|
|
5928
6296
|
});
|
|
@@ -6397,7 +6765,7 @@ function validBoard(value) {
|
|
|
6397
6765
|
}
|
|
6398
6766
|
return next;
|
|
6399
6767
|
}
|
|
6400
|
-
function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatus, modelCatalog }) {
|
|
6768
|
+
function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatus, acliRunner, jiraAuthStatus, modelCatalog }) {
|
|
6401
6769
|
const sink = bus.sink();
|
|
6402
6770
|
const models = modelCatalog ?? createModelCatalog({ version });
|
|
6403
6771
|
let libraryCodexHome = null;
|
|
@@ -6549,6 +6917,11 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6549
6917
|
authStatus: githubAuthStatus ?? getGitHubCliAuthStatus,
|
|
6550
6918
|
repoOf: async (projectPath) => parseGithubRepo((await getGitInfo(projectPath)).remoteUrl)
|
|
6551
6919
|
});
|
|
6920
|
+
const jira = createJiraService({
|
|
6921
|
+
run: acliRunner,
|
|
6922
|
+
authStatus: jiraAuthStatus ?? (() => getJiraAuthStatus(acliRunner)),
|
|
6923
|
+
pointFields: () => getSettings().jira?.storyPointsFields?.length ? getSettings().jira.storyPointsFields : DEFAULT_POINT_FIELDS
|
|
6924
|
+
});
|
|
6552
6925
|
const handlers = {
|
|
6553
6926
|
"vibeflow:getState": () => getState(),
|
|
6554
6927
|
// A card's progress right now (todo list, usage, activity), for a frontend
|
|
@@ -6568,7 +6941,13 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6568
6941
|
return getState();
|
|
6569
6942
|
},
|
|
6570
6943
|
"vibeflow:setSettings": (patch) => {
|
|
6571
|
-
|
|
6944
|
+
const value = obj(patch, "patch");
|
|
6945
|
+
if (value.jira !== void 0) {
|
|
6946
|
+
const fields = obj(value.jira, "jira")?.storyPointsFields;
|
|
6947
|
+
if (fields !== void 0 && (!Array.isArray(fields) || !fields.every((field) => typeof field === "string" && /^customfield_\d+$/.test(field)))) invalid("jira.storyPointsFields must contain customfield IDs");
|
|
6948
|
+
jira.clear();
|
|
6949
|
+
}
|
|
6950
|
+
setSettings(value);
|
|
6572
6951
|
return getState();
|
|
6573
6952
|
},
|
|
6574
6953
|
"settings:githubAuthStatus": () => getGitHubCliAuthStatus(),
|
|
@@ -6589,6 +6968,25 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6589
6968
|
const p = payload === void 0 ? {} : obj(payload, "payload");
|
|
6590
6969
|
return github.taskLinks(getState().board, { force: p.force === true });
|
|
6591
6970
|
},
|
|
6971
|
+
"jira:authStatus": () => (jiraAuthStatus ?? (() => getJiraAuthStatus(acliRunner)))(),
|
|
6972
|
+
"settings:startJiraAuthLogin": () => {
|
|
6973
|
+
startJiraLogin((event) => {
|
|
6974
|
+
if (event.type === "success") jira.clear();
|
|
6975
|
+
bus.emit("jira-auth:event", event);
|
|
6976
|
+
}, acliRunner);
|
|
6977
|
+
},
|
|
6978
|
+
"settings:cancelJiraAuthLogin": () => cancelJiraLogin(),
|
|
6979
|
+
"settings:inputJiraAuthLogin": (payload) => inputJiraLogin(str(payload, "input").slice(0, 1e3)),
|
|
6980
|
+
"settings:logoutJiraAuth": async () => {
|
|
6981
|
+
const status = await logoutJira(acliRunner);
|
|
6982
|
+
jira.clear();
|
|
6983
|
+
bus.emit("jira-auth:event", { type: "signed-out", status });
|
|
6984
|
+
return status;
|
|
6985
|
+
},
|
|
6986
|
+
"jira:inbox": (payload) => {
|
|
6987
|
+
const p = payload === void 0 ? {} : obj(payload, "payload");
|
|
6988
|
+
return jira.inbox({ force: p.force === true });
|
|
6989
|
+
},
|
|
6592
6990
|
"env:detectAgents": () => detectAgents(),
|
|
6593
6991
|
"agents:listModels": (payload) => {
|
|
6594
6992
|
const { agentId: rawId, refresh } = obj(payload, "payload");
|
|
@@ -6620,6 +7018,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6620
7018
|
if (p.effort !== void 0 && !AGENT_EFFORTS.includes(p.effort)) invalid("unknown effort");
|
|
6621
7019
|
if (p.agentCli !== void 0 && !AGENT_IDS2.includes(p.agentCli)) invalid("unknown agent");
|
|
6622
7020
|
if (p.github !== void 0 && !isGithubRef(p.github)) invalid("github must be an issue or pr ref on github.com");
|
|
7021
|
+
if (p.jira !== void 0 && !isJiraRef(p.jira)) invalid("jira must be a Jira ticket ref");
|
|
6623
7022
|
const { task } = await createTaskFromInput({
|
|
6624
7023
|
projectPath: p.projectPath,
|
|
6625
7024
|
title: p.title,
|
|
@@ -6632,7 +7031,8 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
6632
7031
|
effort: p.effort,
|
|
6633
7032
|
autoMode: p.autoMode,
|
|
6634
7033
|
attachments: p.attachments,
|
|
6635
|
-
github: p.github
|
|
7034
|
+
github: p.github,
|
|
7035
|
+
jira: p.jira
|
|
6636
7036
|
});
|
|
6637
7037
|
return { state: getState(), task };
|
|
6638
7038
|
},
|
|
@@ -7049,6 +7449,7 @@ function createCore({ sessions, bus, version, homeDir, ghRunner, githubAuthStatu
|
|
|
7049
7449
|
models.warm();
|
|
7050
7450
|
},
|
|
7051
7451
|
shutdown() {
|
|
7452
|
+
cancelJiraLogin();
|
|
7052
7453
|
sessions.shutdown();
|
|
7053
7454
|
cancelAllChatSends();
|
|
7054
7455
|
unwatchAllSubAgents();
|
|
@@ -7505,12 +7906,12 @@ function connectToHost(lock) {
|
|
|
7505
7906
|
// packages/cli/src/doctor.ts
|
|
7506
7907
|
import fs21 from "fs";
|
|
7507
7908
|
import path25 from "path";
|
|
7508
|
-
import { execFile as
|
|
7509
|
-
import { promisify as
|
|
7909
|
+
import { execFile as execFile9 } from "child_process";
|
|
7910
|
+
import { promisify as promisify6 } from "util";
|
|
7510
7911
|
init_env();
|
|
7511
7912
|
init_git_bash();
|
|
7512
7913
|
init_tmux_backend();
|
|
7513
|
-
var
|
|
7914
|
+
var pexec6 = promisify6(execFile9);
|
|
7514
7915
|
function parseVersion(text) {
|
|
7515
7916
|
const m = /(\d+)\.(\d+)(?:\.(\d+))?/.exec(text);
|
|
7516
7917
|
return m ? [Number(m[1]), Number(m[2]), Number(m[3] ?? 0)] : [];
|
|
@@ -7524,7 +7925,7 @@ function versionAtLeast(have, want) {
|
|
|
7524
7925
|
}
|
|
7525
7926
|
async function run2(cmd, args) {
|
|
7526
7927
|
try {
|
|
7527
|
-
const { stdout } = await
|
|
7928
|
+
const { stdout } = await pexec6(cmd, args, { env: execEnv(), timeout: 1e4, windowsHide: true });
|
|
7528
7929
|
return String(stdout).trim();
|
|
7529
7930
|
} catch {
|
|
7530
7931
|
return null;
|