@arshdelight/practi 0.9.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/LICENSE +21 -0
- package/README.md +81 -0
- package/dist/client.js +84 -0
- package/dist/client.js.map +1 -0
- package/dist/cmd/blob.js +97 -0
- package/dist/cmd/blob.js.map +1 -0
- package/dist/cmd/clone.js +76 -0
- package/dist/cmd/clone.js.map +1 -0
- package/dist/cmd/comment.js +210 -0
- package/dist/cmd/comment.js.map +1 -0
- package/dist/cmd/config.js +30 -0
- package/dist/cmd/config.js.map +1 -0
- package/dist/cmd/edit.js +122 -0
- package/dist/cmd/edit.js.map +1 -0
- package/dist/cmd/init.js +11 -0
- package/dist/cmd/init.js.map +1 -0
- package/dist/cmd/lifecycle.js +69 -0
- package/dist/cmd/lifecycle.js.map +1 -0
- package/dist/cmd/login.js +125 -0
- package/dist/cmd/login.js.map +1 -0
- package/dist/cmd/ls.js +59 -0
- package/dist/cmd/ls.js.map +1 -0
- package/dist/cmd/new.js +57 -0
- package/dist/cmd/new.js.map +1 -0
- package/dist/cmd/pull.js +94 -0
- package/dist/cmd/pull.js.map +1 -0
- package/dist/cmd/push.js +84 -0
- package/dist/cmd/push.js.map +1 -0
- package/dist/cmd/remote.js +48 -0
- package/dist/cmd/remote.js.map +1 -0
- package/dist/cmd/search.js +137 -0
- package/dist/cmd/search.js.map +1 -0
- package/dist/cmd/show.js +61 -0
- package/dist/cmd/show.js.map +1 -0
- package/dist/cmd/skill.js +198 -0
- package/dist/cmd/skill.js.map +1 -0
- package/dist/cmd/spec.js +10 -0
- package/dist/cmd/spec.js.map +1 -0
- package/dist/cmd/update.js +60 -0
- package/dist/cmd/update.js.map +1 -0
- package/dist/credentials.js +65 -0
- package/dist/credentials.js.map +1 -0
- package/dist/index.js +412 -0
- package/dist/index.js.map +1 -0
- package/dist/oauth.js +244 -0
- package/dist/oauth.js.map +1 -0
- package/dist/render.js +25 -0
- package/dist/render.js.map +1 -0
- package/dist/state.js +74 -0
- package/dist/state.js.map +1 -0
- package/dist/version.js +12 -0
- package/dist/version.js.map +1 -0
- package/dist/web.js +243 -0
- package/dist/web.js.map +1 -0
- package/dist/workspace.js +38 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +48 -0
- package/skills/use-practi/SKILL.md +186 -0
package/dist/cmd/push.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { exportSubtree, resolveNodeRef } from '@arshdelight/pop-sdk';
|
|
2
|
+
import { defaultDataDir, loadState } from '../state.js';
|
|
3
|
+
import { openWorkspace } from '../workspace.js';
|
|
4
|
+
import { authedFetch, fetchMine } from '../client.js';
|
|
5
|
+
/**
|
|
6
|
+
* practi push [hash]:把本地认领增量推送到 practihub(git push 的对象协商语义)。
|
|
7
|
+
* - 先分页取 hub 上「我的」认领表(mine),diff 出本地认领而 hub 我还没认领的,
|
|
8
|
+
* 只传这些(带 hash 只推该 direct;不带推全部 direct)——不再全量 POST。
|
|
9
|
+
* - 走 POST /api/v1/pop(内容寻址幂等):hub 没有就存,有则 idempotent 不重复写,
|
|
10
|
+
* 且每次上传都获得 DIRECT 认领。默认存为 PRIVATE;公开仍需 submit 审核。
|
|
11
|
+
*/
|
|
12
|
+
export async function runPush(opts) {
|
|
13
|
+
const dataDir = opts.dataDir ?? defaultDataDir();
|
|
14
|
+
const state = loadState(dataDir);
|
|
15
|
+
if (!state.remote) {
|
|
16
|
+
console.error('error: no remote configured — run `practi remote set <url>` first');
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
const ws = openWorkspace(dataDir);
|
|
20
|
+
const targets = opts.positional[0] ? [opts.positional[0]] : state.direct;
|
|
21
|
+
if (targets.length === 0) {
|
|
22
|
+
console.error('error: no direct pops to push (none registered)');
|
|
23
|
+
return 1;
|
|
24
|
+
}
|
|
25
|
+
// 认领表 diff 的基准:hub 上我已认领的 hash 集合
|
|
26
|
+
let mineHashes;
|
|
27
|
+
try {
|
|
28
|
+
const mine = await fetchMine(dataDir, state.remote.url);
|
|
29
|
+
mineHashes = new Set(mine.map((r) => r.root_hash));
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
console.error(`error: ${e.message}`);
|
|
33
|
+
return 1;
|
|
34
|
+
}
|
|
35
|
+
// 解析目标为完整 hash,只保留本地认领而 hub 我还没认领的(增量)
|
|
36
|
+
const toPush = [];
|
|
37
|
+
let failed = 0;
|
|
38
|
+
for (const ref of targets) {
|
|
39
|
+
let resolved;
|
|
40
|
+
try {
|
|
41
|
+
resolved = resolveNodeRef(ws, ref);
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
console.error(`push failed: ${ref} — ${e.message}`);
|
|
45
|
+
failed++;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (!mineHashes.has(resolved))
|
|
49
|
+
toPush.push(resolved);
|
|
50
|
+
}
|
|
51
|
+
if (toPush.length === 0) {
|
|
52
|
+
console.log('up to date — no new direct pops to push');
|
|
53
|
+
return failed ? 1 : 0;
|
|
54
|
+
}
|
|
55
|
+
for (const ref of toPush) {
|
|
56
|
+
try {
|
|
57
|
+
const node = ws.nodes.get(ref);
|
|
58
|
+
if (!node)
|
|
59
|
+
throw new Error(`node not found: ${ref}`);
|
|
60
|
+
const doc = exportSubtree(node, ws.nodes);
|
|
61
|
+
const res = await authedFetch(dataDir, state.remote.url, '/api/v1/pop', {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
headers: { 'content-type': 'application/json' },
|
|
64
|
+
body: JSON.stringify(doc),
|
|
65
|
+
});
|
|
66
|
+
const body = (await res.json().catch(() => ({})));
|
|
67
|
+
if (!res.ok) {
|
|
68
|
+
const detail = typeof body.message === 'string' ? body.message : typeof body.error === 'string' ? body.error : `HTTP ${res.status}`;
|
|
69
|
+
console.error(`push failed: ${ref} — ${detail}`);
|
|
70
|
+
failed++;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const name = doc.name ?? '';
|
|
74
|
+
const status = String(body.status ?? 'PRIVATE');
|
|
75
|
+
console.log(`pushed: ${ref} (${body.idempotent ? 'already existed' : 'stored'}, ${status}) ${name}`);
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
console.error(`push failed: ${ref} — ${e.message}`);
|
|
79
|
+
failed++;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return failed ? 1 : 0;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=push.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/cmd/push.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { defaultDataDir, loadState, saveState } from '../state.js';
|
|
2
|
+
import { loadCredentials, deleteCredentials } from '../credentials.js';
|
|
3
|
+
import { cliResource, revokeToken } from '../oauth.js';
|
|
4
|
+
export async function runRemote(opts) {
|
|
5
|
+
const dataDir = opts.dataDir ?? defaultDataDir();
|
|
6
|
+
const state = loadState(dataDir);
|
|
7
|
+
const action = opts.positional[0] ?? 'show';
|
|
8
|
+
switch (action) {
|
|
9
|
+
case 'set': {
|
|
10
|
+
const url = opts.positional[1];
|
|
11
|
+
if (!url) {
|
|
12
|
+
console.error('usage: practi remote set <url> e.g. practi remote set https://practihub.com');
|
|
13
|
+
return 1;
|
|
14
|
+
}
|
|
15
|
+
if (!/^https?:\/\/\S+$/i.test(url)) {
|
|
16
|
+
console.error(`error: "${url}" is not an http(s) URL`);
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
state.remote = { url: url.replace(/\/+$/, '') };
|
|
20
|
+
saveState(dataDir, state);
|
|
21
|
+
console.log(`remote set: ${state.remote.url}`);
|
|
22
|
+
// 换 hub 时,旧 hub 签发的凭据对新 remote 无用:revoke(best-effort,打给旧 hub)并清除
|
|
23
|
+
const creds = loadCredentials(dataDir);
|
|
24
|
+
if (creds && creds.resource && creds.resource !== cliResource(state.remote.url)) {
|
|
25
|
+
const oldOrigin = creds.resource.replace(/\/cli$/, '');
|
|
26
|
+
if (oldOrigin)
|
|
27
|
+
await revokeToken(oldOrigin, creds.client_id, creds.refresh_token, 'refresh_token');
|
|
28
|
+
deleteCredentials(dataDir);
|
|
29
|
+
console.log(`note: cleared credentials issued by ${oldOrigin} — run \`practi login\` against ${state.remote.url}`);
|
|
30
|
+
}
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
case 'remove': {
|
|
34
|
+
delete state.remote;
|
|
35
|
+
saveState(dataDir, state);
|
|
36
|
+
console.log('remote removed');
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
case 'show': {
|
|
40
|
+
console.log(state.remote ? state.remote.url : '(not set)');
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
default:
|
|
44
|
+
console.error(`usage: practi remote set <url> | show | remove`);
|
|
45
|
+
return 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=remote.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/cmd/remote.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAOvD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAgB;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,cAAc,EAAE,CAAC;IACjD,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;IAE5C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,OAAO,CAAC,KAAK,CAAC,+EAA+E,CAAC,CAAC;gBAC/F,OAAO,CAAC,CAAC;YACX,CAAC;YACD,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnC,OAAO,CAAC,KAAK,CAAC,WAAW,GAAG,yBAAyB,CAAC,CAAC;gBACvD,OAAO,CAAC,CAAC;YACX,CAAC;YACD,KAAK,CAAC,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;YAChD,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;YAC/C,iEAAiE;YACjE,MAAM,KAAK,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChF,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;gBACvD,IAAI,SAAS;oBAAE,MAAM,WAAW,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;gBACnG,iBAAiB,CAAC,OAAO,CAAC,CAAC;gBAC3B,OAAO,CAAC,GAAG,CAAC,uCAAuC,SAAS,mCAAmC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;YACrH,CAAC;YACD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,OAAO,KAAK,CAAC,MAAM,CAAC;YACpB,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;YAC9B,OAAO,CAAC,CAAC;QACX,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;YAC3D,OAAO,CAAC,CAAC;QACX,CAAC;QACD;YACE,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;YAChE,OAAO,CAAC,CAAC;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { defaultDataDir, loadState } from '../state.js';
|
|
2
|
+
import { openWorkspace } from '../workspace.js';
|
|
3
|
+
import { authedFetch } from '../client.js';
|
|
4
|
+
import { shortHash } from '../render.js';
|
|
5
|
+
/**
|
|
6
|
+
* practi search <query...>:在 remote 上检索 POP(GET /api/v1/pop/search)。
|
|
7
|
+
* - 标题与内容都参与匹配,标题命中优先(服务端排序)。
|
|
8
|
+
* - --scope public=公开库(默认,仅 PUBLISHED);me=自己 direct 认领(全状态);all=并集。
|
|
9
|
+
* - 空 q(`practi search`)返回最近文档,可当浏览用。
|
|
10
|
+
*/
|
|
11
|
+
export async function runSearch(opts) {
|
|
12
|
+
const dataDir = opts.dataDir ?? defaultDataDir();
|
|
13
|
+
const q = opts.positional.join(' ').trim();
|
|
14
|
+
if (opts.local)
|
|
15
|
+
return runLocalSearch(opts, dataDir, q);
|
|
16
|
+
const state = loadState(dataDir);
|
|
17
|
+
if (!state.remote) {
|
|
18
|
+
console.error('error: no remote configured — run `practi remote set <url>` first');
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
if (!['public', 'me', 'all'].includes(opts.scope)) {
|
|
22
|
+
console.error("error: invalid scope — expected public | me | all");
|
|
23
|
+
return 1;
|
|
24
|
+
}
|
|
25
|
+
const params = new URLSearchParams({ q, scope: opts.scope, limit: String(opts.limit) });
|
|
26
|
+
const res = await authedFetch(dataDir, state.remote.url, `/api/v1/pop/search?${params.toString()}`);
|
|
27
|
+
const body = (await res.json().catch(() => ({})));
|
|
28
|
+
if (!res.ok) {
|
|
29
|
+
const detail = typeof body.message === 'string' ? body.message : typeof body.error === 'string' ? body.error : `HTTP ${res.status}`;
|
|
30
|
+
console.error(`search failed: ${detail}`);
|
|
31
|
+
return 1;
|
|
32
|
+
}
|
|
33
|
+
const results = body.results ?? [];
|
|
34
|
+
if (opts.json) {
|
|
35
|
+
console.log(JSON.stringify(body, null, 2));
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
if (results.length === 0) {
|
|
39
|
+
console.log(q ? `no results for "${q}" (scope: ${opts.scope})` : `no documents yet (scope: ${opts.scope})`);
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
for (const r of results) {
|
|
43
|
+
const desc = r.description ? ` — ${r.description}` : '';
|
|
44
|
+
const author = r.authorName ? ` @${r.authorName}` : '';
|
|
45
|
+
console.log(` ${shortHash(r.root_hash)} [${r.status}] ${r.name}${desc}${author}`);
|
|
46
|
+
console.log(` ${r.root_hash}`);
|
|
47
|
+
}
|
|
48
|
+
console.log(`\n${results.length} shown (total ${body.total ?? results.length}, scope: ${opts.scope}) — fetch one with \`practi pull <hash>\``);
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* --local:本地工作区检索,不碰 remote。
|
|
53
|
+
* - 遍历全部已存节点(含 indirect),对 name/description/content 做大小写不敏感子串匹配;
|
|
54
|
+
* 纯 hex 查询词(≥4 位)额外按哈希前缀匹配。
|
|
55
|
+
* - 输出按 direct 树的深度优先步骤顺序排列,共享子树只出现一次并标注全部所属根。
|
|
56
|
+
* - 空查询 = 浏览 direct 根(带各树节点数);--limit 同样生效。
|
|
57
|
+
*/
|
|
58
|
+
function runLocalSearch(opts, dataDir, q) {
|
|
59
|
+
const ws = openWorkspace(dataDir);
|
|
60
|
+
const state = loadState(dataDir);
|
|
61
|
+
const direct = state.direct.filter((h) => ws.nodes.has(h));
|
|
62
|
+
const directSet = new Set(direct);
|
|
63
|
+
// 包含关系:节点 → 所属 direct 根(共享子树可属多个根);根 → 树内节点数
|
|
64
|
+
const owner = new Map();
|
|
65
|
+
const size = new Map();
|
|
66
|
+
for (const root of direct) {
|
|
67
|
+
const seen = new Set();
|
|
68
|
+
const stack = [root];
|
|
69
|
+
while (stack.length > 0) {
|
|
70
|
+
const h = stack.pop();
|
|
71
|
+
if (seen.has(h))
|
|
72
|
+
continue;
|
|
73
|
+
seen.add(h);
|
|
74
|
+
const list = owner.get(h) ?? [];
|
|
75
|
+
if (!list.includes(root))
|
|
76
|
+
list.push(root);
|
|
77
|
+
owner.set(h, list);
|
|
78
|
+
const n = ws.nodes.get(h);
|
|
79
|
+
if (n?.type === 'practice')
|
|
80
|
+
for (const c of n.children)
|
|
81
|
+
stack.push(c.hash);
|
|
82
|
+
}
|
|
83
|
+
size.set(root, seen.size);
|
|
84
|
+
}
|
|
85
|
+
const needle = q.toLowerCase();
|
|
86
|
+
const hits = [];
|
|
87
|
+
const emitted = new Set();
|
|
88
|
+
const visit = (h) => {
|
|
89
|
+
if (emitted.has(h))
|
|
90
|
+
return;
|
|
91
|
+
emitted.add(h);
|
|
92
|
+
const n = ws.nodes.get(h);
|
|
93
|
+
if (!n)
|
|
94
|
+
return;
|
|
95
|
+
const text = `${n.name}\n${n.description ?? ''}\n${n.content ?? ''}`.toLowerCase();
|
|
96
|
+
const hashHit = /^[0-9a-f]{4,64}$/.test(needle) && h.startsWith(`sha256:${needle}`);
|
|
97
|
+
const matched = !needle || text.includes(needle) || hashHit;
|
|
98
|
+
if (matched && (needle !== '' || directSet.has(h))) {
|
|
99
|
+
hits.push({
|
|
100
|
+
hash: h,
|
|
101
|
+
type: n.type,
|
|
102
|
+
...(n.type === 'practice' ? { op: n.op } : {}),
|
|
103
|
+
name: n.name,
|
|
104
|
+
direct: directSet.has(h),
|
|
105
|
+
roots: (owner.get(h) ?? []).filter((r) => r !== h).map((r) => ({ hash: r, name: ws.nodes.get(r)?.name ?? r })),
|
|
106
|
+
...(size.has(h) ? { size: size.get(h) } : {}),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (n.type === 'practice')
|
|
110
|
+
for (const c of n.children)
|
|
111
|
+
visit(c.hash);
|
|
112
|
+
};
|
|
113
|
+
for (const root of direct)
|
|
114
|
+
visit(root);
|
|
115
|
+
const total = hits.length;
|
|
116
|
+
const shown = hits.slice(0, opts.limit);
|
|
117
|
+
if (opts.json) {
|
|
118
|
+
console.log(JSON.stringify({ query: q, local: true, results: shown, total }, null, 2));
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
if (total === 0) {
|
|
122
|
+
console.log(needle ? `no local matches for "${q}"` : '(no direct pops in this workspace)');
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
for (const hit of shown) {
|
|
126
|
+
const tag = hit.type === 'practice' ? `[practice·${hit.op}]` : '[action]';
|
|
127
|
+
const where = hit.direct
|
|
128
|
+
? `direct root, ${hit.size} nodes`
|
|
129
|
+
: hit.roots.map((r) => `in ${shortHash(r.hash)} (${r.name})`).join('; ');
|
|
130
|
+
console.log(` ${shortHash(hit.hash)} ${tag} ${hit.name}`);
|
|
131
|
+
console.log(` ${where}`);
|
|
132
|
+
}
|
|
133
|
+
const label = needle ? `${shown.length} matched` : `${shown.length} direct POP(s), ${ws.nodes.size} nodes`;
|
|
134
|
+
console.log(`\n${label} (local workspace) — inspect with \`practi show <hash>\``);
|
|
135
|
+
return 0;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/cmd/search.ts"],"names":[],"mappings":"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"}
|
package/dist/cmd/show.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { aggregateView, exportSubtree, resolveNodeRef } from '@arshdelight/pop-sdk';
|
|
2
|
+
import { defaultDataDir } from '../state.js';
|
|
3
|
+
import { openWorkspace } from '../workspace.js';
|
|
4
|
+
import { renderSteps, viewHeader } from '../render.js';
|
|
5
|
+
/** Inspect one node: aggregate view (default), --json for the StandardView, --doc for the document form */
|
|
6
|
+
export function runShow(opts) {
|
|
7
|
+
const dataDir = opts.dataDir ?? defaultDataDir();
|
|
8
|
+
const ws = openWorkspace(dataDir);
|
|
9
|
+
const hash = resolveNodeRef(ws, opts.hash);
|
|
10
|
+
const node = ws.nodes.get(hash);
|
|
11
|
+
if (opts.doc) {
|
|
12
|
+
console.log(JSON.stringify(exportSubtree(node, ws.nodes), null, 2));
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
const view = aggregateView(hash, ws.nodes);
|
|
16
|
+
if (opts.json) {
|
|
17
|
+
console.log(JSON.stringify(view, null, 2));
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
console.log(viewHeader(view));
|
|
21
|
+
if (view.description !== undefined)
|
|
22
|
+
console.log(`\ndescription: ${view.description}`);
|
|
23
|
+
if (view.content !== undefined && view.content.trim() !== '')
|
|
24
|
+
console.log(`\n${view.content}`);
|
|
25
|
+
if (view.steps.length > 0) {
|
|
26
|
+
console.log('\nsteps:');
|
|
27
|
+
for (const line of renderSteps(view.steps, ws.nodes))
|
|
28
|
+
console.log(` ${line}`);
|
|
29
|
+
}
|
|
30
|
+
if (view.flow.length > 0) {
|
|
31
|
+
console.log('\nflow:');
|
|
32
|
+
for (const e of view.flow) {
|
|
33
|
+
console.log(` ${e.name} ${short(e.fromHash)} (${e.fromName}) → ${short(e.toHash)} (${e.toName})`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (view.inputs.length > 0) {
|
|
37
|
+
console.log('\ndeclared inputs (needs):');
|
|
38
|
+
for (const d of view.inputs)
|
|
39
|
+
console.log(` ${d.name}${d.spec ? ` — ${d.spec}` : ''} [${short(d.refHash)}]`);
|
|
40
|
+
}
|
|
41
|
+
if (view.outputs.length > 0) {
|
|
42
|
+
console.log('\ndeclared outputs (produces):');
|
|
43
|
+
for (const d of view.outputs)
|
|
44
|
+
console.log(` ${d.name}${d.spec ? ` — ${d.spec}` : ''} [${short(d.refHash)}]`);
|
|
45
|
+
}
|
|
46
|
+
if (view.attachments.length > 0) {
|
|
47
|
+
console.log('\nattachments:');
|
|
48
|
+
for (const a of view.attachments)
|
|
49
|
+
console.log(` ${a.name} ${a.mime ?? ''} ${a.size ?? ''}b ${short(a.hash)}`);
|
|
50
|
+
}
|
|
51
|
+
if (view.revisions !== undefined && view.revisions.length > 0) {
|
|
52
|
+
console.log('\nrevisions:');
|
|
53
|
+
for (const r of view.revisions)
|
|
54
|
+
console.log(` ${r.when} ${r.what}${r.from ? ` (from ${short(r.from)})` : ''}`);
|
|
55
|
+
}
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
function short(hash) {
|
|
59
|
+
return hash.slice('sha256:'.length, 'sha256:'.length + 12);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=show.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"show.js","sourceRoot":"","sources":["../../src/cmd/show.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { exportSkill, importSkill, PracticeError, resolveNodeRef } from '@arshdelight/pop-sdk';
|
|
6
|
+
import { defaultDataDir, loadState, saveState } from '../state.js';
|
|
7
|
+
import { openWorkspace } from '../workspace.js';
|
|
8
|
+
/**
|
|
9
|
+
* practi skill 子命令:
|
|
10
|
+
* - install|update|uninstall:管理随 CLI 打包的 use-practi agent skill。
|
|
11
|
+
* 源:包内 skills/use-practi(package.json files 已含)。仓库根 skills/use-practi
|
|
12
|
+
* 是标准(npx skills 从仓库安装),CI 锁两份逐字节一致。
|
|
13
|
+
* 该 skill 是手写维护的(SKILL.md 即源,无 pop.doc.json sidecar,不从 POP 导出)。
|
|
14
|
+
* 目标:默认 ~/.agents/skills(跨 agent 约定目录,与 npx skills 的落点相同),
|
|
15
|
+
* --dir <skills-dir> 覆盖;安装形态 <skills-dir>/use-practi/SKILL.md。
|
|
16
|
+
* install 幂等同步(含清理源里已不存在的陈旧文件),并顺带移除改名前安装的
|
|
17
|
+
* 旧 use-pop 目录(CLI 自管产物);update 要求已安装;uninstall 删整个目录。
|
|
18
|
+
* - import|export:skill ⇄ POP 转换(spec §1/§8)。
|
|
19
|
+
* export 把 workspace 里的 POP 投影成可安装的技能目录(SKILL.md + 附件 +
|
|
20
|
+
* pop.doc.json sidecar);import 是它的逆运算——sidecar 精确回放(附件文件
|
|
21
|
+
* 重新入库并验哈希),无 sidecar 的外来技能目录被拒绝(E_NO_SIDECAR):
|
|
22
|
+
* 外来 skill 靠重新撰写进入 POP,不做机械压平。
|
|
23
|
+
*/
|
|
24
|
+
const SKILL_NAME = 'use-practi';
|
|
25
|
+
const LEGACY_SKILL_NAME = 'use-pop';
|
|
26
|
+
function sourceDir() {
|
|
27
|
+
// dist/cmd/skill.js → 包根 → skills/use-practi(源码运行与 npm 安装布局同构)
|
|
28
|
+
return fileURLToPath(new URL('../../skills/use-practi', import.meta.url));
|
|
29
|
+
}
|
|
30
|
+
function listFiles(dir, base = dir, out = []) {
|
|
31
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
32
|
+
const full = path.join(dir, e.name);
|
|
33
|
+
if (e.isDirectory())
|
|
34
|
+
listFiles(full, base, out);
|
|
35
|
+
else if (e.isFile())
|
|
36
|
+
out.push(path.relative(base, full).split(path.sep).join('/'));
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
function sameBytes(a, b) {
|
|
41
|
+
const fa = fs.readFileSync(a);
|
|
42
|
+
const fb = fs.readFileSync(b);
|
|
43
|
+
return fa.length === fb.length && fa.equals(fb);
|
|
44
|
+
}
|
|
45
|
+
const kb = (n) => (n < 1024 ? `${n} B` : `${(n / 1024).toFixed(1)} KB`);
|
|
46
|
+
/** 把包内 skill 目录同步到 target:写入缺失/有差异的文件,清理源里已不存在的陈旧文件 */
|
|
47
|
+
function syncTo(src, target) {
|
|
48
|
+
const files = listFiles(src);
|
|
49
|
+
const want = new Set(files);
|
|
50
|
+
let written = 0;
|
|
51
|
+
let unchanged = 0;
|
|
52
|
+
for (const rel of files) {
|
|
53
|
+
const from = path.join(src, rel);
|
|
54
|
+
const to = path.join(target, rel);
|
|
55
|
+
if (fs.existsSync(to) && sameBytes(from, to)) {
|
|
56
|
+
unchanged++;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
fs.mkdirSync(path.dirname(to), { recursive: true });
|
|
60
|
+
fs.copyFileSync(from, to);
|
|
61
|
+
console.log(` ${rel} written (${kb(fs.statSync(from).size)})`);
|
|
62
|
+
written++;
|
|
63
|
+
}
|
|
64
|
+
let pruned = 0;
|
|
65
|
+
if (fs.existsSync(target)) {
|
|
66
|
+
for (const rel of listFiles(target)) {
|
|
67
|
+
if (!want.has(rel)) {
|
|
68
|
+
fs.rmSync(path.join(target, rel));
|
|
69
|
+
console.log(` ${rel} pruned (no longer in the package)`);
|
|
70
|
+
pruned++;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { written, unchanged, pruned };
|
|
75
|
+
}
|
|
76
|
+
export function runSkill(opts) {
|
|
77
|
+
if (opts.action === 'import')
|
|
78
|
+
return runSkillImport(opts);
|
|
79
|
+
if (opts.action === 'export')
|
|
80
|
+
return runSkillExport(opts);
|
|
81
|
+
const skillsDir = opts.dir ? path.resolve(opts.dir) : path.join(os.homedir(), '.agents', 'skills');
|
|
82
|
+
const target = path.join(skillsDir, SKILL_NAME);
|
|
83
|
+
if (opts.action === 'uninstall') {
|
|
84
|
+
if (!fs.existsSync(target)) {
|
|
85
|
+
console.error(`error: nothing to remove — ${target} does not exist`);
|
|
86
|
+
return 1;
|
|
87
|
+
}
|
|
88
|
+
if (!fs.existsSync(path.join(target, 'SKILL.md'))) {
|
|
89
|
+
console.error(`error: ${target} exists but has no SKILL.md — does not look like the ${SKILL_NAME} skill; remove it manually`);
|
|
90
|
+
return 1;
|
|
91
|
+
}
|
|
92
|
+
fs.rmSync(target, { recursive: true });
|
|
93
|
+
console.log(`removed: ${SKILL_NAME} → ${target}`);
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
const src = sourceDir();
|
|
97
|
+
if (!fs.existsSync(src)) {
|
|
98
|
+
console.error(`error: bundled skill not found at ${src} — the cli package is broken; reinstall it (npm install -g @arshdelight/practi)`);
|
|
99
|
+
return 1;
|
|
100
|
+
}
|
|
101
|
+
if (opts.action === 'update' && !fs.existsSync(target)) {
|
|
102
|
+
console.error(`error: ${SKILL_NAME} is not installed in ${skillsDir} — run \`practi skill install\` first`);
|
|
103
|
+
return 1;
|
|
104
|
+
}
|
|
105
|
+
const existed = fs.existsSync(target);
|
|
106
|
+
const { written, unchanged, pruned } = syncTo(src, target);
|
|
107
|
+
if (written === 0 && pruned === 0) {
|
|
108
|
+
console.log(`up to date: ${SKILL_NAME} → ${target} (${unchanged} file(s), nothing changed)`);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const verb = existed ? 'updated' : 'installed';
|
|
112
|
+
console.log(`${verb}: ${SKILL_NAME} → ${target} (${written} written, ${unchanged} unchanged${pruned > 0 ? `, ${pruned} pruned` : ''})`);
|
|
113
|
+
}
|
|
114
|
+
// 改名迁移:旧 CLI 装的 use-pop 是本 CLI 自管产物,装新版时顺带移除,避免两份并存
|
|
115
|
+
const legacyTarget = path.join(skillsDir, LEGACY_SKILL_NAME);
|
|
116
|
+
if (fs.existsSync(path.join(legacyTarget, 'SKILL.md'))) {
|
|
117
|
+
fs.rmSync(legacyTarget, { recursive: true });
|
|
118
|
+
console.log(`removed: ${LEGACY_SKILL_NAME} → ${legacyTarget} (replaced by ${SKILL_NAME})`);
|
|
119
|
+
}
|
|
120
|
+
return 0;
|
|
121
|
+
}
|
|
122
|
+
/** 技能目录名兜底:非 ASCII 名(如中文)slug 后为空 → 用 hash 前缀 */
|
|
123
|
+
function slugOrHash(name, hash) {
|
|
124
|
+
const slug = name
|
|
125
|
+
.toLowerCase()
|
|
126
|
+
.replace(/[^a-z0-9-]+/g, '-')
|
|
127
|
+
.replace(/^-+|-+$/g, '')
|
|
128
|
+
.replace(/-{2,}/g, '-');
|
|
129
|
+
return slug !== '' ? slug : hash.slice('sha256:'.length, 'sha256:'.length + 12);
|
|
130
|
+
}
|
|
131
|
+
/** practi skill import <dir>:回放 `practi skill export` 导出的目录(sidecar 精确复放,附件重新入库)+ 注册 direct */
|
|
132
|
+
function runSkillImport(opts) {
|
|
133
|
+
if (!opts.positional) {
|
|
134
|
+
console.error('usage: practi skill import <skill-dir> [--data-dir <dir>]');
|
|
135
|
+
return 1;
|
|
136
|
+
}
|
|
137
|
+
const dataDir = opts.dataDir ? path.resolve(opts.dataDir) : defaultDataDir();
|
|
138
|
+
const skillDir = path.resolve(opts.positional);
|
|
139
|
+
const ws = openWorkspace(dataDir);
|
|
140
|
+
const warns = [];
|
|
141
|
+
let res;
|
|
142
|
+
try {
|
|
143
|
+
res = importSkill(ws, skillDir, { warn: (m) => warns.push(m) });
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
const detail = e instanceof Error ? e.message : String(e);
|
|
147
|
+
console.error(`import failed: ${skillDir} — ${detail}`);
|
|
148
|
+
if (e instanceof PracticeError && e.hint)
|
|
149
|
+
console.error(` hint: ${e.hint}`);
|
|
150
|
+
return 1;
|
|
151
|
+
}
|
|
152
|
+
const state = loadState(dataDir);
|
|
153
|
+
if (!state.direct.includes(res.root)) {
|
|
154
|
+
state.direct.push(res.root);
|
|
155
|
+
saveState(dataDir, state);
|
|
156
|
+
}
|
|
157
|
+
console.log(`imported: ${res.root} (${res.count} node(s)) [direct]`);
|
|
158
|
+
console.log(` source: ${res.sidecarUsed ? 'pop.doc.json sidecar replay (byte-identical hash)' : 'edited SKILL.md body (sidecar out of sync — new hash)'}`);
|
|
159
|
+
for (const w of warns)
|
|
160
|
+
console.log(` warning: ${w}`);
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
/** practi skill export <ref> [--dir <out>]:POP → 技能目录(SKILL.md 投影 + 附件 + sidecar) */
|
|
164
|
+
function runSkillExport(opts) {
|
|
165
|
+
if (!opts.positional) {
|
|
166
|
+
console.error('usage: practi skill export <ref> [--dir <out-dir>] [--data-dir <dir>]');
|
|
167
|
+
return 1;
|
|
168
|
+
}
|
|
169
|
+
const dataDir = opts.dataDir ? path.resolve(opts.dataDir) : defaultDataDir();
|
|
170
|
+
const ws = openWorkspace(dataDir);
|
|
171
|
+
let rootHash;
|
|
172
|
+
try {
|
|
173
|
+
rootHash = resolveNodeRef(ws, opts.positional);
|
|
174
|
+
}
|
|
175
|
+
catch (e) {
|
|
176
|
+
const detail = e instanceof Error ? e.message : String(e);
|
|
177
|
+
console.error(`export failed: ${opts.positional} — ${detail}`);
|
|
178
|
+
return 1;
|
|
179
|
+
}
|
|
180
|
+
const name = ws.nodes.get(rootHash)?.name ?? rootHash;
|
|
181
|
+
const outDir = opts.dir ? path.resolve(opts.dir) : path.resolve(process.cwd(), slugOrHash(name, rootHash));
|
|
182
|
+
let res;
|
|
183
|
+
try {
|
|
184
|
+
res = exportSkill(ws, opts.positional, outDir);
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
const detail = e instanceof Error ? e.message : String(e);
|
|
188
|
+
console.error(`export failed: ${rootHash} — ${detail}`);
|
|
189
|
+
return 1;
|
|
190
|
+
}
|
|
191
|
+
console.log(`exported: ${res.rootHash} → ${outDir}`);
|
|
192
|
+
console.log(` SKILL.md (projection of the document)`);
|
|
193
|
+
for (const f of res.files)
|
|
194
|
+
console.log(` ${f}`);
|
|
195
|
+
console.log(` pop.doc.json (sidecar — re-import replays this exact document, lossless round-trip)`);
|
|
196
|
+
return 0;
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.js","sourceRoot":"","sources":["../../src/cmd/skill.ts"],"names":[],"mappings":"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"}
|
package/dist/cmd/spec.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { readSpec } from '@arshdelight/pop-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* practi spec:打印本 CLI 所实现协议的 pop-spec.md(SDK 包内分发,readSpec 直读)。
|
|
4
|
+
* 无网络依赖;重定向即导出:practi spec > spec.md。
|
|
5
|
+
*/
|
|
6
|
+
export function runSpec(_opts) {
|
|
7
|
+
console.log(readSpec());
|
|
8
|
+
return 0;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec.js","sourceRoot":"","sources":["../../src/cmd/spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAMhD;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,KAAe;IACrC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IACxB,OAAO,CAAC,CAAC;AACX,CAAC"}
|