sillyspec 3.27.2 → 3.27.5
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/.claude/skills/sillyspec-execute/SKILL.md +8 -0
- package/.claude/skills/sillyspec-quick/SKILL.md +2 -1
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-archive/SKILL.md +87 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-auto/SKILL.md +93 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-brainstorm/SKILL.md +114 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-commit/SKILL.md +67 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-continue/SKILL.md +47 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-doctor/SKILL.md +76 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-execute/SKILL.md +214 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-explore/SKILL.md +102 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-export/SKILL.md +57 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-init/SKILL.md +177 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-plan/SKILL.md +156 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-quick/SKILL.md +116 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-resume/SKILL.md +70 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-scan/SKILL.md +79 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-state/SKILL.md +64 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-status/SKILL.md +54 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-verify/SKILL.md +87 -0
- package/.claude/worktrees/sillyspec-data-model-research/.claude/skills/sillyspec-workspace/SKILL.md +175 -0
- package/.claude/worktrees/sillyspec-data-model-research/.gitattributes +2 -0
- package/.claude/worktrees/sillyspec-data-model-research/.husky/pre-push +20 -0
- package/.claude/worktrees/sillyspec-data-model-research/README.md +203 -0
- package/.claude/worktrees/sillyspec-data-model-research/SKILL.md +91 -0
- package/.claude/worktrees/sillyspec-data-model-research/bin/sillyspec.js +2 -0
- package/.claude/worktrees/sillyspec-data-model-research/logo.jpg +0 -0
- package/.claude/worktrees/sillyspec-data-model-research/package-lock.json +977 -0
- package/.claude/worktrees/sillyspec-data-model-research/package.json +39 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-Bq_Z2hne.js +7446 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/favicon.jpg +0 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/index.html +16 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/logo.jpg +0 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/dist/prototype-overview.html +256 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/package.json +25 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/executor.js +95 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/index.js +679 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/parser.js +526 -0
- package/.claude/worktrees/sillyspec-data-model-research/packages/dashboard/server/watcher.js +357 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/agent-session-log.js +803 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/change-list.js +290 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/change-risk-profile.js +270 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/check-primitives.js +65 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/classify-change.js +109 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/commit-suggest.js +202 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/config-cat.js +88 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/config-schema.js +328 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/constants.js +97 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/contract-matrix.js +480 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/datetime.js +20 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/db-engine.js +55 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/db.js +381 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/decision-distill.js +517 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/local-agent.js +155 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/backends/sillyhub-mcp.js +245 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/probe.js +246 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/dispatch/strategy.js +121 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/docs-check.js +825 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/docs-debt.js +393 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/docs-gate.js +107 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/doctor-diagnostics.js +1099 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/endpoint-extractor.js +420 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/foreign-declared.js +78 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/fs-atomic.js +73 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/git-helper.js +150 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/hooks/claude-pre-tool-use.cjs +130 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/hooks/worktree-guard.js +892 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/index.js +2798 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/init.js +626 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/knowledge-match.js +231 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/local-detect.js +128 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/local-register.js +104 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/machine-interface.js +543 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/migrate.js +127 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/module-impact.js +166 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/module-resolve.js +222 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/modules.js +580 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/change-registry.js +336 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/consistency-doctor.js +355 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/shared.js +36 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/stage-machine.js +594 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress/step-store.js +265 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/progress.js +1304 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/quick-recommend.js +115 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/quicklog.js +852 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/review-tier.js +77 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/command.js +1595 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/complete-handlers.js +1552 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/complete.js +1259 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/concurrent-detect.js +156 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/gates.js +1084 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/multi-repo-context.js +208 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/next.js +128 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/prompt.js +843 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/quick-audit.js +186 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/scan-profile.js +269 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/shared.js +1562 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run/stage.js +584 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/run.js +23 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/scan-diff.js +388 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/scan-postcheck.js +512 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/scan-staleness.js +95 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/setup.js +414 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/client.js +597 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/sillyhub-mcp/config.js +62 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/spec-dir-typo.js +50 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/spec-sync.js +358 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-engine.js +171 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract-spec.js +550 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-contract.js +889 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stage-review.js +597 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/archive.js +199 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm-auto.js +236 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/brainstorm.js +617 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/cmd-existence.js +145 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/doctor.js +540 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/execute.js +1275 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/explore.js +43 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/index.js +29 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/knowledge.js +514 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan-postcheck.js +1344 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/plan.js +650 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/quick.js +167 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/scan.js +608 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/status.js +64 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/stages/verify.js +246 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/sync.js +1470 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/task-review.js +1498 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/taskcard.js +210 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/verify-postcheck.js +1718 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/verify-probes.js +277 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/version.js +19 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/workflow.js +600 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/workspace.js +125 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/worktree-apply.js +1446 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/worktree-deps.js +576 -0
- package/.claude/worktrees/sillyspec-data-model-research/src/worktree.js +1715 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/claude-instruction.md +23 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/taskcard-rules.md +28 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/testcase-design.md +12 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/prompts/verify-probes.md +32 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/archive-impact.yaml +79 -0
- package/.claude/worktrees/sillyspec-data-model-research/templates/workflows/scan-docs.yaml +132 -0
- package/eval/README.md +86 -0
- package/eval/eval.config.json +28 -0
- package/eval/lib/adapters/cli.mjs +63 -0
- package/eval/lib/adapters/dryrun.mjs +27 -0
- package/eval/lib/config.mjs +82 -0
- package/eval/lib/db.mjs +76 -0
- package/eval/lib/report.mjs +120 -0
- package/eval/lib/runner.mjs +157 -0
- package/eval/lib/tasks.mjs +73 -0
- package/eval/lib/util.mjs +107 -0
- package/eval/lib/workdir.mjs +30 -0
- package/eval/run.mjs +83 -0
- package/eval/tasks/001-slugify/files/package.json +6 -0
- package/eval/tasks/001-slugify/solution/src/slugify.mjs +26 -0
- package/eval/tasks/001-slugify/task.json +6 -0
- package/eval/tasks/001-slugify/verify.mjs +28 -0
- package/eval/tasks/002-each-day/files/package.json +6 -0
- package/eval/tasks/002-each-day/files/src/dates.mjs +4 -0
- package/eval/tasks/002-each-day/solution/src/dates.mjs +30 -0
- package/eval/tasks/002-each-day/task.json +6 -0
- package/eval/tasks/002-each-day/verify.mjs +31 -0
- package/eval/tasks/003-word-report/files/data/notes.txt +5 -0
- package/eval/tasks/003-word-report/files/package.json +6 -0
- package/eval/tasks/003-word-report/solution/bin/report.mjs +36 -0
- package/eval/tasks/003-word-report/task.json +6 -0
- package/eval/tasks/003-word-report/verify.mjs +38 -0
- package/package.json +4 -2
- package/src/agent-session-log.js +45 -5
- package/src/change-risk-profile.js +83 -14
- package/src/config-schema.js +18 -3
- package/src/contract-matrix.js +90 -29
- package/src/datetime.js +20 -0
- package/src/decision-distill.js +517 -0
- package/src/dispatch/backends/local-agent.js +4 -4
- package/src/docs-check.js +227 -0
- package/src/docs-debt.js +187 -24
- package/src/doctor-diagnostics.js +102 -2
- package/src/foreign-declared.js +78 -0
- package/src/index.js +89 -9
- package/src/init.js +9 -7
- package/src/knowledge-match.js +107 -6
- package/src/local-register.js +7 -1
- package/src/module-resolve.js +12 -1
- package/src/modules.js +2 -1
- package/src/plan-adopt-waves.js +126 -0
- package/src/quicklog.js +50 -4
- package/src/run/command.js +122 -43
- package/src/run/complete-handlers.js +48 -19
- package/src/run/complete.js +5 -2
- package/src/run/gates.js +87 -22
- package/src/run/prompt.js +84 -42
- package/src/run/quick-audit.js +11 -0
- package/src/run/shared.js +152 -10
- package/src/run.js +2 -2
- package/src/scan-postcheck.js +30 -17
- package/src/stage-contract-spec.js +2 -1
- package/src/stage-contract.js +68 -4
- package/src/stages/archive.js +53 -12
- package/src/stages/brainstorm-auto.js +7 -0
- package/src/stages/brainstorm.js +11 -0
- package/src/stages/doctor.js +157 -1
- package/src/stages/execute.js +32 -6
- package/src/stages/plan-postcheck.js +76 -17
- package/src/stages/plan.js +1 -0
- package/src/stages/quick.js +6 -1
- package/src/stages/verify.js +31 -14
- package/src/sync.js +41 -3
- package/src/task-review.js +2 -2
- package/src/taskcard-placeholders.js +21 -0
- package/src/taskcard.js +10 -1
- package/src/verify-postcheck.js +315 -13
- package/src/verify-probes.js +46 -4
- package/src/worktree-apply.js +184 -7
- package/src/worktree-deps.js +57 -0
- package/src/worktree.js +201 -58
- package/templates/prompts/taskcard-rules.md +1 -0
package/src/contract-matrix.js
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from 'fs'
|
|
12
|
-
import { join, resolve, basename, relative } from 'path'
|
|
12
|
+
import { join, resolve, basename, dirname, relative } from 'path'
|
|
13
13
|
import { gitQuiet } from './git-helper.js'
|
|
14
|
+
import { splitOwnVsForeignDiffFiles } from './foreign-declared.js'
|
|
14
15
|
import {
|
|
15
16
|
scanBackendEndpoints,
|
|
16
17
|
scanFrontendApiCalls,
|
|
@@ -333,26 +334,50 @@ export function buildContractFieldInjection(changeDir, taskName) {
|
|
|
333
334
|
|
|
334
335
|
// ─── Verify 阶段:parity check ──────────────────────────────────────────
|
|
335
336
|
|
|
337
|
+
/**
|
|
338
|
+
* 读 worktree meta(parity 双根扫描 / diff 收窄共用)。
|
|
339
|
+
* 优先 specBase/.runtime/worktrees/<change>/meta.json(主仓 spec 根——cwd=worktree 时 specBase 已被
|
|
340
|
+
* command.js 漂移守卫锚定主仓;旧实现硬编码 scanRoot/.sillyspec/.runtime,worktree 内运行永远读不到
|
|
341
|
+
* meta);兼容回退 scanRoot/.sillyspec/.runtime(旧路径)。
|
|
342
|
+
* @returns {{ meta: object, gitDir: string }|null} gitDir = diff/扫描用 git 根(真实 worktree 或 scanRoot)
|
|
343
|
+
*/
|
|
344
|
+
function _readWorktreeMeta(specBase, scanRoot, changeName) {
|
|
345
|
+
if (!changeName) return null
|
|
346
|
+
const candidates = [
|
|
347
|
+
specBase ? join(specBase, '.runtime', 'worktrees', changeName, 'meta.json') : null,
|
|
348
|
+
join(scanRoot, '.sillyspec', '.runtime', 'worktrees', changeName, 'meta.json'),
|
|
349
|
+
].filter(Boolean)
|
|
350
|
+
for (const metaPath of candidates) {
|
|
351
|
+
try {
|
|
352
|
+
if (!existsSync(metaPath)) continue
|
|
353
|
+
const meta = JSON.parse(readFileSync(metaPath, 'utf8'))
|
|
354
|
+
const gitDir = (meta.worktreePath && meta.mode !== 'in-place-fallback' && existsSync(meta.worktreePath))
|
|
355
|
+
? meta.worktreePath : scanRoot
|
|
356
|
+
return { meta, gitDir }
|
|
357
|
+
} catch { /* 损坏 meta 试下一候选 */ }
|
|
358
|
+
}
|
|
359
|
+
return null
|
|
360
|
+
}
|
|
361
|
+
|
|
336
362
|
/**
|
|
337
363
|
* 取本变更 diff 文件集(parity 前端调用收窄用,坑 probe5-fullrepo-frontend-noise)。
|
|
338
364
|
* 优先 worktree meta 锚点 diff(与 verify 同源);无 meta 退主仓 git diff HEAD。
|
|
339
365
|
* @returns {string[]|null}
|
|
340
366
|
*/
|
|
341
|
-
function _resolveDiffFilesForParity(scanRoot, changeName) {
|
|
367
|
+
function _resolveDiffFilesForParity(specBase, scanRoot, changeName) {
|
|
342
368
|
try {
|
|
343
|
-
const
|
|
344
|
-
if (
|
|
345
|
-
const
|
|
346
|
-
const diffBase = meta.baselineCommit || meta.actualBaseHash || meta.baseHash
|
|
347
|
-
const gitDir = (meta.worktreePath && meta.mode !== 'in-place-fallback' && existsSync(meta.worktreePath))
|
|
348
|
-
? meta.worktreePath : scanRoot
|
|
369
|
+
const wt = _readWorktreeMeta(specBase, scanRoot, changeName)
|
|
370
|
+
if (wt) {
|
|
371
|
+
const diffBase = wt.meta.baselineCommit || wt.meta.actualBaseHash || wt.meta.baseHash
|
|
349
372
|
if (diffBase) {
|
|
350
|
-
const out = gitQuiet(gitDir, ['diff', '--name-only', `${diffBase}..HEAD`], { timeout: 30000 })
|
|
373
|
+
const out = gitQuiet(wt.gitDir, ['diff', '--name-only', `${diffBase}..HEAD`], { timeout: 30000 })
|
|
351
374
|
if (out !== null) {
|
|
352
375
|
const files = out.split('\n').filter(Boolean)
|
|
353
|
-
// 并入 worktree 未提交(子代理默认不 commit 的形态,与 resolveVerifyChangedFiles
|
|
376
|
+
// 并入 worktree 未提交(子代理默认不 commit 的形态,与 resolveVerifyChangedFiles 同口径)。
|
|
377
|
+
// -uall:porcelain 默认把整目录折叠成 `dir/` 一项,文件级匹配(前端调用过滤)会漏新目录
|
|
378
|
+
// 里的文件(坑 probe5-worktree-single-root-noise 实证:web/ 折叠 → feature.js 漏匹配)
|
|
354
379
|
try {
|
|
355
|
-
const wtStatus = gitQuiet(gitDir, ['status', '--porcelain'], { timeout: 30000, trim: false })
|
|
380
|
+
const wtStatus = gitQuiet(wt.gitDir, ['status', '--porcelain', '--untracked-files=all'], { timeout: 30000, trim: false })
|
|
356
381
|
for (const line of String(wtStatus || '').split('\n')) {
|
|
357
382
|
if (!line || line.length < 4) continue
|
|
358
383
|
const p = line.slice(3).trim().split(' -> ').pop() || ''
|
|
@@ -364,9 +389,16 @@ function _resolveDiffFilesForParity(scanRoot, changeName) {
|
|
|
364
389
|
}
|
|
365
390
|
}
|
|
366
391
|
}
|
|
367
|
-
// 无 meta(brownfield/已 cleanup):主仓未提交 diff
|
|
392
|
+
// 无 meta(brownfield/已 cleanup):主仓未提交 diff。他者声明归属过滤(坑
|
|
393
|
+
// verify-reconcile-foreign-wip):并行会话在途 WIP 的前端文件混入会产出「他者调用 ×
|
|
394
|
+
// 本变更端点」的 missingBackend 误报——剔除他者显式声明文件(fail-closed:无主保留)。
|
|
368
395
|
const out = gitQuiet(scanRoot, ['diff', '--name-only', 'HEAD'], { timeout: 30000 })
|
|
369
|
-
|
|
396
|
+
if (out === null) return null
|
|
397
|
+
const { own, foreign } = splitOwnVsForeignDiffFiles(scanRoot, changeName, out.split('\n').filter(Boolean))
|
|
398
|
+
if (foreign.length > 0) {
|
|
399
|
+
console.warn(`⚠️ parity 对账已排除 ${foreign.length} 个并行会话声明的文件(${foreign.slice(0, 5).map(x => x.file).join(', ')}${foreign.length > 5 ? ' 等' : ''})`)
|
|
400
|
+
}
|
|
401
|
+
return own
|
|
370
402
|
} catch { return null }
|
|
371
403
|
}
|
|
372
404
|
|
|
@@ -410,18 +442,42 @@ export function verifyApiParity(specBase, scanRoot, runtimeRoot, changeName = nu
|
|
|
410
442
|
return { ok: true, missingBackend: [], unusedBackend: [], summary: 'No scan root for parity check', backendCount: allProviderEndpoints.length, frontendCount: 0 }
|
|
411
443
|
}
|
|
412
444
|
|
|
413
|
-
// ──
|
|
414
|
-
//
|
|
415
|
-
//
|
|
416
|
-
//
|
|
417
|
-
//
|
|
418
|
-
|
|
419
|
-
|
|
445
|
+
// ── 双根并集现算(坑 probe5-worktree-single-root-noise,2026-08-24 用户实证:worktree 场景
|
|
446
|
+
// 只现算 scanRoot 单根,另一侧端点不在比对集——verify 从主仓跑(apply 前)漏 worktree 新增端点;
|
|
447
|
+
// verify 从 worktree 跑则既读不到 meta(旧路径硬编码 scanRoot/.sillyspec)也漏主仓既有 daemon
|
|
448
|
+
// 端点 → 前端调用全量误报 missing)。后端端点全集 = 主仓既有 ∪ worktree 新增 ∪ 存量 artifact:
|
|
449
|
+
// 现算根集 = [scanRoot, meta.worktreePath, 主仓根(cwd 自身在 linked worktree 内时经
|
|
450
|
+
// git-common-dir 解析)],逐根 scanBackendEndpoints 按 method+path 去重。
|
|
451
|
+
// 存量基线失配坑(probe5-endpoint-baseline-stale,2026-08-22)由本并集一并覆盖:现算当前
|
|
452
|
+
// 代码 ∪ 存量基线;unusedBackend 只对现算端点算(存量过期端点不再误报 unused)。
|
|
453
|
+
const wt = _readWorktreeMeta(specBase, scanRoot, changeName)
|
|
454
|
+
const liveRoots = []
|
|
455
|
+
const pushRoot = (root, label) => {
|
|
456
|
+
if (!root || !existsSync(root)) return
|
|
457
|
+
const abs = resolve(root)
|
|
458
|
+
if (liveRoots.some(r => resolve(r.root) === abs)) return
|
|
459
|
+
liveRoots.push({ root, label })
|
|
460
|
+
}
|
|
461
|
+
pushRoot(scanRoot, 'scan-root')
|
|
462
|
+
if (wt && wt.gitDir !== scanRoot) pushRoot(wt.gitDir, 'worktree')
|
|
463
|
+
// cwd 自身是 linked worktree 时补主仓根(主仓返回 .git → dirname=scanRoot 被 pushRoot 去重)
|
|
464
|
+
try {
|
|
465
|
+
const commonDir = gitQuiet(scanRoot, ['rev-parse', '--git-common-dir'])
|
|
466
|
+
if (commonDir) pushRoot(dirname(resolve(scanRoot, commonDir)), 'main')
|
|
467
|
+
} catch { /* 非 git 目录/解析失败:单根继续 */ }
|
|
468
|
+
|
|
469
|
+
const liveByRoot = []
|
|
470
|
+
for (const { root, label } of liveRoots) {
|
|
471
|
+
try { liveByRoot.push({ root, label, endpoints: scanBackendEndpoints(root) }) } catch { /* 单根失败不拖垮整体 */ }
|
|
472
|
+
}
|
|
473
|
+
const liveEndpoints = liveByRoot.flatMap(r => r.endpoints)
|
|
420
474
|
const liveKeys = new Set(liveEndpoints.map(e => `${e.method} ${e.path}`))
|
|
475
|
+
const mergedKeys = new Set(allProviderEndpoints.map(e => `${e.method} ${e.path}`))
|
|
421
476
|
const mergedProviderEndpoints = [...allProviderEndpoints]
|
|
422
477
|
for (const e of liveEndpoints) {
|
|
423
478
|
const key = `${e.method} ${e.path}`
|
|
424
|
-
if (!
|
|
479
|
+
if (!mergedKeys.has(key)) {
|
|
480
|
+
mergedKeys.add(key)
|
|
425
481
|
mergedProviderEndpoints.push(e)
|
|
426
482
|
}
|
|
427
483
|
}
|
|
@@ -431,24 +487,28 @@ export function verifyApiParity(specBase, scanRoot, runtimeRoot, changeName = nu
|
|
|
431
487
|
// → 143 个 missing 全是误报噪音)。比对口径 = 本变更 diff 文件内的调用 ∪ 全仓(仅当
|
|
432
488
|
// 端点登记源也是全仓时——无 changeName 的 CLI contractScan 场景)。diff 不可得时退回
|
|
433
489
|
// 全仓(不静默跳过对账)。
|
|
490
|
+
// 扫描根优先真实 worktree(坑 probe5-worktree-single-root-noise):apply 前新代码只在
|
|
491
|
+
// worktree,scanRoot(主仓 cwd)里是旧版本——读旧版会漏新调用/多已删调用。
|
|
434
492
|
let frontendCalls = []
|
|
435
493
|
let frontendScope = 'full-repo'
|
|
494
|
+
const frontendRoot = (wt && wt.gitDir !== scanRoot) ? wt.gitDir : scanRoot
|
|
495
|
+
const frontendRootLabel = frontendRoot === scanRoot ? 'scan-root' : 'worktree'
|
|
436
496
|
if (changeName) {
|
|
437
497
|
try {
|
|
438
|
-
const changed = _resolveDiffFilesForParity(scanRoot, changeName)
|
|
498
|
+
const changed = _resolveDiffFilesForParity(specBase, scanRoot, changeName)
|
|
439
499
|
if (changed && changed.length > 0) {
|
|
440
500
|
const changedSet = new Set(changed.map(f => f.replace(/\\/g, '/')))
|
|
441
|
-
frontendCalls = scanFrontendApiCalls(
|
|
501
|
+
frontendCalls = scanFrontendApiCalls(frontendRoot).filter(c => {
|
|
442
502
|
const src = String(c.source || '').replace(/\\/g, '/')
|
|
443
503
|
return changedSet.has(src) || [...changedSet].some(cf => src.endsWith(cf) || cf.endsWith(src))
|
|
444
504
|
})
|
|
445
|
-
frontendScope = `change-diff (${changed.length} files)`
|
|
505
|
+
frontendScope = `change-diff (${changed.length} files @ ${frontendRootLabel})`
|
|
446
506
|
} else {
|
|
447
|
-
frontendCalls = scanFrontendApiCalls(
|
|
507
|
+
frontendCalls = scanFrontendApiCalls(frontendRoot)
|
|
448
508
|
}
|
|
449
|
-
} catch { frontendCalls = scanFrontendApiCalls(
|
|
509
|
+
} catch { frontendCalls = scanFrontendApiCalls(frontendRoot) }
|
|
450
510
|
} else {
|
|
451
|
-
frontendCalls = scanFrontendApiCalls(
|
|
511
|
+
frontendCalls = scanFrontendApiCalls(frontendRoot)
|
|
452
512
|
}
|
|
453
513
|
|
|
454
514
|
const { missingBackend, unusedBackend } = diffApiParity(frontendCalls, mergedProviderEndpoints)
|
|
@@ -460,13 +520,14 @@ export function verifyApiParity(specBase, scanRoot, runtimeRoot, changeName = nu
|
|
|
460
520
|
})
|
|
461
521
|
|
|
462
522
|
const ok = missingBackend.length === 0
|
|
523
|
+
const liveRootSummary = liveByRoot.map(r => `${r.label} ${r.endpoints.length}`).join(' + ')
|
|
463
524
|
let summary = ok
|
|
464
|
-
? `✅ API parity check passed: ${mergedProviderEndpoints.length} backend endpoints (live ${
|
|
525
|
+
? `✅ API parity check passed: ${mergedProviderEndpoints.length} backend endpoints (live [${liveRootSummary}] + artifact ${allProviderEndpoints.length}), ${frontendCalls.length} frontend calls [scope: ${frontendScope}]`
|
|
465
526
|
: `❌ API parity check failed: ${missingBackend.length} frontend calls have no matching backend endpoint [scope: ${frontendScope}]`
|
|
466
527
|
|
|
467
528
|
if (narrowedUnused.length > 0) {
|
|
468
529
|
summary += ` | ${narrowedUnused.length} backend endpoints unused by frontend`
|
|
469
530
|
}
|
|
470
531
|
|
|
471
|
-
return { ok, missingBackend, unusedBackend: narrowedUnused, summary, backendCount: mergedProviderEndpoints.length, frontendCount: frontendCalls.length }
|
|
532
|
+
return { ok, missingBackend, unusedBackend: narrowedUnused, summary, backendCount: mergedProviderEndpoints.length, frontendCount: frontendCalls.length, scanRoots: liveByRoot.map(r => r.root) }
|
|
472
533
|
}
|
package/src/datetime.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 人读墙钟时间工具(坑 taskcard-created-at-utc,2026-08-23 实证:taskcard 骨架 created_at 用
|
|
3
|
+
* toISOString() 落 UTC——本地 09:39 生成写 01:39,子代理两次手工改)。
|
|
4
|
+
*
|
|
5
|
+
* 项目内「人读的 markdown/YAML frontmatter 时间字段」统一走本函数:本地时区 +
|
|
6
|
+
* `YYYY-MM-DD HH:mm:ss` 形状(scan.js 文档示例形状),手工拼接零 locale/ICU 依赖(Node
|
|
7
|
+
* small-icu 构建下 toLocaleString('sv-SE') 不可靠)。机器可读处(JSON/DB 列/目录名)继续用
|
|
8
|
+
* toISOString()——那是 ISO 惯例不是坑。
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 本地墙钟时间字符串(YYYY-MM-DD HH:mm:ss,各段补零)。
|
|
13
|
+
* @param {Date} [d] 可注入时钟(测试用),缺省当前时间
|
|
14
|
+
* @returns {string}
|
|
15
|
+
*/
|
|
16
|
+
export function nowWallClock(d = new Date()) {
|
|
17
|
+
const p = (n) => String(n).padStart(2, '0');
|
|
18
|
+
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} `
|
|
19
|
+
+ `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
|
|
20
|
+
}
|