opencode-skills-deck 0.2.0-rc.0 → 0.3.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 +70 -56
- package/dist/gui-experimental.cjs +61 -0
- package/dist/index.js +1455 -118
- package/dist/index.js.map +4 -4
- package/dist/rpc.js +19929 -0
- package/dist/rpc.js.map +7 -0
- package/dist/tui.js +151 -37
- package/dist/tui.js.map +3 -3
- package/package.json +27 -7
package/dist/tui.js
CHANGED
|
@@ -5089,7 +5089,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
5089
5089
|
var NONE = 0;
|
|
5090
5090
|
var ASSUMED = 1;
|
|
5091
5091
|
var PROVEN = 2;
|
|
5092
|
-
function isRecursive(inst, stack,
|
|
5092
|
+
function isRecursive(inst, stack, resolve3) {
|
|
5093
5093
|
const cached2 = recursive.get(inst);
|
|
5094
5094
|
if (cached2 !== void 0)
|
|
5095
5095
|
return cached2 ? PROVEN : NONE;
|
|
@@ -5099,7 +5099,7 @@ function isRecursive(inst, stack, resolve2) {
|
|
|
5099
5099
|
let result = NONE;
|
|
5100
5100
|
const check2 = (child) => {
|
|
5101
5101
|
if (result !== PROVEN && child?._zod) {
|
|
5102
|
-
const answer = isRecursive(child, stack,
|
|
5102
|
+
const answer = isRecursive(child, stack, resolve3);
|
|
5103
5103
|
if (answer > result)
|
|
5104
5104
|
result = answer;
|
|
5105
5105
|
}
|
|
@@ -5110,7 +5110,7 @@ function isRecursive(inst, stack, resolve2) {
|
|
|
5110
5110
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
5111
5111
|
if (spread && !desc.enumerable)
|
|
5112
5112
|
continue;
|
|
5113
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
5113
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve3) : NONE;
|
|
5114
5114
|
if (child > answer)
|
|
5115
5115
|
answer = child;
|
|
5116
5116
|
}
|
|
@@ -5174,7 +5174,7 @@ function isRecursive(inst, stack, resolve2) {
|
|
|
5174
5174
|
break;
|
|
5175
5175
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
5176
5176
|
case "lazy": {
|
|
5177
|
-
const inner = def._cachedInner ?? (
|
|
5177
|
+
const inner = def._cachedInner ?? (resolve3 ? inst._zod.innerType : void 0);
|
|
5178
5178
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
5179
5179
|
break;
|
|
5180
5180
|
}
|
|
@@ -19790,16 +19790,36 @@ function normalizeOpenKey(value) {
|
|
|
19790
19790
|
// packages/core/src/exec.ts
|
|
19791
19791
|
import { spawn } from "node:child_process";
|
|
19792
19792
|
var MAX_BUFFER = 16 * 1024 * 1024;
|
|
19793
|
-
|
|
19794
|
-
|
|
19793
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
19794
|
+
function createRunner(options = {}) {
|
|
19795
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
19796
|
+
return (command, args, options2) => new Promise((resolve3, reject) => {
|
|
19795
19797
|
const child = spawn(command, args, {
|
|
19796
|
-
cwd:
|
|
19798
|
+
cwd: options2?.cwd,
|
|
19797
19799
|
env: process.env,
|
|
19798
19800
|
stdio: ["ignore", "pipe", "pipe"]
|
|
19799
19801
|
});
|
|
19800
19802
|
let stdout = "";
|
|
19801
19803
|
let stderr = "";
|
|
19802
19804
|
let overflow = false;
|
|
19805
|
+
let settled = false;
|
|
19806
|
+
const fail = (error62) => {
|
|
19807
|
+
if (settled) return;
|
|
19808
|
+
settled = true;
|
|
19809
|
+
clearTimeout(timer);
|
|
19810
|
+
reject(error62);
|
|
19811
|
+
};
|
|
19812
|
+
const succeed = (result) => {
|
|
19813
|
+
if (settled) return;
|
|
19814
|
+
settled = true;
|
|
19815
|
+
clearTimeout(timer);
|
|
19816
|
+
resolve3(result);
|
|
19817
|
+
};
|
|
19818
|
+
const timer = setTimeout(() => {
|
|
19819
|
+
child.kill("SIGTERM");
|
|
19820
|
+
fail(new Error(`${command} ${args.join(" ")} timed out after ${timeoutMs}ms`));
|
|
19821
|
+
}, timeoutMs);
|
|
19822
|
+
timer.unref?.();
|
|
19803
19823
|
child.stdout?.setEncoding("utf8");
|
|
19804
19824
|
child.stderr?.setEncoding("utf8");
|
|
19805
19825
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -19819,19 +19839,20 @@ function createRunner() {
|
|
|
19819
19839
|
}
|
|
19820
19840
|
});
|
|
19821
19841
|
child.on("error", (error62) => {
|
|
19822
|
-
|
|
19842
|
+
fail(new Error(`${command} ${args.join(" ")} failed: ${error62.message}`));
|
|
19823
19843
|
});
|
|
19824
19844
|
child.on("close", (code) => {
|
|
19845
|
+
if (settled) return;
|
|
19825
19846
|
if (overflow) {
|
|
19826
|
-
|
|
19847
|
+
fail(new Error(`${command} ${args.join(" ")} failed: \u51FA\u529B\u304C\u5927\u304D\u3059\u304E\u307E\u3059`));
|
|
19827
19848
|
return;
|
|
19828
19849
|
}
|
|
19829
19850
|
if (code === 0) {
|
|
19830
|
-
|
|
19851
|
+
succeed({ stdout, stderr });
|
|
19831
19852
|
return;
|
|
19832
19853
|
}
|
|
19833
19854
|
const detail = stderr.trim() || `exit code ${code ?? "unknown"}`;
|
|
19834
|
-
|
|
19855
|
+
fail(new Error(`${command} ${args.join(" ")} failed: ${detail}`));
|
|
19835
19856
|
});
|
|
19836
19857
|
});
|
|
19837
19858
|
}
|
|
@@ -19879,7 +19900,7 @@ function resolvePaths(options = {}) {
|
|
|
19879
19900
|
|
|
19880
19901
|
// packages/core/src/repo.ts
|
|
19881
19902
|
import { execFileSync } from "node:child_process";
|
|
19882
|
-
import { join as join3 } from "node:path";
|
|
19903
|
+
import { dirname, join as join3, resolve } from "node:path";
|
|
19883
19904
|
var REMOTE_PATTERNS = [
|
|
19884
19905
|
/^git@[^:]+:(?<owner>[^/]+)\/(?<name>[^/]+?)(?:\.git)?$/,
|
|
19885
19906
|
/^(?:ssh|git|https?):\/\/(?:[^@/]+@)?[^/]+\/(?<owner>[^/]+)\/(?<name>[^/]+?)(?:\.git)?\/?$/
|
|
@@ -20174,8 +20195,8 @@ function launchInTerminal(input2) {
|
|
|
20174
20195
|
}
|
|
20175
20196
|
|
|
20176
20197
|
// packages/core/src/worktree.ts
|
|
20177
|
-
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
20178
|
-
import { join as join6, resolve, sep } from "node:path";
|
|
20198
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, realpathSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
20199
|
+
import { join as join6, resolve as resolve2, sep } from "node:path";
|
|
20179
20200
|
async function defaultBranch(input2) {
|
|
20180
20201
|
if (input2.configured) return input2.configured;
|
|
20181
20202
|
try {
|
|
@@ -20199,12 +20220,44 @@ async function ensureWorktreesExcluded(input2) {
|
|
|
20199
20220
|
writeFileSync2(path, `${existing}${suffix}.worktrees/
|
|
20200
20221
|
`);
|
|
20201
20222
|
}
|
|
20223
|
+
async function readWorktreeEntries(input2) {
|
|
20224
|
+
const { stdout } = await input2.runner("git", ["worktree", "list", "--porcelain"], {
|
|
20225
|
+
cwd: input2.repoRoot
|
|
20226
|
+
});
|
|
20227
|
+
const entries = [];
|
|
20228
|
+
let current = null;
|
|
20229
|
+
for (const line of stdout.split("\n")) {
|
|
20230
|
+
if (line.startsWith("worktree ")) {
|
|
20231
|
+
if (current) entries.push(current);
|
|
20232
|
+
current = {
|
|
20233
|
+
directory: line.slice("worktree ".length).trim(),
|
|
20234
|
+
branch: null,
|
|
20235
|
+
detached: false,
|
|
20236
|
+
bare: false
|
|
20237
|
+
};
|
|
20238
|
+
continue;
|
|
20239
|
+
}
|
|
20240
|
+
if (!current) continue;
|
|
20241
|
+
if (line.startsWith("branch ")) {
|
|
20242
|
+
current.branch = line.slice("branch ".length).replace(/^refs\/heads\//, "").trim();
|
|
20243
|
+
} else if (line === "detached") {
|
|
20244
|
+
current.detached = true;
|
|
20245
|
+
} else if (line === "bare") {
|
|
20246
|
+
current.bare = true;
|
|
20247
|
+
}
|
|
20248
|
+
}
|
|
20249
|
+
if (current) entries.push(current);
|
|
20250
|
+
return entries;
|
|
20251
|
+
}
|
|
20202
20252
|
async function registeredWorktrees(input2) {
|
|
20203
|
-
|
|
20204
|
-
return stdout.split("\n").filter((line) => line.startsWith("worktree ")).map((line) => line.slice("worktree ".length).trim());
|
|
20253
|
+
return (await readWorktreeEntries(input2)).map((entry) => entry.directory);
|
|
20205
20254
|
}
|
|
20206
20255
|
function normalized(path) {
|
|
20207
|
-
|
|
20256
|
+
try {
|
|
20257
|
+
return realpathSync(path).replace(/\/+$/, "");
|
|
20258
|
+
} catch {
|
|
20259
|
+
return resolve2(path).replace(/\/+$/, "");
|
|
20260
|
+
}
|
|
20208
20261
|
}
|
|
20209
20262
|
async function findOrphanWorktrees(input2) {
|
|
20210
20263
|
const root = normalized(join6(input2.repoRoot, ".worktrees"));
|
|
@@ -20372,8 +20425,8 @@ function dispatchDialogue(input2) {
|
|
|
20372
20425
|
}
|
|
20373
20426
|
|
|
20374
20427
|
// packages/core/src/issue.ts
|
|
20375
|
-
import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
20376
|
-
import { dirname, join as join7 } from "node:path";
|
|
20428
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
20429
|
+
import { dirname as dirname2, join as join7 } from "node:path";
|
|
20377
20430
|
var SUMMARY_HEADING = /summary|要約|概要/i;
|
|
20378
20431
|
var CRITERIA_HEADING = /acceptance criteria|受け入れ基準|完了条件|acceptance/i;
|
|
20379
20432
|
var BULLET = /^\s*(?:[-*+]|\d+\.)\s+(?:\[[ xX]\]\s*)?(.+)$/;
|
|
@@ -20433,39 +20486,100 @@ async function fetchIssues(input2) {
|
|
|
20433
20486
|
function issueCachePath(paths, repo) {
|
|
20434
20487
|
return join7(paths.issueCacheDir, `${repo.owner}__${repo.name}.json`);
|
|
20435
20488
|
}
|
|
20489
|
+
function normalizeCachedIssue(value) {
|
|
20490
|
+
if (!value || typeof value !== "object") return null;
|
|
20491
|
+
const issue2 = value;
|
|
20492
|
+
if (typeof issue2.number !== "number" || typeof issue2.title !== "string") return null;
|
|
20493
|
+
return {
|
|
20494
|
+
number: issue2.number,
|
|
20495
|
+
title: issue2.title,
|
|
20496
|
+
labels: Array.isArray(issue2.labels) ? issue2.labels.filter((label) => typeof label === "string") : [],
|
|
20497
|
+
state: typeof issue2.state === "string" ? issue2.state : "OPEN",
|
|
20498
|
+
updatedAt: typeof issue2.updatedAt === "string" ? issue2.updatedAt : (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
20499
|
+
summary: typeof issue2.summary === "string" ? issue2.summary : "",
|
|
20500
|
+
criteria: Array.isArray(issue2.criteria) ? issue2.criteria.filter((criterion) => typeof criterion === "string") : []
|
|
20501
|
+
};
|
|
20502
|
+
}
|
|
20436
20503
|
function readIssueCache(path) {
|
|
20437
20504
|
try {
|
|
20438
20505
|
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
20439
|
-
|
|
20506
|
+
if (!Array.isArray(parsed.issues) || typeof parsed.fetchedAt !== "number") {
|
|
20507
|
+
rmSync2(path, { force: true });
|
|
20508
|
+
return null;
|
|
20509
|
+
}
|
|
20510
|
+
const issues = parsed.issues.map(normalizeCachedIssue);
|
|
20511
|
+
if (issues.some((issue2) => issue2 === null)) {
|
|
20512
|
+
rmSync2(path, { force: true });
|
|
20513
|
+
return null;
|
|
20514
|
+
}
|
|
20515
|
+
return { fetchedAt: parsed.fetchedAt, issues };
|
|
20440
20516
|
} catch {
|
|
20517
|
+
try {
|
|
20518
|
+
rmSync2(path, { force: true });
|
|
20519
|
+
} catch {
|
|
20520
|
+
}
|
|
20441
20521
|
return null;
|
|
20442
20522
|
}
|
|
20443
20523
|
}
|
|
20444
20524
|
function writeIssueCache(path, cache) {
|
|
20445
|
-
mkdirSync2(
|
|
20446
|
-
|
|
20525
|
+
mkdirSync2(dirname2(path), { recursive: true });
|
|
20526
|
+
const temporary = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
20527
|
+
writeFileSync3(temporary, `${JSON.stringify(cache, null, 2)}
|
|
20528
|
+
`);
|
|
20529
|
+
renameSync2(temporary, path);
|
|
20447
20530
|
}
|
|
20448
20531
|
var CACHE_TTL_MS = 6e4;
|
|
20449
|
-
|
|
20532
|
+
function classifyGhError(error62) {
|
|
20533
|
+
const message = error62 instanceof Error ? error62.message : String(error62);
|
|
20534
|
+
if (/not authenticated|authentication|401|gh auth login/i.test(message)) {
|
|
20535
|
+
return { code: "auth", message };
|
|
20536
|
+
}
|
|
20537
|
+
if (/rate limit|secondary rate|403/i.test(message)) {
|
|
20538
|
+
return { code: "rate_limit", message };
|
|
20539
|
+
}
|
|
20540
|
+
if (/ENOTFOUND|ECONNREFUSED|ETIMEDOUT|fetch failed|network/i.test(message)) {
|
|
20541
|
+
return { code: "network", message };
|
|
20542
|
+
}
|
|
20543
|
+
if (/^gh\b|gh issue/i.test(message)) return { code: "gh", message };
|
|
20544
|
+
return { code: "unknown", message };
|
|
20545
|
+
}
|
|
20546
|
+
async function loadIssuesResult(input2) {
|
|
20450
20547
|
const path = issueCachePath(input2.paths, input2.repo);
|
|
20451
20548
|
const now = input2.now ?? Date.now();
|
|
20452
|
-
|
|
20453
|
-
|
|
20454
|
-
|
|
20549
|
+
const cache = readIssueCache(path);
|
|
20550
|
+
if (!input2.force && cache && now - cache.fetchedAt < CACHE_TTL_MS) {
|
|
20551
|
+
return { issues: cache.issues, cached: true, stale: false, fetchedAt: cache.fetchedAt, error: null };
|
|
20455
20552
|
}
|
|
20456
|
-
|
|
20457
|
-
|
|
20458
|
-
|
|
20459
|
-
|
|
20460
|
-
|
|
20461
|
-
|
|
20462
|
-
|
|
20463
|
-
|
|
20553
|
+
try {
|
|
20554
|
+
const issues = await fetchIssues({
|
|
20555
|
+
repo: input2.repo,
|
|
20556
|
+
config: input2.config,
|
|
20557
|
+
runner: input2.runner,
|
|
20558
|
+
cwd: input2.cwd
|
|
20559
|
+
});
|
|
20560
|
+
writeIssueCache(path, { fetchedAt: now, issues });
|
|
20561
|
+
return { issues, cached: false, stale: false, fetchedAt: now, error: null };
|
|
20562
|
+
} catch (error62) {
|
|
20563
|
+
const failure2 = classifyGhError(error62);
|
|
20564
|
+
if (cache) {
|
|
20565
|
+
return {
|
|
20566
|
+
issues: cache.issues,
|
|
20567
|
+
cached: true,
|
|
20568
|
+
stale: true,
|
|
20569
|
+
fetchedAt: cache.fetchedAt,
|
|
20570
|
+
error: failure2
|
|
20571
|
+
};
|
|
20572
|
+
}
|
|
20573
|
+
return { issues: [], cached: false, stale: false, fetchedAt: null, error: failure2 };
|
|
20574
|
+
}
|
|
20575
|
+
}
|
|
20576
|
+
async function loadIssues(input2) {
|
|
20577
|
+
return (await loadIssuesResult(input2)).issues;
|
|
20464
20578
|
}
|
|
20465
20579
|
|
|
20466
20580
|
// packages/core/src/skills.ts
|
|
20467
20581
|
import { createHash } from "node:crypto";
|
|
20468
|
-
import { cpSync, existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync5, rmSync as
|
|
20582
|
+
import { cpSync, existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync5, rmSync as rmSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
20469
20583
|
import { join as join8, relative, sep as sep2 } from "node:path";
|
|
20470
20584
|
var MANIFEST_NAME = ".skills-deck.json";
|
|
20471
20585
|
function hashSkillDir(dir) {
|
|
@@ -20552,7 +20666,7 @@ function installBundledSkills(input2) {
|
|
|
20552
20666
|
result.unchanged.push(name);
|
|
20553
20667
|
continue;
|
|
20554
20668
|
}
|
|
20555
|
-
|
|
20669
|
+
rmSync3(target, { recursive: true, force: true });
|
|
20556
20670
|
cpSync(source, target, { recursive: true });
|
|
20557
20671
|
manifest.skills[name] = { hash: sourceHash, updatedAt: now };
|
|
20558
20672
|
result.updated.push(name);
|
|
@@ -21395,7 +21509,7 @@ function ControlTower() {
|
|
|
21395
21509
|
async function withDialog(open2) {
|
|
21396
21510
|
setDialogOpen(true);
|
|
21397
21511
|
try {
|
|
21398
|
-
await new Promise((
|
|
21512
|
+
await new Promise((resolve3) => setTimeout(resolve3, 0));
|
|
21399
21513
|
return await open2();
|
|
21400
21514
|
} finally {
|
|
21401
21515
|
setDialogOpen(false);
|