@hupan56/wlkj 2.3.3 → 2.3.4
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/package.json
CHANGED
package/templates/cli.js
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// wlkj - workflow toolkit
|
|
3
|
-
// 参考 Trellis 架构:用户看到的极简,背后 scripts/hooks 精确控制
|
|
4
|
-
|
|
5
|
-
const path = require("path");
|
|
6
|
-
const fs = require("fs");
|
|
7
|
-
const { execSync } = require("child_process");
|
|
8
|
-
|
|
9
|
-
const T = path.join(__dirname, "..", "templates");
|
|
10
|
-
|
|
11
|
-
// --- helpers ---
|
|
12
|
-
function py(script, args = []) {
|
|
13
|
-
const p = path.join(process.cwd(), ".qoder", "scripts", script);
|
|
14
|
-
if (!fs.existsSync(p)) {
|
|
15
|
-
console.log("请先运行: npx wlkj init");
|
|
16
|
-
process.exit(1);
|
|
17
|
-
}
|
|
18
|
-
try {
|
|
19
|
-
return execSync(
|
|
20
|
-
`python "${p}" ${args.map(a => `"${a}"`).join(" ")}`,
|
|
21
|
-
{ cwd: process.cwd(), encoding: "utf-8", timeout: 15000 }
|
|
22
|
-
);
|
|
23
|
-
} catch (e) {
|
|
24
|
-
return (e.stdout || e.message);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function cp(src, dest) {
|
|
29
|
-
const s = path.join(T, src);
|
|
30
|
-
const d = path.join(process.cwd(), dest);
|
|
31
|
-
if (!fs.existsSync(s)) return;
|
|
32
|
-
fs.mkdirSync(path.dirname(d), { recursive: true });
|
|
33
|
-
if (!fs.existsSync(d)) { fs.copyFileSync(s, d); return true; }
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function cpDir(src, dest) {
|
|
38
|
-
const s = path.join(T, src);
|
|
39
|
-
const d = path.join(process.cwd(), dest);
|
|
40
|
-
if (!fs.existsSync(s)) return;
|
|
41
|
-
fs.mkdirSync(d, { recursive: true });
|
|
42
|
-
const items = fs.readdirSync(s);
|
|
43
|
-
items.forEach(item => {
|
|
44
|
-
const srcPath = path.join(s, item);
|
|
45
|
-
const destPath = path.join(d, item);
|
|
46
|
-
if (fs.statSync(srcPath).isDirectory()) {
|
|
47
|
-
cpDir(path.join(src, item), path.join(dest, item));
|
|
48
|
-
} else if (!fs.existsSync(destPath)) {
|
|
49
|
-
fs.copyFileSync(srcPath, destPath);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// --- init ---
|
|
55
|
-
function doInit(name) {
|
|
56
|
-
const cwd = process.cwd();
|
|
57
|
-
console.log(``);
|
|
58
|
-
console.log(`wlkj init -> ${cwd}`);
|
|
59
|
-
|
|
60
|
-
// 目录结构
|
|
61
|
-
const dirs = [
|
|
62
|
-
".qoder/rules", ".qoder/context", ".qoder/scripts/common",
|
|
63
|
-
".qoder/scripts/hooks", ".qoder/skills/prd-generator",
|
|
64
|
-
".qoder/skills/spec-generator", ".qoder/skills/spec-coder",
|
|
65
|
-
".qoder/skills/test-generator", ".qoder/agents", ".qoder/hooks",
|
|
66
|
-
".qoder/tasks", ".qoder/archive", ".qoder/workspace",
|
|
67
|
-
".qoder/.runtime/sessions",
|
|
68
|
-
".codex/hooks", ".codex/agents",
|
|
69
|
-
"docs/ai/prd", "docs/ai/specs", "src", "tests"
|
|
70
|
-
];
|
|
71
|
-
dirs.forEach(d => fs.mkdirSync(path.join(cwd, d), { recursive: true }));
|
|
72
|
-
|
|
73
|
-
// 模板文件(flat list,一目了然)
|
|
74
|
-
let copied = 0;
|
|
75
|
-
const files = [
|
|
76
|
-
// .qoder 核心
|
|
77
|
-
["qoder/config.yaml", ".qoder/config.yaml"],
|
|
78
|
-
["qoder/workflow.md", ".qoder/workflow.md"],
|
|
79
|
-
// rules
|
|
80
|
-
["rules/code-style.md", ".qoder/rules/code-style.md"],
|
|
81
|
-
["rules/prd-template.md", ".qoder/rules/prd-template.md"],
|
|
82
|
-
["rules/spec-template.md", ".qoder/rules/spec-template.md"],
|
|
83
|
-
["rules/testing.md", ".qoder/rules/testing.md"],
|
|
84
|
-
// context
|
|
85
|
-
["context/architecture.md", ".qoder/context/architecture.md"],
|
|
86
|
-
["context/data-dictionary.md",".qoder/context/data-dictionary.md"],
|
|
87
|
-
// skills
|
|
88
|
-
["skills/prd-generator/SKILL.md", ".qoder/skills/prd-generator/SKILL.md"],
|
|
89
|
-
["skills/spec-generator/SKILL.md", ".qoder/skills/spec-generator/SKILL.md"],
|
|
90
|
-
["skills/spec-coder/SKILL.md", ".qoder/skills/spec-coder/SKILL.md"],
|
|
91
|
-
["skills/test-generator/SKILL.md", ".qoder/skills/test-generator/SKILL.md"],
|
|
92
|
-
// agents
|
|
93
|
-
["agents/qoder-spec-gen.toml", ".qoder/agents/qoder-spec-gen.toml"],
|
|
94
|
-
["agents/qoder-coder.toml", ".qoder/agents/qoder-coder.toml"],
|
|
95
|
-
["agents/qoder-test-gen.toml", ".qoder/agents/qoder-test-gen.toml"],
|
|
96
|
-
// hooks
|
|
97
|
-
["hooks/post-prd-push.py", ".qoder/hooks/post-prd-push.py"],
|
|
98
|
-
// scripts
|
|
99
|
-
["scripts/init_developer.py", ".qoder/scripts/init_developer.py"],
|
|
100
|
-
["scripts/task.py", ".qoder/scripts/task.py"],
|
|
101
|
-
["scripts/add_session.py", ".qoder/scripts/add_session.py"],
|
|
102
|
-
["scripts/common/__init__.py", ".qoder/scripts/common/__init__.py"],
|
|
103
|
-
["scripts/common/paths.py", ".qoder/scripts/common/paths.py"],
|
|
104
|
-
["scripts/common/developer.py", ".qoder/scripts/common/developer.py"],
|
|
105
|
-
["scripts/common/active_task.py",".qoder/scripts/common/active_task.py"],
|
|
106
|
-
["scripts/common/task_utils.py", ".qoder/scripts/common/task_utils.py"],
|
|
107
|
-
// codex hooks
|
|
108
|
-
["codex/config.toml", ".codex/config.toml"],
|
|
109
|
-
["codex/hooks.json", ".codex/hooks.json"],
|
|
110
|
-
["codex/hooks/inject-pipeline-state.py", ".codex/hooks/inject-pipeline-state.py"],
|
|
111
|
-
["codex/agents/qoder-spec-gen.toml", ".codex/agents/qoder-spec-gen.toml"],
|
|
112
|
-
["codex/agents/qoder-coder.toml", ".codex/agents/qoder-coder.toml"],
|
|
113
|
-
["codex/agents/qoder-test-gen.toml", ".codex/agents/qoder-test-gen.toml"],
|
|
114
|
-
// root
|
|
115
|
-
["root/AGENTS.md", "AGENTS.md"],
|
|
116
|
-
];
|
|
117
|
-
|
|
118
|
-
files.forEach(([s, d]) => { if (cp(s, d)) copied++; });
|
|
119
|
-
console.log(` copied ${copied} files`);
|
|
120
|
-
|
|
121
|
-
// git init
|
|
122
|
-
if (!fs.existsSync(path.join(cwd, ".git"))) {
|
|
123
|
-
try {
|
|
124
|
-
execSync("git init", { cwd, stdio: "pipe" });
|
|
125
|
-
console.log(" git init done");
|
|
126
|
-
} catch (_) {}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// developer
|
|
130
|
-
if (name) {
|
|
131
|
-
console.log("");
|
|
132
|
-
process.stdout.write(py("init_developer.py", [name]));
|
|
133
|
-
} else {
|
|
134
|
-
console.log("");
|
|
135
|
-
console.log(" next: npx wlkj init <your-name>");
|
|
136
|
-
}
|
|
137
|
-
console.log("");
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// --- status ---
|
|
141
|
-
function doStatus() {
|
|
142
|
-
console.log("");
|
|
143
|
-
// developer
|
|
144
|
-
const dev = path.join(process.cwd(), ".qoder", ".developer");
|
|
145
|
-
if (fs.existsSync(dev)) {
|
|
146
|
-
const line = fs.readFileSync(dev, "utf-8").split("\n")[0];
|
|
147
|
-
console.log("dev: " + line.split("=")[1]?.trim());
|
|
148
|
-
} else {
|
|
149
|
-
console.log("dev: -");
|
|
150
|
-
}
|
|
151
|
-
// task
|
|
152
|
-
process.stdout.write(py("task.py", ["current", "--source"]));
|
|
153
|
-
// docs
|
|
154
|
-
const count = (d) => {
|
|
155
|
-
const p = path.join(process.cwd(), d);
|
|
156
|
-
return fs.existsSync(p) ? fs.readdirSync(p).filter(f => f.endsWith(".md")).length : 0;
|
|
157
|
-
};
|
|
158
|
-
console.log(`prd: ${count("docs/ai/prd")} spec: ${count("docs/ai/specs")}`);
|
|
159
|
-
console.log("");
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// --- main ---
|
|
163
|
-
const [,, cmd, ...rest] = process.argv;
|
|
164
|
-
|
|
165
|
-
switch (cmd) {
|
|
166
|
-
case "init":
|
|
167
|
-
doInit(rest[0]);
|
|
168
|
-
break;
|
|
169
|
-
case "task":
|
|
170
|
-
// 映射 -p 到 --priority(CLI 便捷)
|
|
171
|
-
const mapped = rest.map(a => a === "-p" ? "--priority" : a);
|
|
172
|
-
process.stdout.write(py("task.py", mapped));
|
|
173
|
-
break;
|
|
174
|
-
case "status":
|
|
175
|
-
doStatus();
|
|
176
|
-
break;
|
|
177
|
-
case "session":
|
|
178
|
-
process.stdout.write(py("add_session.py", rest));
|
|
179
|
-
break;
|
|
180
|
-
default:
|
|
181
|
-
console.log("");
|
|
182
|
-
console.log("wlkj - workflow toolkit");
|
|
183
|
-
console.log("");
|
|
184
|
-
console.log(" npx wlkj init [name] init workflow + developer");
|
|
185
|
-
console.log(" npx wlkj status show status");
|
|
186
|
-
console.log(" npx wlkj task <cmd> task management");
|
|
187
|
-
console.log(" npx wlkj session <args> record session log");
|
|
188
|
-
console.log("");
|
|
189
|
-
console.log("task commands:");
|
|
190
|
-
console.log(' create "Title" [-p P0|P1|P2|P3] [--assignee who]');
|
|
191
|
-
console.log(" list [--mine] [--status planning|in_progress]");
|
|
192
|
-
console.log(" start <name>");
|
|
193
|
-
console.log(" finish");
|
|
194
|
-
console.log(" current");
|
|
195
|
-
console.log(" archive <name>");
|
|
196
|
-
console.log(" add-subtask <parent> <child>");
|
|
197
|
-
console.log("");
|
|
198
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
DEPRECATED: code_index.py used to keep its own (cruder) index builder
|
|
5
|
-
whose schema conflicted with git_sync.py's - running it would overwrite
|
|
6
|
-
the real indexes. It now delegates to the single implementation.
|
|
7
|
-
|
|
8
|
-
Usage:
|
|
9
|
-
python code_index.py scan # full index rebuild (= git_sync.py --index-only)
|
|
10
|
-
python code_index.py search <kw> # use search_index.py instead
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
import os
|
|
14
|
-
import sys
|
|
15
|
-
|
|
16
|
-
# UTF-8 stdio (防御性: stdout 被捕获时不崩溃)
|
|
17
|
-
try:
|
|
18
|
-
sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
|
19
|
-
except (AttributeError, TypeError, OSError, IOError):
|
|
20
|
-
try:
|
|
21
|
-
sys.stdout.reconfigure(encoding='utf-8')
|
|
22
|
-
except Exception:
|
|
23
|
-
pass
|
|
24
|
-
|
|
25
|
-
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
26
|
-
|
|
27
|
-
if __name__ == '__main__':
|
|
28
|
-
cmd = sys.argv[1] if len(sys.argv) > 1 else ''
|
|
29
|
-
if cmd == 'scan':
|
|
30
|
-
from git_sync import build_full_indexes, FAILURES
|
|
31
|
-
build_full_indexes()
|
|
32
|
-
sys.exit(1 if FAILURES else 0)
|
|
33
|
-
elif cmd == 'search' and len(sys.argv) > 2:
|
|
34
|
-
import subprocess
|
|
35
|
-
script = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'search_index.py')
|
|
36
|
-
sys.exit(subprocess.call([sys.executable, script] + sys.argv[2:]))
|
|
37
|
-
else:
|
|
38
|
-
print('Usage:')
|
|
39
|
-
print(' python code_index.py scan # full index rebuild')
|
|
40
|
-
print(' python code_index.py search <kw> # -> search_index.py')
|
|
41
|
-
sys.exit(1)
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# team.py - Team member registration
|
|
2
|
-
import os, json, sys
|
|
3
|
-
NL = chr(10)
|
|
4
|
-
BASE = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
5
|
-
|
|
6
|
-
def add_member(name, role):
|
|
7
|
-
members_dir = os.path.join(BASE, 'workspace', 'members')
|
|
8
|
-
member_dir = os.path.join(members_dir, name)
|
|
9
|
-
os.makedirs(os.path.join(member_dir, 'journal'), exist_ok=True)
|
|
10
|
-
os.makedirs(os.path.join(member_dir, 'drafts'), exist_ok=True)
|
|
11
|
-
os.makedirs(os.path.join(member_dir, 'inbox'), exist_ok=True)
|
|
12
|
-
info = {'name': name, 'role': role}
|
|
13
|
-
with open(os.path.join(member_dir, 'member.json'), 'w') as f:
|
|
14
|
-
json.dump(info, f, indent=2)
|
|
15
|
-
print('OK: member ' + name + ' (' + role + ') added')
|
|
16
|
-
|
|
17
|
-
def list_members():
|
|
18
|
-
md = os.path.join(BASE, 'workspace', 'members')
|
|
19
|
-
if not os.path.isdir(md): print('No members'); return
|
|
20
|
-
for d in sorted(os.listdir(md)):
|
|
21
|
-
info_f = os.path.join(md, d, 'member.json')
|
|
22
|
-
if os.path.isfile(info_f):
|
|
23
|
-
info = json.load(open(info_f))
|
|
24
|
-
print(d + ' [' + info.get('role', '?') + ']')
|
|
25
|
-
|
|
26
|
-
if __name__ == '__main__':
|
|
27
|
-
if len(sys.argv) < 2: list_members()
|
|
28
|
-
elif sys.argv[1] == 'add' and len(sys.argv) >= 4: add_member(sys.argv[2], sys.argv[3])
|
|
29
|
-
else: list_members()
|