pipe-kan 0.14.0 → 0.15.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/dist/pipe-kan.js +98 -13
- package/package.json +1 -1
package/dist/pipe-kan.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/server.ts
|
|
4
|
-
import { readFileSync as
|
|
4
|
+
import { readFileSync as readFileSync3, writeSync } from "node:fs";
|
|
5
5
|
import { createServer } from "node:http";
|
|
6
6
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
7
|
-
import { join as
|
|
7
|
+
import { join as join7 } from "node:path";
|
|
8
8
|
|
|
9
9
|
// src/board.ts
|
|
10
10
|
function formatDueDate(value) {
|
|
@@ -10763,8 +10763,83 @@ function permissionOptionForDecision(options, decision) {
|
|
|
10763
10763
|
return options.find((o) => o.kind === kind)?.optionId ?? options[0]?.optionId ?? null;
|
|
10764
10764
|
}
|
|
10765
10765
|
|
|
10766
|
+
// src/server/agent/skills.ts
|
|
10767
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync } from "node:fs";
|
|
10768
|
+
import { homedir as homedir2 } from "node:os";
|
|
10769
|
+
import { join as join4 } from "node:path";
|
|
10770
|
+
function createSkillRegistry(bundledDir = join4(import.meta.dirname, "..", "..", "..", ".agents", "skills")) {
|
|
10771
|
+
const userDir = join4(homedir2(), ".pi", "agent", "skills");
|
|
10772
|
+
return {
|
|
10773
|
+
list() {
|
|
10774
|
+
const bundled = listSkills(bundledDir);
|
|
10775
|
+
const user = existsSync3(userDir) ? listSkills(userDir) : [];
|
|
10776
|
+
const map = new Map;
|
|
10777
|
+
for (const skill of bundled)
|
|
10778
|
+
map.set(skill.id, skill);
|
|
10779
|
+
for (const skill of user)
|
|
10780
|
+
map.set(skill.id, skill);
|
|
10781
|
+
return [...map.values()].sort((a, b) => a.id.localeCompare(b.id));
|
|
10782
|
+
},
|
|
10783
|
+
load(id) {
|
|
10784
|
+
const userPath = skillPath(userDir, id);
|
|
10785
|
+
if (existsSync3(userPath))
|
|
10786
|
+
return readSkill(userPath, id);
|
|
10787
|
+
const bundledPath = skillPath(bundledDir, id);
|
|
10788
|
+
if (existsSync3(bundledPath))
|
|
10789
|
+
return readSkill(bundledPath, id);
|
|
10790
|
+
return;
|
|
10791
|
+
}
|
|
10792
|
+
};
|
|
10793
|
+
}
|
|
10794
|
+
function skillContextBlock(skill) {
|
|
10795
|
+
return {
|
|
10796
|
+
type: "resource",
|
|
10797
|
+
resource: {
|
|
10798
|
+
uri: `skill://${skill.id}`,
|
|
10799
|
+
mimeType: "text/markdown",
|
|
10800
|
+
text: skill.body
|
|
10801
|
+
}
|
|
10802
|
+
};
|
|
10803
|
+
}
|
|
10804
|
+
function listSkills(dir) {
|
|
10805
|
+
if (!existsSync3(dir))
|
|
10806
|
+
return [];
|
|
10807
|
+
return readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => readSkill(skillPath(dir, entry.name), entry.name)).filter((skill) => skill !== undefined);
|
|
10808
|
+
}
|
|
10809
|
+
function skillPath(dir, id) {
|
|
10810
|
+
return join4(dir, id, "SKILL.md");
|
|
10811
|
+
}
|
|
10812
|
+
function readSkill(path, id) {
|
|
10813
|
+
try {
|
|
10814
|
+
const text = readFileSync2(path, "utf8");
|
|
10815
|
+
const front = parseFrontMatter(text);
|
|
10816
|
+
return {
|
|
10817
|
+
id,
|
|
10818
|
+
name: front.name ?? id,
|
|
10819
|
+
description: front.description ?? "",
|
|
10820
|
+
body: text
|
|
10821
|
+
};
|
|
10822
|
+
} catch {
|
|
10823
|
+
return;
|
|
10824
|
+
}
|
|
10825
|
+
}
|
|
10826
|
+
function parseFrontMatter(text) {
|
|
10827
|
+
const match = text.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
|
|
10828
|
+
if (!match)
|
|
10829
|
+
return {};
|
|
10830
|
+
const out = {};
|
|
10831
|
+
for (const line of match[1].split(`
|
|
10832
|
+
`)) {
|
|
10833
|
+
const idx = line.indexOf(":");
|
|
10834
|
+
if (idx > 0)
|
|
10835
|
+
out[line.slice(0, idx).trim()] = line.slice(idx + 1).trim();
|
|
10836
|
+
}
|
|
10837
|
+
return out;
|
|
10838
|
+
}
|
|
10839
|
+
|
|
10766
10840
|
// src/server/agent/api.ts
|
|
10767
10841
|
var sessions = new Map;
|
|
10842
|
+
var skills = createSkillRegistry();
|
|
10768
10843
|
function json2(res, status, body) {
|
|
10769
10844
|
res.statusCode = status;
|
|
10770
10845
|
res.setHeader("content-type", "application/json");
|
|
@@ -10795,6 +10870,10 @@ function handleAgentApi(req, res) {
|
|
|
10795
10870
|
});
|
|
10796
10871
|
return true;
|
|
10797
10872
|
}
|
|
10873
|
+
if (url.pathname === "/api/agent/skills" && method === "GET") {
|
|
10874
|
+
json2(res, 200, skills.list().map((s) => ({ id: s.id, name: s.name, description: s.description })));
|
|
10875
|
+
return true;
|
|
10876
|
+
}
|
|
10798
10877
|
if (url.pathname === "/api/agent/session" && method === "POST") {
|
|
10799
10878
|
const cfg = loadAgentConfig();
|
|
10800
10879
|
const backendConfig = cfg.agents[cfg.defaultAgent];
|
|
@@ -10817,7 +10896,13 @@ function handleAgentApi(req, res) {
|
|
|
10817
10896
|
json2(res, 404, { error: "Session not found" });
|
|
10818
10897
|
return;
|
|
10819
10898
|
}
|
|
10820
|
-
|
|
10899
|
+
const context = [...body.context ?? []];
|
|
10900
|
+
if (body.skillId) {
|
|
10901
|
+
const skill = skills.load(body.skillId);
|
|
10902
|
+
if (skill)
|
|
10903
|
+
context.push(skillContextBlock(skill));
|
|
10904
|
+
}
|
|
10905
|
+
return session.prompt(String(body.prompt ?? ""), context).then(() => {
|
|
10821
10906
|
json2(res, 200, { ok: true });
|
|
10822
10907
|
});
|
|
10823
10908
|
}).catch((err) => json2(res, 500, { error: String(err) }));
|
|
@@ -10999,10 +11084,10 @@ function handleRequest(req, res, ctx) {
|
|
|
10999
11084
|
|
|
11000
11085
|
// src/jira-config.ts
|
|
11001
11086
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
11002
|
-
import { join as
|
|
11087
|
+
import { join as join5 } from "node:path";
|
|
11003
11088
|
function writeJiraConfig(dir, server) {
|
|
11004
11089
|
mkdirSync(dir, { recursive: true });
|
|
11005
|
-
const path =
|
|
11090
|
+
const path = join5(dir, "jira.config.yml");
|
|
11006
11091
|
writeFileSync(path, [
|
|
11007
11092
|
"installation: Cloud",
|
|
11008
11093
|
`server: ${server}`,
|
|
@@ -11057,8 +11142,8 @@ function stdinStat() {
|
|
|
11057
11142
|
}
|
|
11058
11143
|
|
|
11059
11144
|
// src/ui.ts
|
|
11060
|
-
import { createReadStream, existsSync as
|
|
11061
|
-
import { dirname, extname, join as
|
|
11145
|
+
import { createReadStream, existsSync as existsSync4, statSync } from "node:fs";
|
|
11146
|
+
import { dirname, extname, join as join6, resolve as resolve2, sep } from "node:path";
|
|
11062
11147
|
import { fileURLToPath } from "node:url";
|
|
11063
11148
|
var types = {
|
|
11064
11149
|
".css": "text/css; charset=utf-8",
|
|
@@ -11075,7 +11160,7 @@ function packageRoot(from = import.meta.url) {
|
|
|
11075
11160
|
return resolve2(dirname(fileURLToPath(from)), "..");
|
|
11076
11161
|
}
|
|
11077
11162
|
function uiDir(root) {
|
|
11078
|
-
return
|
|
11163
|
+
return join6(root, "dist", "ui");
|
|
11079
11164
|
}
|
|
11080
11165
|
function inside(root, file) {
|
|
11081
11166
|
const base = resolve2(root);
|
|
@@ -11084,12 +11169,12 @@ function inside(root, file) {
|
|
|
11084
11169
|
}
|
|
11085
11170
|
function sendUi(root, req, res) {
|
|
11086
11171
|
const ui = uiDir(root);
|
|
11087
|
-
const index =
|
|
11088
|
-
if (!
|
|
11172
|
+
const index = join6(ui, "index.html");
|
|
11173
|
+
if (!existsSync4(index))
|
|
11089
11174
|
return false;
|
|
11090
11175
|
const path = new URL(req.url ?? "/", "http://127.0.0.1").pathname;
|
|
11091
11176
|
const wanted = resolve2(ui, `.${decodeURIComponent(path)}`);
|
|
11092
|
-
const file = inside(ui, wanted) &&
|
|
11177
|
+
const file = inside(ui, wanted) && existsSync4(wanted) && statSync(wanted).isFile() ? wanted : index;
|
|
11093
11178
|
res.setHeader("content-type", types[extname(file)] ?? "application/octet-stream");
|
|
11094
11179
|
createReadStream(file).pipe(res);
|
|
11095
11180
|
return true;
|
|
@@ -11105,7 +11190,7 @@ function announce(line) {
|
|
|
11105
11190
|
}
|
|
11106
11191
|
async function runServer(opts) {
|
|
11107
11192
|
const piped = await readPipe();
|
|
11108
|
-
const raw = piped ?? JSON.parse(
|
|
11193
|
+
const raw = piped ?? JSON.parse(readFileSync3(join7(opts.root, "fixtures/issues.json"), "utf8"));
|
|
11109
11194
|
const { app, store, kind } = await createBoardApp({
|
|
11110
11195
|
raw,
|
|
11111
11196
|
piped: Boolean(piped)
|
|
@@ -11125,7 +11210,7 @@ async function runServer(opts) {
|
|
|
11125
11210
|
const { host, port } = resolveListen();
|
|
11126
11211
|
await bindListen(server, host, port);
|
|
11127
11212
|
const origin = `http://127.0.0.1:${port}`;
|
|
11128
|
-
const fakeConfig = writeJiraConfig(
|
|
11213
|
+
const fakeConfig = writeJiraConfig(join7(tmpdir2(), "pipe-kan"), origin);
|
|
11129
11214
|
announce(`pipe-kan http://${host}:${port}`);
|
|
11130
11215
|
announce(`cli ${kind === "jira" ? resolveJiraBin() : "store"}`);
|
|
11131
11216
|
announce(`Fake Jira ${origin}/rest/api/2/search`);
|