safeword 0.48.0 → 0.51.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/dist/{check-OFMUQD3Q.js → check-LDCKFJ2Y.js} +7 -6
- package/dist/{check-OFMUQD3Q.js.map → check-LDCKFJ2Y.js.map} +1 -1
- package/dist/{chunk-54KAYQTY.js → chunk-2WUL76K5.js} +2 -2
- package/dist/{chunk-42IGUF5V.js → chunk-AY7IBNF3.js} +5 -5
- package/dist/{chunk-UMPMYZ4F.js → chunk-GX7OYXXG.js} +3 -3
- package/dist/{chunk-2HB6H4G5.js → chunk-JLFYAVLP.js} +2 -2
- package/dist/{chunk-4J3GYDJF.js → chunk-LBAC7N4Y.js} +118 -120
- package/dist/chunk-LBAC7N4Y.js.map +1 -0
- package/dist/{chunk-ZNIJO52Z.js → chunk-MPEK5NNA.js} +2 -2
- package/dist/{chunk-445LAX4Y.js → chunk-MPYFFJBF.js} +24 -1
- package/dist/chunk-MPYFFJBF.js.map +1 -0
- package/dist/chunk-WE7ZQLCT.js +66 -0
- package/dist/chunk-WE7ZQLCT.js.map +1 -0
- package/dist/cli.js +16 -10
- package/dist/cli.js.map +1 -1
- package/dist/{codify-HIWCNPCY.js → codify-YUGZVCR4.js} +3 -3
- package/dist/{diff-SACXR7ES.js → diff-WQNR4ODP.js} +5 -4
- package/dist/{diff-SACXR7ES.js.map → diff-WQNR4ODP.js.map} +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/{reset-AJ4B74Y2.js → reset-HY5GM2XR.js} +8 -6
- package/dist/{reset-AJ4B74Y2.js.map → reset-HY5GM2XR.js.map} +1 -1
- package/dist/{setup-IV3O3CKO.js → setup-I4UEA7LT.js} +13 -11
- package/dist/setup-I4UEA7LT.js.map +1 -0
- package/dist/{sync-config-ELXIXIY3.js → sync-config-5FCJLGMW.js} +3 -3
- package/dist/{sync-learnings-D2JYMRKZ.js → sync-learnings-C7GXSMKZ.js} +3 -3
- package/dist/{sync-tickets-YDFPSIVS.js → sync-tickets-SDX4XPVS.js} +4 -4
- package/dist/test-plan-4D3WNSQP.js +211 -0
- package/dist/test-plan-4D3WNSQP.js.map +1 -0
- package/dist/{ticket-new-BATYGHWL.js → ticket-new-CVBD3MVR.js} +3 -3
- package/dist/ticket-new-CVBD3MVR.js.map +1 -0
- package/dist/{upgrade-FYGFT3CJ.js → upgrade-HPGUYAGC.js} +11 -9
- package/dist/{upgrade-FYGFT3CJ.js.map → upgrade-HPGUYAGC.js.map} +1 -1
- package/package.json +4 -4
- package/templates/SAFEWORD.md +1 -1
- package/templates/commands/audit.md +27 -11
- package/templates/commands/self-review.md +12 -2
- package/templates/commands/verify.md +38 -18
- package/templates/doc-templates/task-spec-template.md +2 -2
- package/templates/guides/architecture-guide.md +1 -1
- package/templates/guides/data-architecture-guide.md +1 -0
- package/templates/guides/design-doc-guide.md +1 -0
- package/templates/guides/planning-guide.md +7 -5
- package/templates/hooks/lib/active-ticket.ts +3 -3
- package/templates/hooks/lib/test-runner.ts +90 -44
- package/templates/hooks/record-skill-invocation.ts +6 -3
- package/templates/hooks/stop-quality.ts +1 -1
- package/templates/hooks/write-review-stamp.ts +2 -1
- package/templates/skills/audit/SKILL.md +27 -11
- package/templates/skills/bdd/DISCOVERY.md +1 -1
- package/templates/skills/bdd/SCENARIOS.md +1 -1
- package/templates/skills/bdd/SKILL.md +2 -2
- package/templates/skills/debug/SKILL.md +1 -0
- package/templates/skills/self-review/SKILL.md +12 -3
- package/templates/skills/ticket-system/SKILL.md +5 -3
- package/templates/skills/verify/SKILL.md +38 -18
- package/dist/chunk-445LAX4Y.js.map +0 -1
- package/dist/chunk-4J3GYDJF.js.map +0 -1
- package/dist/setup-IV3O3CKO.js.map +0 -1
- package/dist/ticket-new-BATYGHWL.js.map +0 -1
- /package/dist/{chunk-54KAYQTY.js.map → chunk-2WUL76K5.js.map} +0 -0
- /package/dist/{chunk-42IGUF5V.js.map → chunk-AY7IBNF3.js.map} +0 -0
- /package/dist/{chunk-UMPMYZ4F.js.map → chunk-GX7OYXXG.js.map} +0 -0
- /package/dist/{chunk-2HB6H4G5.js.map → chunk-JLFYAVLP.js.map} +0 -0
- /package/dist/{chunk-ZNIJO52Z.js.map → chunk-MPEK5NNA.js.map} +0 -0
- /package/dist/{codify-HIWCNPCY.js.map → codify-YUGZVCR4.js.map} +0 -0
- /package/dist/{sync-config-ELXIXIY3.js.map → sync-config-5FCJLGMW.js.map} +0 -0
- /package/dist/{sync-learnings-D2JYMRKZ.js.map → sync-learnings-C7GXSMKZ.js.map} +0 -0
- /package/dist/{sync-tickets-YDFPSIVS.js.map → sync-tickets-SDX4XPVS.js.map} +0 -0
|
@@ -4,15 +4,16 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
checkHealth,
|
|
6
6
|
reportHealthSummary
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-AY7IBNF3.js";
|
|
8
8
|
import {
|
|
9
9
|
syncTickets
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-JLFYAVLP.js";
|
|
11
11
|
import "./chunk-NHXVS5FL.js";
|
|
12
12
|
import "./chunk-IGULTNHR.js";
|
|
13
13
|
import "./chunk-QLXFPFIC.js";
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-LBAC7N4Y.js";
|
|
15
|
+
import "./chunk-2WUL76K5.js";
|
|
16
|
+
import "./chunk-WE7ZQLCT.js";
|
|
16
17
|
import "./chunk-LODQOJEK.js";
|
|
17
18
|
import "./chunk-HSC7TELY.js";
|
|
18
19
|
import {
|
|
@@ -21,7 +22,7 @@ import {
|
|
|
21
22
|
keyValue,
|
|
22
23
|
success,
|
|
23
24
|
warn
|
|
24
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-MPYFFJBF.js";
|
|
25
26
|
|
|
26
27
|
// src/commands/check.ts
|
|
27
28
|
import process from "process";
|
|
@@ -109,4 +110,4 @@ async function check(options) {
|
|
|
109
110
|
export {
|
|
110
111
|
check
|
|
111
112
|
};
|
|
112
|
-
//# sourceMappingURL=check-
|
|
113
|
+
//# sourceMappingURL=check-LDCKFJ2Y.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/check.ts"],"sourcesContent":["/**\n * Check command - Verify project health and configuration\n *\n * The config-health core lives in ../health.ts (shared with the setup/upgrade\n * self-verify, ticket 3293WH). This command adds the standalone-only\n * surfaces: npm update-check, version display, and ticket-index refresh.\n */\n\nimport process from 'node:process';\n\nimport { checkHealth, type HealthStatus, reportHealthSummary } from '../health.js';\nimport { syncTickets } from '../ticket-sync/index.js';\nimport { header, info, keyValue, success, warn } from '../utils/output.js';\nimport { isNewerVersion } from '../utils/version.js';\n\ninterface CheckOptions {\n offline?: boolean;\n}\n\n/**\n * Check for latest version from npm (with timeout)\n * @param timeout\n */\nasync function checkLatestVersion(timeout = 3000): Promise<string | undefined> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, timeout);\n\n const response = await fetch('https://registry.npmjs.org/safeword/latest', {\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) return undefined;\n\n const data = (await response.json()) as { version?: string };\n return data.version ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Check for CLI updates and report status\n * @param health\n */\nasync function reportUpdateStatus(health: HealthStatus): Promise<void> {\n info('\\nChecking for updates...');\n const latestVersion = await checkLatestVersion();\n\n if (!latestVersion) {\n warn(\"Couldn't check for updates (offline?)\");\n return;\n }\n\n health.latestVersion = latestVersion;\n health.updateAvailable = isNewerVersion(health.cliVersion, latestVersion);\n\n if (health.updateAvailable) {\n warn(`Update available: v${latestVersion}`);\n info('Run `bunx safeword@latest upgrade` to upgrade');\n } else {\n success('CLI is up to date');\n }\n}\n\n/**\n * Compare project version vs CLI version and report\n * @param health\n */\nfunction reportVersionMismatch(health: HealthStatus): void {\n if (!health.projectVersion) return;\n\n if (isNewerVersion(health.cliVersion, health.projectVersion)) {\n warn(`Project config (v${health.projectVersion}) is newer than CLI (v${health.cliVersion})`);\n info('Consider upgrading the CLI');\n } else if (isNewerVersion(health.projectVersion, health.cliVersion)) {\n info(`\\nUpgrade available for project config`);\n info(\n `Run \\`safeword upgrade\\` to update from v${health.projectVersion} to v${health.cliVersion}`,\n );\n }\n}\n\n/**\n * Regenerate the ticket discovery index, swallowing any error — index\n * freshness must never block or fail a health check. Reports only when it\n * actually rewrote a file.\n * @param cwd\n */\nfunction regenerateTicketIndex(cwd: string): void {\n try {\n const result = syncTickets(cwd);\n if (result.wrote) {\n info('Regenerated ticket index (INDEX.md / INDEX-completed.md)');\n }\n } catch (error: unknown) {\n // Best-effort: index freshness must never fail the health check. Surface\n // under DEBUG, then return — the deliberate swallow point.\n if (process.env.DEBUG) {\n console.error('[check] ticket index regen failed:', error);\n }\n return;\n }\n}\n\n/**\n *\n * @param options\n */\nexport async function check(options: CheckOptions): Promise<void> {\n const cwd = process.cwd();\n\n header('Safeword Health Check');\n\n const health = await checkHealth(cwd);\n\n // Not configured\n if (!health.configured) {\n info('Not configured. Run `safeword setup` to initialize.');\n return;\n }\n\n // Keep the ticket discovery index fresh at this checkpoint (best-effort —\n // never fail the health check on index regen). Ticket 1GGD28.\n regenerateTicketIndex(cwd);\n\n // Show versions\n keyValue('Safeword CLI', `v${health.cliVersion}`);\n keyValue('Project config', health.projectVersion ? `v${health.projectVersion}` : 'unknown');\n\n // Check for updates (unless offline)\n if (options.offline) {\n info('\\nSkipped update check (offline mode)');\n } else {\n await reportUpdateStatus(health);\n }\n\n reportVersionMismatch(health);\n const hasIssues = reportHealthSummary(health);\n\n if (hasIssues) {\n process.exit(1);\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/commands/check.ts"],"sourcesContent":["/**\n * Check command - Verify project health and configuration\n *\n * The config-health core lives in ../health.ts (shared with the setup/upgrade\n * self-verify, ticket 3293WH). This command adds the standalone-only\n * surfaces: npm update-check, version display, and ticket-index refresh.\n */\n\nimport process from 'node:process';\n\nimport { checkHealth, type HealthStatus, reportHealthSummary } from '../health.js';\nimport { syncTickets } from '../ticket-sync/index.js';\nimport { header, info, keyValue, success, warn } from '../utils/output.js';\nimport { isNewerVersion } from '../utils/version.js';\n\ninterface CheckOptions {\n offline?: boolean;\n}\n\n/**\n * Check for latest version from npm (with timeout)\n * @param timeout\n */\nasync function checkLatestVersion(timeout = 3000): Promise<string | undefined> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, timeout);\n\n const response = await fetch('https://registry.npmjs.org/safeword/latest', {\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) return undefined;\n\n const data = (await response.json()) as { version?: string };\n return data.version ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Check for CLI updates and report status\n * @param health\n */\nasync function reportUpdateStatus(health: HealthStatus): Promise<void> {\n info('\\nChecking for updates...');\n const latestVersion = await checkLatestVersion();\n\n if (!latestVersion) {\n warn(\"Couldn't check for updates (offline?)\");\n return;\n }\n\n health.latestVersion = latestVersion;\n health.updateAvailable = isNewerVersion(health.cliVersion, latestVersion);\n\n if (health.updateAvailable) {\n warn(`Update available: v${latestVersion}`);\n info('Run `bunx safeword@latest upgrade` to upgrade');\n } else {\n success('CLI is up to date');\n }\n}\n\n/**\n * Compare project version vs CLI version and report\n * @param health\n */\nfunction reportVersionMismatch(health: HealthStatus): void {\n if (!health.projectVersion) return;\n\n if (isNewerVersion(health.cliVersion, health.projectVersion)) {\n warn(`Project config (v${health.projectVersion}) is newer than CLI (v${health.cliVersion})`);\n info('Consider upgrading the CLI');\n } else if (isNewerVersion(health.projectVersion, health.cliVersion)) {\n info(`\\nUpgrade available for project config`);\n info(\n `Run \\`safeword upgrade\\` to update from v${health.projectVersion} to v${health.cliVersion}`,\n );\n }\n}\n\n/**\n * Regenerate the ticket discovery index, swallowing any error — index\n * freshness must never block or fail a health check. Reports only when it\n * actually rewrote a file.\n * @param cwd\n */\nfunction regenerateTicketIndex(cwd: string): void {\n try {\n const result = syncTickets(cwd);\n if (result.wrote) {\n info('Regenerated ticket index (INDEX.md / INDEX-completed.md)');\n }\n } catch (error: unknown) {\n // Best-effort: index freshness must never fail the health check. Surface\n // under DEBUG, then return — the deliberate swallow point.\n if (process.env.DEBUG) {\n console.error('[check] ticket index regen failed:', error);\n }\n return;\n }\n}\n\n/**\n *\n * @param options\n */\nexport async function check(options: CheckOptions): Promise<void> {\n const cwd = process.cwd();\n\n header('Safeword Health Check');\n\n const health = await checkHealth(cwd);\n\n // Not configured\n if (!health.configured) {\n info('Not configured. Run `safeword setup` to initialize.');\n return;\n }\n\n // Keep the ticket discovery index fresh at this checkpoint (best-effort —\n // never fail the health check on index regen). Ticket 1GGD28.\n regenerateTicketIndex(cwd);\n\n // Show versions\n keyValue('Safeword CLI', `v${health.cliVersion}`);\n keyValue('Project config', health.projectVersion ? `v${health.projectVersion}` : 'unknown');\n\n // Check for updates (unless offline)\n if (options.offline) {\n info('\\nSkipped update check (offline mode)');\n } else {\n await reportUpdateStatus(health);\n }\n\n reportVersionMismatch(health);\n const hasIssues = reportHealthSummary(health);\n\n if (hasIssues) {\n process.exit(1);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,OAAO,aAAa;AAepB,eAAe,mBAAmB,UAAU,KAAmC;AAC7E,MAAI;AACF,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,YAAY,WAAW,MAAM;AACjC,iBAAW,MAAM;AAAA,IACnB,GAAG,OAAO;AAEV,UAAM,WAAW,MAAM,MAAM,8CAA8C;AAAA,MACzE,QAAQ,WAAW;AAAA,IACrB,CAAC;AAED,iBAAa,SAAS;AAEtB,QAAI,CAAC,SAAS,GAAI,QAAO;AAEzB,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,WAAO,KAAK,WAAW;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,eAAe,mBAAmB,QAAqC;AACrE,OAAK,2BAA2B;AAChC,QAAM,gBAAgB,MAAM,mBAAmB;AAE/C,MAAI,CAAC,eAAe;AAClB,SAAK,uCAAuC;AAC5C;AAAA,EACF;AAEA,SAAO,gBAAgB;AACvB,SAAO,kBAAkB,eAAe,OAAO,YAAY,aAAa;AAExE,MAAI,OAAO,iBAAiB;AAC1B,SAAK,sBAAsB,aAAa,EAAE;AAC1C,SAAK,+CAA+C;AAAA,EACtD,OAAO;AACL,YAAQ,mBAAmB;AAAA,EAC7B;AACF;AAMA,SAAS,sBAAsB,QAA4B;AACzD,MAAI,CAAC,OAAO,eAAgB;AAE5B,MAAI,eAAe,OAAO,YAAY,OAAO,cAAc,GAAG;AAC5D,SAAK,oBAAoB,OAAO,cAAc,yBAAyB,OAAO,UAAU,GAAG;AAC3F,SAAK,4BAA4B;AAAA,EACnC,WAAW,eAAe,OAAO,gBAAgB,OAAO,UAAU,GAAG;AACnE,SAAK;AAAA,qCAAwC;AAC7C;AAAA,MACE,4CAA4C,OAAO,cAAc,QAAQ,OAAO,UAAU;AAAA,IAC5F;AAAA,EACF;AACF;AAQA,SAAS,sBAAsB,KAAmB;AAChD,MAAI;AACF,UAAM,SAAS,YAAY,GAAG;AAC9B,QAAI,OAAO,OAAO;AAChB,WAAK,0DAA0D;AAAA,IACjE;AAAA,EACF,SAAS,OAAgB;AAGvB,QAAI,QAAQ,IAAI,OAAO;AACrB,cAAQ,MAAM,sCAAsC,KAAK;AAAA,IAC3D;AACA;AAAA,EACF;AACF;AAMA,eAAsB,MAAM,SAAsC;AAChE,QAAM,MAAM,QAAQ,IAAI;AAExB,SAAO,uBAAuB;AAE9B,QAAM,SAAS,MAAM,YAAY,GAAG;AAGpC,MAAI,CAAC,OAAO,YAAY;AACtB,SAAK,qDAAqD;AAC1D;AAAA,EACF;AAIA,wBAAsB,GAAG;AAGzB,WAAS,gBAAgB,IAAI,OAAO,UAAU,EAAE;AAChD,WAAS,kBAAkB,OAAO,iBAAiB,IAAI,OAAO,cAAc,KAAK,SAAS;AAG1F,MAAI,QAAQ,SAAS;AACnB,SAAK,uCAAuC;AAAA,EAC9C,OAAO;AACL,UAAM,mBAAmB,MAAM;AAAA,EACjC;AAEA,wBAAsB,MAAM;AAC5B,QAAM,YAAY,oBAAoB,MAAM;AAE5C,MAAI,WAAW;AACb,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isDirectory,
|
|
3
3
|
readFileSafe
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MPYFFJBF.js";
|
|
5
5
|
|
|
6
6
|
// src/utils/configured-paths.ts
|
|
7
7
|
import nodePath from "path";
|
|
@@ -117,4 +117,4 @@ export {
|
|
|
117
117
|
defaultConfiguredPath,
|
|
118
118
|
resolveConfiguredPath
|
|
119
119
|
};
|
|
120
|
-
//# sourceMappingURL=chunk-
|
|
120
|
+
//# sourceMappingURL=chunk-2WUL76K5.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
findDanglingDependencies,
|
|
3
3
|
findTicketsInCycles,
|
|
4
4
|
readTickets
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-JLFYAVLP.js";
|
|
6
6
|
import {
|
|
7
7
|
formatTicketReference
|
|
8
8
|
} from "./chunk-NHXVS5FL.js";
|
|
@@ -22,14 +22,14 @@ import {
|
|
|
22
22
|
createProjectContext,
|
|
23
23
|
getMissingPacks,
|
|
24
24
|
reconcile
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-LBAC7N4Y.js";
|
|
26
26
|
import {
|
|
27
27
|
defaultConfiguredPath,
|
|
28
28
|
readConfiguredDocumentationSources,
|
|
29
29
|
readConfiguredPath,
|
|
30
30
|
resolveConfiguredPath,
|
|
31
31
|
resolveTicketsDirectory
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-2WUL76K5.js";
|
|
33
33
|
import {
|
|
34
34
|
VERSION
|
|
35
35
|
} from "./chunk-HSC7TELY.js";
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
readFileSafe,
|
|
43
43
|
success,
|
|
44
44
|
warn
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-MPYFFJBF.js";
|
|
46
46
|
|
|
47
47
|
// src/health.ts
|
|
48
48
|
import { readdirSync as readdirSync2 } from "fs";
|
|
@@ -698,4 +698,4 @@ export {
|
|
|
698
698
|
checkHealth,
|
|
699
699
|
reportHealthSummary
|
|
700
700
|
};
|
|
701
|
-
//# sourceMappingURL=chunk-
|
|
701
|
+
//# sourceMappingURL=chunk-AY7IBNF3.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
addInstalledPack,
|
|
4
4
|
isGitRepo,
|
|
5
5
|
isPackInstalled
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-LBAC7N4Y.js";
|
|
7
7
|
import {
|
|
8
8
|
SAFEWORD_PEER_DEPENDENCIES
|
|
9
9
|
} from "./chunk-HSC7TELY.js";
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
listItem,
|
|
14
14
|
readJson,
|
|
15
15
|
warn
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-MPYFFJBF.js";
|
|
17
17
|
|
|
18
18
|
// src/packs/install.ts
|
|
19
19
|
function installPack(packId, cwd) {
|
|
@@ -390,4 +390,4 @@ export {
|
|
|
390
390
|
getEslintPeerMismatchWarning,
|
|
391
391
|
maybeAutoPatchOrNudge
|
|
392
392
|
};
|
|
393
|
-
//# sourceMappingURL=chunk-
|
|
393
|
+
//# sourceMappingURL=chunk-GX7OYXXG.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-NHXVS5FL.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveTicketsDirectory
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-2WUL76K5.js";
|
|
7
7
|
|
|
8
8
|
// src/ticket-sync/index.ts
|
|
9
9
|
import { existsSync, readdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -244,4 +244,4 @@ export {
|
|
|
244
244
|
readTickets,
|
|
245
245
|
syncTickets
|
|
246
246
|
};
|
|
247
|
-
//# sourceMappingURL=chunk-
|
|
247
|
+
//# sourceMappingURL=chunk-JLFYAVLP.js.map
|
|
@@ -2,7 +2,10 @@ import {
|
|
|
2
2
|
NAMESPACE_ROOT_LEGACY,
|
|
3
3
|
readConfiguredPath,
|
|
4
4
|
resolveNamespaceRoot
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-2WUL76K5.js";
|
|
6
|
+
import {
|
|
7
|
+
MCP_SERVERS
|
|
8
|
+
} from "./chunk-WE7ZQLCT.js";
|
|
6
9
|
import {
|
|
7
10
|
detect
|
|
8
11
|
} from "./chunk-LODQOJEK.js";
|
|
@@ -15,19 +18,15 @@ import {
|
|
|
15
18
|
existsInTree,
|
|
16
19
|
findInTree,
|
|
17
20
|
getTemplatesDirectory,
|
|
18
|
-
info,
|
|
19
|
-
listItem,
|
|
20
21
|
makeScriptsExecutable,
|
|
21
22
|
readFile,
|
|
22
23
|
readFileSafe,
|
|
23
24
|
readJson,
|
|
24
25
|
remove,
|
|
25
26
|
removeIfEmpty,
|
|
26
|
-
success,
|
|
27
|
-
warn,
|
|
28
27
|
writeFile,
|
|
29
28
|
writeJson
|
|
30
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-MPYFFJBF.js";
|
|
31
30
|
|
|
32
31
|
// src/packs/config.ts
|
|
33
32
|
import nodePath from "path";
|
|
@@ -496,8 +495,8 @@ function getConditionalPackages(conditionalPackages, projectType) {
|
|
|
496
495
|
}
|
|
497
496
|
return packages;
|
|
498
497
|
}
|
|
499
|
-
function shouldSkipForNonGit(
|
|
500
|
-
return
|
|
498
|
+
function shouldSkipForNonGit(path, isGitRepo2) {
|
|
499
|
+
return path.startsWith(HUSKY_DIR) && !isGitRepo2;
|
|
501
500
|
}
|
|
502
501
|
function planMissingDirectories(directories, cwd, isGitRepo2) {
|
|
503
502
|
const actions = [];
|
|
@@ -607,19 +606,19 @@ function withResolvedNamespaceRoot(schema, ctx) {
|
|
|
607
606
|
const root = ctx.namespaceRoot ?? resolveNamespaceRoot(ctx.cwd);
|
|
608
607
|
const label = nodePath7.relative(ctx.cwd, root) || ".";
|
|
609
608
|
if (label === NAMESPACE_ROOT_LEGACY) return schema;
|
|
610
|
-
const translate = (
|
|
611
|
-
if (
|
|
612
|
-
return
|
|
609
|
+
const translate = (path) => {
|
|
610
|
+
if (path !== NAMESPACE_ROOT_LEGACY && !path.startsWith(`${NAMESPACE_ROOT_LEGACY}/`)) {
|
|
611
|
+
return path;
|
|
613
612
|
}
|
|
614
|
-
const subpath =
|
|
613
|
+
const subpath = path.slice(NAMESPACE_ROOT_LEGACY.length).replace(/^\//, "");
|
|
615
614
|
return label === "." ? subpath || "." : nodePath7.join(label, subpath);
|
|
616
615
|
};
|
|
617
616
|
return {
|
|
618
617
|
...schema,
|
|
619
|
-
preservedDirs: schema.preservedDirs.map((
|
|
618
|
+
preservedDirs: schema.preservedDirs.map((path) => translate(path)),
|
|
620
619
|
managedFiles: Object.fromEntries(
|
|
621
|
-
Object.entries(schema.managedFiles).map(([
|
|
622
|
-
translate(
|
|
620
|
+
Object.entries(schema.managedFiles).map(([path, definition]) => [
|
|
621
|
+
translate(path),
|
|
623
622
|
definition
|
|
624
623
|
])
|
|
625
624
|
)
|
|
@@ -849,13 +848,13 @@ function executePlan(plan, ctx) {
|
|
|
849
848
|
return result;
|
|
850
849
|
}
|
|
851
850
|
function executeChmod(cwd, paths) {
|
|
852
|
-
for (const
|
|
853
|
-
const fullPath = nodePath7.join(cwd,
|
|
851
|
+
for (const path of paths) {
|
|
852
|
+
const fullPath = nodePath7.join(cwd, path);
|
|
854
853
|
if (exists(fullPath)) makeScriptsExecutable(fullPath);
|
|
855
854
|
}
|
|
856
855
|
}
|
|
857
|
-
function executeRmdir(cwd,
|
|
858
|
-
if (removeIfEmpty(nodePath7.join(cwd,
|
|
856
|
+
function executeRmdir(cwd, path, result) {
|
|
857
|
+
if (removeIfEmpty(nodePath7.join(cwd, path))) result.removed.push(path);
|
|
859
858
|
}
|
|
860
859
|
function executeAction(action, ctx, result) {
|
|
861
860
|
switch (action.type) {
|
|
@@ -899,11 +898,11 @@ function executeAction(action, ctx, result) {
|
|
|
899
898
|
}
|
|
900
899
|
}
|
|
901
900
|
}
|
|
902
|
-
function executeWrite(cwd,
|
|
903
|
-
const fullPath = nodePath7.join(cwd,
|
|
901
|
+
function executeWrite(cwd, path, content, result) {
|
|
902
|
+
const fullPath = nodePath7.join(cwd, path);
|
|
904
903
|
const existed = exists(fullPath);
|
|
905
904
|
writeFile(fullPath, content);
|
|
906
|
-
(existed ? result.updated : result.created).push(
|
|
905
|
+
(existed ? result.updated : result.created).push(path);
|
|
907
906
|
}
|
|
908
907
|
function resolveFileContent(definition, ctx) {
|
|
909
908
|
if (definition.template) {
|
|
@@ -945,8 +944,8 @@ function stripVersionSpecifier(pkg) {
|
|
|
945
944
|
const atIndex = pkg.startsWith("@") ? pkg.indexOf("@", 1) : pkg.indexOf("@");
|
|
946
945
|
return atIndex === -1 ? pkg : pkg.slice(0, atIndex);
|
|
947
946
|
}
|
|
948
|
-
function executeJsonMerge(cwd,
|
|
949
|
-
const fullPath = nodePath7.join(cwd,
|
|
947
|
+
function executeJsonMerge(cwd, path, definition, ctx) {
|
|
948
|
+
const fullPath = nodePath7.join(cwd, path);
|
|
950
949
|
const rawExisting = readJson(fullPath);
|
|
951
950
|
if (!rawExisting && definition.skipIfMissing) return;
|
|
952
951
|
const existing = rawExisting ?? {};
|
|
@@ -954,8 +953,8 @@ function executeJsonMerge(cwd, path2, definition, ctx) {
|
|
|
954
953
|
if (JSON.stringify(existing) === JSON.stringify(merged)) return;
|
|
955
954
|
writeJson(fullPath, merged);
|
|
956
955
|
}
|
|
957
|
-
function executeJsonUnmerge(cwd,
|
|
958
|
-
const fullPath = nodePath7.join(cwd,
|
|
956
|
+
function executeJsonUnmerge(cwd, path, definition, ctx) {
|
|
957
|
+
const fullPath = nodePath7.join(cwd, path);
|
|
959
958
|
if (!exists(fullPath)) return;
|
|
960
959
|
const existing = readJson(fullPath);
|
|
961
960
|
if (!existing) return;
|
|
@@ -969,8 +968,8 @@ function executeJsonUnmerge(cwd, path2, definition, ctx) {
|
|
|
969
968
|
}
|
|
970
969
|
writeJson(fullPath, unmerged);
|
|
971
970
|
}
|
|
972
|
-
function executeTextPatch(cwd,
|
|
973
|
-
const fullPath = nodePath7.join(cwd,
|
|
971
|
+
function executeTextPatch(cwd, path, definition) {
|
|
972
|
+
const fullPath = nodePath7.join(cwd, path);
|
|
974
973
|
let content = readFileSafe(fullPath) ?? "";
|
|
975
974
|
if (content.includes(definition.marker)) {
|
|
976
975
|
if (content.includes("\n\n---#")) {
|
|
@@ -982,8 +981,8 @@ function executeTextPatch(cwd, path2, definition) {
|
|
|
982
981
|
content = definition.operation === "prepend" ? definition.content + content : content + definition.content;
|
|
983
982
|
writeFile(fullPath, content);
|
|
984
983
|
}
|
|
985
|
-
function executeTextUnpatch(cwd,
|
|
986
|
-
const fullPath = nodePath7.join(cwd,
|
|
984
|
+
function executeTextUnpatch(cwd, path, definition) {
|
|
985
|
+
const fullPath = nodePath7.join(cwd, path);
|
|
987
986
|
const content = readFileSafe(fullPath);
|
|
988
987
|
if (!content) return;
|
|
989
988
|
let unpatched = removeExactTextPatchContent(content, definition);
|
|
@@ -1022,58 +1021,6 @@ function shouldRemoveTextPatchTarget(content, definition) {
|
|
|
1022
1021
|
return definition.removeFileIfContentEquals?.some((candidate) => trimmed === candidate.trim()) ?? false;
|
|
1023
1022
|
}
|
|
1024
1023
|
|
|
1025
|
-
// src/utils/install.ts
|
|
1026
|
-
import { execFileSync } from "child_process";
|
|
1027
|
-
import { existsSync as existsSync3 } from "fs";
|
|
1028
|
-
import path from "path";
|
|
1029
|
-
var DEV_FLAG = "-D";
|
|
1030
|
-
var PM_COMMANDS = {
|
|
1031
|
-
npm: { install: "install", uninstall: "uninstall" },
|
|
1032
|
-
yarn: { install: "add", uninstall: "remove" },
|
|
1033
|
-
pnpm: { install: "add", uninstall: "remove" },
|
|
1034
|
-
bun: { install: "add", uninstall: "remove" }
|
|
1035
|
-
};
|
|
1036
|
-
function detectPackageManager(cwd) {
|
|
1037
|
-
if (existsSync3(path.join(cwd, "bun.lockb")) || existsSync3(path.join(cwd, "bun.lock")))
|
|
1038
|
-
return "bun";
|
|
1039
|
-
if (existsSync3(path.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
1040
|
-
if (existsSync3(path.join(cwd, "yarn.lock"))) return "yarn";
|
|
1041
|
-
if (existsSync3(path.join(cwd, "package-lock.json"))) return "npm";
|
|
1042
|
-
if (process.versions.bun) return "bun";
|
|
1043
|
-
return "npm";
|
|
1044
|
-
}
|
|
1045
|
-
function getUninstallCommand(pm, packages) {
|
|
1046
|
-
const { uninstall } = PM_COMMANDS[pm];
|
|
1047
|
-
return `${pm} ${uninstall} ${packages.join(" ")}`;
|
|
1048
|
-
}
|
|
1049
|
-
function installDependencies(cwd, packages, label = "packages") {
|
|
1050
|
-
if (packages.length === 0) return;
|
|
1051
|
-
if (process.env.SAFEWORD_SKIP_INSTALL) return;
|
|
1052
|
-
const pm = detectPackageManager(cwd);
|
|
1053
|
-
const { install } = PM_COMMANDS[pm];
|
|
1054
|
-
const displayCommand = `${pm} ${install} ${DEV_FLAG} ${packages.join(" ")}`;
|
|
1055
|
-
info(`
|
|
1056
|
-
Installing ${label}...`);
|
|
1057
|
-
info(`Running: ${displayCommand}`);
|
|
1058
|
-
try {
|
|
1059
|
-
execFileSync(pm, [install, DEV_FLAG, ...packages], { cwd, stdio: "pipe", timeout: 12e4 });
|
|
1060
|
-
success(`Installed ${label}`);
|
|
1061
|
-
} catch {
|
|
1062
|
-
warn(`Failed to install ${label}. Run manually:`);
|
|
1063
|
-
listItem(displayCommand);
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
var MCP_SERVERS = {
|
|
1067
|
-
context7: {
|
|
1068
|
-
command: "bunx",
|
|
1069
|
-
args: ["@upstash/context7-mcp@latest"]
|
|
1070
|
-
},
|
|
1071
|
-
playwright: {
|
|
1072
|
-
command: "bunx",
|
|
1073
|
-
args: ["@playwright/mcp@latest"]
|
|
1074
|
-
}
|
|
1075
|
-
};
|
|
1076
|
-
|
|
1077
1024
|
// src/packs/golang/files.ts
|
|
1078
1025
|
import { readFileSync as readFileSync2 } from "fs";
|
|
1079
1026
|
import nodePath8 from "path";
|
|
@@ -1281,11 +1228,11 @@ var golangManagedFiles = {
|
|
|
1281
1228
|
};
|
|
1282
1229
|
|
|
1283
1230
|
// src/packs/python/files.ts
|
|
1284
|
-
import { existsSync as
|
|
1231
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
1285
1232
|
import nodePath9 from "path";
|
|
1286
1233
|
function hasLegacyCustomerRuffExtend(cwd) {
|
|
1287
1234
|
const ruffPath = nodePath9.join(cwd, "ruff.toml");
|
|
1288
|
-
if (!
|
|
1235
|
+
if (!existsSync3(ruffPath)) return false;
|
|
1289
1236
|
try {
|
|
1290
1237
|
const content = readFileSync3(ruffPath, "utf8");
|
|
1291
1238
|
return content.includes('extend = ".safeword/ruff.toml"');
|
|
@@ -1446,7 +1393,7 @@ var pythonManagedFiles = {
|
|
|
1446
1393
|
};
|
|
1447
1394
|
|
|
1448
1395
|
// src/packs/rust/files.ts
|
|
1449
|
-
import { existsSync as
|
|
1396
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
1450
1397
|
import nodePath10 from "path";
|
|
1451
1398
|
var SAFEWORD_CLIPPY_THRESHOLDS = {
|
|
1452
1399
|
"cognitive-complexity-threshold": 10,
|
|
@@ -1471,7 +1418,7 @@ ${generateClippyThresholds()}
|
|
|
1471
1418
|
`;
|
|
1472
1419
|
}
|
|
1473
1420
|
const configPath = nodePath10.join(cwd, existingConfig);
|
|
1474
|
-
if (!
|
|
1421
|
+
if (!existsSync4(configPath)) {
|
|
1475
1422
|
return `# Safeword clippy config - standalone (no project config to merge)
|
|
1476
1423
|
# Used by hooks for LLM enforcement.
|
|
1477
1424
|
|
|
@@ -1546,7 +1493,7 @@ var rustManagedFiles = {
|
|
|
1546
1493
|
};
|
|
1547
1494
|
|
|
1548
1495
|
// src/packs/sql/dialect.ts
|
|
1549
|
-
import { existsSync as
|
|
1496
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
1550
1497
|
import nodePath11 from "path";
|
|
1551
1498
|
import process3 from "process";
|
|
1552
1499
|
import YAML2 from "yaml";
|
|
@@ -1619,7 +1566,7 @@ function detectSqlDialect(cwd) {
|
|
|
1619
1566
|
return detectFromProfiles(cwd) ?? detectFromPythonDeps(cwd) ?? detectFromSqlcConfig(cwd) ?? detectFromPrismaSchema(cwd) ?? detectFromDrizzleConfig(cwd) ?? detectFromDatabaseUrl(cwd);
|
|
1620
1567
|
}
|
|
1621
1568
|
function resolveProfileType(profilesPath, profileName) {
|
|
1622
|
-
if (!
|
|
1569
|
+
if (!existsSync5(profilesPath)) return void 0;
|
|
1623
1570
|
const content = readFileSync5(profilesPath, "utf8");
|
|
1624
1571
|
const profiles = YAML2.parse(content, { schema: "failsafe" });
|
|
1625
1572
|
const profile = profiles[profileName];
|
|
@@ -1662,9 +1609,9 @@ function detectFromPythonDeps(cwd) {
|
|
|
1662
1609
|
const pyprojectPath = nodePath11.join(directory, "pyproject.toml");
|
|
1663
1610
|
try {
|
|
1664
1611
|
let content;
|
|
1665
|
-
if (
|
|
1612
|
+
if (existsSync5(requirementsPath)) {
|
|
1666
1613
|
content = readFileSync5(requirementsPath, "utf8");
|
|
1667
|
-
} else if (
|
|
1614
|
+
} else if (existsSync5(pyprojectPath)) {
|
|
1668
1615
|
content = readFileSync5(pyprojectPath, "utf8");
|
|
1669
1616
|
}
|
|
1670
1617
|
if (!content) return void 0;
|
|
@@ -1694,7 +1641,7 @@ function detectFromSqlcConfig(cwd) {
|
|
|
1694
1641
|
}
|
|
1695
1642
|
function detectFromPrismaSchema(cwd) {
|
|
1696
1643
|
const schemaPath = nodePath11.join(cwd, "prisma", "schema.prisma");
|
|
1697
|
-
if (!
|
|
1644
|
+
if (!existsSync5(schemaPath)) return void 0;
|
|
1698
1645
|
try {
|
|
1699
1646
|
const content = readFileSync5(schemaPath, "utf8");
|
|
1700
1647
|
const match = /provider\s*=\s*"(\w+)"/.exec(content);
|
|
@@ -1707,7 +1654,7 @@ function detectFromPrismaSchema(cwd) {
|
|
|
1707
1654
|
function detectFromDrizzleConfig(cwd) {
|
|
1708
1655
|
for (const filename of ["drizzle.config.ts", "drizzle.config.js", "drizzle.config.mjs"]) {
|
|
1709
1656
|
const filePath = nodePath11.join(cwd, filename);
|
|
1710
|
-
if (!
|
|
1657
|
+
if (!existsSync5(filePath)) continue;
|
|
1711
1658
|
try {
|
|
1712
1659
|
const content = readFileSync5(filePath, "utf8");
|
|
1713
1660
|
const match = /dialect\s*:\s*["'](\w+)["']/.exec(content);
|
|
@@ -1720,7 +1667,7 @@ function detectFromDrizzleConfig(cwd) {
|
|
|
1720
1667
|
}
|
|
1721
1668
|
function detectFromDatabaseUrl(cwd) {
|
|
1722
1669
|
const envPath = nodePath11.join(cwd, ".env");
|
|
1723
|
-
if (!
|
|
1670
|
+
if (!existsSync5(envPath)) return void 0;
|
|
1724
1671
|
try {
|
|
1725
1672
|
const content = readFileSync5(envPath, "utf8");
|
|
1726
1673
|
const match = /DATABASE_URL\s*=\s*["']?(\w+):/.exec(content);
|
|
@@ -2229,7 +2176,7 @@ var typescriptManagedFiles = {
|
|
|
2229
2176
|
// Knip config for dead code detection (used by /audit)
|
|
2230
2177
|
// Plugins auto-enable based on deps, we just configure ignore patterns
|
|
2231
2178
|
"knip.json": {
|
|
2232
|
-
generator: (ctx) => ctx.
|
|
2179
|
+
generator: (ctx) => ctx.projectType?.hasJsSource ? JSON.stringify(getKnipConfig(ctx), void 0, 2) : void 0
|
|
2233
2180
|
},
|
|
2234
2181
|
// Project-level Prettier config (created only if no existing formatter)
|
|
2235
2182
|
".prettierrc": {
|
|
@@ -2266,7 +2213,6 @@ var typescriptJsonMerges = {
|
|
|
2266
2213
|
"scripts.lint:gherkin",
|
|
2267
2214
|
"scripts.format",
|
|
2268
2215
|
"scripts.format:check",
|
|
2269
|
-
"scripts.knip",
|
|
2270
2216
|
"scripts.test:bdd"
|
|
2271
2217
|
],
|
|
2272
2218
|
skipIfMissing: true,
|
|
@@ -2275,14 +2221,16 @@ var typescriptJsonMerges = {
|
|
|
2275
2221
|
existingLinter: ["scripts.lint:eslint"],
|
|
2276
2222
|
// Projects with existing linter get separate ESLint script
|
|
2277
2223
|
publishableLibrary: ["scripts.publint"],
|
|
2278
|
-
shell: ["scripts.lint:sh"]
|
|
2224
|
+
shell: ["scripts.lint:sh"],
|
|
2225
|
+
hasJsSource: ["scripts.knip"]
|
|
2226
|
+
// knip script only added for repos with real JS source (BE7C7B)
|
|
2279
2227
|
},
|
|
2280
2228
|
merge: (existing, ctx) => {
|
|
2281
2229
|
const scripts = { ...existing.scripts };
|
|
2282
2230
|
const result = { ...existing };
|
|
2283
2231
|
mergeLintScripts(scripts, ctx.projectType);
|
|
2284
2232
|
mergeFormatScripts(scripts, ctx.projectType);
|
|
2285
|
-
addScriptIfMissing(scripts, "knip", "knip");
|
|
2233
|
+
if (ctx.projectType.hasJsSource) addScriptIfMissing(scripts, "knip", "knip");
|
|
2286
2234
|
addScriptIfMissing(scripts, "test:bdd", "cucumber-js");
|
|
2287
2235
|
if (ctx.projectType.publishableLibrary) {
|
|
2288
2236
|
addScriptIfMissing(scripts, "publint", "publint");
|
|
@@ -2364,13 +2312,10 @@ var typescriptJsonMerges = {
|
|
|
2364
2312
|
var ESLINT_PACKAGE = "eslint@^9.22.0";
|
|
2365
2313
|
var typescriptPackages = {
|
|
2366
2314
|
base: [
|
|
2367
|
-
// Core tools (always needed for JS/TS)
|
|
2315
|
+
// Core tools (always needed for JS/TS — eslint/prettier also lint the BDD lane's .ts step files)
|
|
2368
2316
|
ESLINT_PACKAGE,
|
|
2369
2317
|
// Safeword (bundles eslint-config-prettier + all ESLint plugins)
|
|
2370
2318
|
"safeword",
|
|
2371
|
-
// Architecture and dead code tools (used by /audit)
|
|
2372
|
-
"dependency-cruiser",
|
|
2373
|
-
"knip",
|
|
2374
2319
|
// BDD acceptance lane (ticket 102b) — cucumber-js runs the scaffolded
|
|
2375
2320
|
// .feature files; tsx transpiles the TypeScript step definitions, and
|
|
2376
2321
|
// @types/node lets the scaffolded steps (node: imports) pass typechecks.
|
|
@@ -2391,7 +2336,11 @@ var typescriptPackages = {
|
|
|
2391
2336
|
shellcheck: ["shellcheck"],
|
|
2392
2337
|
// Renamed from shell to avoid conflict with prettier-plugin-sh
|
|
2393
2338
|
// Legacy ESLint config compat (needed when extending .eslintrc.* configs)
|
|
2394
|
-
legacyEslint: ["@eslint/eslintrc"]
|
|
2339
|
+
legacyEslint: ["@eslint/eslintrc"],
|
|
2340
|
+
// Architecture + dead-code tools (used by /audit) — these scan JS APPLICATION
|
|
2341
|
+
// code/deps, so only for repos with real JS source, not a non-JS repo carrying
|
|
2342
|
+
// just the TS BDD lane (BE7C7B).
|
|
2343
|
+
hasJsSource: ["dependency-cruiser", "knip"]
|
|
2395
2344
|
}
|
|
2396
2345
|
};
|
|
2397
2346
|
|
|
@@ -2404,9 +2353,9 @@ function computeSafewordPathPrefixes(schema) {
|
|
|
2404
2353
|
...Object.keys(schema.textPatches)
|
|
2405
2354
|
];
|
|
2406
2355
|
const prefixes = /* @__PURE__ */ new Set();
|
|
2407
|
-
for (const
|
|
2408
|
-
const slashIndex =
|
|
2409
|
-
prefixes.add(slashIndex === -1 ?
|
|
2356
|
+
for (const path of allPaths) {
|
|
2357
|
+
const slashIndex = path.indexOf("/");
|
|
2358
|
+
prefixes.add(slashIndex === -1 ? path : path.slice(0, slashIndex + 1));
|
|
2410
2359
|
}
|
|
2411
2360
|
return [...prefixes].toSorted((a, b) => a.localeCompare(b));
|
|
2412
2361
|
}
|
|
@@ -3333,7 +3282,7 @@ ${SAFEWORD_TRANSIENT_PATHS.join("\n")}
|
|
|
3333
3282
|
};
|
|
3334
3283
|
|
|
3335
3284
|
// src/utils/git.ts
|
|
3336
|
-
import { execFileSync
|
|
3285
|
+
import { execFileSync } from "child_process";
|
|
3337
3286
|
import nodePath12 from "path";
|
|
3338
3287
|
function isGitRepo(cwd) {
|
|
3339
3288
|
return exists(nodePath12.join(cwd, ".git"));
|
|
@@ -3342,7 +3291,7 @@ function untrackIgnoredFiles(cwd, paths) {
|
|
|
3342
3291
|
if (!isGitRepo(cwd)) return;
|
|
3343
3292
|
for (const pattern of paths) {
|
|
3344
3293
|
try {
|
|
3345
|
-
|
|
3294
|
+
execFileSync("git", ["rm", "--cached", "--ignore-unmatch", "--", pattern], {
|
|
3346
3295
|
cwd,
|
|
3347
3296
|
stdio: "pipe"
|
|
3348
3297
|
});
|
|
@@ -3355,7 +3304,7 @@ function untrackIgnoredFiles(cwd, paths) {
|
|
|
3355
3304
|
import nodePath14 from "path";
|
|
3356
3305
|
|
|
3357
3306
|
// src/utils/project-detector.ts
|
|
3358
|
-
import { existsSync as
|
|
3307
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync6 } from "fs";
|
|
3359
3308
|
import nodePath13 from "path";
|
|
3360
3309
|
var {
|
|
3361
3310
|
TAILWIND_PACKAGES,
|
|
@@ -3416,15 +3365,15 @@ function hasShellScripts(cwd, maxDepth = 4) {
|
|
|
3416
3365
|
return scan(cwd, 0);
|
|
3417
3366
|
}
|
|
3418
3367
|
function findFirstExisting(cwd, candidates) {
|
|
3419
|
-
return candidates.find((file) =>
|
|
3368
|
+
return candidates.find((file) => existsSync6(nodePath13.join(cwd, file)));
|
|
3420
3369
|
}
|
|
3421
3370
|
function findExistingEslintConfig(cwd) {
|
|
3422
3371
|
return findFirstExisting(cwd, ESLINT_CONFIG_FILES);
|
|
3423
3372
|
}
|
|
3424
3373
|
function findExistingRuffConfig(cwd) {
|
|
3425
|
-
if (
|
|
3374
|
+
if (existsSync6(nodePath13.join(cwd, "ruff.toml"))) return "ruff.toml";
|
|
3426
3375
|
const pyprojectPath = nodePath13.join(cwd, PYPROJECT_TOML);
|
|
3427
|
-
if (!
|
|
3376
|
+
if (!existsSync6(pyprojectPath)) return void 0;
|
|
3428
3377
|
try {
|
|
3429
3378
|
const content = readFileSync6(pyprojectPath, "utf8");
|
|
3430
3379
|
return content.includes("[tool.ruff]") ? "pyproject.toml" : void 0;
|
|
@@ -3433,10 +3382,10 @@ function findExistingRuffConfig(cwd) {
|
|
|
3433
3382
|
}
|
|
3434
3383
|
}
|
|
3435
3384
|
function hasExistingMypyConfig(cwd) {
|
|
3436
|
-
if (
|
|
3437
|
-
if (
|
|
3385
|
+
if (existsSync6(nodePath13.join(cwd, "mypy.ini"))) return true;
|
|
3386
|
+
if (existsSync6(nodePath13.join(cwd, ".mypy.ini"))) return true;
|
|
3438
3387
|
const pyprojectPath = nodePath13.join(cwd, PYPROJECT_TOML);
|
|
3439
|
-
if (!
|
|
3388
|
+
if (!existsSync6(pyprojectPath)) return false;
|
|
3440
3389
|
try {
|
|
3441
3390
|
const content = readFileSync6(pyprojectPath, "utf8");
|
|
3442
3391
|
return content.includes("[tool.mypy]");
|
|
@@ -3445,9 +3394,9 @@ function hasExistingMypyConfig(cwd) {
|
|
|
3445
3394
|
}
|
|
3446
3395
|
}
|
|
3447
3396
|
function hasExistingImportLinterConfig(cwd) {
|
|
3448
|
-
if (
|
|
3397
|
+
if (existsSync6(nodePath13.join(cwd, ".importlinter"))) return true;
|
|
3449
3398
|
const pyprojectPath = nodePath13.join(cwd, PYPROJECT_TOML);
|
|
3450
|
-
if (!
|
|
3399
|
+
if (!existsSync6(pyprojectPath)) return false;
|
|
3451
3400
|
try {
|
|
3452
3401
|
const content = readFileSync6(pyprojectPath, "utf8");
|
|
3453
3402
|
return content.includes("[tool.importlinter]");
|
|
@@ -3500,6 +3449,57 @@ function detectExistingTooling(cwd, scripts) {
|
|
|
3500
3449
|
...detectSystemsTooling(cwd)
|
|
3501
3450
|
};
|
|
3502
3451
|
}
|
|
3452
|
+
var JS_SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
3453
|
+
".ts",
|
|
3454
|
+
".tsx",
|
|
3455
|
+
".js",
|
|
3456
|
+
".jsx",
|
|
3457
|
+
".mjs",
|
|
3458
|
+
".cjs",
|
|
3459
|
+
".mts",
|
|
3460
|
+
".cts"
|
|
3461
|
+
]);
|
|
3462
|
+
var JS_SOURCE_DIR_EXCLUDE = /* @__PURE__ */ new Set([
|
|
3463
|
+
"node_modules",
|
|
3464
|
+
".git",
|
|
3465
|
+
".safeword",
|
|
3466
|
+
"dist",
|
|
3467
|
+
"build",
|
|
3468
|
+
"target",
|
|
3469
|
+
"coverage",
|
|
3470
|
+
"vendor"
|
|
3471
|
+
]);
|
|
3472
|
+
var LANE_DIRS = /* @__PURE__ */ new Set(["steps", "features"]);
|
|
3473
|
+
var LANE_FILES = /* @__PURE__ */ new Set(["cucumber.mjs", "eslint.config.mjs", ".prettierrc"]);
|
|
3474
|
+
function isExcludedSourceDirectory(name, depth) {
|
|
3475
|
+
if (name.startsWith(".") || JS_SOURCE_DIR_EXCLUDE.has(name)) return true;
|
|
3476
|
+
return depth === 0 && LANE_DIRS.has(name);
|
|
3477
|
+
}
|
|
3478
|
+
function isJsSourceFile(name, depth) {
|
|
3479
|
+
if (depth === 0 && LANE_FILES.has(name)) return false;
|
|
3480
|
+
return JS_SOURCE_EXTENSIONS.has(nodePath13.extname(name));
|
|
3481
|
+
}
|
|
3482
|
+
function scanForJsSource(directory, depth, maxDepth) {
|
|
3483
|
+
let entries;
|
|
3484
|
+
try {
|
|
3485
|
+
entries = readdirSync4(directory, { withFileTypes: true });
|
|
3486
|
+
} catch {
|
|
3487
|
+
return false;
|
|
3488
|
+
}
|
|
3489
|
+
for (const entry of entries) {
|
|
3490
|
+
if (entry.isFile()) {
|
|
3491
|
+
if (isJsSourceFile(entry.name, depth)) return true;
|
|
3492
|
+
continue;
|
|
3493
|
+
}
|
|
3494
|
+
if (!entry.isDirectory() || depth >= maxDepth || isExcludedSourceDirectory(entry.name, depth))
|
|
3495
|
+
continue;
|
|
3496
|
+
if (scanForJsSource(nodePath13.join(directory, entry.name), depth + 1, maxDepth)) return true;
|
|
3497
|
+
}
|
|
3498
|
+
return false;
|
|
3499
|
+
}
|
|
3500
|
+
function hasJsSource(cwd, maxDepth = 6) {
|
|
3501
|
+
return scanForJsSource(cwd, 0, maxDepth);
|
|
3502
|
+
}
|
|
3503
3503
|
function detectProjectType(packageJson, cwd) {
|
|
3504
3504
|
const deps = packageJson.dependencies ?? {};
|
|
3505
3505
|
const developmentDeps = packageJson.devDependencies ?? {};
|
|
@@ -3509,6 +3509,7 @@ function detectProjectType(packageJson, cwd) {
|
|
|
3509
3509
|
...detectFrameworks(deps, developmentDeps, allDeps),
|
|
3510
3510
|
publishableLibrary: detectPublishable(packageJson),
|
|
3511
3511
|
shell: cwd ? hasShellScripts(cwd) : false,
|
|
3512
|
+
hasJsSource: cwd ? hasJsSource(cwd) : false,
|
|
3512
3513
|
...detectExistingTooling(cwd, scripts)
|
|
3513
3514
|
};
|
|
3514
3515
|
}
|
|
@@ -3542,13 +3543,10 @@ export {
|
|
|
3542
3543
|
getMissingPacks,
|
|
3543
3544
|
getWorkspacePatterns,
|
|
3544
3545
|
reconcile,
|
|
3545
|
-
detectPackageManager,
|
|
3546
|
-
getUninstallCommand,
|
|
3547
|
-
installDependencies,
|
|
3548
3546
|
SAFEWORD_TRANSIENT_PATHS,
|
|
3549
3547
|
SAFEWORD_SCHEMA,
|
|
3550
3548
|
isGitRepo,
|
|
3551
3549
|
untrackIgnoredFiles,
|
|
3552
3550
|
createProjectContext
|
|
3553
3551
|
};
|
|
3554
|
-
//# sourceMappingURL=chunk-
|
|
3552
|
+
//# sourceMappingURL=chunk-LBAC7N4Y.js.map
|