paqad-ai 0.1.0 → 0.1.2
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/cli/index.js +206 -172
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +241 -234
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/runtime/base/rules/design-system.md +13 -0
- package/runtime/capabilities/security/rules/pentest.md +69 -0
- package/runtime/templates/agent-configs/agents.md.hbs +2 -0
- package/runtime/templates/agent-configs/claude.md.hbs +2 -0
- package/runtime/templates/agent-configs/gemini.md.hbs +2 -0
- package/runtime/templates/agent-configs/junie.md.hbs +3 -0
package/dist/cli/index.js
CHANGED
|
@@ -4117,7 +4117,8 @@ function walk(root) {
|
|
|
4117
4117
|
}
|
|
4118
4118
|
|
|
4119
4119
|
// src/install/bootstrap.ts
|
|
4120
|
-
import { mkdirSync as mkdirSync3 } from "fs";
|
|
4120
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync3, rmSync, symlinkSync } from "fs";
|
|
4121
|
+
import { dirname as dirname12 } from "path";
|
|
4121
4122
|
|
|
4122
4123
|
// src/onboarding/manifest-writer.ts
|
|
4123
4124
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
@@ -4154,7 +4155,12 @@ function resolveFrameworkInstallPath() {
|
|
|
4154
4155
|
// src/install/bootstrap.ts
|
|
4155
4156
|
function bootstrapFramework(projectRoot) {
|
|
4156
4157
|
const frameworkHome = resolveFrameworkInstallPath();
|
|
4157
|
-
|
|
4158
|
+
const runtimeRoot = getRuntimeRoot();
|
|
4159
|
+
mkdirSync3(dirname12(frameworkHome), { recursive: true });
|
|
4160
|
+
if (existsSync11(frameworkHome)) {
|
|
4161
|
+
rmSync(frameworkHome, { recursive: true, force: true });
|
|
4162
|
+
}
|
|
4163
|
+
symlinkSync(runtimeRoot, frameworkHome);
|
|
4158
4164
|
writeFrameworkMetadata(projectRoot, VERSION);
|
|
4159
4165
|
return {
|
|
4160
4166
|
framework_home: frameworkHome,
|
|
@@ -4165,7 +4171,7 @@ function bootstrapFramework(projectRoot) {
|
|
|
4165
4171
|
|
|
4166
4172
|
// src/document/workflow.ts
|
|
4167
4173
|
import { mkdir as mkdir10, readFile as readFile12, readdir as readdir2, writeFile as writeFile10 } from "fs/promises";
|
|
4168
|
-
import { dirname as
|
|
4174
|
+
import { dirname as dirname14, join as join26, relative } from "path";
|
|
4169
4175
|
|
|
4170
4176
|
// src/onboarding/registry-generator.ts
|
|
4171
4177
|
import { readdir } from "fs/promises";
|
|
@@ -4399,7 +4405,7 @@ async function readTemplate(packRoot, templatePath) {
|
|
|
4399
4405
|
|
|
4400
4406
|
// src/document/progress-tracker.ts
|
|
4401
4407
|
import { mkdir as mkdir9, readFile as readFile10, rm, writeFile as writeFile9 } from "fs/promises";
|
|
4402
|
-
import { dirname as
|
|
4408
|
+
import { dirname as dirname13, join as join24 } from "path";
|
|
4403
4409
|
var DocumentProgressTracker = class {
|
|
4404
4410
|
constructor(validator = new SchemaValidator()) {
|
|
4405
4411
|
this.validator = validator;
|
|
@@ -4420,7 +4426,7 @@ var DocumentProgressTracker = class {
|
|
|
4420
4426
|
}
|
|
4421
4427
|
async save(projectRoot, progress) {
|
|
4422
4428
|
const target = join24(projectRoot, PATHS.DOC_PROGRESS);
|
|
4423
|
-
await mkdir9(
|
|
4429
|
+
await mkdir9(dirname13(target), { recursive: true });
|
|
4424
4430
|
await writeFile9(target, `${JSON.stringify(progress, null, 2)}
|
|
4425
4431
|
`);
|
|
4426
4432
|
}
|
|
@@ -4583,7 +4589,7 @@ var DocumentationWorkflow = class {
|
|
|
4583
4589
|
stackSnapshot,
|
|
4584
4590
|
profile
|
|
4585
4591
|
});
|
|
4586
|
-
await mkdir10(
|
|
4592
|
+
await mkdir10(dirname14(join26(options.projectRoot, contentOutputPath)), { recursive: true });
|
|
4587
4593
|
await writeFile10(join26(options.projectRoot, contentOutputPath), contentBody);
|
|
4588
4594
|
generated.push(contentOutputPath);
|
|
4589
4595
|
steps.push({
|
|
@@ -4626,7 +4632,7 @@ var DocumentationWorkflow = class {
|
|
|
4626
4632
|
}
|
|
4627
4633
|
await Promise.all(
|
|
4628
4634
|
themeArtifacts.map(async (artifact) => {
|
|
4629
|
-
await mkdir10(
|
|
4635
|
+
await mkdir10(dirname14(join26(options.projectRoot, artifact.path)), { recursive: true });
|
|
4630
4636
|
await writeFile10(join26(options.projectRoot, artifact.path), artifact.content);
|
|
4631
4637
|
designSystemGenerated.push(artifact.path);
|
|
4632
4638
|
})
|
|
@@ -4913,7 +4919,7 @@ async function processEntry(input) {
|
|
|
4913
4919
|
input.entry.state = "generating";
|
|
4914
4920
|
input.entry.started_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
4915
4921
|
input.entry.error = null;
|
|
4916
|
-
await mkdir10(
|
|
4922
|
+
await mkdir10(dirname14(join26(input.projectRoot, input.entry.output_path)), { recursive: true });
|
|
4917
4923
|
await writeFile10(join26(input.projectRoot, input.entry.output_path), input.content);
|
|
4918
4924
|
input.generated.push(input.entry.output_path);
|
|
4919
4925
|
input.entry.state = "done";
|
|
@@ -5491,15 +5497,15 @@ function basenameWithoutExtension(path) {
|
|
|
5491
5497
|
}
|
|
5492
5498
|
|
|
5493
5499
|
// src/onboarding/file-writer.ts
|
|
5494
|
-
import { chmodSync, existsSync as
|
|
5495
|
-
import { dirname as
|
|
5500
|
+
import { chmodSync, existsSync as existsSync12, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
5501
|
+
import { dirname as dirname15, join as join27 } from "path";
|
|
5496
5502
|
function writeGeneratedFiles(projectRoot, files) {
|
|
5497
5503
|
const written = [];
|
|
5498
5504
|
const skipped = [];
|
|
5499
5505
|
for (const file of files) {
|
|
5500
5506
|
const target = join27(projectRoot, file.path);
|
|
5501
|
-
mkdirSync4(
|
|
5502
|
-
if (!file.autoUpdate &&
|
|
5507
|
+
mkdirSync4(dirname15(target), { recursive: true });
|
|
5508
|
+
if (!file.autoUpdate && existsSync12(target)) {
|
|
5503
5509
|
skipped.push(file.path);
|
|
5504
5510
|
continue;
|
|
5505
5511
|
}
|
|
@@ -5705,6 +5711,8 @@ function resolveArtifactDirectoryName(artifactType) {
|
|
|
5705
5711
|
var RULE_SEED_PRIORITY = [
|
|
5706
5712
|
"constitution",
|
|
5707
5713
|
"security",
|
|
5714
|
+
"pentest",
|
|
5715
|
+
"design-system",
|
|
5708
5716
|
"content-rules",
|
|
5709
5717
|
"testing",
|
|
5710
5718
|
"documentation",
|
|
@@ -5800,9 +5808,34 @@ function getRulePriority(filePath) {
|
|
|
5800
5808
|
return index === -1 ? RULE_SEED_PRIORITY.length : index;
|
|
5801
5809
|
}
|
|
5802
5810
|
|
|
5811
|
+
// src/onboarding/gitignore-writer.ts
|
|
5812
|
+
import { existsSync as existsSync13, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "fs";
|
|
5813
|
+
import { join as join30 } from "path";
|
|
5814
|
+
var PAQAD_MARKER = "# paqad-ai";
|
|
5815
|
+
var PAQAD_GITIGNORE_ENTRIES = [
|
|
5816
|
+
PAQAD_MARKER,
|
|
5817
|
+
".paqad/cache/",
|
|
5818
|
+
".paqad/session/",
|
|
5819
|
+
".paqad/context/",
|
|
5820
|
+
".paqad/workflows/",
|
|
5821
|
+
".paqad/indexes/",
|
|
5822
|
+
".paqad/pentest/",
|
|
5823
|
+
".paqad/theme/"
|
|
5824
|
+
].join("\n");
|
|
5825
|
+
function writeGitignore(projectRoot) {
|
|
5826
|
+
const gitignorePath = join30(projectRoot, ".gitignore");
|
|
5827
|
+
const existing = existsSync13(gitignorePath) ? readFileSync11(gitignorePath, "utf8") : "";
|
|
5828
|
+
if (existing.includes(PAQAD_MARKER)) {
|
|
5829
|
+
return;
|
|
5830
|
+
}
|
|
5831
|
+
const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
|
|
5832
|
+
writeFileSync4(gitignorePath, `${existing}${separator}
|
|
5833
|
+
${PAQAD_GITIGNORE_ENTRIES}
|
|
5834
|
+
`);
|
|
5835
|
+
}
|
|
5836
|
+
|
|
5803
5837
|
// src/onboarding/prompts.ts
|
|
5804
5838
|
import { checkbox, select } from "@inquirer/prompts";
|
|
5805
|
-
var ALL_PROVIDERS = ["codex-cli", "claude-code", "gemini-cli", "junie"];
|
|
5806
5839
|
function isInteractive() {
|
|
5807
5840
|
return Boolean(process.stdout.isTTY && process.stdin.isTTY);
|
|
5808
5841
|
}
|
|
@@ -5836,7 +5869,7 @@ function buildFromOverridesAndDetection(detection, snapshot, overrides) {
|
|
|
5836
5869
|
snapshot
|
|
5837
5870
|
));
|
|
5838
5871
|
return {
|
|
5839
|
-
providers: overrides?.providers ??
|
|
5872
|
+
providers: overrides?.providers ?? ["claude-code"],
|
|
5840
5873
|
domain,
|
|
5841
5874
|
stack_profile: stackProfile,
|
|
5842
5875
|
stack: overrides?.stack ?? (snapshot?.profile ? getPrimaryStack({
|
|
@@ -6227,9 +6260,9 @@ function inferSelectionDomain(detection, overrides, snapshot) {
|
|
|
6227
6260
|
}
|
|
6228
6261
|
|
|
6229
6262
|
// src/onboarding/reference-generator.ts
|
|
6230
|
-
import { existsSync as
|
|
6263
|
+
import { existsSync as existsSync14 } from "fs";
|
|
6231
6264
|
import { readFile as readFile13 } from "fs/promises";
|
|
6232
|
-
import { join as
|
|
6265
|
+
import { join as join31, relative as relative4 } from "path";
|
|
6233
6266
|
import fg3 from "fast-glob";
|
|
6234
6267
|
async function generateReferenceGuides(runtimeRoot, context) {
|
|
6235
6268
|
if (context.domain !== "coding") {
|
|
@@ -6240,8 +6273,8 @@ async function generateReferenceGuides(runtimeRoot, context) {
|
|
|
6240
6273
|
routing: { domain: context.domain },
|
|
6241
6274
|
stack_profile: context.stack_profile
|
|
6242
6275
|
});
|
|
6243
|
-
const referencesRoot =
|
|
6244
|
-
if (!
|
|
6276
|
+
const referencesRoot = join31(runtimeRoot, "capabilities", "coding", "stacks", stack, "references");
|
|
6277
|
+
if (!existsSync14(referencesRoot)) {
|
|
6245
6278
|
return [buildFallbackReferenceGuide(stack)];
|
|
6246
6279
|
}
|
|
6247
6280
|
const entries = await fg3(["tools/*.md", "tools-catalog.md"], {
|
|
@@ -6263,14 +6296,14 @@ async function generateReferenceGuides(runtimeRoot, context) {
|
|
|
6263
6296
|
function toProjectReferencePath(stack, relativePath) {
|
|
6264
6297
|
const normalized = relativePath.replaceAll("\\", "/");
|
|
6265
6298
|
if (normalized === "tools-catalog.md") {
|
|
6266
|
-
return
|
|
6299
|
+
return join31(PATHS.TOOLS_DIR, stack, "README.md");
|
|
6267
6300
|
}
|
|
6268
|
-
return
|
|
6301
|
+
return join31(PATHS.TOOLS_DIR, stack, normalized.replace(/^tools\//, ""));
|
|
6269
6302
|
}
|
|
6270
6303
|
function buildFallbackReferenceGuide(stack) {
|
|
6271
6304
|
const title = stack.split("-").map((segment) => segment.slice(0, 1).toUpperCase() + segment.slice(1)).join(" ");
|
|
6272
6305
|
return {
|
|
6273
|
-
path:
|
|
6306
|
+
path: join31(PATHS.TOOLS_DIR, stack, "README.md"),
|
|
6274
6307
|
autoUpdate: false,
|
|
6275
6308
|
content: [
|
|
6276
6309
|
`# ${title} Tool References`,
|
|
@@ -6288,7 +6321,7 @@ function buildFallbackReferenceGuide(stack) {
|
|
|
6288
6321
|
|
|
6289
6322
|
// src/onboarding/rule-generator.ts
|
|
6290
6323
|
import { readFile as readFile14 } from "fs/promises";
|
|
6291
|
-
import { join as
|
|
6324
|
+
import { join as join32 } from "path";
|
|
6292
6325
|
async function generateProjectRules(rules) {
|
|
6293
6326
|
return Promise.all(
|
|
6294
6327
|
rules.map(async (rule) => ({
|
|
@@ -6301,22 +6334,22 @@ async function generateProjectRules(rules) {
|
|
|
6301
6334
|
function toProjectRulePath(source) {
|
|
6302
6335
|
const normalized = source.replaceAll("\\", "/");
|
|
6303
6336
|
if (normalized.startsWith("base/rules/")) {
|
|
6304
|
-
return
|
|
6337
|
+
return join32(PATHS.RULES_DIR, "_shared", normalized.replace(/^base\/rules\//, ""));
|
|
6305
6338
|
}
|
|
6306
6339
|
if (normalized.startsWith("capabilities/")) {
|
|
6307
6340
|
const capabilityNormalized = normalized.replace(/^capabilities\//, "");
|
|
6308
6341
|
const [prefix2, suffix2] = capabilityNormalized.split("/rules/");
|
|
6309
6342
|
if (prefix2 !== void 0 && suffix2 !== void 0) {
|
|
6310
6343
|
const target2 = suffix2.endsWith("/guide.md") ? suffix2.replace("/guide.md", ".md") : suffix2;
|
|
6311
|
-
return
|
|
6344
|
+
return join32(PATHS.RULES_DIR, prefix2, target2);
|
|
6312
6345
|
}
|
|
6313
6346
|
}
|
|
6314
6347
|
const [prefix, suffix] = normalized.split("/rules/");
|
|
6315
6348
|
if (prefix === void 0 || suffix === void 0) {
|
|
6316
|
-
return
|
|
6349
|
+
return join32(PATHS.RULES_DIR, normalized);
|
|
6317
6350
|
}
|
|
6318
6351
|
const target = suffix.endsWith("/guide.md") ? suffix.replace("/guide.md", ".md") : suffix;
|
|
6319
|
-
return
|
|
6352
|
+
return join32(PATHS.RULES_DIR, prefix, target);
|
|
6320
6353
|
}
|
|
6321
6354
|
|
|
6322
6355
|
// src/onboarding/orchestrator.ts
|
|
@@ -6331,7 +6364,7 @@ var OnboardingOrchestrator = class {
|
|
|
6331
6364
|
const runtimeRoot = options.runtimeRoot ?? getRuntimeRoot();
|
|
6332
6365
|
const resolver = new Resolver({ runtimeRoot });
|
|
6333
6366
|
const resolved = await resolver.resolve(selections);
|
|
6334
|
-
const adapters = options.adapters ?? selections.providers ?? ["claude-code"
|
|
6367
|
+
const adapters = options.adapters ?? selections.providers ?? ["claude-code"];
|
|
6335
6368
|
const profile = buildProjectProfile(selections, liveSnapshot, options.profileOverrides);
|
|
6336
6369
|
const validator = new SchemaValidator();
|
|
6337
6370
|
const validation = validator.validate("project-profile", profile);
|
|
@@ -6368,8 +6401,9 @@ var OnboardingOrchestrator = class {
|
|
|
6368
6401
|
{ writeHumanDocs: false }
|
|
6369
6402
|
);
|
|
6370
6403
|
writeProjectProfile2(options.projectRoot, profile);
|
|
6404
|
+
writeGitignore(options.projectRoot);
|
|
6371
6405
|
writeDetectionReport(options.projectRoot, detection);
|
|
6372
|
-
|
|
6406
|
+
bootstrapFramework(options.projectRoot);
|
|
6373
6407
|
const manifestPath = writeOnboardingManifest(options.projectRoot, {
|
|
6374
6408
|
framework_version: VERSION,
|
|
6375
6409
|
adapter: adapters[0],
|
|
@@ -6642,7 +6676,7 @@ function buildRustCommands(usingCompose) {
|
|
|
6642
6676
|
}
|
|
6643
6677
|
|
|
6644
6678
|
// src/onboarding/scaffold-generator.ts
|
|
6645
|
-
import { join as
|
|
6679
|
+
import { join as join33 } from "path";
|
|
6646
6680
|
|
|
6647
6681
|
// src/templates/registry.ts
|
|
6648
6682
|
import fg4 from "fast-glob";
|
|
@@ -6650,29 +6684,29 @@ import { basename as basename4, relative as relative5 } from "pathe";
|
|
|
6650
6684
|
|
|
6651
6685
|
// src/onboarding/scaffold-generator.ts
|
|
6652
6686
|
var FEATURE_TEMPLATE_TARGETS = [
|
|
6653
|
-
["business.md.hbs",
|
|
6654
|
-
["technical.md.hbs",
|
|
6687
|
+
["business.md.hbs", join33(PATHS.MODULE_FEATURES_DIR, "core", "business.md")],
|
|
6688
|
+
["technical.md.hbs", join33(PATHS.MODULE_FEATURES_DIR, "core", "technical.md")]
|
|
6655
6689
|
];
|
|
6656
6690
|
|
|
6657
6691
|
// src/packs/manager.ts
|
|
6658
6692
|
import {
|
|
6659
6693
|
cpSync,
|
|
6660
|
-
existsSync as
|
|
6694
|
+
existsSync as existsSync15,
|
|
6661
6695
|
mkdirSync as mkdirSync5,
|
|
6662
6696
|
mkdtempSync,
|
|
6663
6697
|
readdirSync as readdirSync3,
|
|
6664
|
-
rmSync,
|
|
6665
|
-
writeFileSync as
|
|
6698
|
+
rmSync as rmSync2,
|
|
6699
|
+
writeFileSync as writeFileSync5
|
|
6666
6700
|
} from "fs";
|
|
6667
6701
|
import { homedir as homedir2 } from "os";
|
|
6668
|
-
import { join as
|
|
6702
|
+
import { join as join34, resolve as resolve2 } from "path";
|
|
6669
6703
|
import { execa } from "execa";
|
|
6670
6704
|
var SOURCE_ORDER2 = ["built-in", "global", "project"];
|
|
6671
6705
|
function resolvePackManagerRoots(projectRoot = process.cwd(), overrides = {}) {
|
|
6672
6706
|
return {
|
|
6673
6707
|
runtimeRoot: overrides.runtimeRoot ?? getRuntimeRoot(),
|
|
6674
|
-
globalPacksRoot: overrides.globalPacksRoot ?? process.env.PAQAD_GLOBAL_PACKS_ROOT ??
|
|
6675
|
-
projectPacksRoot: overrides.projectPacksRoot ??
|
|
6708
|
+
globalPacksRoot: overrides.globalPacksRoot ?? process.env.PAQAD_GLOBAL_PACKS_ROOT ?? join34(homedir2(), ".paqad", "packs"),
|
|
6709
|
+
projectPacksRoot: overrides.projectPacksRoot ?? join34(projectRoot, ".paqad", "packs"),
|
|
6676
6710
|
registryUrl: overrides.registryUrl ?? process.env.PAQAD_PACK_REGISTRY_URL
|
|
6677
6711
|
};
|
|
6678
6712
|
}
|
|
@@ -6720,8 +6754,8 @@ async function installPack(source, options = {}) {
|
|
|
6720
6754
|
if (!pack.validation.valid) {
|
|
6721
6755
|
throw new Error(formatValidationIssues(pack.validation.issues));
|
|
6722
6756
|
}
|
|
6723
|
-
const destination =
|
|
6724
|
-
|
|
6757
|
+
const destination = join34(installRoot, pack.manifest.name);
|
|
6758
|
+
rmSync2(destination, { recursive: true, force: true });
|
|
6725
6759
|
cpSync(candidateRoot, destination, { recursive: true });
|
|
6726
6760
|
const installed = loader.validatePack(destination, scope === "project" ? "project" : "global");
|
|
6727
6761
|
if (!installed.validation.valid) {
|
|
@@ -6732,13 +6766,13 @@ async function installPack(source, options = {}) {
|
|
|
6732
6766
|
function removePack(name, projectRoot = process.cwd(), scope = "global", overrides = {}) {
|
|
6733
6767
|
const roots = resolvePackManagerRoots(projectRoot, overrides);
|
|
6734
6768
|
const targetRoot = scope === "project" ? roots.projectPacksRoot : roots.globalPacksRoot;
|
|
6735
|
-
const target =
|
|
6736
|
-
if (
|
|
6737
|
-
|
|
6769
|
+
const target = join34(targetRoot, name);
|
|
6770
|
+
if (existsSync15(target)) {
|
|
6771
|
+
rmSync2(target, { recursive: true, force: true });
|
|
6738
6772
|
return;
|
|
6739
6773
|
}
|
|
6740
|
-
const builtInRoot =
|
|
6741
|
-
if (
|
|
6774
|
+
const builtInRoot = join34(roots.runtimeRoot, "capabilities", "coding", "stacks", name);
|
|
6775
|
+
if (existsSync15(builtInRoot)) {
|
|
6742
6776
|
throw new Error(
|
|
6743
6777
|
`Cannot remove built-in pack "${name}"; remove a global or project override instead`
|
|
6744
6778
|
);
|
|
@@ -6755,14 +6789,14 @@ function validatePackAt(path) {
|
|
|
6755
6789
|
function createPack(name, options = {}) {
|
|
6756
6790
|
const destinationRoot = options.destinationRoot ?? process.cwd();
|
|
6757
6791
|
const ecosystem = options.ecosystem ?? "node";
|
|
6758
|
-
const packRoot =
|
|
6759
|
-
if (
|
|
6792
|
+
const packRoot = join34(destinationRoot, name);
|
|
6793
|
+
if (existsSync15(packRoot)) {
|
|
6760
6794
|
throw new Error(`Pack scaffold already exists at ${packRoot}`);
|
|
6761
6795
|
}
|
|
6762
|
-
mkdirSync5(
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6796
|
+
mkdirSync5(join34(packRoot, "rules"), { recursive: true });
|
|
6797
|
+
writeFileSync5(join34(packRoot, "pack.yaml"), renderPackTemplate(name, ecosystem));
|
|
6798
|
+
writeFileSync5(
|
|
6799
|
+
join34(packRoot, "rules", "conventions.md"),
|
|
6766
6800
|
`# ${name}
|
|
6767
6801
|
|
|
6768
6802
|
Document project-specific conventions for the ${name} stack here.
|
|
@@ -6772,14 +6806,14 @@ Document project-specific conventions for the ${name} stack here.
|
|
|
6772
6806
|
}
|
|
6773
6807
|
function listPackNamesForSource(source, roots) {
|
|
6774
6808
|
const sourceRoot = resolveSourceRoot(source, roots);
|
|
6775
|
-
if (!
|
|
6809
|
+
if (!existsSync15(sourceRoot)) {
|
|
6776
6810
|
return [];
|
|
6777
6811
|
}
|
|
6778
6812
|
return readdirSync3(sourceRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
6779
6813
|
}
|
|
6780
6814
|
function resolveSourceRoot(source, roots) {
|
|
6781
6815
|
if (source === "built-in") {
|
|
6782
|
-
return
|
|
6816
|
+
return join34(roots.runtimeRoot, "capabilities", "coding", "stacks");
|
|
6783
6817
|
}
|
|
6784
6818
|
return source === "global" ? roots.globalPacksRoot : roots.projectPacksRoot;
|
|
6785
6819
|
}
|
|
@@ -6799,27 +6833,27 @@ async function materializePackSource(source, roots) {
|
|
|
6799
6833
|
return clonePackSource(buildRegistryPackUrl(roots.registryUrl, source));
|
|
6800
6834
|
}
|
|
6801
6835
|
function looksLikeLocalPath(source) {
|
|
6802
|
-
return source.startsWith(".") || source.startsWith("/") ||
|
|
6836
|
+
return source.startsWith(".") || source.startsWith("/") || existsSync15(resolve2(source));
|
|
6803
6837
|
}
|
|
6804
6838
|
function looksLikeGitUrl(source) {
|
|
6805
6839
|
return source.startsWith("http://") || source.startsWith("https://") || source.startsWith("ssh://") || source.startsWith("git@") || source.startsWith("file://") || source.endsWith(".git");
|
|
6806
6840
|
}
|
|
6807
6841
|
async function clonePackSource(source) {
|
|
6808
|
-
const tempRoot = mkdtempSync(
|
|
6842
|
+
const tempRoot = mkdtempSync(join34(homedir2(), ".paqad-pack-clone-"));
|
|
6809
6843
|
try {
|
|
6810
6844
|
await execa("git", ["clone", "--depth", "1", source, tempRoot]);
|
|
6811
6845
|
} catch (error) {
|
|
6812
|
-
|
|
6846
|
+
rmSync2(tempRoot, { recursive: true, force: true });
|
|
6813
6847
|
throw error;
|
|
6814
6848
|
}
|
|
6815
6849
|
return findPackRoot(tempRoot);
|
|
6816
6850
|
}
|
|
6817
6851
|
function findPackRoot(root) {
|
|
6818
|
-
const rootManifest =
|
|
6819
|
-
if (
|
|
6852
|
+
const rootManifest = join34(root, "pack.yaml");
|
|
6853
|
+
if (existsSync15(rootManifest)) {
|
|
6820
6854
|
return root;
|
|
6821
6855
|
}
|
|
6822
|
-
const candidates = readdirSync3(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) =>
|
|
6856
|
+
const candidates = readdirSync3(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => join34(root, entry.name)).filter((candidate) => existsSync15(join34(candidate, "pack.yaml")));
|
|
6823
6857
|
if (candidates.length === 1) {
|
|
6824
6858
|
return candidates[0];
|
|
6825
6859
|
}
|
|
@@ -6918,15 +6952,15 @@ async function queryOsv(packages) {
|
|
|
6918
6952
|
}
|
|
6919
6953
|
|
|
6920
6954
|
// src/pentest/progress-tracker.ts
|
|
6921
|
-
import { existsSync as
|
|
6955
|
+
import { existsSync as existsSync17 } from "fs";
|
|
6922
6956
|
import { mkdir as mkdir12, readdir as readdir4, readFile as readFile16, writeFile as writeFile12 } from "fs/promises";
|
|
6923
|
-
import { dirname as
|
|
6957
|
+
import { dirname as dirname17, join as join36 } from "path";
|
|
6924
6958
|
|
|
6925
6959
|
// src/pentest/shared.ts
|
|
6926
6960
|
import { createHash as createHash7 } from "crypto";
|
|
6927
|
-
import { existsSync as
|
|
6961
|
+
import { existsSync as existsSync16 } from "fs";
|
|
6928
6962
|
import { mkdir as mkdir11, readFile as readFile15, readdir as readdir3, writeFile as writeFile11 } from "fs/promises";
|
|
6929
|
-
import { basename as basename5, dirname as
|
|
6963
|
+
import { basename as basename5, dirname as dirname16, join as join35, relative as relative6 } from "path";
|
|
6930
6964
|
import { execa as execa2 } from "execa";
|
|
6931
6965
|
import fg5 from "fast-glob";
|
|
6932
6966
|
function toLocalTimestamp(date) {
|
|
@@ -6939,12 +6973,12 @@ function toLocalTimestamp(date) {
|
|
|
6939
6973
|
return `${year}-${month}-${day}-${hours}-${minutes}-${seconds}`;
|
|
6940
6974
|
}
|
|
6941
6975
|
async function writeJson(target, data) {
|
|
6942
|
-
await mkdir11(
|
|
6976
|
+
await mkdir11(dirname16(target), { recursive: true });
|
|
6943
6977
|
await writeFile11(target, `${JSON.stringify(data, null, 2)}
|
|
6944
6978
|
`);
|
|
6945
6979
|
}
|
|
6946
6980
|
async function readJsonIfExists(target) {
|
|
6947
|
-
if (!
|
|
6981
|
+
if (!existsSync16(target)) {
|
|
6948
6982
|
return null;
|
|
6949
6983
|
}
|
|
6950
6984
|
return JSON.parse(await readFile15(target, "utf8"));
|
|
@@ -6990,8 +7024,8 @@ async function discoverTargetUrl(projectRoot, stack, explicit) {
|
|
|
6990
7024
|
}
|
|
6991
7025
|
const envFiles = [".env", ".env.local", ".env.example"];
|
|
6992
7026
|
for (const envFile of envFiles) {
|
|
6993
|
-
const path =
|
|
6994
|
-
if (!
|
|
7027
|
+
const path = join35(projectRoot, envFile);
|
|
7028
|
+
if (!existsSync16(path)) {
|
|
6995
7029
|
continue;
|
|
6996
7030
|
}
|
|
6997
7031
|
const content = await readFile15(path, "utf8");
|
|
@@ -7012,11 +7046,11 @@ async function discoverTargetUrl(projectRoot, stack, explicit) {
|
|
|
7012
7046
|
return null;
|
|
7013
7047
|
}
|
|
7014
7048
|
async function runProjectScript(projectRoot, scriptName, env, logDir) {
|
|
7015
|
-
const scriptPath =
|
|
7016
|
-
const stdoutPath =
|
|
7017
|
-
const stderrPath =
|
|
7049
|
+
const scriptPath = join35(projectRoot, PATHS.SCRIPTS_DIR, scriptName);
|
|
7050
|
+
const stdoutPath = join35(logDir, `${scriptName}.stdout.log`);
|
|
7051
|
+
const stderrPath = join35(logDir, `${scriptName}.stderr.log`);
|
|
7018
7052
|
await mkdir11(logDir, { recursive: true });
|
|
7019
|
-
if (!
|
|
7053
|
+
if (!existsSync16(scriptPath)) {
|
|
7020
7054
|
await writeFile11(stdoutPath, "");
|
|
7021
7055
|
await writeFile11(stderrPath, `Missing script: ${relative6(projectRoot, scriptPath)}
|
|
7022
7056
|
`);
|
|
@@ -7044,8 +7078,8 @@ async function runProjectScript(projectRoot, scriptName, env, logDir) {
|
|
|
7044
7078
|
};
|
|
7045
7079
|
}
|
|
7046
7080
|
async function loadModuleDocs(projectRoot, focusModules = []) {
|
|
7047
|
-
const moduleRoot =
|
|
7048
|
-
if (!
|
|
7081
|
+
const moduleRoot = join35(projectRoot, PATHS.MODULES_DIR);
|
|
7082
|
+
if (!existsSync16(moduleRoot)) {
|
|
7049
7083
|
return [];
|
|
7050
7084
|
}
|
|
7051
7085
|
const dirs = (await readdir3(moduleRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((moduleName) => focusModules.length === 0 || focusModules.includes(moduleName)).sort();
|
|
@@ -7113,7 +7147,7 @@ function inferSourceArtifacts(baseDir, scriptResults) {
|
|
|
7113
7147
|
return [
|
|
7114
7148
|
...new Set(
|
|
7115
7149
|
artifacts.map(
|
|
7116
|
-
(artifact) => artifact.startsWith(".") ? artifact : relative6(
|
|
7150
|
+
(artifact) => artifact.startsWith(".") ? artifact : relative6(dirname16(baseDir), join35(dirname16(baseDir), artifact))
|
|
7117
7151
|
)
|
|
7118
7152
|
)
|
|
7119
7153
|
];
|
|
@@ -7187,8 +7221,8 @@ var PentestProgressTracker = class {
|
|
|
7187
7221
|
};
|
|
7188
7222
|
}
|
|
7189
7223
|
async load(projectRoot, runId) {
|
|
7190
|
-
const target =
|
|
7191
|
-
if (!
|
|
7224
|
+
const target = join36(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "progress.json");
|
|
7225
|
+
if (!existsSync17(target)) {
|
|
7192
7226
|
return null;
|
|
7193
7227
|
}
|
|
7194
7228
|
const parsed = JSON.parse(await readFile16(target, "utf8"));
|
|
@@ -7199,9 +7233,9 @@ var PentestProgressTracker = class {
|
|
|
7199
7233
|
return parsed;
|
|
7200
7234
|
}
|
|
7201
7235
|
async save(projectRoot, progress) {
|
|
7202
|
-
const target =
|
|
7236
|
+
const target = join36(projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "progress.json");
|
|
7203
7237
|
progress.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
7204
|
-
await mkdir12(
|
|
7238
|
+
await mkdir12(dirname17(target), { recursive: true });
|
|
7205
7239
|
await writeFile12(target, `${JSON.stringify(progress, null, 2)}
|
|
7206
7240
|
`);
|
|
7207
7241
|
}
|
|
@@ -7258,8 +7292,8 @@ var PentestProgressTracker = class {
|
|
|
7258
7292
|
return step.status === "completed" && step.input_hash === inputHash;
|
|
7259
7293
|
}
|
|
7260
7294
|
async findIncompleteRun(projectRoot, workflow, sourceReportPath) {
|
|
7261
|
-
const runsDir =
|
|
7262
|
-
if (!
|
|
7295
|
+
const runsDir = join36(projectRoot, PATHS.PENTEST_RUNS_DIR);
|
|
7296
|
+
if (!existsSync17(runsDir)) {
|
|
7263
7297
|
return null;
|
|
7264
7298
|
}
|
|
7265
7299
|
const entries = (await readdir4(runsDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().reverse();
|
|
@@ -7301,15 +7335,15 @@ var PentestProgressTracker = class {
|
|
|
7301
7335
|
}
|
|
7302
7336
|
};
|
|
7303
7337
|
function runArtifactsDir(projectRoot, runId) {
|
|
7304
|
-
return
|
|
7338
|
+
return join36(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "artifacts");
|
|
7305
7339
|
}
|
|
7306
7340
|
function runLogsDir(projectRoot, runId) {
|
|
7307
|
-
return
|
|
7341
|
+
return join36(projectRoot, PATHS.PENTEST_RUNS_DIR, runId, "logs");
|
|
7308
7342
|
}
|
|
7309
7343
|
|
|
7310
7344
|
// src/pipeline/lane-runner.ts
|
|
7311
7345
|
import { mkdir as mkdir16, writeFile as writeFile16 } from "fs/promises";
|
|
7312
|
-
import { dirname as
|
|
7346
|
+
import { dirname as dirname20, join as join42 } from "path";
|
|
7313
7347
|
|
|
7314
7348
|
// src/pipeline/phases/shared.ts
|
|
7315
7349
|
function createPassResult(phase, summary, context, artifacts = [`handoff:${context.phases.length + 1}`]) {
|
|
@@ -7429,12 +7463,12 @@ var LoadDocsPhase = class {
|
|
|
7429
7463
|
|
|
7430
7464
|
// src/workflows/pentest.ts
|
|
7431
7465
|
import { mkdir as mkdir13, writeFile as writeFile13 } from "fs/promises";
|
|
7432
|
-
import { join as
|
|
7466
|
+
import { join as join39, relative as relative7 } from "path";
|
|
7433
7467
|
|
|
7434
7468
|
// src/pentest/findings.ts
|
|
7435
|
-
import { existsSync as
|
|
7469
|
+
import { existsSync as existsSync18 } from "fs";
|
|
7436
7470
|
import { readFile as readFile17 } from "fs/promises";
|
|
7437
|
-
import { join as
|
|
7471
|
+
import { join as join37 } from "path";
|
|
7438
7472
|
function createFinding(input) {
|
|
7439
7473
|
return {
|
|
7440
7474
|
id: "",
|
|
@@ -7608,8 +7642,8 @@ function buildModuleFindings(docs, tests) {
|
|
|
7608
7642
|
return findings;
|
|
7609
7643
|
}
|
|
7610
7644
|
async function buildSecretFindings(artifactDir) {
|
|
7611
|
-
const path =
|
|
7612
|
-
if (!
|
|
7645
|
+
const path = join37(artifactDir, "secrets", "matches.txt");
|
|
7646
|
+
if (!existsSync18(path)) {
|
|
7613
7647
|
return [];
|
|
7614
7648
|
}
|
|
7615
7649
|
const matches = parseSecretMatches(await readFile17(path, "utf8"));
|
|
@@ -7721,8 +7755,8 @@ function normalizeImpact(content) {
|
|
|
7721
7755
|
}
|
|
7722
7756
|
async function readNativeAuditFindings(artifactDir) {
|
|
7723
7757
|
const findings = [];
|
|
7724
|
-
const dependencyDir =
|
|
7725
|
-
const npmAudit = await readJsonMaybe(
|
|
7758
|
+
const dependencyDir = join37(artifactDir, "dependencies");
|
|
7759
|
+
const npmAudit = await readJsonMaybe(join37(dependencyDir, "npm-audit.json"));
|
|
7726
7760
|
for (const [name, vulnerability] of Object.entries(npmAudit?.vulnerabilities ?? {})) {
|
|
7727
7761
|
const via = (vulnerability.via ?? []).find((entry) => typeof entry === "object");
|
|
7728
7762
|
findings.push({
|
|
@@ -7734,7 +7768,7 @@ async function readNativeAuditFindings(artifactDir) {
|
|
|
7734
7768
|
details: via?.url ?? ""
|
|
7735
7769
|
});
|
|
7736
7770
|
}
|
|
7737
|
-
const pnpmAudit = await readJsonMaybe(
|
|
7771
|
+
const pnpmAudit = await readJsonMaybe(join37(dependencyDir, "pnpm-audit.json"));
|
|
7738
7772
|
for (const advisory of Object.values(pnpmAudit?.advisories ?? {})) {
|
|
7739
7773
|
findings.push({
|
|
7740
7774
|
package_name: advisory.module_name ?? "unknown",
|
|
@@ -7745,7 +7779,7 @@ async function readNativeAuditFindings(artifactDir) {
|
|
|
7745
7779
|
details: advisory.overview ?? ""
|
|
7746
7780
|
});
|
|
7747
7781
|
}
|
|
7748
|
-
const composerAudit = await readJsonMaybe(
|
|
7782
|
+
const composerAudit = await readJsonMaybe(join37(dependencyDir, "composer-audit.json"));
|
|
7749
7783
|
if (Array.isArray(composerAudit?.advisories)) {
|
|
7750
7784
|
for (const advisory of composerAudit.advisories) {
|
|
7751
7785
|
findings.push({
|
|
@@ -7782,7 +7816,7 @@ async function readNativeAuditFindings(artifactDir) {
|
|
|
7782
7816
|
});
|
|
7783
7817
|
}
|
|
7784
7818
|
async function readJsonMaybe(path) {
|
|
7785
|
-
if (!
|
|
7819
|
+
if (!existsSync18(path)) {
|
|
7786
7820
|
return null;
|
|
7787
7821
|
}
|
|
7788
7822
|
try {
|
|
@@ -7858,7 +7892,7 @@ var FileCheckMapper = class {
|
|
|
7858
7892
|
|
|
7859
7893
|
// src/pentest/incremental-scanner.ts
|
|
7860
7894
|
import { readFile as readFile18 } from "fs/promises";
|
|
7861
|
-
import { join as
|
|
7895
|
+
import { join as join38 } from "path";
|
|
7862
7896
|
import { createHash as createHash8 } from "crypto";
|
|
7863
7897
|
import { execa as execa3 } from "execa";
|
|
7864
7898
|
var IncrementalScanner = class {
|
|
@@ -7892,7 +7926,7 @@ var IncrementalScanner = class {
|
|
|
7892
7926
|
}
|
|
7893
7927
|
}
|
|
7894
7928
|
async gitDiff(projectRoot, lastRunId) {
|
|
7895
|
-
const progressPath =
|
|
7929
|
+
const progressPath = join38(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
|
|
7896
7930
|
let baseCommit;
|
|
7897
7931
|
try {
|
|
7898
7932
|
const raw = await readFile18(progressPath, "utf8");
|
|
@@ -7909,7 +7943,7 @@ var IncrementalScanner = class {
|
|
|
7909
7943
|
return result.stdout.split("\n").map((f) => f.trim()).filter(Boolean);
|
|
7910
7944
|
}
|
|
7911
7945
|
async hashDiff(projectRoot, lastRunId) {
|
|
7912
|
-
const manifestPath =
|
|
7946
|
+
const manifestPath = join38(projectRoot, ".paqad", "pentest", "runs", lastRunId, "progress.json");
|
|
7913
7947
|
let fileManifest = {};
|
|
7914
7948
|
try {
|
|
7915
7949
|
const raw = await readFile18(manifestPath, "utf8");
|
|
@@ -7921,7 +7955,7 @@ var IncrementalScanner = class {
|
|
|
7921
7955
|
const changed = [];
|
|
7922
7956
|
for (const [filePath, storedHash] of Object.entries(fileManifest)) {
|
|
7923
7957
|
try {
|
|
7924
|
-
const content = await readFile18(
|
|
7958
|
+
const content = await readFile18(join38(projectRoot, filePath), "utf8");
|
|
7925
7959
|
const currentHash = createHash8("sha256").update(content).digest("hex");
|
|
7926
7960
|
if (currentHash !== storedHash) {
|
|
7927
7961
|
changed.push(filePath);
|
|
@@ -7934,11 +7968,11 @@ var IncrementalScanner = class {
|
|
|
7934
7968
|
}
|
|
7935
7969
|
async warnIfFullScanStale(projectRoot, thresholdDays) {
|
|
7936
7970
|
try {
|
|
7937
|
-
const runsDir =
|
|
7971
|
+
const runsDir = join38(projectRoot, ".paqad", "pentest", "runs");
|
|
7938
7972
|
const { readdir: readdir8 } = await import("fs/promises");
|
|
7939
7973
|
const runs = await readdir8(runsDir).catch(() => []);
|
|
7940
7974
|
for (const run of runs.sort().reverse()) {
|
|
7941
|
-
const progressPath =
|
|
7975
|
+
const progressPath = join38(runsDir, run, "progress.json");
|
|
7942
7976
|
try {
|
|
7943
7977
|
const raw = await readFile18(progressPath, "utf8");
|
|
7944
7978
|
const progress = JSON.parse(raw);
|
|
@@ -8136,8 +8170,8 @@ var PentestWorkflow = class {
|
|
|
8136
8170
|
await this.tracker.save(options.projectRoot, progress);
|
|
8137
8171
|
const docs = await loadModuleDocs(options.projectRoot, focusModules);
|
|
8138
8172
|
const tests = await loadTests(options.projectRoot, focusModules);
|
|
8139
|
-
const docsPath =
|
|
8140
|
-
const testsPath =
|
|
8173
|
+
const docsPath = join39(artifactsDir, "docs-summary.json");
|
|
8174
|
+
const testsPath = join39(artifactsDir, "tests-summary.json");
|
|
8141
8175
|
await writeJson(docsPath, docs);
|
|
8142
8176
|
await writeJson(
|
|
8143
8177
|
testsPath,
|
|
@@ -8238,7 +8272,7 @@ var PentestWorkflow = class {
|
|
|
8238
8272
|
progressRunId: progress.run_id,
|
|
8239
8273
|
reportTimestamp: new Date(progress.started_at)
|
|
8240
8274
|
});
|
|
8241
|
-
const findingIndexPath =
|
|
8275
|
+
const findingIndexPath = join39(
|
|
8242
8276
|
options.projectRoot,
|
|
8243
8277
|
PATHS.PENTEST_RUNS_DIR,
|
|
8244
8278
|
progress.run_id,
|
|
@@ -8255,7 +8289,7 @@ var PentestWorkflow = class {
|
|
|
8255
8289
|
}
|
|
8256
8290
|
if (report === null) {
|
|
8257
8291
|
const existingSidecar = progress.sidecar_path ? await readJsonIfExists(
|
|
8258
|
-
|
|
8292
|
+
join39(options.projectRoot, progress.sidecar_path)
|
|
8259
8293
|
) : null;
|
|
8260
8294
|
report = existingSidecar;
|
|
8261
8295
|
}
|
|
@@ -8270,18 +8304,18 @@ var PentestWorkflow = class {
|
|
|
8270
8304
|
this.tracker.markStepRunning(progress, "write-report", writeHash);
|
|
8271
8305
|
await this.tracker.save(options.projectRoot, progress);
|
|
8272
8306
|
await writeJson(
|
|
8273
|
-
|
|
8307
|
+
join39(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "report-preview.json"),
|
|
8274
8308
|
{ report_id: report.report_id, findings: report.findings.length }
|
|
8275
8309
|
);
|
|
8276
|
-
await writeJson(
|
|
8310
|
+
await writeJson(join39(options.projectRoot, report.sidecar_path), report);
|
|
8277
8311
|
await writeJson(
|
|
8278
|
-
|
|
8312
|
+
join39(options.projectRoot, PATHS.PENTEST_RUNS_DIR, progress.run_id, "blocked-checks.json"),
|
|
8279
8313
|
report.blocked_checks
|
|
8280
8314
|
);
|
|
8281
|
-
await mkdir13(
|
|
8315
|
+
await mkdir13(join39(options.projectRoot, PATHS.PENTEST_DIR), { recursive: true });
|
|
8282
8316
|
const markdown = buildPentestMarkdown(report);
|
|
8283
|
-
await writeJson(
|
|
8284
|
-
await writeFile13(
|
|
8317
|
+
await writeJson(join39(options.projectRoot, report.sidecar_path), report);
|
|
8318
|
+
await writeFile13(join39(options.projectRoot, report.report_path), markdown);
|
|
8285
8319
|
this.tracker.markStepCompleted(
|
|
8286
8320
|
progress,
|
|
8287
8321
|
"write-report",
|
|
@@ -8308,7 +8342,7 @@ async function buildCurrentPentestReport(input) {
|
|
|
8308
8342
|
const docs = await loadModuleDocs(input.projectRoot, input.focusModules);
|
|
8309
8343
|
const tests = await loadTests(input.projectRoot, input.focusModules);
|
|
8310
8344
|
const osvFindings = await queryOsv(input.snapshot.packages);
|
|
8311
|
-
const osvPath =
|
|
8345
|
+
const osvPath = join39(input.artifactsDir, "dependencies", "osv-results.json");
|
|
8312
8346
|
await writeJson(osvPath, osvFindings);
|
|
8313
8347
|
const dependencyFindings = await buildDependencyFindings(
|
|
8314
8348
|
input.snapshot,
|
|
@@ -8317,7 +8351,7 @@ async function buildCurrentPentestReport(input) {
|
|
|
8317
8351
|
);
|
|
8318
8352
|
const moduleFindings = buildModuleFindings(docs, tests);
|
|
8319
8353
|
const secretFindings = await buildSecretFindings(input.artifactsDir);
|
|
8320
|
-
const runtimePayload = await readJsonIfExists(
|
|
8354
|
+
const runtimePayload = await readJsonIfExists(join39(input.artifactsDir, "runtime", "runtime-checks.json"));
|
|
8321
8355
|
const runtimeStatus = input.targetUrl ? runtimePayload?.reachable ? {
|
|
8322
8356
|
target_url: input.targetUrl,
|
|
8323
8357
|
status: "reachable",
|
|
@@ -8343,8 +8377,8 @@ async function buildCurrentPentestReport(input) {
|
|
|
8343
8377
|
...runtimeFindings
|
|
8344
8378
|
]);
|
|
8345
8379
|
const timestamp = toLocalTimestamp(input.reportTimestamp);
|
|
8346
|
-
const reportPath =
|
|
8347
|
-
const sidecarPath =
|
|
8380
|
+
const reportPath = join39(PATHS.PENTEST_DIR, `${timestamp}.md`);
|
|
8381
|
+
const sidecarPath = join39(PATHS.PENTEST_DIR, `${timestamp}.json`);
|
|
8348
8382
|
const stack = getPrimaryStack({
|
|
8349
8383
|
routing: { domain: "coding" },
|
|
8350
8384
|
stack_profile: input.snapshot.profile
|
|
@@ -8397,9 +8431,9 @@ async function buildCurrentPentestReport(input) {
|
|
|
8397
8431
|
raw_evidence_paths: [
|
|
8398
8432
|
relative7(input.projectRoot, osvPath),
|
|
8399
8433
|
...[
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8434
|
+
join39(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "finding-index.json"),
|
|
8435
|
+
join39(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "docs-summary.json"),
|
|
8436
|
+
join39(PATHS.PENTEST_RUNS_DIR, input.progressRunId, "artifacts", "tests-summary.json")
|
|
8403
8437
|
]
|
|
8404
8438
|
]
|
|
8405
8439
|
};
|
|
@@ -8439,7 +8473,7 @@ var PentestPhase = class {
|
|
|
8439
8473
|
|
|
8440
8474
|
// src/workflows/pentest-retest.ts
|
|
8441
8475
|
import { mkdir as mkdir14, writeFile as writeFile14 } from "fs/promises";
|
|
8442
|
-
import { dirname as
|
|
8476
|
+
import { dirname as dirname18, join as join40 } from "path";
|
|
8443
8477
|
var RETEST_STEPS = [
|
|
8444
8478
|
{ id: "load-source-report", title: "Load source pentest report" },
|
|
8445
8479
|
{ id: "rerun-evidence", title: "Collect fresh evidence for source findings" },
|
|
@@ -8460,7 +8494,7 @@ var PentestRetestWorkflow = class {
|
|
|
8460
8494
|
}
|
|
8461
8495
|
const normalizedSourcePath = normalizeSidecarPath(sourceReportPath);
|
|
8462
8496
|
const sourceSidecar = await readJsonIfExists(
|
|
8463
|
-
|
|
8497
|
+
join40(options.projectRoot, normalizedSourcePath)
|
|
8464
8498
|
);
|
|
8465
8499
|
if (sourceSidecar === null) {
|
|
8466
8500
|
throw new Error(`Source pentest sidecar not found at ${normalizedSourcePath}`);
|
|
@@ -8485,12 +8519,12 @@ var PentestRetestWorkflow = class {
|
|
|
8485
8519
|
if (!this.tracker.shouldSkipStep(progress, "load-source-report", sourceHash)) {
|
|
8486
8520
|
this.tracker.markStepRunning(progress, "load-source-report", sourceHash);
|
|
8487
8521
|
await this.tracker.save(options.projectRoot, progress);
|
|
8488
|
-
const sourceCopy =
|
|
8522
|
+
const sourceCopy = join40(artifactsDir, "source-report.json");
|
|
8489
8523
|
await writeJson(sourceCopy, sourceSidecar);
|
|
8490
8524
|
this.tracker.markStepCompleted(
|
|
8491
8525
|
progress,
|
|
8492
8526
|
"load-source-report",
|
|
8493
|
-
[
|
|
8527
|
+
[join40(PATHS.PENTEST_RUNS_DIR, progress.run_id, "artifacts", "source-report.json")],
|
|
8494
8528
|
[...RETEST_SKILLS.source].map(skillPath)
|
|
8495
8529
|
);
|
|
8496
8530
|
await this.tracker.save(options.projectRoot, progress);
|
|
@@ -8507,7 +8541,7 @@ var PentestRetestWorkflow = class {
|
|
|
8507
8541
|
PENTEST_RUN_ID: progress.run_id,
|
|
8508
8542
|
PENTEST_ARTIFACT_DIR: artifactsDir,
|
|
8509
8543
|
PENTEST_TARGET_URL: targetUrl ?? "",
|
|
8510
|
-
PENTEST_SOURCE_REPORT:
|
|
8544
|
+
PENTEST_SOURCE_REPORT: join40(options.projectRoot, normalizedSourcePath),
|
|
8511
8545
|
PENTEST_DB_CONNECTION_NAME: options.dbConnectionName ?? ""
|
|
8512
8546
|
};
|
|
8513
8547
|
const scriptResults = await Promise.all([
|
|
@@ -8556,8 +8590,8 @@ var PentestRetestWorkflow = class {
|
|
|
8556
8590
|
...currentReport,
|
|
8557
8591
|
report_id: toReportId("RETEST", new Date(progress.started_at)),
|
|
8558
8592
|
workflow: "pentest-retest",
|
|
8559
|
-
report_path:
|
|
8560
|
-
sidecar_path:
|
|
8593
|
+
report_path: join40(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.md`),
|
|
8594
|
+
sidecar_path: join40(PATHS.PENTEST_RETEST_DIR, `${timestamp}-${sourceSlug}.json`),
|
|
8561
8595
|
source_report_path: normalizedSourcePath,
|
|
8562
8596
|
source_report_id: sourceSidecar.report_id,
|
|
8563
8597
|
findings: retestFindings,
|
|
@@ -8570,7 +8604,7 @@ var PentestRetestWorkflow = class {
|
|
|
8570
8604
|
...[...RETEST_SKILLS.source, ...RETEST_SKILLS.evaluate].map(skillPath)
|
|
8571
8605
|
]
|
|
8572
8606
|
};
|
|
8573
|
-
const findingIndexPath =
|
|
8607
|
+
const findingIndexPath = join40(
|
|
8574
8608
|
options.projectRoot,
|
|
8575
8609
|
PATHS.PENTEST_RUNS_DIR,
|
|
8576
8610
|
progress.run_id,
|
|
@@ -8580,14 +8614,14 @@ var PentestRetestWorkflow = class {
|
|
|
8580
8614
|
this.tracker.markStepCompleted(
|
|
8581
8615
|
progress,
|
|
8582
8616
|
"evaluate-source-findings",
|
|
8583
|
-
[
|
|
8617
|
+
[join40(PATHS.PENTEST_RUNS_DIR, progress.run_id, "finding-index.json")],
|
|
8584
8618
|
[...RETEST_SKILLS.evaluate].map(skillPath)
|
|
8585
8619
|
);
|
|
8586
8620
|
await this.tracker.save(options.projectRoot, progress);
|
|
8587
8621
|
}
|
|
8588
8622
|
if (retestReport === null) {
|
|
8589
8623
|
const existing = progress.sidecar_path ? await readJsonIfExists(
|
|
8590
|
-
|
|
8624
|
+
join40(options.projectRoot, progress.sidecar_path)
|
|
8591
8625
|
) : null;
|
|
8592
8626
|
retestReport = existing;
|
|
8593
8627
|
}
|
|
@@ -8601,12 +8635,12 @@ var PentestRetestWorkflow = class {
|
|
|
8601
8635
|
if (!this.tracker.shouldSkipStep(progress, "write-report", writeHash)) {
|
|
8602
8636
|
this.tracker.markStepRunning(progress, "write-report", writeHash);
|
|
8603
8637
|
await this.tracker.save(options.projectRoot, progress);
|
|
8604
|
-
await writeJson(
|
|
8605
|
-
await mkdir14(
|
|
8638
|
+
await writeJson(join40(options.projectRoot, retestReport.sidecar_path), retestReport);
|
|
8639
|
+
await mkdir14(dirname18(join40(options.projectRoot, retestReport.report_path)), {
|
|
8606
8640
|
recursive: true
|
|
8607
8641
|
});
|
|
8608
8642
|
await writeFile14(
|
|
8609
|
-
|
|
8643
|
+
join40(options.projectRoot, retestReport.report_path),
|
|
8610
8644
|
buildPentestMarkdown(retestReport)
|
|
8611
8645
|
);
|
|
8612
8646
|
this.tracker.markStepCompleted(
|
|
@@ -8684,7 +8718,7 @@ var ProjectQuestionPhase = class {
|
|
|
8684
8718
|
|
|
8685
8719
|
// src/workflows/root-cause-analysis.ts
|
|
8686
8720
|
import { mkdir as mkdir15, writeFile as writeFile15 } from "fs/promises";
|
|
8687
|
-
import { dirname as
|
|
8721
|
+
import { dirname as dirname19, join as join41 } from "path";
|
|
8688
8722
|
var DEFAULT_TITLE_SLUG = "root-cause-analysis";
|
|
8689
8723
|
var RCA_SECTIONS = [
|
|
8690
8724
|
"Summary",
|
|
@@ -8703,9 +8737,9 @@ var RootCauseAnalysisWorkflow = class {
|
|
|
8703
8737
|
async run(options) {
|
|
8704
8738
|
const title = deriveTitle(options.classification.request_text);
|
|
8705
8739
|
const filename = `${toLocalTimestamp2(/* @__PURE__ */ new Date())}-${slugify2(title) || DEFAULT_TITLE_SLUG}.md`;
|
|
8706
|
-
const relativePath =
|
|
8707
|
-
const outputPath =
|
|
8708
|
-
await mkdir15(
|
|
8740
|
+
const relativePath = join41(PATHS.RCA_DIR, filename);
|
|
8741
|
+
const outputPath = join41(options.projectRoot, relativePath);
|
|
8742
|
+
await mkdir15(dirname19(outputPath), { recursive: true });
|
|
8709
8743
|
await writeFile15(outputPath, buildRcaDocument(title, options.classification));
|
|
8710
8744
|
return {
|
|
8711
8745
|
output_path: relativePath,
|
|
@@ -8853,22 +8887,22 @@ var DEFAULT_PHASES = {
|
|
|
8853
8887
|
|
|
8854
8888
|
// src/pipeline/stream-truncator.ts
|
|
8855
8889
|
import { appendFile, mkdir as mkdir17 } from "fs/promises";
|
|
8856
|
-
import { join as
|
|
8890
|
+
import { join as join43, dirname as dirname21 } from "path";
|
|
8857
8891
|
|
|
8858
8892
|
// src/resolver/deduplicator.ts
|
|
8859
8893
|
import { createHash as createHash9 } from "crypto";
|
|
8860
8894
|
import { readFile as readFile19, writeFile as writeFile17, mkdir as mkdir18 } from "fs/promises";
|
|
8861
|
-
import { join as
|
|
8895
|
+
import { join as join44, dirname as dirname22 } from "path";
|
|
8862
8896
|
|
|
8863
8897
|
// src/scripts/generator.ts
|
|
8864
8898
|
import { chmodSync as chmodSync2 } from "fs";
|
|
8865
8899
|
import { mkdir as mkdir19, writeFile as writeFile18 } from "fs/promises";
|
|
8866
|
-
import { dirname as
|
|
8900
|
+
import { dirname as dirname23, join as join45 } from "path";
|
|
8867
8901
|
|
|
8868
8902
|
// src/skills/cache-manager.ts
|
|
8869
8903
|
import { createHash as createHash10 } from "crypto";
|
|
8870
8904
|
import { mkdir as mkdir20, readFile as readFile20, readdir as readdir5, rm as rm2, stat as stat3, writeFile as writeFile19 } from "fs/promises";
|
|
8871
|
-
import { join as
|
|
8905
|
+
import { join as join46 } from "path";
|
|
8872
8906
|
import fg6 from "fast-glob";
|
|
8873
8907
|
|
|
8874
8908
|
// src/skills/frontmatter-parser.ts
|
|
@@ -8893,7 +8927,7 @@ var conditionalProcessor = new ConditionalSectionProcessor();
|
|
|
8893
8927
|
|
|
8894
8928
|
// src/skills/index-generator.ts
|
|
8895
8929
|
import { mkdir as mkdir21, readFile as readFile21, writeFile as writeFile20 } from "fs/promises";
|
|
8896
|
-
import { dirname as
|
|
8930
|
+
import { dirname as dirname24, join as join47, relative as relative8 } from "path";
|
|
8897
8931
|
import fg7 from "fast-glob";
|
|
8898
8932
|
|
|
8899
8933
|
// src/skills/loader.ts
|
|
@@ -8901,16 +8935,16 @@ import { readFile as readFile22 } from "fs/promises";
|
|
|
8901
8935
|
import { basename as basename6 } from "pathe";
|
|
8902
8936
|
|
|
8903
8937
|
// src/update/updater.ts
|
|
8904
|
-
import { chmodSync as chmodSync3, existsSync as
|
|
8938
|
+
import { chmodSync as chmodSync3, existsSync as existsSync19, mkdirSync as mkdirSync6, readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "fs";
|
|
8905
8939
|
import { mkdtemp, readdir as readdir6, readFile as readFile23, rm as rm3 } from "fs/promises";
|
|
8906
8940
|
import { tmpdir } from "os";
|
|
8907
|
-
import { dirname as
|
|
8941
|
+
import { dirname as dirname25, join as join48, relative as relative9 } from "path";
|
|
8908
8942
|
var FrameworkUpdater = class {
|
|
8909
8943
|
constructor(options = {}) {
|
|
8910
8944
|
this.options = options;
|
|
8911
8945
|
}
|
|
8912
8946
|
async run(projectRoot) {
|
|
8913
|
-
const previousVersion = readText(
|
|
8947
|
+
const previousVersion = readText(join48(projectRoot, PATHS.FRAMEWORK_VERSION));
|
|
8914
8948
|
const manifest = readManifest(projectRoot);
|
|
8915
8949
|
const artifactPolicy = new Map(
|
|
8916
8950
|
manifest?.generated_artifacts.map((artifact) => [artifact.path, artifact.auto_update]) ?? []
|
|
@@ -8920,19 +8954,19 @@ var FrameworkUpdater = class {
|
|
|
8920
8954
|
const skipped = [];
|
|
8921
8955
|
const newScripts = [];
|
|
8922
8956
|
for (const candidate of candidates) {
|
|
8923
|
-
const target =
|
|
8924
|
-
const existed =
|
|
8957
|
+
const target = join48(projectRoot, candidate.path);
|
|
8958
|
+
const existed = existsSync19(target);
|
|
8925
8959
|
const autoUpdate = artifactPolicy.get(candidate.path) ?? candidate.autoUpdate;
|
|
8926
8960
|
if (existed && autoUpdate === false) {
|
|
8927
8961
|
skipped.push({
|
|
8928
8962
|
path: candidate.path,
|
|
8929
|
-
before:
|
|
8963
|
+
before: readFileSync12(target, "utf8"),
|
|
8930
8964
|
after: candidate.content
|
|
8931
8965
|
});
|
|
8932
8966
|
continue;
|
|
8933
8967
|
}
|
|
8934
|
-
mkdirSync6(
|
|
8935
|
-
|
|
8968
|
+
mkdirSync6(dirname25(target), { recursive: true });
|
|
8969
|
+
writeFileSync6(target, candidate.content);
|
|
8936
8970
|
if (candidate.executable === true) {
|
|
8937
8971
|
chmodSync3(target, 493);
|
|
8938
8972
|
}
|
|
@@ -8941,8 +8975,8 @@ var FrameworkUpdater = class {
|
|
|
8941
8975
|
newScripts.push(candidate.path);
|
|
8942
8976
|
}
|
|
8943
8977
|
}
|
|
8944
|
-
mkdirSync6(
|
|
8945
|
-
|
|
8978
|
+
mkdirSync6(dirname25(join48(projectRoot, PATHS.FRAMEWORK_VERSION)), { recursive: true });
|
|
8979
|
+
writeFileSync6(join48(projectRoot, PATHS.FRAMEWORK_VERSION), `${VERSION}
|
|
8946
8980
|
`);
|
|
8947
8981
|
return {
|
|
8948
8982
|
previous_version: previousVersion,
|
|
@@ -8962,7 +8996,7 @@ var FrameworkUpdater = class {
|
|
|
8962
8996
|
if (profile === null) {
|
|
8963
8997
|
throw new Error("Cannot update framework-managed artifacts without a project profile");
|
|
8964
8998
|
}
|
|
8965
|
-
const tempRoot = await mkdtemp(
|
|
8999
|
+
const tempRoot = await mkdtemp(join48(tmpdir(), "paqad-ai-update-"));
|
|
8966
9000
|
try {
|
|
8967
9001
|
const result = await new OnboardingOrchestrator().run({
|
|
8968
9002
|
projectRoot: tempRoot,
|
|
@@ -8982,27 +9016,27 @@ var FrameworkUpdater = class {
|
|
|
8982
9016
|
}
|
|
8983
9017
|
};
|
|
8984
9018
|
function readManifest(projectRoot) {
|
|
8985
|
-
const path =
|
|
8986
|
-
if (!
|
|
9019
|
+
const path = join48(projectRoot, PATHS.ONBOARDING_MANIFEST);
|
|
9020
|
+
if (!existsSync19(path)) {
|
|
8987
9021
|
return null;
|
|
8988
9022
|
}
|
|
8989
|
-
return JSON.parse(
|
|
9023
|
+
return JSON.parse(readFileSync12(path, "utf8"));
|
|
8990
9024
|
}
|
|
8991
9025
|
function readProfile(projectRoot) {
|
|
8992
9026
|
return readProjectProfile(projectRoot);
|
|
8993
9027
|
}
|
|
8994
9028
|
function readText(path) {
|
|
8995
|
-
if (!
|
|
9029
|
+
if (!existsSync19(path)) {
|
|
8996
9030
|
return null;
|
|
8997
9031
|
}
|
|
8998
|
-
return
|
|
9032
|
+
return readFileSync12(path, "utf8").trim();
|
|
8999
9033
|
}
|
|
9000
9034
|
async function collectFiles(root, generated) {
|
|
9001
9035
|
const paths = generated.length > 0 ? generated : await walk3(root);
|
|
9002
9036
|
return Promise.all(
|
|
9003
9037
|
paths.map(async (file) => ({
|
|
9004
9038
|
path: file,
|
|
9005
|
-
content: await readFile23(
|
|
9039
|
+
content: await readFile23(join48(root, file), "utf8"),
|
|
9006
9040
|
autoUpdate: true,
|
|
9007
9041
|
executable: file.startsWith("scripts/")
|
|
9008
9042
|
}))
|
|
@@ -9012,7 +9046,7 @@ async function walk3(root, current = root) {
|
|
|
9012
9046
|
const entries = await readdir6(current, { withFileTypes: true });
|
|
9013
9047
|
const files = [];
|
|
9014
9048
|
for (const entry of entries) {
|
|
9015
|
-
const absolute =
|
|
9049
|
+
const absolute = join48(current, entry.name);
|
|
9016
9050
|
if (entry.isDirectory()) {
|
|
9017
9051
|
files.push(...await walk3(root, absolute));
|
|
9018
9052
|
continue;
|
|
@@ -9023,31 +9057,31 @@ async function walk3(root, current = root) {
|
|
|
9023
9057
|
}
|
|
9024
9058
|
|
|
9025
9059
|
// src/verification/gates/documentation-freshness.ts
|
|
9026
|
-
import { existsSync as
|
|
9027
|
-
import { join as
|
|
9060
|
+
import { existsSync as existsSync20 } from "fs";
|
|
9061
|
+
import { join as join49 } from "path";
|
|
9028
9062
|
var STALENESS_WINDOW_MS2 = 1e3 * 60 * 60 * 24 * 7;
|
|
9029
9063
|
|
|
9030
9064
|
// src/patterns/pattern-store.ts
|
|
9031
9065
|
import { readFile as readFile24, writeFile as writeFile21, mkdir as mkdir22, unlink } from "fs/promises";
|
|
9032
|
-
import { join as
|
|
9066
|
+
import { join as join50, dirname as dirname26 } from "path";
|
|
9033
9067
|
import { homedir as homedir3 } from "os";
|
|
9034
|
-
var GLOBAL_PATTERNS_DIR =
|
|
9068
|
+
var GLOBAL_PATTERNS_DIR = join50(homedir3(), ".paqad", "patterns");
|
|
9035
9069
|
var PatternStore = class {
|
|
9036
9070
|
get indexPath() {
|
|
9037
|
-
return
|
|
9071
|
+
return join50(GLOBAL_PATTERNS_DIR, "index.json");
|
|
9038
9072
|
}
|
|
9039
9073
|
get entriesDir() {
|
|
9040
|
-
return
|
|
9074
|
+
return join50(GLOBAL_PATTERNS_DIR, "entries");
|
|
9041
9075
|
}
|
|
9042
9076
|
async save(pattern) {
|
|
9043
9077
|
await mkdir22(this.entriesDir, { recursive: true });
|
|
9044
|
-
const entryPath =
|
|
9078
|
+
const entryPath = join50(this.entriesDir, `${pattern.id}.json`);
|
|
9045
9079
|
await writeFile21(entryPath, JSON.stringify(pattern, null, 2), "utf8");
|
|
9046
9080
|
await this.updateIndex(pattern);
|
|
9047
9081
|
}
|
|
9048
9082
|
async load(id) {
|
|
9049
9083
|
try {
|
|
9050
|
-
const raw = await readFile24(
|
|
9084
|
+
const raw = await readFile24(join50(this.entriesDir, `${id}.json`), "utf8");
|
|
9051
9085
|
return JSON.parse(raw);
|
|
9052
9086
|
} catch {
|
|
9053
9087
|
return null;
|
|
@@ -9077,12 +9111,12 @@ var PatternStore = class {
|
|
|
9077
9111
|
} else {
|
|
9078
9112
|
index.entries.push(entry);
|
|
9079
9113
|
}
|
|
9080
|
-
await mkdir22(
|
|
9114
|
+
await mkdir22(dirname26(this.indexPath), { recursive: true });
|
|
9081
9115
|
await writeFile21(this.indexPath, JSON.stringify(index, null, 2), "utf8");
|
|
9082
9116
|
}
|
|
9083
9117
|
async delete(id) {
|
|
9084
9118
|
try {
|
|
9085
|
-
await unlink(
|
|
9119
|
+
await unlink(join50(this.entriesDir, `${id}.json`));
|
|
9086
9120
|
} catch {
|
|
9087
9121
|
}
|
|
9088
9122
|
const index = await this.loadIndex();
|
|
@@ -9182,12 +9216,12 @@ ${p.solution}
|
|
|
9182
9216
|
|
|
9183
9217
|
// src/workflows/template-loader.ts
|
|
9184
9218
|
import { readFile as readFile25, readdir as readdir7 } from "fs/promises";
|
|
9185
|
-
import { join as
|
|
9219
|
+
import { join as join51 } from "path";
|
|
9186
9220
|
import YAML6 from "yaml";
|
|
9187
9221
|
|
|
9188
9222
|
// src/workflows/engine.ts
|
|
9189
9223
|
import { readFile as readFile26, writeFile as writeFile23, mkdir as mkdir23 } from "fs/promises";
|
|
9190
|
-
import { join as
|
|
9224
|
+
import { join as join52, dirname as dirname27 } from "path";
|
|
9191
9225
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
9192
9226
|
|
|
9193
9227
|
// src/index.ts
|
|
@@ -9367,8 +9401,8 @@ function createPacksCommand() {
|
|
|
9367
9401
|
|
|
9368
9402
|
// src/cli/commands/refresh.ts
|
|
9369
9403
|
import { Command as Command7 } from "commander";
|
|
9370
|
-
import { readFileSync as
|
|
9371
|
-
import { join as
|
|
9404
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "fs";
|
|
9405
|
+
import { join as join53 } from "path";
|
|
9372
9406
|
function createRefreshCommand() {
|
|
9373
9407
|
return new Command7("refresh").description("Refresh derived framework artifacts").option("--project-root <path>", "Project root", process.cwd()).option("--design-system", "Refresh design-system markdown from design tokens").option("--stack", "Refresh the cached stack snapshot").action(async (options) => {
|
|
9374
9408
|
const shouldRefreshDesignSystem = options.designSystem ?? true;
|
|
@@ -9404,14 +9438,14 @@ function createRefreshCommand() {
|
|
|
9404
9438
|
});
|
|
9405
9439
|
}
|
|
9406
9440
|
function writeRefreshDrift(projectRoot, refreshDrift) {
|
|
9407
|
-
const path =
|
|
9441
|
+
const path = join53(projectRoot, PATHS.STACK_DRIFT);
|
|
9408
9442
|
const current = readExistingJson(path);
|
|
9409
|
-
|
|
9443
|
+
writeFileSync7(path, `${JSON.stringify({ ...current ?? {}, ...refreshDrift }, null, 2)}
|
|
9410
9444
|
`);
|
|
9411
9445
|
}
|
|
9412
9446
|
function readExistingJson(path) {
|
|
9413
9447
|
try {
|
|
9414
|
-
return JSON.parse(
|
|
9448
|
+
return JSON.parse(readFileSync13(path, "utf8"));
|
|
9415
9449
|
} catch {
|
|
9416
9450
|
return null;
|
|
9417
9451
|
}
|