docguard-cli 0.9.6__tar.gz → 0.9.7__tar.gz
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.
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.docguard.json +2 -1
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.github/workflows/spec-kit-extension.yml +1 -1
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/PKG-INFO +1 -1
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/diff.mjs +16 -3
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/init.mjs +4 -0
- docguard_cli-0.9.7/cli/commands/setup.mjs +455 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/docguard.mjs +12 -0
- docguard_cli-0.9.7/cli/ensure-skills.mjs +96 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/doc-quality.mjs +2 -2
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/docs-sync.mjs +41 -6
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/todo-tracking.mjs +11 -6
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/README.md +13 -15
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/extension.yml +23 -40
- docguard_cli-0.9.7/extensions/spec-kit-docguard/skills/docguard-fix/SKILL.md +218 -0
- docguard_cli-0.9.7/extensions/spec-kit-docguard/skills/docguard-guard/SKILL.md +167 -0
- docguard_cli-0.9.7/extensions/spec-kit-docguard/skills/docguard-review/SKILL.md +182 -0
- docguard_cli-0.9.7/extensions/spec-kit-docguard/skills/docguard-score/SKILL.md +178 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/templates/extensions.yml +5 -5
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/package.json +1 -1
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/pyproject.toml +1 -1
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/commands/speckit.analyze.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/commands/speckit.checklist.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/commands/speckit.clarify.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/commands/speckit.constitution.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/commands/speckit.implement.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/commands/speckit.plan.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/commands/speckit.specify.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/commands/speckit.tasks.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/commands/speckit.taskstoissues.md +0 -0
- {docguard_cli-0.9.6/extensions/spec-kit-docguard → docguard_cli-0.9.7/.agent}/skills/docguard-fix/SKILL.md +0 -0
- {docguard_cli-0.9.6/extensions/spec-kit-docguard → docguard_cli-0.9.7/.agent}/skills/docguard-guard/SKILL.md +0 -0
- {docguard_cli-0.9.6/extensions/spec-kit-docguard → docguard_cli-0.9.7/.agent}/skills/docguard-review/SKILL.md +0 -0
- {docguard_cli-0.9.6/extensions/spec-kit-docguard → docguard_cli-0.9.7/.agent}/skills/docguard-score/SKILL.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/skills/speckit-analyze/SKILL.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/skills/speckit-checklist/SKILL.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/skills/speckit-clarify/SKILL.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/skills/speckit-constitution/SKILL.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/skills/speckit-implement/SKILL.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/skills/speckit-plan/SKILL.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/skills/speckit-specify/SKILL.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/skills/speckit-tasks/SKILL.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.agent/skills/speckit-taskstoissues/SKILL.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.docguardignore +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.github/workflows/ci.yml +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.gitignore +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.npmignore +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/init-options.json +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/memory/constitution.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/scripts/bash/check-prerequisites.sh +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/scripts/bash/common.sh +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/scripts/bash/create-new-feature.sh +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/scripts/bash/setup-plan.sh +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/scripts/bash/update-agent-context.sh +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/templates/agent-file-template.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/templates/checklist-template.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/templates/constitution-template.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/templates/plan-template.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/templates/spec-template.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/.specify/templates/tasks-template.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/AGENTS.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/CHANGELOG.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/CODE_OF_CONDUCT.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/COMPARISONS.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/CONTRIBUTING.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/DRIFT-LOG.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/LICENSE +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/PHILOSOPHY.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/README.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/ROADMAP.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/SECURITY.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/STANDARD.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/SUPPORT.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/action.yml +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/agents.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/badge.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/ci.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/diagnose.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/fix.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/generate.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/guard.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/hooks.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/llms.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/publish.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/score.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/trace.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/commands/watch.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/scanners/doc-tools.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/scanners/routes.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/scanners/schemas.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/scanners/speckit.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/shared.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/architecture.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/changelog.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/docs-coverage.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/docs-diff.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/drift.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/environment.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/freshness.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/metadata-sync.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/metrics-consistency.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/schema-sync.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/security.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/structure.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/test-spec.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/cli/validators/traceability.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/commands/docguard.fix.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/commands/docguard.guard.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/commands/docguard.review.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/commands/docguard.score.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/configs/fastify.json +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/configs/generic.json +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/configs/nextjs.json +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/configs/python.json +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docguard_cli/__init__.py +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docguard_cli/wrapper.py +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docs/ai-integration.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docs/commands.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docs/configuration.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docs/faq.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docs/installation.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docs/profiles.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docs/quickstart.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docs-canonical/ARCHITECTURE.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docs-canonical/DATA-MODEL.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docs-canonical/ENVIRONMENT.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docs-canonical/SECURITY.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/docs-canonical/TEST-SPEC.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/LICENSE +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/commands/diagnose.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/commands/generate.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/commands/guard.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/commands/init.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/commands/score.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/commands/trace.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/scripts/bash/common.sh +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/scripts/bash/docguard-check-docs.sh +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/scripts/bash/docguard-init-doc.sh +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/extensions/spec-kit-docguard/scripts/bash/docguard-suggest-fix.sh +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/ADR.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/AGENTS.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/ARCHITECTURE.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/CHANGELOG.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/CURRENT-STATE.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/DATA-MODEL.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/DEPLOYMENT.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/DRIFT-LOG.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/ENVIRONMENT.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/KNOWN-GOTCHAS.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/REQUIREMENTS.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/ROADMAP.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/RUNBOOKS.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/SECURITY.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/TEST-SPEC.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/TROUBLESHOOTING.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/VENDOR-BUGS.md.template +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/ci/github-actions.yml +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/commands/docguard.fix.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/commands/docguard.guard.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/commands/docguard.init.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/commands/docguard.review.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/templates/commands/docguard.update.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/tests/commands.test.mjs +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/vscode-extension/.vscodeignore +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/vscode-extension/README.md +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/vscode-extension/extension.js +0 -0
- {docguard_cli-0.9.6 → docguard_cli-0.9.7}/vscode-extension/package.json +0 -0
|
@@ -19,7 +19,7 @@ jobs:
|
|
|
19
19
|
|
|
20
20
|
- name: Sync version in extension.yml
|
|
21
21
|
run: |
|
|
22
|
-
sed -i
|
|
22
|
+
sed -i 's/^ version: ".*"/ version: "'"${GITHUB_REF_NAME#v}"'"/' extensions/spec-kit-docguard/extension.yml
|
|
23
23
|
echo "Updated extension.yml to version ${GITHUB_REF_NAME#v}"
|
|
24
24
|
grep 'version:' extensions/spec-kit-docguard/extension.yml
|
|
25
25
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docguard-cli
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.7
|
|
4
4
|
Summary: The enforcement tool for Canonical-Driven Development (CDD). Audit, generate, and guard your project documentation. Zero dependencies.
|
|
5
5
|
Project-URL: Homepage, https://github.com/raccioly/docguard
|
|
6
6
|
Project-URL: Documentation, https://github.com/raccioly/docguard#readme
|
|
@@ -157,7 +157,12 @@ function diffEntities(dir) {
|
|
|
157
157
|
'EntityName', 'Entity', 'metadata', 'tbd', 'cascade', 'fields',
|
|
158
158
|
'purpose', 'version', 'author', 'example', 'TODO', 'Overview',
|
|
159
159
|
'Revision', 'History', 'Entities', 'Relationships', 'Indexes',
|
|
160
|
-
'Migration', 'Strategy',
|
|
160
|
+
'Migration', 'Strategy', 'Trade-offs', 'Tradeoffs', 'Notes',
|
|
161
|
+
'Summary', 'Details', 'Configuration', 'Setup', 'Reference',
|
|
162
|
+
'Appendix', 'Glossary', 'FAQ', 'Introduction', 'Background',
|
|
163
|
+
'Prerequisites', 'Requirements', 'Assumptions', 'Constraints',
|
|
164
|
+
'Dependencies', 'Architecture', 'Design', 'Implementation',
|
|
165
|
+
'Testing', 'Deployment', 'Monitoring', 'Operations', 'Security',
|
|
161
166
|
]);
|
|
162
167
|
|
|
163
168
|
const headerRegex = /^### (\S+)/gm;
|
|
@@ -165,9 +170,11 @@ function diffEntities(dir) {
|
|
|
165
170
|
while ((match = headerRegex.exec(content)) !== null) {
|
|
166
171
|
const name = match[1].replace(/[`*]/g, '');
|
|
167
172
|
// Skip template placeholders (<!-- ... -->) and noise words
|
|
168
|
-
if (name.startsWith('<!--') || name.length <=
|
|
173
|
+
if (name.startsWith('<!--') || name.length <= 2 || HEADER_NOISE.has(name) || HEADER_NOISE.has(name.toLowerCase())) {
|
|
169
174
|
continue;
|
|
170
175
|
}
|
|
176
|
+
// Skip hyphenated words (e.g., 'Trade-offs', 'Set-up') — these are section titles, not entities
|
|
177
|
+
if (name.includes('-')) continue;
|
|
171
178
|
docEntities.add(name.toLowerCase());
|
|
172
179
|
}
|
|
173
180
|
|
|
@@ -194,10 +201,16 @@ function diffEntities(dir) {
|
|
|
194
201
|
// Common table headers and template words
|
|
195
202
|
'true', 'false', 'header', 'checks', 'project', 'count', 'grade',
|
|
196
203
|
'breakdown', 'issuecount', 'autofixable', 'projectname', 'projecttype',
|
|
204
|
+
// Common doc section words (not entity names)
|
|
205
|
+
'trade', 'offs', 'tradeoffs', 'setup', 'overview', 'summary',
|
|
206
|
+
'details', 'configuration', 'reference', 'pattern', 'patterns',
|
|
207
|
+
'strategy', 'approach', 'impact', 'benefit', 'risk', 'concern',
|
|
208
|
+
'action', 'result', 'outcome', 'inverted', 'composite', 'secondary',
|
|
197
209
|
]);
|
|
198
210
|
while ((match = tableRegex.exec(content)) !== null) {
|
|
199
211
|
const name = match[1];
|
|
200
|
-
|
|
212
|
+
// Skip short names (<=3 chars) and noise words
|
|
213
|
+
if (name.length > 3 && !TABLE_NOISE.has(name.toLowerCase())) {
|
|
201
214
|
docEntities.add(name.toLowerCase());
|
|
202
215
|
}
|
|
203
216
|
}
|
|
@@ -8,6 +8,7 @@ import { resolve, dirname } from 'node:path';
|
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import { createInterface } from 'node:readline';
|
|
10
10
|
import { c, PROFILES } from '../shared.mjs';
|
|
11
|
+
import { ensureSkills } from '../ensure-skills.mjs';
|
|
11
12
|
|
|
12
13
|
function detectProjectType(dir) {
|
|
13
14
|
const pkgPath = resolve(dir, 'package.json');
|
|
@@ -285,4 +286,7 @@ export async function runInit(projectDir, config, flags) {
|
|
|
285
286
|
} else {
|
|
286
287
|
console.log(`\n ${c.dim}Run${c.reset} ${c.cyan}docguard diagnose${c.reset} ${c.dim}to check for issues.${c.reset}\n`);
|
|
287
288
|
}
|
|
289
|
+
|
|
290
|
+
// Auto-install skills and commands
|
|
291
|
+
ensureSkills(projectDir, flags);
|
|
288
292
|
}
|
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup Command — Interactive onboarding wizard for DocGuard
|
|
3
|
+
*
|
|
4
|
+
* Walks through 7 steps to ensure DocGuard is fully configured:
|
|
5
|
+
* 1. Project detection & config
|
|
6
|
+
* 2. Canonical docs
|
|
7
|
+
* 3. AI skills
|
|
8
|
+
* 4. Slash commands
|
|
9
|
+
* 5. Agent configs
|
|
10
|
+
* 6. External integrations (spec-kit, understanding)
|
|
11
|
+
* 7. Git hooks
|
|
12
|
+
*
|
|
13
|
+
* Each step shows current status (✅/⚠️) and offers to fix what's missing.
|
|
14
|
+
* Supports --skip-prompts for non-interactive CI mode.
|
|
15
|
+
*
|
|
16
|
+
* Zero dependencies — pure Node.js built-ins only.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from 'node:fs';
|
|
20
|
+
import { resolve, dirname, basename } from 'node:path';
|
|
21
|
+
import { fileURLToPath } from 'node:url';
|
|
22
|
+
import { createInterface } from 'node:readline';
|
|
23
|
+
import { execSync } from 'node:child_process';
|
|
24
|
+
import { c } from '../shared.mjs';
|
|
25
|
+
import { ensureSkills } from '../ensure-skills.mjs';
|
|
26
|
+
|
|
27
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
28
|
+
const __dirname = dirname(__filename);
|
|
29
|
+
const TEMPLATES_DIR = resolve(__dirname, '../../templates');
|
|
30
|
+
const SKILLS_SOURCE = resolve(__dirname, '../../extensions/spec-kit-docguard/skills');
|
|
31
|
+
const COMMANDS_SOURCE = resolve(__dirname, '../../commands');
|
|
32
|
+
|
|
33
|
+
// ── Readline Helper ─────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
function askQuestion(prompt) {
|
|
36
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
37
|
+
return new Promise(res => {
|
|
38
|
+
rl.question(prompt, answer => {
|
|
39
|
+
rl.close();
|
|
40
|
+
res(answer.trim().toLowerCase());
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function askYesNo(prompt, defaultYes = true) {
|
|
46
|
+
const label = defaultYes ? 'Y/n' : 'y/N';
|
|
47
|
+
const answer = await askQuestion(`${prompt} [${label}]: `);
|
|
48
|
+
if (answer === '') return defaultYes;
|
|
49
|
+
return answer === 'y' || answer === 'yes';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ── Project Type Detection ──────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
function detectProjectType(dir) {
|
|
55
|
+
const pkgPath = resolve(dir, 'package.json');
|
|
56
|
+
if (existsSync(pkgPath)) {
|
|
57
|
+
try {
|
|
58
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
59
|
+
const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
60
|
+
if (pkg.bin) return 'cli';
|
|
61
|
+
if (allDeps.next || allDeps.react || allDeps.vue || allDeps['@angular/core'] ||
|
|
62
|
+
allDeps.svelte || allDeps.nuxt) return 'webapp';
|
|
63
|
+
if (allDeps.express || allDeps.fastify || allDeps.hono || allDeps.koa) return 'api';
|
|
64
|
+
if (pkg.main || pkg.exports || pkg.module) return 'library';
|
|
65
|
+
} catch { /* fall through */ }
|
|
66
|
+
}
|
|
67
|
+
if (existsSync(resolve(dir, 'manage.py'))) return 'webapp';
|
|
68
|
+
if (existsSync(resolve(dir, 'setup.py')) || existsSync(resolve(dir, 'pyproject.toml'))) return 'library';
|
|
69
|
+
return 'unknown';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ── CLI Detection ───────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
function isCliAvailable(name) {
|
|
75
|
+
try {
|
|
76
|
+
const cmd = process.platform === 'win32' ? `where ${name}` : `which ${name}`;
|
|
77
|
+
execSync(`${cmd} 2>/dev/null`, { encoding: 'utf-8', timeout: 3000 });
|
|
78
|
+
return true;
|
|
79
|
+
} catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function detectAgentDirs(projectDir) {
|
|
85
|
+
const agentDirs = [
|
|
86
|
+
{ name: 'GitHub Copilot', dir: '.github', commandsPath: '.github/commands' },
|
|
87
|
+
{ name: 'Cursor', dir: '.cursor', commandsPath: '.cursor/rules' },
|
|
88
|
+
{ name: 'Google Gemini', dir: '.gemini', commandsPath: '.gemini/commands' },
|
|
89
|
+
{ name: 'Claude Code', dir: '.claude', commandsPath: '.claude/commands' },
|
|
90
|
+
{ name: 'Antigravity', dir: '.agents', commandsPath: '.agents/workflows' },
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
return agentDirs.filter(a => existsSync(resolve(projectDir, a.dir)));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ── Main Setup Wizard ───────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
export async function runSetup(projectDir, config, flags) {
|
|
99
|
+
console.log(`${c.bold}🧙 DocGuard Setup Wizard${c.reset}`);
|
|
100
|
+
console.log(`${c.dim} Directory: ${projectDir}${c.reset}\n`);
|
|
101
|
+
|
|
102
|
+
const interactive = !flags.skipPrompts;
|
|
103
|
+
let configured = 0;
|
|
104
|
+
let alreadyGood = 0;
|
|
105
|
+
|
|
106
|
+
// ── Step 1: Project Detection & Config ──────────────────────────────
|
|
107
|
+
|
|
108
|
+
console.log(` ${c.bold}Step 1/7: Project Detection${c.reset}`);
|
|
109
|
+
|
|
110
|
+
const detectedType = detectProjectType(projectDir);
|
|
111
|
+
console.log(` ${c.green}✅${c.reset} Project type: ${c.cyan}${detectedType}${c.reset}`);
|
|
112
|
+
|
|
113
|
+
const configPath = resolve(projectDir, '.docguard.json');
|
|
114
|
+
if (existsSync(configPath)) {
|
|
115
|
+
const cfg = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
116
|
+
console.log(` ${c.green}✅${c.reset} .docguard.json exists (profile: ${c.cyan}${cfg.profile || 'standard'}${c.reset})`);
|
|
117
|
+
alreadyGood++;
|
|
118
|
+
} else {
|
|
119
|
+
console.log(` ${c.yellow}⚠️${c.reset} .docguard.json missing`);
|
|
120
|
+
const create = interactive
|
|
121
|
+
? await askYesNo(` → Create config file?`)
|
|
122
|
+
: true;
|
|
123
|
+
|
|
124
|
+
if (create) {
|
|
125
|
+
const typeDefaults = {
|
|
126
|
+
cli: { needsEnvVars: false, needsEnvExample: false, needsE2E: false, needsDatabase: false },
|
|
127
|
+
library: { needsEnvVars: false, needsEnvExample: false, needsE2E: false, needsDatabase: false },
|
|
128
|
+
webapp: { needsEnvVars: true, needsEnvExample: true, needsE2E: true, needsDatabase: true },
|
|
129
|
+
api: { needsEnvVars: true, needsEnvExample: true, needsE2E: false, needsDatabase: true },
|
|
130
|
+
unknown: { needsEnvVars: true, needsEnvExample: true, needsE2E: false, needsDatabase: true },
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const defaultConfig = {
|
|
134
|
+
projectName: config.projectName,
|
|
135
|
+
version: '0.4',
|
|
136
|
+
profile: 'standard',
|
|
137
|
+
projectType: detectedType,
|
|
138
|
+
projectTypeConfig: typeDefaults[detectedType] || typeDefaults.unknown,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2) + '\n', 'utf-8');
|
|
142
|
+
console.log(` ${c.green}✅ Created .docguard.json${c.reset}`);
|
|
143
|
+
configured++;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
console.log('');
|
|
148
|
+
|
|
149
|
+
// ── Step 2: Canonical Docs ──────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
console.log(` ${c.bold}Step 2/7: Canonical Docs${c.reset}`);
|
|
152
|
+
|
|
153
|
+
const canonicalDocs = [
|
|
154
|
+
{ file: 'docs-canonical/ARCHITECTURE.md', template: 'ARCHITECTURE.md.template', label: 'Architecture', defaultYes: true },
|
|
155
|
+
{ file: 'docs-canonical/DATA-MODEL.md', template: 'DATA-MODEL.md.template', label: 'Data Model', defaultYes: ['webapp', 'api'].includes(detectedType) },
|
|
156
|
+
{ file: 'docs-canonical/SECURITY.md', template: 'SECURITY.md.template', label: 'Security', defaultYes: ['webapp', 'api'].includes(detectedType) },
|
|
157
|
+
{ file: 'docs-canonical/TEST-SPEC.md', template: 'TEST-SPEC.md.template', label: 'Test Spec', defaultYes: true },
|
|
158
|
+
{ file: 'docs-canonical/ENVIRONMENT.md', template: 'ENVIRONMENT.md.template', label: 'Environment', defaultYes: ['webapp', 'api'].includes(detectedType) },
|
|
159
|
+
{ file: 'docs-canonical/REQUIREMENTS.md', template: 'REQUIREMENTS.md.template', label: 'Requirements', defaultYes: true },
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
const trackingFiles = [
|
|
163
|
+
{ file: 'AGENTS.md', template: 'AGENTS.md.template', label: 'Agent Instructions' },
|
|
164
|
+
{ file: 'CHANGELOG.md', template: 'CHANGELOG.md.template', label: 'Changelog' },
|
|
165
|
+
{ file: 'DRIFT-LOG.md', template: 'DRIFT-LOG.md.template', label: 'Drift Log' },
|
|
166
|
+
];
|
|
167
|
+
|
|
168
|
+
let missingDocs = [];
|
|
169
|
+
|
|
170
|
+
// Check canonical docs
|
|
171
|
+
for (const doc of [...canonicalDocs, ...trackingFiles]) {
|
|
172
|
+
const fullPath = resolve(projectDir, doc.file);
|
|
173
|
+
if (existsSync(fullPath)) {
|
|
174
|
+
console.log(` ${c.green}✅${c.reset} ${doc.file}`);
|
|
175
|
+
alreadyGood++;
|
|
176
|
+
} else {
|
|
177
|
+
console.log(` ${c.yellow}⚠️${c.reset} ${doc.file} ${c.dim}(missing)${c.reset}`);
|
|
178
|
+
missingDocs.push(doc);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (missingDocs.length > 0) {
|
|
183
|
+
const create = interactive
|
|
184
|
+
? await askYesNo(` → Create ${missingDocs.length} missing doc(s) from templates?`)
|
|
185
|
+
: true;
|
|
186
|
+
|
|
187
|
+
if (create) {
|
|
188
|
+
const today = new Date().toISOString().split('T')[0];
|
|
189
|
+
for (const doc of missingDocs) {
|
|
190
|
+
const destPath = resolve(projectDir, doc.file);
|
|
191
|
+
const templatePath = resolve(TEMPLATES_DIR, doc.template);
|
|
192
|
+
|
|
193
|
+
const destDir = dirname(destPath);
|
|
194
|
+
if (!existsSync(destDir)) {
|
|
195
|
+
mkdirSync(destDir, { recursive: true });
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (existsSync(templatePath)) {
|
|
199
|
+
const content = readFileSync(templatePath, 'utf-8').replace(/YYYY-MM-DD/g, today);
|
|
200
|
+
writeFileSync(destPath, content, 'utf-8');
|
|
201
|
+
console.log(` ${c.green}✅ Created ${doc.file}${c.reset}`);
|
|
202
|
+
configured++;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
console.log('');
|
|
209
|
+
|
|
210
|
+
// ── Step 3: AI Skills ──────────────────────────────────────────────
|
|
211
|
+
|
|
212
|
+
console.log(` ${c.bold}Step 3/7: AI Skills${c.reset}`);
|
|
213
|
+
|
|
214
|
+
const skillNames = ['docguard-guard', 'docguard-fix', 'docguard-review', 'docguard-score'];
|
|
215
|
+
const skillsDest = resolve(projectDir, '.agent/skills');
|
|
216
|
+
let missingSkills = [];
|
|
217
|
+
|
|
218
|
+
for (const skill of skillNames) {
|
|
219
|
+
const skillPath = resolve(skillsDest, skill, 'SKILL.md');
|
|
220
|
+
if (existsSync(skillPath)) {
|
|
221
|
+
console.log(` ${c.green}✅${c.reset} ${skill}`);
|
|
222
|
+
alreadyGood++;
|
|
223
|
+
} else {
|
|
224
|
+
console.log(` ${c.yellow}⚠️${c.reset} ${skill} ${c.dim}(not installed)${c.reset}`);
|
|
225
|
+
missingSkills.push(skill);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (missingSkills.length > 0) {
|
|
230
|
+
const install = interactive
|
|
231
|
+
? await askYesNo(` → Install ${missingSkills.length} AI skill(s) to .agent/skills/?`)
|
|
232
|
+
: true;
|
|
233
|
+
|
|
234
|
+
if (install) {
|
|
235
|
+
for (const skill of missingSkills) {
|
|
236
|
+
const srcSkill = resolve(SKILLS_SOURCE, skill, 'SKILL.md');
|
|
237
|
+
const destDir = resolve(skillsDest, skill);
|
|
238
|
+
if (existsSync(srcSkill)) {
|
|
239
|
+
if (!existsSync(destDir)) mkdirSync(destDir, { recursive: true });
|
|
240
|
+
writeFileSync(resolve(destDir, 'SKILL.md'), readFileSync(srcSkill, 'utf-8'), 'utf-8');
|
|
241
|
+
console.log(` ${c.green}✅ Installed ${skill}${c.reset}`);
|
|
242
|
+
configured++;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
console.log('');
|
|
249
|
+
|
|
250
|
+
// ── Step 4: Slash Commands ─────────────────────────────────────────
|
|
251
|
+
|
|
252
|
+
console.log(` ${c.bold}Step 4/7: Slash Commands${c.reset}`);
|
|
253
|
+
|
|
254
|
+
// Check root commands/ dir
|
|
255
|
+
const rootCommandsDir = resolve(projectDir, 'commands');
|
|
256
|
+
const rootCommandsExist = existsSync(resolve(rootCommandsDir, 'docguard.guard.md'));
|
|
257
|
+
|
|
258
|
+
if (rootCommandsExist) {
|
|
259
|
+
console.log(` ${c.green}✅${c.reset} commands/ ${c.dim}(root)${c.reset}`);
|
|
260
|
+
alreadyGood++;
|
|
261
|
+
} else {
|
|
262
|
+
console.log(` ${c.yellow}⚠️${c.reset} commands/ ${c.dim}(not installed)${c.reset}`);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Detect agent directories and sync commands
|
|
266
|
+
const detectedAgents = detectAgentDirs(projectDir);
|
|
267
|
+
let unsyncedAgents = [];
|
|
268
|
+
|
|
269
|
+
for (const agent of detectedAgents) {
|
|
270
|
+
const agentCommandCheck = resolve(projectDir, agent.commandsPath, 'docguard.guard.md');
|
|
271
|
+
if (existsSync(agentCommandCheck)) {
|
|
272
|
+
console.log(` ${c.green}✅${c.reset} ${agent.commandsPath}/ ${c.dim}(${agent.name})${c.reset}`);
|
|
273
|
+
alreadyGood++;
|
|
274
|
+
} else {
|
|
275
|
+
console.log(` ${c.yellow}⚠️${c.reset} ${agent.commandsPath}/ ${c.dim}(${agent.name} — not synced)${c.reset}`);
|
|
276
|
+
unsyncedAgents.push(agent);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const needsCommands = !rootCommandsExist || unsyncedAgents.length > 0;
|
|
281
|
+
|
|
282
|
+
if (needsCommands && existsSync(COMMANDS_SOURCE)) {
|
|
283
|
+
const install = interactive
|
|
284
|
+
? await askYesNo(` → Install/sync slash commands?`)
|
|
285
|
+
: true;
|
|
286
|
+
|
|
287
|
+
if (install) {
|
|
288
|
+
const commandFiles = readdirSync(COMMANDS_SOURCE).filter(f => f.endsWith('.md'));
|
|
289
|
+
|
|
290
|
+
// Install to root commands/
|
|
291
|
+
if (!rootCommandsExist) {
|
|
292
|
+
if (!existsSync(rootCommandsDir)) mkdirSync(rootCommandsDir, { recursive: true });
|
|
293
|
+
for (const file of commandFiles) {
|
|
294
|
+
const destPath = resolve(rootCommandsDir, file);
|
|
295
|
+
if (!existsSync(destPath)) {
|
|
296
|
+
writeFileSync(destPath, readFileSync(resolve(COMMANDS_SOURCE, file), 'utf-8'), 'utf-8');
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
console.log(` ${c.green}✅ Installed to commands/${c.reset}`);
|
|
300
|
+
configured++;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Sync to agent-specific dirs
|
|
304
|
+
for (const agent of unsyncedAgents) {
|
|
305
|
+
const destDir = resolve(projectDir, agent.commandsPath);
|
|
306
|
+
if (!existsSync(destDir)) mkdirSync(destDir, { recursive: true });
|
|
307
|
+
for (const file of commandFiles) {
|
|
308
|
+
const destPath = resolve(destDir, file);
|
|
309
|
+
if (!existsSync(destPath)) {
|
|
310
|
+
writeFileSync(destPath, readFileSync(resolve(COMMANDS_SOURCE, file), 'utf-8'), 'utf-8');
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
console.log(` ${c.green}✅ Synced to ${agent.commandsPath}/ (${agent.name})${c.reset}`);
|
|
314
|
+
configured++;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
console.log('');
|
|
320
|
+
|
|
321
|
+
// ── Step 5: Agent Configs ──────────────────────────────────────────
|
|
322
|
+
|
|
323
|
+
console.log(` ${c.bold}Step 5/7: Agent Configs${c.reset}`);
|
|
324
|
+
|
|
325
|
+
const agentConfigs = [
|
|
326
|
+
{ file: 'AGENTS.md', label: 'Agent Instructions' },
|
|
327
|
+
{ file: 'CLAUDE.md', label: 'Claude Code' },
|
|
328
|
+
{ file: '.cursor/rules/cdd.mdc', label: 'Cursor' },
|
|
329
|
+
{ file: '.github/copilot-instructions.md', label: 'GitHub Copilot' },
|
|
330
|
+
];
|
|
331
|
+
|
|
332
|
+
let missingConfigs = [];
|
|
333
|
+
for (const cfg of agentConfigs) {
|
|
334
|
+
const fullPath = resolve(projectDir, cfg.file);
|
|
335
|
+
if (existsSync(fullPath)) {
|
|
336
|
+
console.log(` ${c.green}✅${c.reset} ${cfg.file} ${c.dim}(${cfg.label})${c.reset}`);
|
|
337
|
+
alreadyGood++;
|
|
338
|
+
} else {
|
|
339
|
+
// AGENTS.md is handled in step 2, skip it here
|
|
340
|
+
if (cfg.file !== 'AGENTS.md') {
|
|
341
|
+
console.log(` ${c.dim}──${c.reset} ${cfg.file} ${c.dim}(${cfg.label} — not generated)${c.reset}`);
|
|
342
|
+
missingConfigs.push(cfg);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (missingConfigs.length > 0) {
|
|
348
|
+
console.log(` ${c.dim} Run ${c.cyan}docguard agents${c.dim} to generate agent-specific configs${c.reset}`);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
console.log('');
|
|
352
|
+
|
|
353
|
+
// ── Step 6: Integrations ───────────────────────────────────────────
|
|
354
|
+
|
|
355
|
+
console.log(` ${c.bold}Step 6/7: Integrations${c.reset}`);
|
|
356
|
+
|
|
357
|
+
// Check spec-kit framework
|
|
358
|
+
const speckitDir = resolve(projectDir, '.speckit');
|
|
359
|
+
const hasSpeckit = existsSync(speckitDir) || existsSync(resolve(projectDir, 'spec.md'));
|
|
360
|
+
if (hasSpeckit) {
|
|
361
|
+
console.log(` ${c.green}✅${c.reset} spec-kit ${c.dim}(spec-driven development configured)${c.reset}`);
|
|
362
|
+
alreadyGood++;
|
|
363
|
+
} else {
|
|
364
|
+
console.log(` ${c.dim}──${c.reset} spec-kit ${c.dim}(not configured — optional)${c.reset}`);
|
|
365
|
+
console.log(` ${c.dim} Spec Kit enables spec-driven development with AI agents${c.reset}`);
|
|
366
|
+
console.log(` ${c.dim} See: ${c.cyan}https://github.com/github/spec-kit${c.reset}`);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Check for spec-kit extensions
|
|
370
|
+
const extensionsDir = resolve(projectDir, 'extensions');
|
|
371
|
+
|
|
372
|
+
// DocGuard extension (this project IS DocGuard, so check if extension is bundled)
|
|
373
|
+
const docguardExt = resolve(extensionsDir, 'spec-kit-docguard', 'extension.yml');
|
|
374
|
+
if (existsSync(docguardExt)) {
|
|
375
|
+
console.log(` ${c.green}✅${c.reset} docguard extension ${c.dim}(spec-kit CDD enforcement)${c.reset}`);
|
|
376
|
+
alreadyGood++;
|
|
377
|
+
} else {
|
|
378
|
+
// DocGuard is installed as a CLI, not necessarily as a spec-kit extension
|
|
379
|
+
console.log(` ${c.green}✅${c.reset} docguard CLI ${c.dim}(standalone — 19 validators + 31 quality metrics)${c.reset}`);
|
|
380
|
+
alreadyGood++;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Understanding extension (spec-kit community extension)
|
|
384
|
+
const understandingExt = resolve(extensionsDir, 'spec-kit-understanding', 'extension.yml');
|
|
385
|
+
if (existsSync(understandingExt)) {
|
|
386
|
+
console.log(` ${c.green}✅${c.reset} understanding ${c.dim}(spec-kit deep doc analysis)${c.reset}`);
|
|
387
|
+
alreadyGood++;
|
|
388
|
+
} else {
|
|
389
|
+
console.log(` ${c.dim}──${c.reset} understanding ${c.dim}(spec-kit extension — optional)${c.reset}`);
|
|
390
|
+
console.log(` ${c.dim} Install via spec-kit: ${c.cyan}https://github.com/github/spec-kit/tree/main/extensions${c.reset}`);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
console.log('');
|
|
394
|
+
|
|
395
|
+
// ── Step 7: Git Hooks ──────────────────────────────────────────────
|
|
396
|
+
|
|
397
|
+
console.log(` ${c.bold}Step 7/7: Git Hooks${c.reset}`);
|
|
398
|
+
|
|
399
|
+
const gitDir = resolve(projectDir, '.git');
|
|
400
|
+
if (!existsSync(gitDir)) {
|
|
401
|
+
console.log(` ${c.dim}──${c.reset} No .git directory ${c.dim}(not a git repo)${c.reset}`);
|
|
402
|
+
} else {
|
|
403
|
+
const preCommitHook = resolve(gitDir, 'hooks', 'pre-commit');
|
|
404
|
+
let hasDocguardHook = false;
|
|
405
|
+
|
|
406
|
+
if (existsSync(preCommitHook)) {
|
|
407
|
+
const content = readFileSync(preCommitHook, 'utf-8');
|
|
408
|
+
hasDocguardHook = content.includes('docguard');
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (hasDocguardHook) {
|
|
412
|
+
console.log(` ${c.green}✅${c.reset} pre-commit hook ${c.dim}(docguard guard)${c.reset}`);
|
|
413
|
+
alreadyGood++;
|
|
414
|
+
} else {
|
|
415
|
+
console.log(` ${c.dim}──${c.reset} pre-commit hook ${c.dim}(not installed)${c.reset}`);
|
|
416
|
+
if (interactive) {
|
|
417
|
+
const install = await askYesNo(` → Install docguard guard as pre-commit hook?`, false);
|
|
418
|
+
if (install) {
|
|
419
|
+
try {
|
|
420
|
+
const hooksDir = resolve(gitDir, 'hooks');
|
|
421
|
+
if (!existsSync(hooksDir)) mkdirSync(hooksDir, { recursive: true });
|
|
422
|
+
|
|
423
|
+
const hookContent = existsSync(preCommitHook)
|
|
424
|
+
? readFileSync(preCommitHook, 'utf-8') + '\n\n# DocGuard CDD validation\nnpx docguard guard --fail-on-warning\n'
|
|
425
|
+
: '#!/bin/sh\n\n# DocGuard CDD validation\nnpx docguard guard --fail-on-warning\n';
|
|
426
|
+
|
|
427
|
+
writeFileSync(preCommitHook, hookContent, { mode: 0o755 });
|
|
428
|
+
console.log(` ${c.green}✅ Pre-commit hook installed${c.reset}`);
|
|
429
|
+
configured++;
|
|
430
|
+
} catch (e) {
|
|
431
|
+
console.log(` ${c.yellow}⚠️ Failed to install hook: ${e.message}${c.reset}`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// ── Summary ────────────────────────────────────────────────────────
|
|
439
|
+
|
|
440
|
+
console.log(`\n ${c.bold}─────────────────────────────────────${c.reset}`);
|
|
441
|
+
|
|
442
|
+
if (configured > 0) {
|
|
443
|
+
console.log(` ${c.green}✅ Setup complete!${c.reset} ${configured} item(s) configured, ${alreadyGood} already good.`);
|
|
444
|
+
} else if (alreadyGood > 0) {
|
|
445
|
+
console.log(` ${c.green}✅ Everything is set up!${c.reset} ${alreadyGood} item(s) verified.`);
|
|
446
|
+
} else {
|
|
447
|
+
console.log(` ${c.dim}No changes made.${c.reset}`);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
console.log(`\n ${c.bold}Next steps:${c.reset}`);
|
|
451
|
+
console.log(` ${c.dim}Fill docs:${c.reset} ${c.cyan}docguard diagnose${c.reset}`);
|
|
452
|
+
console.log(` ${c.dim}Validate:${c.reset} ${c.cyan}docguard guard${c.reset}`);
|
|
453
|
+
console.log(` ${c.dim}Check score:${c.reset} ${c.cyan}docguard score${c.reset}`);
|
|
454
|
+
console.log('');
|
|
455
|
+
}
|
|
@@ -38,6 +38,8 @@ import { runDiagnose } from './commands/diagnose.mjs';
|
|
|
38
38
|
import { runPublish } from './commands/publish.mjs';
|
|
39
39
|
import { runTrace } from './commands/trace.mjs';
|
|
40
40
|
import { runLlms } from './commands/llms.mjs';
|
|
41
|
+
import { runSetup } from './commands/setup.mjs';
|
|
42
|
+
import { ensureSkills } from './ensure-skills.mjs';
|
|
41
43
|
|
|
42
44
|
// ── Shared constants (imported to break circular dependencies) ──────────
|
|
43
45
|
import { c, PROFILES } from './shared.mjs';
|
|
@@ -218,6 +220,7 @@ function printHelp() {
|
|
|
218
220
|
|
|
219
221
|
${c.bold}Getting Started:${c.reset}
|
|
220
222
|
${c.green}init${c.reset} Initialize CDD docs (interactive setup)
|
|
223
|
+
${c.green}setup${c.reset} Full onboarding wizard (skills, integrations, hooks)
|
|
221
224
|
${c.green}generate${c.reset} Reverse-engineer canonical docs from existing code
|
|
222
225
|
|
|
223
226
|
${c.bold}Enforcement:${c.reset}
|
|
@@ -376,6 +379,11 @@ async function main() {
|
|
|
376
379
|
|
|
377
380
|
const config = loadConfig(projectDir);
|
|
378
381
|
|
|
382
|
+
// Silent auto-check: install skills/commands if missing
|
|
383
|
+
if (command !== 'setup' && command !== 'init') {
|
|
384
|
+
ensureSkills(projectDir, flags);
|
|
385
|
+
}
|
|
386
|
+
|
|
379
387
|
switch (command) {
|
|
380
388
|
case 'audit':
|
|
381
389
|
// audit is an alias for guard — guard does everything the old audit did + 50 more checks
|
|
@@ -384,6 +392,10 @@ async function main() {
|
|
|
384
392
|
case 'init':
|
|
385
393
|
await runInit(projectDir, config, flags);
|
|
386
394
|
break;
|
|
395
|
+
case 'setup':
|
|
396
|
+
case 'onboard':
|
|
397
|
+
await runSetup(projectDir, config, flags);
|
|
398
|
+
break;
|
|
387
399
|
case 'guard':
|
|
388
400
|
runGuard(projectDir, config, flags);
|
|
389
401
|
break;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure Skills — Silent auto-check for DocGuard AI skills and commands
|
|
3
|
+
*
|
|
4
|
+
* Called before every command execution. If skills or commands are missing,
|
|
5
|
+
* copies them from the package's bundled assets into the project directory.
|
|
6
|
+
*
|
|
7
|
+
* Zero dependencies — pure Node.js built-ins only.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, cpSync } from 'node:fs';
|
|
11
|
+
import { resolve, dirname, join } from 'node:path';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import { c } from './shared.mjs';
|
|
14
|
+
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = dirname(__filename);
|
|
17
|
+
|
|
18
|
+
// Source locations in the npm package
|
|
19
|
+
const SKILLS_SOURCE = resolve(__dirname, '..', 'extensions', 'spec-kit-docguard', 'skills');
|
|
20
|
+
const COMMANDS_SOURCE = resolve(__dirname, '..', 'commands');
|
|
21
|
+
|
|
22
|
+
// Destination in the user's project
|
|
23
|
+
const SKILLS_DEST = '.agent/skills';
|
|
24
|
+
const COMMANDS_DEST = 'commands';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Silently ensure skills and commands are installed in the project.
|
|
28
|
+
*
|
|
29
|
+
* @param {string} projectDir - The project root directory
|
|
30
|
+
* @param {object} flags - CLI flags (format, etc.)
|
|
31
|
+
* @returns {{ skillsInstalled: boolean, commandsInstalled: boolean }}
|
|
32
|
+
*/
|
|
33
|
+
export function ensureSkills(projectDir, flags = {}) {
|
|
34
|
+
const result = { skillsInstalled: false, commandsInstalled: false };
|
|
35
|
+
const silent = flags.format === 'json';
|
|
36
|
+
|
|
37
|
+
// ── Skills ────────────────────────────────────────────────────────────
|
|
38
|
+
const skillsCheck = resolve(projectDir, SKILLS_DEST, 'docguard-guard', 'SKILL.md');
|
|
39
|
+
if (!existsSync(skillsCheck) && existsSync(SKILLS_SOURCE)) {
|
|
40
|
+
try {
|
|
41
|
+
const skillDirs = readdirSync(SKILLS_SOURCE).filter(d =>
|
|
42
|
+
existsSync(resolve(SKILLS_SOURCE, d, 'SKILL.md'))
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
for (const skillDir of skillDirs) {
|
|
46
|
+
const destDir = resolve(projectDir, SKILLS_DEST, skillDir);
|
|
47
|
+
if (!existsSync(destDir)) {
|
|
48
|
+
mkdirSync(destDir, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
const srcSkill = resolve(SKILLS_SOURCE, skillDir, 'SKILL.md');
|
|
51
|
+
const destSkill = resolve(destDir, 'SKILL.md');
|
|
52
|
+
if (!existsSync(destSkill)) {
|
|
53
|
+
writeFileSync(destSkill, readFileSync(srcSkill, 'utf-8'), 'utf-8');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
result.skillsInstalled = true;
|
|
58
|
+
if (!silent) {
|
|
59
|
+
console.log(` ${c.cyan}✨ DocGuard AI skills installed → ${SKILLS_DEST}/${c.reset}`);
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
// Silent failure — skills are optional enhancement
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ── Slash Commands ────────────────────────────────────────────────────
|
|
67
|
+
const commandsCheck = resolve(projectDir, COMMANDS_DEST, 'docguard.guard.md');
|
|
68
|
+
if (!existsSync(commandsCheck) && existsSync(COMMANDS_SOURCE)) {
|
|
69
|
+
try {
|
|
70
|
+
const commandFiles = readdirSync(COMMANDS_SOURCE).filter(f => f.endsWith('.md'));
|
|
71
|
+
|
|
72
|
+
if (commandFiles.length > 0) {
|
|
73
|
+
const destDir = resolve(projectDir, COMMANDS_DEST);
|
|
74
|
+
if (!existsSync(destDir)) {
|
|
75
|
+
mkdirSync(destDir, { recursive: true });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
for (const file of commandFiles) {
|
|
79
|
+
const destPath = resolve(destDir, file);
|
|
80
|
+
if (!existsSync(destPath)) {
|
|
81
|
+
writeFileSync(destPath, readFileSync(resolve(COMMANDS_SOURCE, file), 'utf-8'), 'utf-8');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
result.commandsInstalled = true;
|
|
86
|
+
if (!silent) {
|
|
87
|
+
console.log(` ${c.cyan}✨ DocGuard slash commands installed → ${COMMANDS_DEST}/${c.reset}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
// Silent failure — commands are optional enhancement
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return result;
|
|
96
|
+
}
|