wize-dev-kit 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +37 -0
- package/ARCH.md +77 -24
- package/CHANGELOG.md +14 -0
- package/DECISIONS.md +27 -1
- package/README.es.md +296 -0
- package/README.md +3 -2
- package/README.pt-BR.md +294 -0
- package/ROSTER.md +11 -3
- package/adapters/README.md +9 -7
- package/adapters/antigravity/README.md +5 -5
- package/adapters/claude-code/README.md +1 -1
- package/adapters/codex/README.md +5 -5
- package/adapters/codex/adapter.yaml +1 -1
- package/adapters/codex/render.js +1 -1
- package/adapters/continue/README.md +5 -5
- package/adapters/cursor/README.md +2 -2
- package/adapters/generic/README.md +1 -1
- package/adapters/hermes/README.md +23 -0
- package/adapters/hermes/adapter.yaml +8 -0
- package/adapters/hermes/render.js +17 -0
- package/adapters/kimi-code/README.md +5 -5
- package/adapters/kimi-code/render.js +2 -2
- package/adapters/kiro/README.md +30 -0
- package/adapters/kiro/adapter.yaml +8 -0
- package/adapters/kiro/render.js +21 -0
- package/adapters/opencode/README.md +3 -3
- package/adapters/opencode/render.js +27 -1
- package/adapters/windsurf/README.md +3 -3
- package/docs/harnesses/antigravity.md +20 -0
- package/docs/harnesses/antigravity.pt-BR.md +20 -0
- package/docs/harnesses/claude-code.md +23 -0
- package/docs/harnesses/claude-code.pt-BR.md +23 -0
- package/docs/harnesses/codex.md +21 -0
- package/docs/harnesses/codex.pt-BR.md +21 -0
- package/docs/harnesses/continue.md +21 -0
- package/docs/harnesses/continue.pt-BR.md +21 -0
- package/docs/harnesses/cursor.md +22 -0
- package/docs/harnesses/cursor.pt-BR.md +22 -0
- package/docs/harnesses/generic.md +20 -0
- package/docs/harnesses/generic.pt-BR.md +20 -0
- package/docs/harnesses/hermes.md +26 -0
- package/docs/harnesses/hermes.pt-BR.md +26 -0
- package/docs/harnesses/kimi-code.md +19 -0
- package/docs/harnesses/kimi-code.pt-BR.md +19 -0
- package/docs/harnesses/kiro.md +26 -0
- package/docs/harnesses/kiro.pt-BR.md +26 -0
- package/docs/harnesses/opencode.md +31 -0
- package/docs/harnesses/opencode.pt-BR.md +31 -0
- package/docs/harnesses/windsurf.md +22 -0
- package/docs/harnesses/windsurf.pt-BR.md +22 -0
- package/package.json +1 -1
- package/schemas/agent.schema.json +2 -2
- package/schemas/workflow.schema.json +1 -1
- package/src/app-overlay/wize-app-release-channels/workflow.md +2 -0
- package/src/app-overlay/wize-app-scaffold/workflow.md +2 -0
- package/src/app-overlay/wize-app-store-listing/workflow.md +2 -0
- package/src/builder-skills/wize-create-agent/workflow.md +2 -0
- package/src/builder-skills/wize-create-skill/workflow.md +2 -0
- package/src/builder-skills/wize-create-workflow/workflow.md +2 -0
- package/src/core-skills/wize-advanced-elicitation/skill.md +2 -0
- package/src/core-skills/wize-brainstorming/skill.md +2 -0
- package/src/core-skills/wize-customize/skill.md +116 -0
- package/src/core-skills/wize-editorial-review-prose/skill.md +94 -0
- package/src/core-skills/wize-editorial-review-structure/skill.md +99 -0
- package/src/core-skills/wize-grill/skill.md +77 -0
- package/src/core-skills/wize-index-docs/skill.md +119 -0
- package/src/core-skills/wize-pre-pr-check/skill.md +134 -0
- package/src/core-skills/wize-review-adversarial/skill.md +3 -0
- package/src/core-skills/wize-review-edge-case-hunter/skill.md +115 -0
- package/src/core-skills/wize-shard-doc/skill.md +2 -0
- package/src/core-skills/wize-spec/assets/headless-schemas.md +39 -0
- package/src/core-skills/wize-spec/assets/spec-template.md +40 -0
- package/src/core-skills/wize-spec/customize.toml +20 -0
- package/src/core-skills/wize-spec/skill.md +112 -0
- package/src/method-skills/1-analysis/wize-agent-analyst/agent.yaml +3 -0
- package/src/method-skills/1-analysis/wize-document-project/documentation-requirements.csv +12 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/api-contracts-template.md +38 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/architecture-template.md +54 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/component-inventory-template.md +40 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/contribution-guide-template.md +34 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/data-models-template.md +36 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/deep-dive-template.md +312 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/deployment-guide-template.md +42 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/development-guide-template.md +61 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/index-template.md +185 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/project-overview-template.md +110 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/project-scan-report-schema.json +159 -0
- package/src/method-skills/1-analysis/wize-document-project/templates/source-tree-template.md +142 -0
- package/src/method-skills/1-analysis/wize-document-project/workflow.md +213 -20
- package/src/method-skills/1-analysis/wize-domain-research/customize.toml +14 -0
- package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-01-init.md +49 -0
- package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-02-domain-analysis.md +39 -0
- package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-03-competitive-landscape.md +39 -0
- package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-04-regulatory-focus.md +39 -0
- package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-05-technical-trends.md +39 -0
- package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-06-research-synthesis.md +43 -0
- package/src/method-skills/1-analysis/wize-domain-research/research.template.md +31 -0
- package/src/method-skills/1-analysis/wize-domain-research/workflow.md +58 -0
- package/src/method-skills/1-analysis/wize-market-research/customize.toml +14 -0
- package/src/method-skills/1-analysis/wize-market-research/research.template.md +31 -0
- package/src/method-skills/1-analysis/wize-market-research/steps/step-01-init.md +57 -0
- package/src/method-skills/1-analysis/wize-market-research/steps/step-02-customer-behavior.md +39 -0
- package/src/method-skills/1-analysis/wize-market-research/steps/step-03-customer-pain-points.md +37 -0
- package/src/method-skills/1-analysis/wize-market-research/steps/step-04-customer-decisions.md +39 -0
- package/src/method-skills/1-analysis/wize-market-research/steps/step-05-competitive-analysis.md +37 -0
- package/src/method-skills/1-analysis/wize-market-research/steps/step-06-research-completion.md +47 -0
- package/src/method-skills/1-analysis/wize-market-research/workflow.md +66 -0
- package/src/method-skills/1-analysis/wize-prfaq/workflow.md +152 -11
- package/src/method-skills/1-analysis/wize-product-brief/workflow.md +92 -19
- package/src/method-skills/1-analysis/wize-refresh-knowledge/workflow.md +129 -0
- package/src/method-skills/1-analysis/wize-research/workflow.md +39 -12
- package/src/method-skills/1-analysis/wize-technical-research/customize.toml +14 -0
- package/src/method-skills/1-analysis/wize-technical-research/research.template.md +31 -0
- package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-01-init.md +49 -0
- package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-02-technical-overview.md +45 -0
- package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-03-integration-patterns.md +39 -0
- package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-04-architectural-patterns.md +39 -0
- package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-05-implementation-research.md +42 -0
- package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-06-research-synthesis.md +46 -0
- package/src/method-skills/1-analysis/wize-technical-research/workflow.md +60 -0
- package/src/method-skills/1-analysis/wize-trigger-map/workflow.md +82 -16
- package/src/method-skills/2-plan-workflows/wize-create-prd/workflow.md +135 -23
- package/src/method-skills/2-plan-workflows/wize-edit-prd/workflow.md +110 -0
- package/src/method-skills/2-plan-workflows/wize-ux-design/workflow.md +134 -28
- package/src/method-skills/2-plan-workflows/wize-ux-scenarios/workflow.md +93 -15
- package/src/method-skills/2-plan-workflows/wize-validate-prd/workflow.md +108 -12
- package/src/method-skills/3-solutioning/wize-check-implementation-readiness/workflow.md +103 -11
- package/src/method-skills/3-solutioning/wize-create-architecture/architecture-decision-template.md +41 -0
- package/src/method-skills/3-solutioning/wize-create-architecture/customize.toml +20 -0
- package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-01-init.md +95 -0
- package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-01b-continue.md +32 -0
- package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-02-context.md +126 -0
- package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-03-starter.md +110 -0
- package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-04-decisions.md +129 -0
- package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-05-patterns.md +109 -0
- package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-06-structure.md +97 -0
- package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-07-validation.md +124 -0
- package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-08-complete.md +59 -0
- package/src/method-skills/3-solutioning/wize-create-architecture/workflow.md +55 -48
- package/src/method-skills/3-solutioning/wize-create-epics-and-stories/workflow.md +154 -15
- package/src/method-skills/3-solutioning/wize-design-system/workflow.md +184 -22
- package/src/method-skills/3-solutioning/wize-nfr-principles/workflow.md +145 -17
- package/src/method-skills/3-solutioning/wize-project-context/workflow.md +120 -0
- package/src/method-skills/3-solutioning/wize-tech-vision/workflow.md +130 -22
- package/src/method-skills/4-implementation/wize-agent-dev/persona.md +12 -0
- package/src/method-skills/4-implementation/wize-changelog/workflow.md +184 -0
- package/src/method-skills/4-implementation/wize-checkpoint-preview/workflow.md +117 -0
- package/src/method-skills/4-implementation/wize-code-review/customize.toml +21 -0
- package/src/method-skills/4-implementation/wize-code-review/steps/step-01-gather-context.md +64 -0
- package/src/method-skills/4-implementation/wize-code-review/steps/step-02-review.md +40 -0
- package/src/method-skills/4-implementation/wize-code-review/steps/step-03-triage.md +43 -0
- package/src/method-skills/4-implementation/wize-code-review/steps/step-04-present.md +100 -0
- package/src/method-skills/4-implementation/wize-code-review/workflow.md +54 -12
- package/src/method-skills/4-implementation/wize-correct-course/workflow.md +93 -0
- package/src/method-skills/4-implementation/wize-create-story/workflow.md +154 -10
- package/src/method-skills/4-implementation/wize-dev-story/workflow.md +185 -17
- package/src/method-skills/4-implementation/wize-investigate/workflow.md +123 -0
- package/src/method-skills/4-implementation/wize-quick-dev/workflow.md +136 -18
- package/src/method-skills/4-implementation/wize-release/workflow.md +162 -0
- package/src/method-skills/4-implementation/wize-retrospective/workflow.md +114 -10
- package/src/method-skills/4-implementation/wize-sprint-planning/workflow.md +78 -11
- package/src/method-skills/4-implementation/wize-sprint-status/workflow.md +45 -11
- package/src/method-skills/module.yaml +28 -0
- package/src/orchestrator-skills/module.yaml +7 -1
- package/src/orchestrator-skills/wize/skill.md +164 -0
- package/src/orchestrator-skills/wize-check/skill.md +98 -0
- package/src/orchestrator-skills/wize-help/skill.md +227 -67
- package/src/orchestrator-skills/wize-onboarding/workflow.md +78 -14
- package/src/orchestrator-skills/wize-orchestrator/agent.yaml +2 -0
- package/src/orchestrator-skills/wize-orchestrator/persona.md +44 -3
- package/src/orchestrator-skills/wize-party-mode/workflow.md +2 -0
- package/src/security-overlay/_shared/allowlist.js +154 -0
- package/src/security-overlay/_shared/backlog.js +169 -0
- package/src/security-overlay/_shared/cli-runner.js +87 -0
- package/src/security-overlay/_shared/cvss.js +108 -0
- package/src/security-overlay/_shared/detect.js +125 -0
- package/src/security-overlay/_shared/install-script.js +205 -0
- package/src/security-overlay/_shared/invoke-phase.js +86 -0
- package/src/security-overlay/_shared/owasp.js +56 -0
- package/src/security-overlay/_shared/partial.js +225 -0
- package/src/security-overlay/_shared/preflight.js +175 -0
- package/src/security-overlay/_shared/scope-gate.js +172 -0
- package/src/security-overlay/_shared/scope-parser.js +147 -0
- package/src/security-overlay/agents/red-teamer/agent.yaml +54 -0
- package/src/security-overlay/agents/red-teamer/persona.md +49 -0
- package/src/security-overlay/data/common.txt +115 -0
- package/src/security-overlay/data/owasp-top10.json +15 -0
- package/src/security-overlay/data/tool-allowlist.json +31 -0
- package/src/security-overlay/skills/wize-sec-enumerate/scripts/run-enumerate.js +180 -0
- package/src/security-overlay/skills/wize-sec-enumerate/skill.md +34 -0
- package/src/security-overlay/skills/wize-sec-exploit/data/common.txt +117 -0
- package/src/security-overlay/skills/wize-sec-exploit/scripts/run-ffuf.js +147 -0
- package/src/security-overlay/skills/wize-sec-exploit/scripts/run-nikto.js +145 -0
- package/src/security-overlay/skills/wize-sec-exploit/scripts/run-nuclei.js +176 -0
- package/src/security-overlay/skills/wize-sec-exploit/scripts/run-sqlmap.js +139 -0
- package/src/security-overlay/skills/wize-sec-pentest/scripts/run-pipeline.js +184 -0
- package/src/security-overlay/skills/wize-sec-pentest/skill.md +54 -0
- package/src/security-overlay/skills/wize-sec-recon/scripts/run-gitleaks.js +139 -0
- package/src/security-overlay/skills/wize-sec-recon/scripts/run-osv.js +227 -0
- package/src/security-overlay/skills/wize-sec-recon/scripts/run-recon.js +162 -0
- package/src/security-overlay/skills/wize-sec-recon/skill.md +37 -0
- package/src/security-overlay/skills/wize-sec-report/scripts/render-report.js +1033 -0
- package/src/security-overlay/skills/wize-sec-scope/scripts/generate-scope.js +106 -0
- package/src/security-overlay/skills/wize-sec-scope/skill.md +52 -0
- package/src/tea-skills/wize-qa-generate-e2e-tests/workflow.md +121 -0
- package/src/tea-skills/wize-tea-design/workflow.md +107 -13
- package/src/tea-skills/wize-tea-gate/workflow.md +118 -25
- package/src/tea-skills/wize-tea-nfr/workflow.md +107 -14
- package/src/tea-skills/wize-tea-review/workflow.md +123 -13
- package/src/tea-skills/wize-tea-risk/workflow.md +113 -10
- package/src/tea-skills/wize-tea-trace/workflow.md +86 -12
- package/src/web-overlay/wize-web-deploy/workflow.md +2 -0
- package/src/web-overlay/wize-web-scaffold/workflow.md +2 -0
- package/src/web-overlay/wize-web-seo-audit/workflow.md +2 -0
- package/tools/check-eli5-all-adapters.js +3 -2
- package/tools/installer/baseline.js +138 -0
- package/tools/installer/commands/agent.js +197 -0
- package/tools/installer/commands/doctor.js +321 -0
- package/tools/installer/commands/document-project.js +93 -0
- package/tools/installer/commands/sync.js +45 -0
- package/tools/installer/commands/update.js +172 -0
- package/tools/installer/document-project/batch-scanner.js +93 -0
- package/tools/installer/document-project/classify.js +170 -0
- package/tools/installer/document-project/modes/deep-dive.js +196 -0
- package/tools/installer/document-project/modes/full-rescan.js +15 -0
- package/tools/installer/document-project/modes/initial-scan.js +100 -0
- package/tools/installer/document-project/modes/quick.js +211 -0
- package/tools/installer/document-project/render-index.js +101 -0
- package/tools/installer/document-project/state.js +110 -0
- package/tools/installer/onboarding.js +14 -20
- package/tools/installer/render-shared.js +159 -15
- package/tools/installer/setup-helpers.js +2 -0
- package/tools/installer/validators/run-all.js +3 -2
- package/tools/installer/version-check.js +117 -0
- package/tools/installer/wize-cli.js +501 -70
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// State file management for `wize-dev-kit document-project`.
|
|
2
|
+
//
|
|
3
|
+
// Tracks scan progress so long-running deep/exhaustive scans can resume.
|
|
4
|
+
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const fs = require('node:fs');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
|
|
10
|
+
const WORKFLOW_VERSION = '0.3.1';
|
|
11
|
+
const STATE_FILE = 'project-scan-report.json';
|
|
12
|
+
const ARCHIVE_DIR = '_archive';
|
|
13
|
+
|
|
14
|
+
function nowIso() {
|
|
15
|
+
return new Date().toISOString();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function statePath(projectRoot) {
|
|
19
|
+
return path.join(projectRoot, '.wize', 'knowledge', 'document-project', STATE_FILE);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function archivePath(projectRoot, timestamp) {
|
|
23
|
+
const dir = path.join(projectRoot, '.wize', 'knowledge', 'document-project', ARCHIVE_DIR);
|
|
24
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
25
|
+
const safe = timestamp.replace(/[:.]/g, '-');
|
|
26
|
+
return path.join(dir, `project-scan-report-${safe}.json`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function initState(projectRoot, mode, scanLevel) {
|
|
30
|
+
const state = {
|
|
31
|
+
workflow_version: WORKFLOW_VERSION,
|
|
32
|
+
timestamps: { started: nowIso(), last_updated: nowIso() },
|
|
33
|
+
mode,
|
|
34
|
+
scan_level: scanLevel,
|
|
35
|
+
project_root: projectRoot,
|
|
36
|
+
project_knowledge: path.join(projectRoot, '.wize', 'knowledge', 'document-project'),
|
|
37
|
+
completed_steps: [],
|
|
38
|
+
current_step: 'step_1',
|
|
39
|
+
findings: {},
|
|
40
|
+
outputs_generated: [STATE_FILE],
|
|
41
|
+
resume_instructions: `Starting ${mode} (${scanLevel}) from step_1`
|
|
42
|
+
};
|
|
43
|
+
writeState(projectRoot, state);
|
|
44
|
+
return state;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function loadState(projectRoot) {
|
|
48
|
+
const p = statePath(projectRoot);
|
|
49
|
+
if (!fs.existsSync(p)) return null;
|
|
50
|
+
try {
|
|
51
|
+
const content = fs.readFileSync(p, 'utf-8');
|
|
52
|
+
const state = JSON.parse(content);
|
|
53
|
+
if (!state.workflow_version || !state.timestamps || !state.mode || !state.scan_level) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
return state;
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function writeState(projectRoot, state) {
|
|
63
|
+
const p = statePath(projectRoot);
|
|
64
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
65
|
+
state.timestamps.last_updated = nowIso();
|
|
66
|
+
fs.writeFileSync(p, JSON.stringify(state, null, 2), 'utf-8');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function updateState(projectRoot, patch) {
|
|
70
|
+
const state = loadState(projectRoot) || initState(projectRoot, 'quick', 'quick');
|
|
71
|
+
for (const key of Object.keys(patch)) {
|
|
72
|
+
const val = patch[key];
|
|
73
|
+
if (Array.isArray(val) && Array.isArray(state[key])) {
|
|
74
|
+
state[key].push(...val);
|
|
75
|
+
} else if (typeof val === 'object' && val !== null && !Array.isArray(val)) {
|
|
76
|
+
state[key] = { ...(state[key] || {}), ...val };
|
|
77
|
+
} else {
|
|
78
|
+
state[key] = val;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
writeState(projectRoot, state);
|
|
82
|
+
return state;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function archiveOldState(projectRoot) {
|
|
86
|
+
const p = statePath(projectRoot);
|
|
87
|
+
if (!fs.existsSync(p)) return false;
|
|
88
|
+
const content = fs.readFileSync(p, 'utf-8');
|
|
89
|
+
const archived = archivePath(projectRoot, nowIso());
|
|
90
|
+
fs.writeFileSync(archived, content, 'utf-8');
|
|
91
|
+
fs.rmSync(p);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function stateAgeDays(state) {
|
|
96
|
+
if (!state || !state.timestamps || !state.timestamps.last_updated) return null;
|
|
97
|
+
const then = Date.parse(state.timestamps.last_updated);
|
|
98
|
+
if (Number.isNaN(then)) return null;
|
|
99
|
+
return Math.floor((Date.now() - then) / (24 * 3600 * 1000));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = {
|
|
103
|
+
statePath,
|
|
104
|
+
initState,
|
|
105
|
+
loadState,
|
|
106
|
+
updateState,
|
|
107
|
+
archiveOldState,
|
|
108
|
+
stateAgeDays,
|
|
109
|
+
WORKFLOW_VERSION
|
|
110
|
+
};
|
|
@@ -1,31 +1,25 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Onboarding handoff — Wizer-driven triage after install.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Returns a clean, minimal message (≤3 lines) that always ends with "→ /wize".
|
|
5
|
+
* The message adapts to brownfield detection and active profiles without
|
|
6
|
+
* turning into a wall of text.
|
|
6
7
|
*/
|
|
7
8
|
'use strict';
|
|
8
9
|
|
|
9
10
|
function compose(detection, profiles) {
|
|
10
|
-
const lines = [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
lines.push('
|
|
19
|
-
lines.push(' → /wize-document-project');
|
|
11
|
+
const lines = [];
|
|
12
|
+
const profileCodes = new Set(profiles.map(p => p.code));
|
|
13
|
+
|
|
14
|
+
if (detection && detection.brownfield) {
|
|
15
|
+
lines.push('Brownfield detected — baseline ready.');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (profileCodes.has('security-overlay')) {
|
|
19
|
+
lines.push('Security pentest available (/wize-sec-recon).');
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
lines.push('
|
|
23
|
-
lines.push(' → /wize-product-brief (Pepper)');
|
|
24
|
-
lines.push(' → /wize-create-prd (Maria Hill, if brief exists)');
|
|
25
|
-
lines.push(' → /wize-create-architecture (Tony, if PRD exists)');
|
|
26
|
-
lines.push(' → /wize-quick-dev (Shuri, for small fixes)');
|
|
27
|
-
if (profiles.find(p => p.code === 'web-overlay')) lines.push(' → /wize-web-scaffold (overlay)');
|
|
28
|
-
if (profiles.find(p => p.code === 'app-overlay')) lines.push(' → /wize-app-scaffold (overlay)');
|
|
21
|
+
|
|
22
|
+
lines.push('→ /wize');
|
|
29
23
|
return lines.join('\n');
|
|
30
24
|
}
|
|
31
25
|
|
|
@@ -12,11 +12,51 @@ const fs = require('node:fs');
|
|
|
12
12
|
const path = require('node:path');
|
|
13
13
|
const { walkAgents, walkWorkflows, walkSkills } = require('./validators/walk.js');
|
|
14
14
|
|
|
15
|
+
// Shared block-scalar reader used by both readYamlField (agent.yaml) and
|
|
16
|
+
// readFrontmatter (skill.md / workflow.md). Returns { value, nextIndex }.
|
|
17
|
+
function readBlockScalar(lines, startIndex, folded) {
|
|
18
|
+
const collected = [];
|
|
19
|
+
let baseIndent = null;
|
|
20
|
+
let i = startIndex;
|
|
21
|
+
for (; i < lines.length; i++) {
|
|
22
|
+
const line = lines[i];
|
|
23
|
+
if (line.trim() === '') { collected.push(''); continue; }
|
|
24
|
+
const indent = line.match(/^(\s*)/)[1].length;
|
|
25
|
+
if (indent === 0) break; // dedent to a sibling top-level key ends the block
|
|
26
|
+
if (baseIndent === null) baseIndent = indent;
|
|
27
|
+
collected.push(line.slice(baseIndent));
|
|
28
|
+
}
|
|
29
|
+
while (collected.length && collected[collected.length - 1] === '') collected.pop();
|
|
30
|
+
if (folded) {
|
|
31
|
+
const value = collected.reduce((acc, ln, idx) => {
|
|
32
|
+
if (idx === 0) return ln;
|
|
33
|
+
if (ln === '' || collected[idx - 1] === '') return acc + '\n' + ln;
|
|
34
|
+
return acc + ' ' + ln;
|
|
35
|
+
}, '').trim();
|
|
36
|
+
return { value, nextIndex: i };
|
|
37
|
+
}
|
|
38
|
+
return { value: collected.join('\n').trim(), nextIndex: i };
|
|
39
|
+
}
|
|
40
|
+
|
|
15
41
|
function readYamlField(content, field) {
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
42
|
+
const lines = content.split('\n');
|
|
43
|
+
const keyRe = new RegExp('^' + field + ':\\s*(.*)$');
|
|
44
|
+
for (let i = 0; i < lines.length; i++) {
|
|
45
|
+
const m = lines[i].match(keyRe);
|
|
46
|
+
if (!m) continue;
|
|
47
|
+
const inline = m[1].trim();
|
|
48
|
+
|
|
49
|
+
// Block scalar (| literal, > folded) with optional chomp/indent indicator.
|
|
50
|
+
const block = inline.match(/^([|>])[+-]?\d*\s*$/);
|
|
51
|
+
if (block) {
|
|
52
|
+
return readBlockScalar(lines, i + 1, block[1] === '>').value;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Inline scalar: quoted or plain.
|
|
56
|
+
const q = inline.match(/^"([^"]*)"$/) || inline.match(/^'([^']*)'$/);
|
|
57
|
+
return (q ? q[1] : inline).trim();
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
20
60
|
}
|
|
21
61
|
|
|
22
62
|
function readFrontmatter(content) {
|
|
@@ -25,9 +65,25 @@ function readFrontmatter(content) {
|
|
|
25
65
|
if (end === -1) return {};
|
|
26
66
|
const lines = content.slice(3, end).split('\n');
|
|
27
67
|
const out = {};
|
|
28
|
-
for (
|
|
68
|
+
for (let i = 0; i < lines.length; i++) {
|
|
69
|
+
const line = lines[i];
|
|
29
70
|
const m = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\s*(.*?)\s*$/);
|
|
30
|
-
if (m)
|
|
71
|
+
if (!m) continue;
|
|
72
|
+
const key = m[1];
|
|
73
|
+
const inline = m[2].trim();
|
|
74
|
+
|
|
75
|
+
// Block scalar (| literal, > folded) with optional chomp/indent indicator.
|
|
76
|
+
const block = inline.match(/^([|>])[+-]?\d*\s*$/);
|
|
77
|
+
if (block) {
|
|
78
|
+
const result = readBlockScalar(lines, i + 1, block[1] === '>');
|
|
79
|
+
out[key] = result.value;
|
|
80
|
+
i = result.nextIndex - 1; // -1 because the for loop will increment
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Inline scalar: quoted or plain.
|
|
85
|
+
const q = inline.match(/^"([^"]*)"$/) || inline.match(/^'([^']*)'$/);
|
|
86
|
+
out[key] = (q ? q[1] : inline).trim();
|
|
31
87
|
}
|
|
32
88
|
return out;
|
|
33
89
|
}
|
|
@@ -53,6 +109,42 @@ function ensureDir(dir) {
|
|
|
53
109
|
fs.mkdirSync(dir, { recursive: true });
|
|
54
110
|
}
|
|
55
111
|
|
|
112
|
+
// Companion files (steps/, templates/, data/, *.csv, *-template.md,
|
|
113
|
+
// customize.toml, research.template.md, etc.) that micro-file workflows
|
|
114
|
+
// reference from their body. We must copy these alongside the SKILL.md so
|
|
115
|
+
// the IDE can resolve paths like "./steps/step-01-init.md" at runtime.
|
|
116
|
+
const SKIP_NAMES = new Set(['.DS_Store', 'Thumbs.db', 'node_modules', '.git']);
|
|
117
|
+
const SKIP_FILES = new Set([
|
|
118
|
+
'skill.md', 'workflow.md', 'agent.yaml', 'persona.md',
|
|
119
|
+
'package.json', 'package-lock.json'
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
function isCompanion(entry) {
|
|
123
|
+
if (entry.name.startsWith('.')) return false;
|
|
124
|
+
if (SKIP_NAMES.has(entry.name)) return false;
|
|
125
|
+
if (SKIP_FILES.has(entry.name)) return false;
|
|
126
|
+
if (entry.name.endsWith('.test.js')) return false;
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function copyCompanionFiles(srcDir, destDir, written, relPrefix = '') {
|
|
131
|
+
if (!srcDir || !fs.existsSync(srcDir)) return;
|
|
132
|
+
for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
|
|
133
|
+
if (!isCompanion(entry)) continue;
|
|
134
|
+
const s = path.join(srcDir, entry.name);
|
|
135
|
+
const d = path.join(destDir, entry.name);
|
|
136
|
+
const rel = relPrefix ? `${relPrefix}/${entry.name}` : entry.name;
|
|
137
|
+
if (entry.isDirectory()) {
|
|
138
|
+
ensureDir(d);
|
|
139
|
+
copyCompanionFiles(s, d, written, rel);
|
|
140
|
+
} else if (entry.isFile()) {
|
|
141
|
+
ensureDir(path.dirname(d));
|
|
142
|
+
fs.copyFileSync(s, d);
|
|
143
|
+
written.push(rel);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
56
148
|
// Walks the kit and returns a flat array of "assets" the adapters can render.
|
|
57
149
|
// Each asset has: { kind: 'agent'|'workflow'|'skill', code, name, title, description, body, overlay }
|
|
58
150
|
function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
|
|
@@ -69,7 +161,7 @@ function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
|
|
|
69
161
|
if (!code || !name) continue;
|
|
70
162
|
const personaPath = path.join(dir, 'persona.md');
|
|
71
163
|
const persona = fs.existsSync(personaPath) ? fs.readFileSync(personaPath, 'utf-8') : '';
|
|
72
|
-
out.push({ kind: 'agent', code, name, title, description, body: persona || description, overlay: null });
|
|
164
|
+
out.push({ kind: 'agent', code, name, title, description, body: persona || description, overlay: null, srcDir: dir });
|
|
73
165
|
}
|
|
74
166
|
|
|
75
167
|
for (const wfPath of walkWorkflows(kitRoot)) {
|
|
@@ -78,14 +170,18 @@ function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
|
|
|
78
170
|
if (!fm.code) continue;
|
|
79
171
|
if (fm.overlay === 'web' && !profSet.has('web-overlay')) continue;
|
|
80
172
|
if (fm.overlay === 'app' && !profSet.has('app-overlay')) continue;
|
|
173
|
+
if (fm.overlay === 'security' && !profSet.has('security-overlay')) continue;
|
|
81
174
|
out.push({
|
|
82
175
|
kind: 'workflow',
|
|
83
176
|
code: fm.code,
|
|
84
177
|
name: fm.name || fm.code,
|
|
85
178
|
title: fm.phase || fm.gate || '',
|
|
86
|
-
description: `${fm.phase || fm.gate || 'workflow'}: ${fm.name || fm.code}`,
|
|
179
|
+
description: fm.description || `${fm.phase || fm.gate || 'workflow'}: ${fm.name || fm.code}`,
|
|
87
180
|
body: bodyAfterFrontmatter(content),
|
|
88
|
-
overlay: fm.overlay || null
|
|
181
|
+
overlay: fm.overlay || null,
|
|
182
|
+
owner: fm.owner || null,
|
|
183
|
+
subtask: fm.subtask === 'true',
|
|
184
|
+
srcDir: path.dirname(wfPath)
|
|
89
185
|
});
|
|
90
186
|
}
|
|
91
187
|
|
|
@@ -93,14 +189,20 @@ function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
|
|
|
93
189
|
const content = fs.readFileSync(skPath, 'utf-8');
|
|
94
190
|
const fm = readFrontmatter(content);
|
|
95
191
|
if (!fm.code) continue;
|
|
192
|
+
if (fm.overlay === 'web' && !profSet.has('web-overlay')) continue;
|
|
193
|
+
if (fm.overlay === 'app' && !profSet.has('app-overlay')) continue;
|
|
194
|
+
if (fm.overlay === 'security' && !profSet.has('security-overlay')) continue;
|
|
96
195
|
out.push({
|
|
97
196
|
kind: 'skill',
|
|
98
197
|
code: fm.code,
|
|
99
198
|
name: fm.name || fm.code,
|
|
100
199
|
title: fm.module || '',
|
|
101
|
-
description: fm.module ? `${fm.module} skill: ${fm.name || fm.code}` : (fm.name || fm.code),
|
|
200
|
+
description: fm.description || (fm.module ? `${fm.module} skill: ${fm.name || fm.code}` : (fm.name || fm.code)),
|
|
102
201
|
body: bodyAfterFrontmatter(content),
|
|
103
|
-
overlay: null
|
|
202
|
+
overlay: fm.overlay || null,
|
|
203
|
+
owner: fm.owner || null,
|
|
204
|
+
subtask: fm.subtask === 'true',
|
|
205
|
+
srcDir: path.dirname(skPath)
|
|
104
206
|
});
|
|
105
207
|
}
|
|
106
208
|
|
|
@@ -140,6 +242,10 @@ function renderAnthropicSkills(kitRoot, targetDir, opts = {}) {
|
|
|
140
242
|
ensureDir(skillDir);
|
|
141
243
|
fs.writeFileSync(path.join(skillDir, 'SKILL.md'), content, 'utf-8');
|
|
142
244
|
written.push(`${a.code}/SKILL.md`);
|
|
245
|
+
// Copy companion files (steps/, templates/, data/, *.csv, customize.toml,
|
|
246
|
+
// *-template.md, research.template.md, etc.) so micro-file workflows can
|
|
247
|
+
// resolve relative paths from inside the SKILL body.
|
|
248
|
+
copyCompanionFiles(a.srcDir, skillDir, written, a.code);
|
|
143
249
|
}
|
|
144
250
|
}
|
|
145
251
|
return { written, skipped: [] };
|
|
@@ -147,9 +253,30 @@ function renderAnthropicSkills(kitRoot, targetDir, opts = {}) {
|
|
|
147
253
|
|
|
148
254
|
// Convenience emitter for a root-level AGENTS.md — read by Codex, Cursor,
|
|
149
255
|
// Windsurf and Antigravity as a baseline pointer to the kit's deeper docs.
|
|
256
|
+
// Canonical roster order so AGENTS.md is deterministic regardless of the
|
|
257
|
+
// filesystem walk order. Codes not listed sort last, alphabetically.
|
|
258
|
+
const AGENT_ORDER = [
|
|
259
|
+
'wize-orchestrator',
|
|
260
|
+
'wize-agent-analyst',
|
|
261
|
+
'wize-agent-tech-writer',
|
|
262
|
+
'wize-agent-pm',
|
|
263
|
+
'wize-agent-ux-designer',
|
|
264
|
+
'wize-agent-solution-strategist',
|
|
265
|
+
'wize-agent-architect',
|
|
266
|
+
'wize-agent-test-architect',
|
|
267
|
+
'wize-agent-dev',
|
|
268
|
+
'wize-sec-red-teamer'
|
|
269
|
+
];
|
|
270
|
+
|
|
150
271
|
function renderAgentsMd(kitRoot, projectRoot, opts = {}) {
|
|
151
272
|
const assets = collectAssets(kitRoot, opts);
|
|
152
|
-
const
|
|
273
|
+
const rank = (code) => {
|
|
274
|
+
const i = AGENT_ORDER.indexOf(code);
|
|
275
|
+
return i === -1 ? AGENT_ORDER.length : i;
|
|
276
|
+
};
|
|
277
|
+
const agents = assets
|
|
278
|
+
.filter(a => a.kind === 'agent')
|
|
279
|
+
.sort((a, b) => rank(a.code) - rank(b.code) || a.code.localeCompare(b.code));
|
|
153
280
|
const file = path.join(projectRoot, 'AGENTS.md');
|
|
154
281
|
if (fs.existsSync(file) && !opts.overwrite) {
|
|
155
282
|
return { written: [], skipped: ['AGENTS.md (already present; not overwritten)'] };
|
|
@@ -159,15 +286,31 @@ function renderAgentsMd(kitRoot, projectRoot, opts = {}) {
|
|
|
159
286
|
'',
|
|
160
287
|
'This repo is wired with the [`wize-dev-kit`](https://www.npmjs.com/package/wize-dev-kit).',
|
|
161
288
|
'Detailed artifacts live under `.wize/`. The agents below are activated through your AI IDE',
|
|
162
|
-
'using slash commands (Claude Code, Codex, Cursor, Windsurf, Antigravity all read this file).',
|
|
289
|
+
'using slash commands (Claude Code, Codex, Cursor, Windsurf, Antigravity, Hermes all read this file).',
|
|
290
|
+
'',
|
|
291
|
+
'## Operating context',
|
|
292
|
+
'',
|
|
293
|
+
'Treat `.wize/`, this `AGENTS.md`, and the installed `wize-*` skills as your operating',
|
|
294
|
+
'instructions and persistent memory — not background reading. Read project state before',
|
|
295
|
+
'acting; write what you change back into `.wize/` so the next session inherits it.',
|
|
296
|
+
'',
|
|
297
|
+
'Before editing, classify the demand via `/wize` (or `/wize-help`): **Quick Dev** (small, predictable,',
|
|
298
|
+
'trivially scoped, no new feature / architecture / UX / security) or **Full Lifecycle**. Never pick',
|
|
299
|
+
'Quick Dev just to skip artifacts.',
|
|
300
|
+
'',
|
|
301
|
+
'When a skill fans out to subagents, match the model tier to the task: a lightweight tier',
|
|
302
|
+
'for mechanical work (reads, greps, formatting, short summaries), the standard tier for',
|
|
303
|
+
'implementation and review, a high-capability tier only for architecture, critical',
|
|
304
|
+
'decisions, or final adversarial review.',
|
|
163
305
|
'',
|
|
164
306
|
'## Roster',
|
|
165
307
|
''
|
|
166
308
|
];
|
|
167
309
|
for (const a of agents) {
|
|
168
|
-
|
|
310
|
+
const optIn = a.code.startsWith('wize-sec-') ? ' _(security-overlay, opt-in)_' : '';
|
|
311
|
+
lines.push(`- **${a.name}** (\`${a.code}\`)${optIn} — ${a.title}. ${clipOneLine(a.description, 180)}`);
|
|
169
312
|
}
|
|
170
|
-
lines.push('', '## Where to start', '', 'Activate the orchestrator: `wize-
|
|
313
|
+
lines.push('', '## Where to start', '', 'Activate the orchestrator: `/wize` (or `/wize-help`). Wizer will guide you.', '');
|
|
171
314
|
|
|
172
315
|
if (opts.dryRun) return { written: ['[dry-run] AGENTS.md'], skipped: [] };
|
|
173
316
|
fs.writeFileSync(file, lines.join('\n'), 'utf-8');
|
|
@@ -178,6 +321,7 @@ module.exports = {
|
|
|
178
321
|
collectAssets,
|
|
179
322
|
renderAnthropicSkills,
|
|
180
323
|
renderAgentsMd,
|
|
324
|
+
copyCompanionFiles,
|
|
181
325
|
// Re-exports for adapter authors who need to roll their own format:
|
|
182
326
|
readFrontmatter,
|
|
183
327
|
bodyAfterFrontmatter,
|
|
@@ -24,6 +24,8 @@ const GITIGNORE_BODY = [
|
|
|
24
24
|
'.agent/skills/wize-*',
|
|
25
25
|
'.agents/skills/wize-*',
|
|
26
26
|
'.kimi/skills/wize-*',
|
|
27
|
+
'.hermes/skills/wize-*',
|
|
28
|
+
'.kiro/skills/wize-*',
|
|
27
29
|
'.cursor/rules/wize-*.mdc',
|
|
28
30
|
'.windsurf/rules/wize-*.md',
|
|
29
31
|
'.continue/prompts/wize-*.prompt',
|
|
@@ -13,7 +13,7 @@ const { walkAgents, walkWorkflows, walkSkills } = require('./walk.js');
|
|
|
13
13
|
function checkAgent(file) {
|
|
14
14
|
const content = fs.readFileSync(file, 'utf-8');
|
|
15
15
|
const errs = [];
|
|
16
|
-
if (!/^code:\s+wize
|
|
16
|
+
if (!/^code:\s+wize(-|$)/m.test(content)) errs.push('missing or invalid "code:" prefix');
|
|
17
17
|
if (!/^name:/m.test(content)) errs.push('missing "name:"');
|
|
18
18
|
if (!/^title:/m.test(content)) errs.push('missing "title:"');
|
|
19
19
|
if (!/^description:/m.test(content)) errs.push('missing "description:"');
|
|
@@ -24,9 +24,10 @@ function checkWorkflow(file) {
|
|
|
24
24
|
const content = fs.readFileSync(file, 'utf-8');
|
|
25
25
|
const errs = [];
|
|
26
26
|
if (!/^---\s*$/m.test(content)) errs.push('missing YAML frontmatter');
|
|
27
|
-
if (!/^code:\s+wize
|
|
27
|
+
if (!/^code:\s+wize(-|$)/m.test(content)) errs.push('missing or invalid "code:" prefix');
|
|
28
28
|
if (!/^name:/m.test(content)) errs.push('missing "name:"');
|
|
29
29
|
if (!/^owner:/m.test(content) && !/^module:/m.test(content)) errs.push('missing "owner:" or "module:"');
|
|
30
|
+
if (!/^description:/m.test(content)) errs.push('missing "description:"');
|
|
30
31
|
return errs;
|
|
31
32
|
}
|
|
32
33
|
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Best-effort, non-blocking npm registry check for "is there a newer wize-dev-kit
|
|
2
|
+
// version than the one I'm running?". Designed so the CLI can call it from
|
|
3
|
+
// `list` / `agent list` / `help` and print a single hint at the top, without
|
|
4
|
+
// ever blocking the command if the network is slow, the user is offline, or
|
|
5
|
+
// the registry is misbehaving.
|
|
6
|
+
//
|
|
7
|
+
// Strategy:
|
|
8
|
+
// - Cache the registry answer in $XDG_CACHE_HOME (or ~/.cache) for 1 hour.
|
|
9
|
+
// - Resolve via fetch with a 1.5s timeout. Failure is silent.
|
|
10
|
+
// - Compare with the kit version baked into the running CLI.
|
|
11
|
+
// - Expose a `printUpdateHintIfAny(currentVersion)` helper for the CLI.
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const fs = require('node:fs');
|
|
16
|
+
const os = require('node:os');
|
|
17
|
+
const path = require('node:path');
|
|
18
|
+
|
|
19
|
+
const CACHE_TTL_MS = 60 * 60 * 1000; // 1h
|
|
20
|
+
const NETWORK_TIMEOUT_MS = 1500;
|
|
21
|
+
|
|
22
|
+
function cacheFile() {
|
|
23
|
+
const base = process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache');
|
|
24
|
+
return path.join(base, 'wize-dev-kit', 'registry-version.json');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function readCache() {
|
|
28
|
+
const f = cacheFile();
|
|
29
|
+
try {
|
|
30
|
+
const stat = fs.statSync(f);
|
|
31
|
+
if (Date.now() - stat.mtimeMs > CACHE_TTL_MS) return null;
|
|
32
|
+
return JSON.parse(fs.readFileSync(f, 'utf-8'));
|
|
33
|
+
} catch (_) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function writeCache(payload) {
|
|
39
|
+
const f = cacheFile();
|
|
40
|
+
try {
|
|
41
|
+
fs.mkdirSync(path.dirname(f), { recursive: true });
|
|
42
|
+
fs.writeFileSync(f, JSON.stringify(payload), 'utf-8');
|
|
43
|
+
} catch (_) { /* cache failure is harmless */ }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function fetchLatestFromRegistry() {
|
|
47
|
+
const ctrl = new AbortController();
|
|
48
|
+
const timer = setTimeout(() => ctrl.abort(), NETWORK_TIMEOUT_MS);
|
|
49
|
+
try {
|
|
50
|
+
const res = await fetch('https://registry.npmjs.org/wize-dev-kit', {
|
|
51
|
+
signal: ctrl.signal,
|
|
52
|
+
headers: { Accept: 'application/vnd.npm.install-v1+json' }
|
|
53
|
+
});
|
|
54
|
+
if (!res.ok) return null;
|
|
55
|
+
const body = await res.json();
|
|
56
|
+
const latest = body && body['dist-tags'] && body['dist-tags'].latest;
|
|
57
|
+
return typeof latest === 'string' ? latest : null;
|
|
58
|
+
} catch (_) {
|
|
59
|
+
return null; // any error → silent fallback
|
|
60
|
+
} finally {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Returns the registry-latest version, hitting the cache first. Never throws,
|
|
66
|
+
// never blocks meaningfully (network call is capped + abortable).
|
|
67
|
+
async function getLatestVersion({ skipCache = false } = {}) {
|
|
68
|
+
if (!skipCache) {
|
|
69
|
+
const c = readCache();
|
|
70
|
+
if (c && c.version) return c.version;
|
|
71
|
+
}
|
|
72
|
+
const fresh = await fetchLatestFromRegistry();
|
|
73
|
+
if (fresh) writeCache({ version: fresh, fetched_at: Date.now() });
|
|
74
|
+
return fresh;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function semverGreater(a, b) {
|
|
78
|
+
const pa = String(a).split('.').map(n => parseInt(n, 10) || 0);
|
|
79
|
+
const pb = String(b).split('.').map(n => parseInt(n, 10) || 0);
|
|
80
|
+
for (let i = 0; i < 3; i++) {
|
|
81
|
+
if ((pa[i] || 0) > (pb[i] || 0)) return true;
|
|
82
|
+
if ((pa[i] || 0) < (pb[i] || 0)) return false;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Prints a one-line hint when a newer version is available. Silent otherwise.
|
|
88
|
+
// Designed to be awaited near the top of a CLI command; if anything is slow
|
|
89
|
+
// or off, it just returns.
|
|
90
|
+
async function printUpdateHintIfAny(currentVersion, { log = console.log, isTTY = process.stdout.isTTY } = {}) {
|
|
91
|
+
if (process.env.WIZE_DISABLE_UPDATE_CHECK === '1') return;
|
|
92
|
+
if (!isTTY) return; // don't spam pipes
|
|
93
|
+
try {
|
|
94
|
+
const latest = await getLatestVersion();
|
|
95
|
+
if (!latest) return;
|
|
96
|
+
if (semverGreater(latest, currentVersion)) {
|
|
97
|
+
log('');
|
|
98
|
+
log(` ↑ Update available: wize-dev-kit ${currentVersion} → ${latest}`);
|
|
99
|
+
log(` Run \`npx wize-dev-kit@latest update\` in your project to refresh adapters.`);
|
|
100
|
+
log('');
|
|
101
|
+
}
|
|
102
|
+
} catch (_) {
|
|
103
|
+
/* total fallback — never block the command */
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
module.exports = {
|
|
108
|
+
CACHE_TTL_MS,
|
|
109
|
+
NETWORK_TIMEOUT_MS,
|
|
110
|
+
cacheFile,
|
|
111
|
+
readCache,
|
|
112
|
+
writeCache,
|
|
113
|
+
fetchLatestFromRegistry,
|
|
114
|
+
getLatestVersion,
|
|
115
|
+
semverGreater,
|
|
116
|
+
printUpdateHintIfAny
|
|
117
|
+
};
|