@colin4k1024/tsp 2.4.0 → 2.4.1
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 +81 -4
- package/bin/lib/post-install-bridge.js +2 -2
- package/bin/tsp-create.js +11 -11
- package/commands/team-help.md +2 -2
- package/commands/team-plan.md +1 -1
- package/commands/update-codemaps.md +3 -2
- package/manifests/install-components.json +1 -1
- package/manifests/install-modules.json +4 -2
- package/package.json +3 -1
- package/scripts/gitnexus-preflight.js +187 -0
- package/scripts/lib/team-skills-data.json +7 -6
- package/scripts/project-progress.js +852 -0
- package/scripts/release-health-summary.js +49 -7
- package/scripts/release.sh +1 -1
- package/scripts/validate-packed-tarball.js +25 -0
- package/scripts/workflow-help.js +3 -3
- package/skills/gitnexus/SKILL.md +60 -0
- package/skills/gitnexus/agents/openai.yaml +4 -0
|
@@ -115,7 +115,7 @@ function buildDocFreshnessCheck(root) {
|
|
|
115
115
|
id: 'validate-doc-freshness',
|
|
116
116
|
label: 'validate-doc-freshness',
|
|
117
117
|
command: 'node scripts/validate-doc-freshness.js',
|
|
118
|
-
status: report.errorCount > 0 ? 'fail' :
|
|
118
|
+
status: report.errorCount > 0 ? 'fail' : 'pass',
|
|
119
119
|
details: report.errorCount > 0
|
|
120
120
|
? report.errors[0]
|
|
121
121
|
: (report.warningCount > 0 ? report.warnings[0] : `checked ${report.markdownFileCount} markdown files`),
|
|
@@ -148,20 +148,60 @@ function buildPrebuiltCheck(root) {
|
|
|
148
148
|
};
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
function packCurrentTarball(root) {
|
|
152
|
+
const result = spawnSync('npm', ['pack', '--json', '--ignore-scripts'], {
|
|
153
|
+
cwd: root,
|
|
154
|
+
encoding: 'utf8',
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (result.status !== 0) {
|
|
158
|
+
throw new Error(summarizeOutput(result.stderr || result.stdout) || `npm pack failed with exit ${result.status}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let data;
|
|
162
|
+
try {
|
|
163
|
+
data = JSON.parse(result.stdout);
|
|
164
|
+
} catch (error) {
|
|
165
|
+
throw new Error(`Unable to parse npm pack JSON output: ${error.message}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (!Array.isArray(data) || !data[0] || typeof data[0].filename !== 'string' || data[0].filename.length === 0) {
|
|
169
|
+
throw new Error('npm pack JSON output is missing a filename entry.');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const tarballPath = path.join(root, data[0].filename);
|
|
173
|
+
return {
|
|
174
|
+
tarballPath,
|
|
175
|
+
cleanup() {
|
|
176
|
+
fs.rmSync(tarballPath, { force: true });
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
151
181
|
function buildTarballCheck(options) {
|
|
182
|
+
let cleanup = null;
|
|
152
183
|
try {
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
184
|
+
const usingExplicitInput = Boolean(options.tarball || options.packJson);
|
|
185
|
+
const tarballPath = usingExplicitInput
|
|
186
|
+
? resolveTarballPath({
|
|
187
|
+
root: options.root,
|
|
188
|
+
tarball: options.tarball,
|
|
189
|
+
packJson: options.packJson,
|
|
190
|
+
})
|
|
191
|
+
: (() => {
|
|
192
|
+
const packed = packCurrentTarball(options.root);
|
|
193
|
+
cleanup = packed.cleanup;
|
|
194
|
+
return packed.tarballPath;
|
|
195
|
+
})();
|
|
158
196
|
const result = validateTarball(tarballPath, validatePrebuilt({ root: options.root }).platforms);
|
|
159
197
|
return {
|
|
160
198
|
id: 'validate-packed-tarball',
|
|
161
199
|
label: 'validate-packed-tarball',
|
|
162
200
|
command: options.packJson
|
|
163
201
|
? `node scripts/validate-packed-tarball.js --pack-json ${path.relative(options.root, options.packJson)}`
|
|
164
|
-
:
|
|
202
|
+
: options.tarball
|
|
203
|
+
? `node scripts/validate-packed-tarball.js --tarball ${path.relative(options.root, tarballPath)}`
|
|
204
|
+
: `npm pack --json --ignore-scripts && node scripts/validate-packed-tarball.js --tarball ${path.relative(options.root, tarballPath)}`,
|
|
165
205
|
status: result.missing.length > 0 ? 'fail' : 'pass',
|
|
166
206
|
details: result.missing.length > 0
|
|
167
207
|
? result.missing[0]
|
|
@@ -187,6 +227,8 @@ function buildTarballCheck(options) {
|
|
|
187
227
|
status: 'skip',
|
|
188
228
|
details: message,
|
|
189
229
|
};
|
|
230
|
+
} finally {
|
|
231
|
+
cleanup?.();
|
|
190
232
|
}
|
|
191
233
|
}
|
|
192
234
|
|
package/scripts/release.sh
CHANGED
|
@@ -65,7 +65,7 @@ if [[ "$PUBLISH" == "true" ]]; then
|
|
|
65
65
|
echo " Size: $(( TARBALL_SIZE / 1024 / 1024 ))MB (${TARBALL_SIZE} bytes)"
|
|
66
66
|
|
|
67
67
|
echo ""
|
|
68
|
-
echo "🚀 Publishing @colin4k1024/tsp
|
|
68
|
+
echo "🚀 Publishing @colin4k1024/tsp@${NEW_VERSION} to npm ..."
|
|
69
69
|
npm publish "${TARBALL}" --access public
|
|
70
70
|
echo "✅ Published to npm."
|
|
71
71
|
|
|
@@ -59,6 +59,25 @@ function parseArgs(argv) {
|
|
|
59
59
|
return options;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
function expectedTarballFilenameForRoot(root) {
|
|
63
|
+
const packageJsonPath = path.join(root, 'package.json');
|
|
64
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
70
|
+
if (typeof pkg.name !== 'string' || pkg.name.length === 0 || typeof pkg.version !== 'string' || pkg.version.length === 0) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const normalizedName = pkg.name.replace(/^@/, '').replace(/\//g, '-');
|
|
75
|
+
return `${normalizedName}-${pkg.version}.tgz`;
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
62
81
|
function resolveTarballPath(options) {
|
|
63
82
|
if (options.tarball) {
|
|
64
83
|
return options.tarball;
|
|
@@ -92,6 +111,11 @@ function resolveTarballPath(options) {
|
|
|
92
111
|
throw new Error(`No .tgz tarball found under ${options.root}; pass --tarball or --pack-json explicitly.`);
|
|
93
112
|
}
|
|
94
113
|
|
|
114
|
+
const expectedTarballFilename = expectedTarballFilenameForRoot(options.root);
|
|
115
|
+
if (expectedTarballFilename && candidates.includes(expectedTarballFilename)) {
|
|
116
|
+
return path.join(options.root, expectedTarballFilename);
|
|
117
|
+
}
|
|
118
|
+
|
|
95
119
|
return path.join(options.root, candidates[0]);
|
|
96
120
|
}
|
|
97
121
|
|
|
@@ -142,6 +166,7 @@ if (require.main === module) {
|
|
|
142
166
|
}
|
|
143
167
|
|
|
144
168
|
module.exports = {
|
|
169
|
+
expectedTarballFilenameForRoot,
|
|
145
170
|
main,
|
|
146
171
|
parseArgs,
|
|
147
172
|
resolveTarballPath,
|
package/scripts/workflow-help.js
CHANGED
|
@@ -399,7 +399,7 @@ function analyzeTask(options) {
|
|
|
399
399
|
result.reason = routeReason(catalog, '/team-intake', '未检测到任务 artifact 目录,主链应从 intake 开始。');
|
|
400
400
|
result.missingPrerequisites.push('缺少 docs/artifacts/{YYYY-MM-DD}-{slug}/ 任务目录');
|
|
401
401
|
if (brownfieldRepo) {
|
|
402
|
-
result.brownfieldSuggestions.push('既有项目建议先执行 /update-codemaps,再进入 /team-plan 补齐 Brownfield Context Snapshot。');
|
|
402
|
+
result.brownfieldSuggestions.push('既有项目建议先执行 /update-codemaps;需要轻量结构证据时用 Graphify,需要跨模块影响面或 MCP 证据时用 GitNexus,再进入 /team-plan 补齐 Brownfield Context Snapshot。');
|
|
403
403
|
}
|
|
404
404
|
if (!projectContext.exists || projectContext.missingSections.length > 0) {
|
|
405
405
|
addProjectContextRemediation(result, null);
|
|
@@ -443,7 +443,7 @@ function analyzeTask(options) {
|
|
|
443
443
|
result.reason = routeReason(catalog, '/team-plan', '已有 PRD,但尚未形成 Delivery Plan。');
|
|
444
444
|
result.missingPrerequisites.push('缺少 delivery-plan.md');
|
|
445
445
|
if (brownfieldRepo) {
|
|
446
|
-
result.brownfieldSuggestions.push('如果是 brownfield 任务,在 delivery-plan.md 中补齐 Brownfield Context Snapshot
|
|
446
|
+
result.brownfieldSuggestions.push('如果是 brownfield 任务,在 delivery-plan.md 中补齐 Brownfield Context Snapshot;必要时引用 Graphify 或 GitNexus 图谱证据。');
|
|
447
447
|
}
|
|
448
448
|
addProjectContextRemediation(result, taskDir);
|
|
449
449
|
return finalizeResult(result, catalog);
|
|
@@ -462,7 +462,7 @@ function analyzeTask(options) {
|
|
|
462
462
|
|
|
463
463
|
const deliveryPlanText = readText(deliveryPlanPath).toLowerCase();
|
|
464
464
|
if (brownfieldRepo && !deliveryPlanText.includes('brownfield context snapshot')) {
|
|
465
|
-
result.brownfieldSuggestions.push('建议在 delivery-plan.md 中补齐 Brownfield Context Snapshot
|
|
465
|
+
result.brownfieldSuggestions.push('建议在 delivery-plan.md 中补齐 Brownfield Context Snapshot;必要时引用 Graphify 或 GitNexus 图谱证据。');
|
|
466
466
|
}
|
|
467
467
|
|
|
468
468
|
if (!hasHandoffEvidence && !exists(executeLogPath)) {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gitnexus
|
|
3
|
+
description: >
|
|
4
|
+
将 GitNexus 作为受控可选代码智能能力接入,用于 brownfield MCP 查询、影响面分析、
|
|
5
|
+
detect_changes、多仓分析和更深代码图谱证据。输出必须回落到 `/team-*` 主链和 artifacts。
|
|
6
|
+
origin: abhigyanpatwari/GitNexus (reference-only controlled integration)
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# GitNexus
|
|
10
|
+
|
|
11
|
+
## 用途
|
|
12
|
+
|
|
13
|
+
- 对存量仓库做更深代码图谱分析:符号上下游、调用链、执行流、跨仓影响面。
|
|
14
|
+
- 在改动前用 `impact` / `detect_changes` 类证据确认 blast radius。
|
|
15
|
+
- 为 `/team-plan`、`/team-execute`、`/team-review` 提供可追溯的 MCP/图谱证据。
|
|
16
|
+
|
|
17
|
+
## 触发信号
|
|
18
|
+
|
|
19
|
+
- brownfield 项目改动跨多个模块、服务或仓库。
|
|
20
|
+
- 需要回答“改这个 symbol/API 会影响谁”“这段流程从哪里进入、流向哪里”。
|
|
21
|
+
- 评审或发布前需要对 git diff 做影响面确认。
|
|
22
|
+
- Graphify 的轻量结构扫描不够,需要 MCP tool、资源或多仓上下文。
|
|
23
|
+
|
|
24
|
+
## 默认工作流
|
|
25
|
+
|
|
26
|
+
1. 先跑 `npm run gitnexus:doctor`,确认 Node、npm/npx 与上游包元数据。
|
|
27
|
+
2. 用户自行确认 GitNexus 上游许可证和项目使用场景是否匹配。
|
|
28
|
+
3. 在目标项目根目录显式执行索引命令,并保留 TSP 的 AGENTS/CLAUDE 契约:
|
|
29
|
+
```bash
|
|
30
|
+
npx --yes gitnexus@latest analyze --skip-agents-md
|
|
31
|
+
```
|
|
32
|
+
4. 通过 MCP 或 CLI 查询 `query/context/impact/detect_changes` 等结果。
|
|
33
|
+
5. 把关键发现回落到主链:
|
|
34
|
+
- 规划阶段 -> `/team-plan` 的 Brownfield Context Snapshot 和 readiness 证据
|
|
35
|
+
- 执行阶段 -> `/team-execute` 的 story slice 影响面说明
|
|
36
|
+
- 评审阶段 -> `/team-review` 的风险、回归边界和放行建议
|
|
37
|
+
|
|
38
|
+
## 输出约定
|
|
39
|
+
|
|
40
|
+
- GitNexus 索引由上游工具管理,通常写入目标仓库 `.gitnexus/` 与用户级 registry。
|
|
41
|
+
- TSP 侧只沉淀结论,不沉淀上游数据库:
|
|
42
|
+
- 分析目标
|
|
43
|
+
- 查询入口(MCP tool/resource 或 CLI 命令)
|
|
44
|
+
- 核心发现
|
|
45
|
+
- 对 `/team-*` 决策的影响
|
|
46
|
+
- 后续验证或回退建议
|
|
47
|
+
|
|
48
|
+
## 边界与禁用项
|
|
49
|
+
|
|
50
|
+
- 不把 GitNexus 当作 TSP 依赖或默认安装项。
|
|
51
|
+
- 不自动运行 `gitnexus setup`,避免改写用户全局 MCP/editor 配置。
|
|
52
|
+
- 不在 TSP 管理仓库里运行不带 `--skip-agents-md` 的 `gitnexus analyze`。
|
|
53
|
+
- 不复制 GitNexus 源码、hooks、skills 或生成产物到 TSP canonical source。
|
|
54
|
+
- 当前按上游 npm 元数据视为非商业许可证约束;商业使用前需要用户自行确认授权。
|
|
55
|
+
|
|
56
|
+
## 推荐组合
|
|
57
|
+
|
|
58
|
+
- 轻量 brownfield 结构扫描:`/team-help -> /update-codemaps -> graphify -> /team-plan`
|
|
59
|
+
- 深影响面分析:`/team-help -> /update-codemaps -> GitNexus impact/detect_changes -> /team-plan`
|
|
60
|
+
- 高风险评审:`/team-execute -> GitNexus detect_changes -> /handoff -> /team-review`
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "GitNexus Code Intelligence"
|
|
3
|
+
short_description: "用 GitNexus 补齐 brownfield MCP 查询与影响面证据"
|
|
4
|
+
default_prompt: "Use $gitnexus when brownfield work needs MCP-backed code intelligence, impact analysis, detect_changes, or multi-repo graph evidence. Keep GitNexus optional, preserve existing AGENTS/CLAUDE contracts, and feed findings back into /team-plan, /team-execute, or /team-review."
|