safeword 0.2.4 → 0.2.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/dist/check-3NGQ4NR5.js +129 -0
- package/dist/check-3NGQ4NR5.js.map +1 -0
- package/dist/chunk-2XWIUEQK.js +190 -0
- package/dist/chunk-2XWIUEQK.js.map +1 -0
- package/dist/chunk-GZRQL3SX.js +146 -0
- package/dist/chunk-GZRQL3SX.js.map +1 -0
- package/dist/chunk-ORQHKDT2.js +10 -0
- package/dist/chunk-ORQHKDT2.js.map +1 -0
- package/dist/chunk-W66Z3C5H.js +21 -0
- package/dist/chunk-W66Z3C5H.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +34 -0
- package/dist/cli.js.map +1 -0
- package/dist/diff-Y6QTAW4O.js +166 -0
- package/dist/diff-Y6QTAW4O.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/reset-3ACTIYYE.js +143 -0
- package/dist/reset-3ACTIYYE.js.map +1 -0
- package/dist/setup-RR4M334C.js +266 -0
- package/dist/setup-RR4M334C.js.map +1 -0
- package/dist/upgrade-6AR3DHUV.js +134 -0
- package/dist/upgrade-6AR3DHUV.js.map +1 -0
- package/package.json +44 -19
- package/{.safeword → templates}/hooks/agents-md-check.sh +0 -0
- package/{.safeword → templates}/hooks/post-tool.sh +0 -0
- package/{.safeword → templates}/hooks/pre-commit.sh +0 -0
- package/.claude/commands/arch-review.md +0 -32
- package/.claude/commands/lint.md +0 -6
- package/.claude/commands/quality-review.md +0 -13
- package/.claude/commands/setup-linting.md +0 -6
- package/.claude/hooks/auto-lint.sh +0 -6
- package/.claude/hooks/auto-quality-review.sh +0 -170
- package/.claude/hooks/check-linting-sync.sh +0 -17
- package/.claude/hooks/inject-timestamp.sh +0 -6
- package/.claude/hooks/question-protocol.sh +0 -12
- package/.claude/hooks/run-linters.sh +0 -8
- package/.claude/hooks/run-quality-review.sh +0 -76
- package/.claude/hooks/version-check.sh +0 -10
- package/.claude/mcp/README.md +0 -96
- package/.claude/mcp/arcade.sample.json +0 -9
- package/.claude/mcp/context7.sample.json +0 -7
- package/.claude/mcp/playwright.sample.json +0 -7
- package/.claude/settings.json +0 -62
- package/.claude/skills/quality-reviewer/SKILL.md +0 -190
- package/.claude/skills/safeword-quality-reviewer/SKILL.md +0 -13
- package/.env.arcade.example +0 -4
- package/.env.example +0 -11
- package/.gitmodules +0 -4
- package/.safeword/SAFEWORD.md +0 -33
- package/.safeword/eslint/eslint-base.mjs +0 -101
- package/.safeword/guides/architecture-guide.md +0 -404
- package/.safeword/guides/code-philosophy.md +0 -174
- package/.safeword/guides/context-files-guide.md +0 -405
- package/.safeword/guides/data-architecture-guide.md +0 -183
- package/.safeword/guides/design-doc-guide.md +0 -165
- package/.safeword/guides/learning-extraction.md +0 -515
- package/.safeword/guides/llm-instruction-design.md +0 -239
- package/.safeword/guides/llm-prompting.md +0 -95
- package/.safeword/guides/tdd-best-practices.md +0 -570
- package/.safeword/guides/test-definitions-guide.md +0 -243
- package/.safeword/guides/testing-methodology.md +0 -573
- package/.safeword/guides/user-story-guide.md +0 -237
- package/.safeword/guides/zombie-process-cleanup.md +0 -214
- package/.safeword/planning/002-user-story-quality-evaluation.md +0 -1840
- package/.safeword/planning/003-langsmith-eval-setup-prompt.md +0 -363
- package/.safeword/planning/004-llm-eval-test-cases.md +0 -3226
- package/.safeword/planning/005-architecture-enforcement-system.md +0 -169
- package/.safeword/planning/006-reactive-fix-prevention-research.md +0 -135
- package/.safeword/planning/011-cli-ux-vision.md +0 -330
- package/.safeword/planning/012-project-structure-cleanup.md +0 -154
- package/.safeword/planning/README.md +0 -39
- package/.safeword/planning/automation-plan-v2.md +0 -1225
- package/.safeword/planning/automation-plan-v3.md +0 -1291
- package/.safeword/planning/automation-plan.md +0 -3058
- package/.safeword/planning/design/005-cli-implementation.md +0 -343
- package/.safeword/planning/design/013-cli-self-contained-templates.md +0 -596
- package/.safeword/planning/design/013a-eslint-plugin-suite.md +0 -256
- package/.safeword/planning/design/013b-implementation-snippets.md +0 -385
- package/.safeword/planning/design/013c-config-isolation-strategy.md +0 -242
- package/.safeword/planning/design/code-philosophy-improvements.md +0 -60
- package/.safeword/planning/mcp-analysis.md +0 -545
- package/.safeword/planning/phase2-subagents-vs-skills-analysis.md +0 -451
- package/.safeword/planning/settings-improvements.md +0 -970
- package/.safeword/planning/test-definitions/005-cli-implementation.md +0 -1301
- package/.safeword/planning/test-definitions/cli-self-contained-templates.md +0 -205
- package/.safeword/planning/user-stories/001-guides-review-user-stories.md +0 -1381
- package/.safeword/planning/user-stories/003-reactive-fix-prevention.md +0 -132
- package/.safeword/planning/user-stories/004-technical-constraints.md +0 -86
- package/.safeword/planning/user-stories/005-cli-implementation.md +0 -311
- package/.safeword/planning/user-stories/cli-self-contained-templates.md +0 -172
- package/.safeword/planning/versioned-distribution.md +0 -740
- package/.safeword/prompts/arch-review.md +0 -43
- package/.safeword/prompts/quality-review.md +0 -11
- package/.safeword/scripts/arch-review.sh +0 -235
- package/.safeword/scripts/check-linting-sync.sh +0 -58
- package/.safeword/scripts/setup-linting.sh +0 -559
- package/.safeword/templates/architecture-template.md +0 -136
- package/.safeword/templates/ci/architecture-check.yml +0 -79
- package/.safeword/templates/design-doc-template.md +0 -127
- package/.safeword/templates/test-definitions-feature.md +0 -100
- package/.safeword/templates/ticket-template.md +0 -74
- package/.safeword/templates/user-stories-template.md +0 -82
- package/.safeword/tickets/001-guides-review-user-stories.md +0 -83
- package/.safeword/tickets/002-architecture-enforcement.md +0 -211
- package/.safeword/tickets/003-reactive-fix-prevention.md +0 -57
- package/.safeword/tickets/004-technical-constraints-in-user-stories.md +0 -39
- package/.safeword/tickets/005-cli-implementation.md +0 -248
- package/.safeword/tickets/006-flesh-out-skills.md +0 -43
- package/.safeword/tickets/007-flesh-out-questioning.md +0 -44
- package/.safeword/tickets/008-upgrade-questioning.md +0 -58
- package/.safeword/tickets/009-naming-conventions.md +0 -41
- package/.safeword/tickets/010-safeword-md-cleanup.md +0 -34
- package/.safeword/tickets/011-cursor-setup.md +0 -86
- package/.safeword/tickets/README.md +0 -73
- package/.safeword/version +0 -1
- package/AGENTS.md +0 -59
- package/CLAUDE.md +0 -12
- package/README.md +0 -347
- package/docs/001-cli-implementation-plan.md +0 -856
- package/docs/elite-dx-implementation-plan.md +0 -1034
- package/framework/README.md +0 -131
- package/framework/mcp/README.md +0 -96
- package/framework/mcp/arcade.sample.json +0 -8
- package/framework/mcp/context7.sample.json +0 -6
- package/framework/mcp/playwright.sample.json +0 -6
- package/framework/scripts/arch-review.sh +0 -235
- package/framework/scripts/check-linting-sync.sh +0 -58
- package/framework/scripts/load-env.sh +0 -49
- package/framework/scripts/setup-claude.sh +0 -223
- package/framework/scripts/setup-linting.sh +0 -559
- package/framework/scripts/setup-quality.sh +0 -477
- package/framework/scripts/setup-safeword.sh +0 -550
- package/framework/templates/ci/architecture-check.yml +0 -78
- package/learnings/ai-sdk-v5-breaking-changes.md +0 -178
- package/learnings/e2e-test-zombie-processes.md +0 -231
- package/learnings/milkdown-crepe-editor-property.md +0 -96
- package/learnings/prosemirror-fragment-traversal.md +0 -119
- package/packages/cli/AGENTS.md +0 -1
- package/packages/cli/ARCHITECTURE.md +0 -279
- package/packages/cli/package.json +0 -51
- package/packages/cli/src/cli.ts +0 -63
- package/packages/cli/src/commands/check.ts +0 -166
- package/packages/cli/src/commands/diff.ts +0 -209
- package/packages/cli/src/commands/reset.ts +0 -190
- package/packages/cli/src/commands/setup.ts +0 -325
- package/packages/cli/src/commands/upgrade.ts +0 -163
- package/packages/cli/src/index.ts +0 -3
- package/packages/cli/src/templates/config.ts +0 -58
- package/packages/cli/src/templates/content.ts +0 -18
- package/packages/cli/src/templates/index.ts +0 -12
- package/packages/cli/src/utils/agents-md.ts +0 -66
- package/packages/cli/src/utils/fs.ts +0 -179
- package/packages/cli/src/utils/git.ts +0 -124
- package/packages/cli/src/utils/hooks.ts +0 -29
- package/packages/cli/src/utils/output.ts +0 -60
- package/packages/cli/src/utils/project-detector.test.ts +0 -185
- package/packages/cli/src/utils/project-detector.ts +0 -44
- package/packages/cli/src/utils/version.ts +0 -28
- package/packages/cli/src/version.ts +0 -6
- package/packages/cli/templates/SAFEWORD.md +0 -776
- package/packages/cli/templates/doc-templates/architecture-template.md +0 -136
- package/packages/cli/templates/doc-templates/design-doc-template.md +0 -134
- package/packages/cli/templates/doc-templates/test-definitions-feature.md +0 -131
- package/packages/cli/templates/doc-templates/ticket-template.md +0 -82
- package/packages/cli/templates/doc-templates/user-stories-template.md +0 -92
- package/packages/cli/templates/guides/architecture-guide.md +0 -423
- package/packages/cli/templates/guides/code-philosophy.md +0 -195
- package/packages/cli/templates/guides/context-files-guide.md +0 -457
- package/packages/cli/templates/guides/data-architecture-guide.md +0 -200
- package/packages/cli/templates/guides/design-doc-guide.md +0 -171
- package/packages/cli/templates/guides/learning-extraction.md +0 -552
- package/packages/cli/templates/guides/llm-instruction-design.md +0 -248
- package/packages/cli/templates/guides/llm-prompting.md +0 -102
- package/packages/cli/templates/guides/tdd-best-practices.md +0 -615
- package/packages/cli/templates/guides/test-definitions-guide.md +0 -334
- package/packages/cli/templates/guides/testing-methodology.md +0 -618
- package/packages/cli/templates/guides/user-story-guide.md +0 -256
- package/packages/cli/templates/guides/zombie-process-cleanup.md +0 -219
- package/packages/cli/templates/hooks/agents-md-check.sh +0 -27
- package/packages/cli/templates/hooks/post-tool.sh +0 -4
- package/packages/cli/templates/hooks/pre-commit.sh +0 -10
- package/packages/cli/templates/prompts/arch-review.md +0 -43
- package/packages/cli/templates/prompts/quality-review.md +0 -10
- package/packages/cli/templates/skills/safeword-quality-reviewer/SKILL.md +0 -207
- package/packages/cli/tests/commands/check.test.ts +0 -129
- package/packages/cli/tests/commands/cli.test.ts +0 -89
- package/packages/cli/tests/commands/diff.test.ts +0 -115
- package/packages/cli/tests/commands/reset.test.ts +0 -310
- package/packages/cli/tests/commands/self-healing.test.ts +0 -170
- package/packages/cli/tests/commands/setup-blocking.test.ts +0 -71
- package/packages/cli/tests/commands/setup-core.test.ts +0 -135
- package/packages/cli/tests/commands/setup-git.test.ts +0 -139
- package/packages/cli/tests/commands/setup-hooks.test.ts +0 -334
- package/packages/cli/tests/commands/setup-linting.test.ts +0 -189
- package/packages/cli/tests/commands/setup-noninteractive.test.ts +0 -80
- package/packages/cli/tests/commands/setup-templates.test.ts +0 -181
- package/packages/cli/tests/commands/upgrade.test.ts +0 -215
- package/packages/cli/tests/helpers.ts +0 -243
- package/packages/cli/tests/npm-package.test.ts +0 -83
- package/packages/cli/tests/technical-constraints.test.ts +0 -96
- package/packages/cli/tsconfig.json +0 -25
- package/packages/cli/tsup.config.ts +0 -11
- package/packages/cli/vitest.config.ts +0 -23
- package/promptfoo.yaml +0 -3270
- /package/{framework → templates}/SAFEWORD.md +0 -0
- /package/{packages/cli/templates → templates}/commands/arch-review.md +0 -0
- /package/{packages/cli/templates → templates}/commands/lint.md +0 -0
- /package/{packages/cli/templates → templates}/commands/quality-review.md +0 -0
- /package/{framework/templates → templates/doc-templates}/architecture-template.md +0 -0
- /package/{framework/templates → templates/doc-templates}/design-doc-template.md +0 -0
- /package/{framework/templates → templates/doc-templates}/test-definitions-feature.md +0 -0
- /package/{framework/templates → templates/doc-templates}/ticket-template.md +0 -0
- /package/{framework/templates → templates/doc-templates}/user-stories-template.md +0 -0
- /package/{framework → templates}/guides/architecture-guide.md +0 -0
- /package/{framework → templates}/guides/code-philosophy.md +0 -0
- /package/{framework → templates}/guides/context-files-guide.md +0 -0
- /package/{framework → templates}/guides/data-architecture-guide.md +0 -0
- /package/{framework → templates}/guides/design-doc-guide.md +0 -0
- /package/{framework → templates}/guides/learning-extraction.md +0 -0
- /package/{framework → templates}/guides/llm-instruction-design.md +0 -0
- /package/{framework → templates}/guides/llm-prompting.md +0 -0
- /package/{framework → templates}/guides/tdd-best-practices.md +0 -0
- /package/{framework → templates}/guides/test-definitions-guide.md +0 -0
- /package/{framework → templates}/guides/testing-methodology.md +0 -0
- /package/{framework → templates}/guides/user-story-guide.md +0 -0
- /package/{framework → templates}/guides/zombie-process-cleanup.md +0 -0
- /package/{packages/cli/templates → templates}/hooks/inject-timestamp.sh +0 -0
- /package/{packages/cli/templates → templates}/lib/common.sh +0 -0
- /package/{packages/cli/templates → templates}/lib/jq-fallback.sh +0 -0
- /package/{packages/cli/templates → templates}/markdownlint.jsonc +0 -0
- /package/{framework → templates}/prompts/arch-review.md +0 -0
- /package/{framework → templates}/prompts/quality-review.md +0 -0
- /package/{framework/skills/quality-reviewer → templates/skills/safeword-quality-reviewer}/SKILL.md +0 -0
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test Suite 6: Non-Interactive Setup
|
|
3
|
-
*
|
|
4
|
-
* Tests for CI/headless operation.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
8
|
-
import {
|
|
9
|
-
createTempDir,
|
|
10
|
-
removeTempDir,
|
|
11
|
-
createTypeScriptPackageJson,
|
|
12
|
-
runCli,
|
|
13
|
-
fileExists,
|
|
14
|
-
} from '../helpers';
|
|
15
|
-
|
|
16
|
-
describe('Test Suite 6: Non-Interactive Setup', () => {
|
|
17
|
-
let tempDir: string;
|
|
18
|
-
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
tempDir = createTempDir();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
afterEach(() => {
|
|
24
|
-
removeTempDir(tempDir);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('Test 6.1: --yes flag skips all prompts', () => {
|
|
28
|
-
it('should complete without hanging', async () => {
|
|
29
|
-
createTypeScriptPackageJson(tempDir);
|
|
30
|
-
// No git init - should skip git prompt with --yes
|
|
31
|
-
|
|
32
|
-
const result = await runCli(['setup', '--yes'], {
|
|
33
|
-
cwd: tempDir,
|
|
34
|
-
timeout: 30000,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
expect(result.exitCode).toBe(0);
|
|
38
|
-
expect(fileExists(tempDir, '.safeword')).toBe(true);
|
|
39
|
-
|
|
40
|
-
// Git should be skipped (no .git created)
|
|
41
|
-
expect(fileExists(tempDir, '.git')).toBe(false);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
describe('Test 6.2: No TTY uses defaults', () => {
|
|
46
|
-
it('should complete without stdin in non-TTY mode', async () => {
|
|
47
|
-
createTypeScriptPackageJson(tempDir);
|
|
48
|
-
// No git init
|
|
49
|
-
|
|
50
|
-
// Force non-TTY by setting environment
|
|
51
|
-
const result = await runCli(['setup'], {
|
|
52
|
-
cwd: tempDir,
|
|
53
|
-
timeout: 30000,
|
|
54
|
-
env: {
|
|
55
|
-
CI: 'true', // Many tools detect CI and use non-interactive mode
|
|
56
|
-
TERM: 'dumb',
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Should complete (either with defaults or --yes required message)
|
|
61
|
-
// The exact behavior depends on implementation
|
|
62
|
-
expect(result.exitCode).toBeDefined();
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe('Test 6.3: Warning shown when git skipped', () => {
|
|
67
|
-
it('should show warning about skipped git initialization', async () => {
|
|
68
|
-
createTypeScriptPackageJson(tempDir);
|
|
69
|
-
// No git init
|
|
70
|
-
|
|
71
|
-
const result = await runCli(['setup', '--yes'], { cwd: tempDir });
|
|
72
|
-
|
|
73
|
-
expect(result.exitCode).toBe(0);
|
|
74
|
-
|
|
75
|
-
// Should mention skipped git
|
|
76
|
-
const output = result.stdout + result.stderr;
|
|
77
|
-
expect(output.toLowerCase()).toMatch(/skipped|git|warning/i);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
});
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test Suite: Setup - Template Bundling (Story 1)
|
|
3
|
-
*
|
|
4
|
-
* Tests for the "self-contained templates" feature.
|
|
5
|
-
* The CLI should bundle full methodology files (not stubs) so
|
|
6
|
-
* `npx safeword setup` works without external dependencies.
|
|
7
|
-
*
|
|
8
|
-
* First 3 tests FAIL until Story 1 is implemented.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
12
|
-
import { readdirSync, readFileSync } from 'node:fs';
|
|
13
|
-
import { join } from 'node:path';
|
|
14
|
-
import {
|
|
15
|
-
createTempDir,
|
|
16
|
-
removeTempDir,
|
|
17
|
-
createTypeScriptPackageJson,
|
|
18
|
-
runCli,
|
|
19
|
-
readTestFile,
|
|
20
|
-
writeTestFile,
|
|
21
|
-
fileExists,
|
|
22
|
-
initGitRepo,
|
|
23
|
-
} from '../helpers';
|
|
24
|
-
|
|
25
|
-
describe('Setup - Template Bundling (Story 1)', () => {
|
|
26
|
-
let tempDir: string;
|
|
27
|
-
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
tempDir = createTempDir();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
afterEach(() => {
|
|
33
|
-
removeTempDir(tempDir);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should install full SAFEWORD.md (not a stub)', async () => {
|
|
37
|
-
createTypeScriptPackageJson(tempDir);
|
|
38
|
-
initGitRepo(tempDir);
|
|
39
|
-
|
|
40
|
-
await runCli(['setup', '--yes'], { cwd: tempDir });
|
|
41
|
-
|
|
42
|
-
expect(fileExists(tempDir, '.safeword/SAFEWORD.md')).toBe(true);
|
|
43
|
-
|
|
44
|
-
const content = readTestFile(tempDir, '.safeword/SAFEWORD.md');
|
|
45
|
-
// Full file is ~31KB, stub is <1KB
|
|
46
|
-
expect(content.length).toBeGreaterThan(1000);
|
|
47
|
-
// Verify it's the full methodology file, not a stub
|
|
48
|
-
expect(content).toContain('# Global Instructions for AI Coding Agents');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should install methodology guides to .safeword/guides/', async () => {
|
|
52
|
-
createTypeScriptPackageJson(tempDir);
|
|
53
|
-
initGitRepo(tempDir);
|
|
54
|
-
|
|
55
|
-
await runCli(['setup', '--yes'], { cwd: tempDir });
|
|
56
|
-
|
|
57
|
-
expect(fileExists(tempDir, '.safeword/guides')).toBe(true);
|
|
58
|
-
|
|
59
|
-
const guidesDir = join(tempDir, '.safeword/guides');
|
|
60
|
-
const mdFiles = readdirSync(guidesDir).filter((f) => f.endsWith('.md'));
|
|
61
|
-
|
|
62
|
-
expect(mdFiles.length).toBeGreaterThan(0);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should install document templates', async () => {
|
|
66
|
-
createTypeScriptPackageJson(tempDir);
|
|
67
|
-
initGitRepo(tempDir);
|
|
68
|
-
|
|
69
|
-
await runCli(['setup', '--yes'], { cwd: tempDir });
|
|
70
|
-
|
|
71
|
-
expect(fileExists(tempDir, '.safeword/templates')).toBe(true);
|
|
72
|
-
|
|
73
|
-
const templatesDir = join(tempDir, '.safeword/templates');
|
|
74
|
-
const mdFiles = readdirSync(templatesDir).filter((f) => f.endsWith('.md'));
|
|
75
|
-
|
|
76
|
-
expect(mdFiles.length).toBeGreaterThan(0);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should install review prompts to .safeword/prompts/', async () => {
|
|
80
|
-
createTypeScriptPackageJson(tempDir);
|
|
81
|
-
initGitRepo(tempDir);
|
|
82
|
-
|
|
83
|
-
await runCli(['setup', '--yes'], { cwd: tempDir });
|
|
84
|
-
|
|
85
|
-
expect(fileExists(tempDir, '.safeword/prompts')).toBe(true);
|
|
86
|
-
|
|
87
|
-
const promptsDir = join(tempDir, '.safeword/prompts');
|
|
88
|
-
const mdFiles = readdirSync(promptsDir).filter((f) => f.endsWith('.md'));
|
|
89
|
-
|
|
90
|
-
// Should have 2 review prompts
|
|
91
|
-
expect(mdFiles.length).toBeGreaterThan(0);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('should block re-run and preserve user content', async () => {
|
|
95
|
-
createTypeScriptPackageJson(tempDir);
|
|
96
|
-
initGitRepo(tempDir);
|
|
97
|
-
|
|
98
|
-
await runCli(['setup', '--yes'], { cwd: tempDir });
|
|
99
|
-
|
|
100
|
-
// Create user content
|
|
101
|
-
writeTestFile(
|
|
102
|
-
tempDir,
|
|
103
|
-
'.safeword/learnings/my-learning.md',
|
|
104
|
-
'# My Learning\n\nImportant info.',
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
// Re-run setup should exit with error (already configured)
|
|
108
|
-
const result = await runCli(['setup', '--yes'], { cwd: tempDir });
|
|
109
|
-
expect(result.exitCode).toBe(1);
|
|
110
|
-
expect(result.stderr).toContain('Already configured');
|
|
111
|
-
|
|
112
|
-
// User content should be untouched
|
|
113
|
-
expect(fileExists(tempDir, '.safeword/learnings/my-learning.md')).toBe(true);
|
|
114
|
-
const content = readTestFile(tempDir, '.safeword/learnings/my-learning.md');
|
|
115
|
-
expect(content).toContain('My Learning');
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('should have no broken internal links in installed templates', async () => {
|
|
119
|
-
createTypeScriptPackageJson(tempDir);
|
|
120
|
-
initGitRepo(tempDir);
|
|
121
|
-
|
|
122
|
-
await runCli(['setup', '--yes'], { cwd: tempDir });
|
|
123
|
-
|
|
124
|
-
// Collect all markdown files in .safeword/
|
|
125
|
-
const safewordDir = join(tempDir, '.safeword');
|
|
126
|
-
const allMdFiles: string[] = [];
|
|
127
|
-
|
|
128
|
-
function collectMdFiles(dir: string) {
|
|
129
|
-
if (!fileExists(tempDir, dir.replace(tempDir + '/', ''))) return;
|
|
130
|
-
const entries = readdirSync(dir, { withFileTypes: true });
|
|
131
|
-
for (const entry of entries) {
|
|
132
|
-
const fullPath = join(dir, entry.name);
|
|
133
|
-
if (entry.isDirectory()) {
|
|
134
|
-
collectMdFiles(fullPath);
|
|
135
|
-
} else if (entry.name.endsWith('.md')) {
|
|
136
|
-
allMdFiles.push(fullPath);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
collectMdFiles(safewordDir);
|
|
142
|
-
|
|
143
|
-
// Must have at least SAFEWORD.md with links to verify
|
|
144
|
-
expect(allMdFiles.length).toBeGreaterThan(0);
|
|
145
|
-
|
|
146
|
-
// Extract all @./.safeword/ links and verify targets exist
|
|
147
|
-
// Pattern: @./.safeword/path.md - stop at whitespace, backticks, quotes, parens, or markdown formatting
|
|
148
|
-
const linkPattern = /@\.\/\.safeword\/[a-zA-Z0-9_\-/]+\.md/g;
|
|
149
|
-
const brokenLinks: { file: string; link: string }[] = [];
|
|
150
|
-
let totalLinks = 0;
|
|
151
|
-
|
|
152
|
-
for (const mdFile of allMdFiles) {
|
|
153
|
-
const content = readFileSync(mdFile, 'utf-8');
|
|
154
|
-
const links = content.match(linkPattern) || [];
|
|
155
|
-
totalLinks += links.length;
|
|
156
|
-
|
|
157
|
-
for (const link of links) {
|
|
158
|
-
// Convert @./.safeword/path to relative path
|
|
159
|
-
const relativePath = link.replace('@./', '');
|
|
160
|
-
|
|
161
|
-
if (!fileExists(tempDir, relativePath)) {
|
|
162
|
-
brokenLinks.push({
|
|
163
|
-
file: mdFile.replace(tempDir + '/', ''),
|
|
164
|
-
link,
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Report all broken links
|
|
171
|
-
if (brokenLinks.length > 0) {
|
|
172
|
-
const report = brokenLinks
|
|
173
|
-
.map((b) => ` ${b.file}: ${b.link}`)
|
|
174
|
-
.join('\n');
|
|
175
|
-
expect.fail(`Found ${brokenLinks.length} broken links:\n${report}`);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Should have found at least some links to validate
|
|
179
|
-
expect(totalLinks).toBeGreaterThan(0);
|
|
180
|
-
});
|
|
181
|
-
});
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test Suite 9: Upgrade
|
|
3
|
-
*
|
|
4
|
-
* Tests for `safeword upgrade` command.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
8
|
-
import {
|
|
9
|
-
createTempDir,
|
|
10
|
-
removeTempDir,
|
|
11
|
-
createTypeScriptPackageJson,
|
|
12
|
-
createConfiguredProject,
|
|
13
|
-
runCli,
|
|
14
|
-
readTestFile,
|
|
15
|
-
writeTestFile,
|
|
16
|
-
fileExists,
|
|
17
|
-
} from '../helpers';
|
|
18
|
-
|
|
19
|
-
describe('Test Suite 9: Upgrade', () => {
|
|
20
|
-
let tempDir: string;
|
|
21
|
-
|
|
22
|
-
beforeEach(() => {
|
|
23
|
-
tempDir = createTempDir();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
afterEach(() => {
|
|
27
|
-
removeTempDir(tempDir);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
describe('Test 9.1: Overwrites .safeword files', () => {
|
|
31
|
-
it('should restore modified files to CLI version', async () => {
|
|
32
|
-
await createConfiguredProject(tempDir);
|
|
33
|
-
|
|
34
|
-
// Modify a safeword file
|
|
35
|
-
const originalContent = readTestFile(tempDir, '.safeword/SAFEWORD.md');
|
|
36
|
-
writeTestFile(tempDir, '.safeword/SAFEWORD.md', '# Modified content\n');
|
|
37
|
-
|
|
38
|
-
await runCli(['upgrade'], { cwd: tempDir });
|
|
39
|
-
|
|
40
|
-
const restoredContent = readTestFile(tempDir, '.safeword/SAFEWORD.md');
|
|
41
|
-
// Should be restored (not the modified content)
|
|
42
|
-
expect(restoredContent).not.toBe('# Modified content\n');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should update .safeword/version', async () => {
|
|
46
|
-
await createConfiguredProject(tempDir);
|
|
47
|
-
|
|
48
|
-
// Set an older version
|
|
49
|
-
writeTestFile(tempDir, '.safeword/version', '0.0.1');
|
|
50
|
-
|
|
51
|
-
await runCli(['upgrade'], { cwd: tempDir });
|
|
52
|
-
|
|
53
|
-
const version = readTestFile(tempDir, '.safeword/version').trim();
|
|
54
|
-
expect(version).not.toBe('0.0.1');
|
|
55
|
-
expect(version).toMatch(/^\d+\.\d+\.\d+/);
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
describe('Test 9.2: Updates skills', () => {
|
|
60
|
-
it('should restore modified skill files', async () => {
|
|
61
|
-
await createConfiguredProject(tempDir);
|
|
62
|
-
|
|
63
|
-
// Find and modify a skill file if it exists
|
|
64
|
-
if (fileExists(tempDir, '.claude/skills')) {
|
|
65
|
-
// The actual skill path depends on implementation
|
|
66
|
-
// This test structure is correct for when skills are implemented
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const result = await runCli(['upgrade'], { cwd: tempDir });
|
|
70
|
-
expect(result.exitCode).toBe(0);
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
describe('Test 9.3: Preserves non-safeword hooks', () => {
|
|
75
|
-
it('should preserve custom hooks', async () => {
|
|
76
|
-
await createConfiguredProject(tempDir);
|
|
77
|
-
|
|
78
|
-
// Add a custom hook
|
|
79
|
-
const settings = JSON.parse(readTestFile(tempDir, '.claude/settings.json'));
|
|
80
|
-
settings.hooks = settings.hooks || {};
|
|
81
|
-
settings.hooks.SessionStart = settings.hooks.SessionStart || [];
|
|
82
|
-
settings.hooks.SessionStart.push({
|
|
83
|
-
command: 'echo "My custom hook"',
|
|
84
|
-
description: 'Custom hook',
|
|
85
|
-
});
|
|
86
|
-
writeTestFile(tempDir, '.claude/settings.json', JSON.stringify(settings, null, 2));
|
|
87
|
-
|
|
88
|
-
await runCli(['upgrade'], { cwd: tempDir });
|
|
89
|
-
|
|
90
|
-
const updatedSettings = JSON.parse(readTestFile(tempDir, '.claude/settings.json'));
|
|
91
|
-
const hasCustomHook = updatedSettings.hooks.SessionStart.some(
|
|
92
|
-
(hook: { command?: string }) => hook.command === 'echo "My custom hook"',
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
expect(hasCustomHook).toBe(true);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
describe('Test 9.4: Same-version reinstalls', () => {
|
|
100
|
-
it('should restore files even at same version', async () => {
|
|
101
|
-
await createConfiguredProject(tempDir);
|
|
102
|
-
|
|
103
|
-
// Get current version
|
|
104
|
-
const version = readTestFile(tempDir, '.safeword/version').trim();
|
|
105
|
-
|
|
106
|
-
// Modify a file
|
|
107
|
-
writeTestFile(tempDir, '.safeword/SAFEWORD.md', '# Corrupted\n');
|
|
108
|
-
|
|
109
|
-
await runCli(['upgrade'], { cwd: tempDir });
|
|
110
|
-
|
|
111
|
-
// File should be restored
|
|
112
|
-
const content = readTestFile(tempDir, '.safeword/SAFEWORD.md');
|
|
113
|
-
expect(content).not.toBe('# Corrupted\n');
|
|
114
|
-
|
|
115
|
-
// Version should remain same
|
|
116
|
-
const newVersion = readTestFile(tempDir, '.safeword/version').trim();
|
|
117
|
-
expect(newVersion).toBe(version);
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
describe('Test 9.5: Refuses to downgrade', () => {
|
|
122
|
-
it('should error when project is newer than CLI', async () => {
|
|
123
|
-
await createConfiguredProject(tempDir);
|
|
124
|
-
|
|
125
|
-
// Set a future version
|
|
126
|
-
writeTestFile(tempDir, '.safeword/version', '99.99.99');
|
|
127
|
-
|
|
128
|
-
const result = await runCli(['upgrade'], { cwd: tempDir });
|
|
129
|
-
|
|
130
|
-
expect(result.exitCode).toBe(1);
|
|
131
|
-
expect(result.stderr.toLowerCase()).toMatch(/older|downgrade|cli|update/i);
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
describe('Test 9.6: Unconfigured project error', () => {
|
|
136
|
-
it('should error on unconfigured project', async () => {
|
|
137
|
-
createTypeScriptPackageJson(tempDir);
|
|
138
|
-
// No setup
|
|
139
|
-
|
|
140
|
-
const result = await runCli(['upgrade'], { cwd: tempDir });
|
|
141
|
-
|
|
142
|
-
expect(result.exitCode).toBe(1);
|
|
143
|
-
expect(result.stderr.toLowerCase()).toContain('not configured');
|
|
144
|
-
expect(result.stderr.toLowerCase()).toContain('setup');
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
describe('Test 9.7: Prints summary of changes', () => {
|
|
149
|
-
it('should show what changed', async () => {
|
|
150
|
-
await createConfiguredProject(tempDir);
|
|
151
|
-
|
|
152
|
-
// Modify to create changes
|
|
153
|
-
writeTestFile(tempDir, '.safeword/version', '0.0.1');
|
|
154
|
-
|
|
155
|
-
const result = await runCli(['upgrade'], { cwd: tempDir });
|
|
156
|
-
|
|
157
|
-
expect(result.exitCode).toBe(0);
|
|
158
|
-
// Should show some summary of changes
|
|
159
|
-
expect(result.stdout.toLowerCase()).toMatch(/upgrad|update|version|file/i);
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
describe('Test 9.8: Preserves learnings directory', () => {
|
|
164
|
-
it('should preserve user learnings on upgrade', async () => {
|
|
165
|
-
await createConfiguredProject(tempDir);
|
|
166
|
-
|
|
167
|
-
// Create user learning file
|
|
168
|
-
writeTestFile(
|
|
169
|
-
tempDir,
|
|
170
|
-
'.safeword/learnings/my-custom-learning.md',
|
|
171
|
-
'# My Learning\n\nImportant discovery about the codebase.',
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
// Modify version to trigger upgrade
|
|
175
|
-
writeTestFile(tempDir, '.safeword/version', '0.0.1');
|
|
176
|
-
|
|
177
|
-
await runCli(['upgrade'], { cwd: tempDir });
|
|
178
|
-
|
|
179
|
-
// User learning should be preserved
|
|
180
|
-
expect(fileExists(tempDir, '.safeword/learnings/my-custom-learning.md')).toBe(true);
|
|
181
|
-
|
|
182
|
-
const content = readTestFile(tempDir, '.safeword/learnings/my-custom-learning.md');
|
|
183
|
-
expect(content).toContain('My Learning');
|
|
184
|
-
expect(content).toContain('Important discovery');
|
|
185
|
-
});
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
describe('Test 9.9: Creates backup before upgrade', () => {
|
|
189
|
-
it('should create .safeword.backup directory', async () => {
|
|
190
|
-
await createConfiguredProject(tempDir);
|
|
191
|
-
|
|
192
|
-
// Modify version to trigger upgrade
|
|
193
|
-
writeTestFile(tempDir, '.safeword/version', '0.0.1');
|
|
194
|
-
|
|
195
|
-
// Check for backup during upgrade (it may be deleted after success)
|
|
196
|
-
// We verify by checking that upgrade succeeds without data loss
|
|
197
|
-
const originalSafeword = readTestFile(tempDir, '.safeword/SAFEWORD.md');
|
|
198
|
-
|
|
199
|
-
await runCli(['upgrade'], { cwd: tempDir });
|
|
200
|
-
|
|
201
|
-
// After successful upgrade, backup should be deleted
|
|
202
|
-
expect(fileExists(tempDir, '.safeword.backup')).toBe(false);
|
|
203
|
-
|
|
204
|
-
// Files should still exist
|
|
205
|
-
expect(fileExists(tempDir, '.safeword/SAFEWORD.md')).toBe(true);
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
describe('Test 9.10: Restores backup on failure', () => {
|
|
210
|
-
it.skip('should restore from backup if upgrade fails mid-way', async () => {
|
|
211
|
-
// This test would require a way to force upgrade failure
|
|
212
|
-
// Skipped as it requires mocking internal failures
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
});
|