@hasna/instructions 0.4.14 → 0.4.16
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 +80 -28
- package/dist/index.js +71 -20
- package/dist/lib/apply-secret-placeholder-guard.test.d.ts +2 -0
- package/dist/lib/apply-secret-placeholder-guard.test.d.ts.map +1 -0
- package/dist/lib/apply-text-format-credential-guard.test.d.ts +2 -0
- package/dist/lib/apply-text-format-credential-guard.test.d.ts.map +1 -0
- package/dist/lib/apply.d.ts +1 -1
- package/dist/lib/apply.d.ts.map +1 -1
- package/dist/lib/redact.d.ts +24 -0
- package/dist/lib/redact.d.ts.map +1 -1
- package/dist/lib/sync.d.ts.map +1 -1
- package/dist/mcp/index.js +76 -25
- package/package.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -2641,9 +2641,6 @@ function templateizeMachineContent(content, machine) {
|
|
|
2641
2641
|
next = next.replace(/~\/workspace/g, "{{WORKSPACE_ROOT}}").replace(/~\/Workspace/g, "{{WORKSPACE_ROOT}}").replace(/\/opt\/homebrew\/bin\/bun/g, "{{BUN_PATH}}");
|
|
2642
2642
|
return { content: next, changed: next !== content };
|
|
2643
2643
|
}
|
|
2644
|
-
function renderMachineAwareContent(content, variables) {
|
|
2645
|
-
return isTemplate(content) ? renderTemplate(content, variables) : content;
|
|
2646
|
-
}
|
|
2647
2644
|
function renderMachineAwareContentPreview(content, variables) {
|
|
2648
2645
|
return isTemplate(content) ? renderTemplatePreview(content, variables) : { content, unresolved: [] };
|
|
2649
2646
|
}
|
|
@@ -7532,6 +7529,14 @@ function reasonFor(key, value) {
|
|
|
7532
7529
|
function isReferenceValue(value) {
|
|
7533
7530
|
return /^\{\{[A-Z][A-Z0-9_]*\}\}$/.test(value) || /^\$\{[A-Z][A-Z0-9_]*\}$/.test(value) || /^\$[A-Z][A-Z0-9_]*$/.test(value) || /^%[A-Z][A-Z0-9_]*%$/.test(value);
|
|
7534
7531
|
}
|
|
7532
|
+
function redactFormatForTarget(targetPath, storedFormat) {
|
|
7533
|
+
const p = targetPath.toLowerCase();
|
|
7534
|
+
if (/(^|\/)\.(zshrc|zprofile|bashrc|bash_profile|profile|zshenv|env)$/.test(p) || p.endsWith(".env"))
|
|
7535
|
+
return "shell";
|
|
7536
|
+
if (/(^|\/)\.(npmrc|yarnrc|curlrc|netrc)$/.test(p))
|
|
7537
|
+
return "ini";
|
|
7538
|
+
return storedFormat;
|
|
7539
|
+
}
|
|
7535
7540
|
function redactContent(content, format) {
|
|
7536
7541
|
switch (format) {
|
|
7537
7542
|
case "shell":
|
|
@@ -11577,8 +11582,9 @@ function normalizeTargetPath(p) {
|
|
|
11577
11582
|
}
|
|
11578
11583
|
}
|
|
11579
11584
|
async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
|
|
11580
|
-
const
|
|
11581
|
-
const
|
|
11585
|
+
const variables = opts.vars ?? {};
|
|
11586
|
+
const renderedTarget = renderForApply(targetPath, variables);
|
|
11587
|
+
const rendered = renderForApply(content, variables);
|
|
11582
11588
|
const renderedTargetPath = renderedTarget.content;
|
|
11583
11589
|
const renderedContent = rendered.content;
|
|
11584
11590
|
const targetAgent = meta.agent ?? config.agent;
|
|
@@ -11617,13 +11623,42 @@ async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
|
|
|
11617
11623
|
...meta
|
|
11618
11624
|
};
|
|
11619
11625
|
}
|
|
11620
|
-
function renderForApply(content, variables
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11624
|
-
|
|
11625
|
-
|
|
11626
|
-
|
|
11626
|
+
function renderForApply(content, variables) {
|
|
11627
|
+
return renderMachineAwareContentPreview(content, variables);
|
|
11628
|
+
}
|
|
11629
|
+
function wouldDestroyACredential(targetPath, renderedContent, format) {
|
|
11630
|
+
const secretTokens = parseTemplateVars(renderedContent).filter(isSecretVarName);
|
|
11631
|
+
if (secretTokens.length === 0)
|
|
11632
|
+
return [];
|
|
11633
|
+
let current;
|
|
11634
|
+
try {
|
|
11635
|
+
const path = expandPath(targetPath);
|
|
11636
|
+
if (!existsSync7(path))
|
|
11637
|
+
return [];
|
|
11638
|
+
current = readFileSync4(path, "utf-8");
|
|
11639
|
+
} catch {
|
|
11640
|
+
return secretTokens;
|
|
11641
|
+
}
|
|
11642
|
+
if (current === renderedContent)
|
|
11643
|
+
return [];
|
|
11644
|
+
if (scanSecrets(current, redactFormatForTarget(targetPath, format)).length > 0)
|
|
11645
|
+
return secretTokens;
|
|
11646
|
+
return secretTokens.filter((name) => countPlaceholder(current, name) < countPlaceholder(renderedContent, name));
|
|
11647
|
+
}
|
|
11648
|
+
function countPlaceholder(content, name) {
|
|
11649
|
+
return content.match(new RegExp(`\\{\\{${name}(?::[^}]*)?\\}\\}`, "g"))?.length ?? 0;
|
|
11650
|
+
}
|
|
11651
|
+
async function resolveApplyVariables(opts) {
|
|
11652
|
+
const machine = detectMachineContext();
|
|
11653
|
+
let base;
|
|
11654
|
+
try {
|
|
11655
|
+
const store = opts.store ?? resolveConfigStore();
|
|
11656
|
+
const profile = await store.resolveProfileForMachine(machine);
|
|
11657
|
+
base = resolveProfileVariables(profile, machine);
|
|
11658
|
+
} catch {
|
|
11659
|
+
base = machineContextToVariables(machine);
|
|
11660
|
+
}
|
|
11661
|
+
return { ...base, ...opts.vars ?? {} };
|
|
11627
11662
|
}
|
|
11628
11663
|
function isAntigravityRuleTarget(agent, targetPath) {
|
|
11629
11664
|
return agent === "antigravity" && /\.(md|mdc|markdown)$/i.test(targetPath);
|
|
@@ -11708,7 +11743,8 @@ async function applyConfigs(configs, opts = {}) {
|
|
|
11708
11743
|
return report.results;
|
|
11709
11744
|
}
|
|
11710
11745
|
async function applyConfigsWithReport(configs, opts = {}) {
|
|
11711
|
-
const
|
|
11746
|
+
const effective = { ...opts, vars: await resolveApplyVariables(opts) };
|
|
11747
|
+
const prepared = prepareConfigBatch(configs, effective);
|
|
11712
11748
|
if (prepared.failures.length > 0) {
|
|
11713
11749
|
return {
|
|
11714
11750
|
results: [],
|
|
@@ -11722,7 +11758,7 @@ async function applyConfigsWithReport(configs, opts = {}) {
|
|
|
11722
11758
|
if (config.kind === "reference" || isRetiredOrUnsupportedConfigAgent(config.agent))
|
|
11723
11759
|
continue;
|
|
11724
11760
|
try {
|
|
11725
|
-
results.push(await applyPreparedConfig(config,
|
|
11761
|
+
results.push(await applyPreparedConfig(config, effective));
|
|
11726
11762
|
} catch (error) {
|
|
11727
11763
|
failures.push({
|
|
11728
11764
|
config_id: config.id,
|
|
@@ -11762,7 +11798,27 @@ function prepareConfigBatch(configs, opts) {
|
|
|
11762
11798
|
}
|
|
11763
11799
|
return false;
|
|
11764
11800
|
});
|
|
11765
|
-
const
|
|
11801
|
+
const renderSafeConfigs = activeConfigs.filter((config) => {
|
|
11802
|
+
const behavior = canonicalConfigApplyBehavior(config, opts, activeConfigs);
|
|
11803
|
+
const targets = [
|
|
11804
|
+
...behavior.primary ? [{ path: behavior.primary.path, content: behavior.primary.content }] : [],
|
|
11805
|
+
...behavior.outputs.map((output) => ({ path: output.path, content: output.content }))
|
|
11806
|
+
];
|
|
11807
|
+
const blocked = [...new Set(targets.flatMap((target) => wouldDestroyACredential(target.path, target.content, config.format)))].sort();
|
|
11808
|
+
if (blocked.length === 0)
|
|
11809
|
+
return true;
|
|
11810
|
+
for (const target of targets) {
|
|
11811
|
+
skipped.push({
|
|
11812
|
+
config_id: config.id,
|
|
11813
|
+
config_slug: config.slug,
|
|
11814
|
+
path: target.path,
|
|
11815
|
+
owner: "unresolved-secret-placeholder",
|
|
11816
|
+
reason: `no value for ${blocked.map((name) => `{{${name}}}`).join(", ")} and the file holds something else there; writing the placeholder would overwrite a live credential`
|
|
11817
|
+
});
|
|
11818
|
+
}
|
|
11819
|
+
return false;
|
|
11820
|
+
});
|
|
11821
|
+
const { configs: deduplicated, duplicates } = deduplicateEquivalentProfileConfigs(renderSafeConfigs, opts);
|
|
11766
11822
|
for (const duplicate of duplicates) {
|
|
11767
11823
|
for (const target of configTargets(duplicate, opts, activeConfigs)) {
|
|
11768
11824
|
skipped.push({
|
|
@@ -11914,6 +11970,8 @@ var init_apply = __esm(() => {
|
|
|
11914
11970
|
init_machine();
|
|
11915
11971
|
init_session_render();
|
|
11916
11972
|
init_session_render_ownership();
|
|
11973
|
+
init_redact();
|
|
11974
|
+
init_template();
|
|
11917
11975
|
init_transforms();
|
|
11918
11976
|
});
|
|
11919
11977
|
|
|
@@ -12304,14 +12362,6 @@ function redactionPlaceholders(storedLine) {
|
|
|
12304
12362
|
}
|
|
12305
12363
|
return found;
|
|
12306
12364
|
}
|
|
12307
|
-
function redactFormatForTarget(targetPath, storedFormat) {
|
|
12308
|
-
const p = targetPath.toLowerCase();
|
|
12309
|
-
if (/(^|\/)\.(zshrc|zprofile|bashrc|bash_profile|profile|zshenv|env)$/.test(p) || p.endsWith(".env"))
|
|
12310
|
-
return "shell";
|
|
12311
|
-
if (/(^|\/)\.(npmrc|yarnrc|curlrc|netrc)$/.test(p))
|
|
12312
|
-
return "ini";
|
|
12313
|
-
return storedFormat;
|
|
12314
|
-
}
|
|
12315
12365
|
function storedPlaceholderIsLiteralOnDisk(storedLine, diskLine) {
|
|
12316
12366
|
return redactionPlaceholders(storedLine).some((p) => !diskLine.includes(p));
|
|
12317
12367
|
}
|
|
@@ -15538,6 +15588,9 @@ program.command("apply <id>").description("Apply a config to its target_path and
|
|
|
15538
15588
|
const status = opts.dryRun ? chalk.yellow("[dry-run]") : result.primary_changed ? chalk.green("\u2713") : chalk.dim("=");
|
|
15539
15589
|
const change = result.primary_changed ? "changed" : "unchanged";
|
|
15540
15590
|
console.log(`${status} ${result.path} ${chalk.dim(`(${change})`)}`);
|
|
15591
|
+
if (result.unresolved_template_vars?.length) {
|
|
15592
|
+
console.log(` ${chalk.yellow("!")} left unexpanded: ${result.unresolved_template_vars.map((name) => `{{${name}}}`).join(", ")}` + ` ${chalk.dim("(no value for these; secret placeholders are preserved on purpose)")}`);
|
|
15593
|
+
}
|
|
15541
15594
|
for (const output of result.outputs ?? []) {
|
|
15542
15595
|
const outputStatus = opts.dryRun ? chalk.yellow("[dry-run]") : output.primary_changed ? chalk.green("\u2713") : chalk.dim("=");
|
|
15543
15596
|
const outputChange = output.primary_changed ? "changed" : "unchanged";
|
|
@@ -15818,11 +15871,10 @@ profileCmd.command("apply [id]").description("Apply all configs in a profile to
|
|
|
15818
15871
|
for (const skipped of report.skipped) {
|
|
15819
15872
|
console.log(`${chalk.dim("[owned]")} ${skipped.path} ${chalk.dim(skipped.owner)}`);
|
|
15820
15873
|
}
|
|
15821
|
-
|
|
15822
|
-
|
|
15823
|
-
|
|
15824
|
-
|
|
15825
|
-
}
|
|
15874
|
+
const unresolved = [...new Set(results.flatMap((result) => result.unresolved_template_vars ?? []))];
|
|
15875
|
+
if (unresolved.length > 0) {
|
|
15876
|
+
const where = opts.dryRun ? "would be left unexpanded" : "left unexpanded";
|
|
15877
|
+
console.log(chalk.yellow(`Unresolved secret/runtime template references ${where}: ${unresolved.join(", ")}`));
|
|
15826
15878
|
}
|
|
15827
15879
|
for (const failure of report.failures) {
|
|
15828
15880
|
console.error(chalk.red(`[failed] ${failure.config_slug}: ${failure.message}`));
|
package/dist/index.js
CHANGED
|
@@ -5494,6 +5494,14 @@ function reasonFor(key, value) {
|
|
|
5494
5494
|
function isReferenceValue(value) {
|
|
5495
5495
|
return /^\{\{[A-Z][A-Z0-9_]*\}\}$/.test(value) || /^\$\{[A-Z][A-Z0-9_]*\}$/.test(value) || /^\$[A-Z][A-Z0-9_]*$/.test(value) || /^%[A-Z][A-Z0-9_]*%$/.test(value);
|
|
5496
5496
|
}
|
|
5497
|
+
function redactFormatForTarget(targetPath, storedFormat) {
|
|
5498
|
+
const p = targetPath.toLowerCase();
|
|
5499
|
+
if (/(^|\/)\.(zshrc|zprofile|bashrc|bash_profile|profile|zshenv|env)$/.test(p) || p.endsWith(".env"))
|
|
5500
|
+
return "shell";
|
|
5501
|
+
if (/(^|\/)\.(npmrc|yarnrc|curlrc|netrc)$/.test(p))
|
|
5502
|
+
return "ini";
|
|
5503
|
+
return storedFormat;
|
|
5504
|
+
}
|
|
5497
5505
|
function redactContent(content, format) {
|
|
5498
5506
|
switch (format) {
|
|
5499
5507
|
case "shell":
|
|
@@ -9591,8 +9599,9 @@ function normalizeTargetPath(p) {
|
|
|
9591
9599
|
}
|
|
9592
9600
|
}
|
|
9593
9601
|
async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
|
|
9594
|
-
const
|
|
9595
|
-
const
|
|
9602
|
+
const variables = opts.vars ?? {};
|
|
9603
|
+
const renderedTarget = renderForApply(targetPath, variables);
|
|
9604
|
+
const rendered = renderForApply(content, variables);
|
|
9596
9605
|
const renderedTargetPath = renderedTarget.content;
|
|
9597
9606
|
const renderedContent = rendered.content;
|
|
9598
9607
|
const targetAgent = meta.agent ?? config.agent;
|
|
@@ -9631,13 +9640,42 @@ async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
|
|
|
9631
9640
|
...meta
|
|
9632
9641
|
};
|
|
9633
9642
|
}
|
|
9634
|
-
function renderForApply(content, variables
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
9638
|
-
|
|
9639
|
-
|
|
9640
|
-
|
|
9643
|
+
function renderForApply(content, variables) {
|
|
9644
|
+
return renderMachineAwareContentPreview(content, variables);
|
|
9645
|
+
}
|
|
9646
|
+
function wouldDestroyACredential(targetPath, renderedContent, format) {
|
|
9647
|
+
const secretTokens = parseTemplateVars(renderedContent).filter(isSecretVarName);
|
|
9648
|
+
if (secretTokens.length === 0)
|
|
9649
|
+
return [];
|
|
9650
|
+
let current;
|
|
9651
|
+
try {
|
|
9652
|
+
const path = expandPath(targetPath);
|
|
9653
|
+
if (!existsSync6(path))
|
|
9654
|
+
return [];
|
|
9655
|
+
current = readFileSync4(path, "utf-8");
|
|
9656
|
+
} catch {
|
|
9657
|
+
return secretTokens;
|
|
9658
|
+
}
|
|
9659
|
+
if (current === renderedContent)
|
|
9660
|
+
return [];
|
|
9661
|
+
if (scanSecrets(current, redactFormatForTarget(targetPath, format)).length > 0)
|
|
9662
|
+
return secretTokens;
|
|
9663
|
+
return secretTokens.filter((name) => countPlaceholder(current, name) < countPlaceholder(renderedContent, name));
|
|
9664
|
+
}
|
|
9665
|
+
function countPlaceholder(content, name) {
|
|
9666
|
+
return content.match(new RegExp(`\\{\\{${name}(?::[^}]*)?\\}\\}`, "g"))?.length ?? 0;
|
|
9667
|
+
}
|
|
9668
|
+
async function resolveApplyVariables(opts) {
|
|
9669
|
+
const machine = detectMachineContext();
|
|
9670
|
+
let base;
|
|
9671
|
+
try {
|
|
9672
|
+
const store = opts.store ?? resolveConfigStore();
|
|
9673
|
+
const profile = await store.resolveProfileForMachine(machine);
|
|
9674
|
+
base = resolveProfileVariables(profile, machine);
|
|
9675
|
+
} catch {
|
|
9676
|
+
base = machineContextToVariables(machine);
|
|
9677
|
+
}
|
|
9678
|
+
return { ...base, ...opts.vars ?? {} };
|
|
9641
9679
|
}
|
|
9642
9680
|
function isAntigravityRuleTarget(agent, targetPath) {
|
|
9643
9681
|
return agent === "antigravity" && /\.(md|mdc|markdown)$/i.test(targetPath);
|
|
@@ -9722,7 +9760,8 @@ async function applyConfigs(configs, opts = {}) {
|
|
|
9722
9760
|
return report.results;
|
|
9723
9761
|
}
|
|
9724
9762
|
async function applyConfigsWithReport(configs, opts = {}) {
|
|
9725
|
-
const
|
|
9763
|
+
const effective = { ...opts, vars: await resolveApplyVariables(opts) };
|
|
9764
|
+
const prepared = prepareConfigBatch(configs, effective);
|
|
9726
9765
|
if (prepared.failures.length > 0) {
|
|
9727
9766
|
return {
|
|
9728
9767
|
results: [],
|
|
@@ -9736,7 +9775,7 @@ async function applyConfigsWithReport(configs, opts = {}) {
|
|
|
9736
9775
|
if (config.kind === "reference" || isRetiredOrUnsupportedConfigAgent(config.agent))
|
|
9737
9776
|
continue;
|
|
9738
9777
|
try {
|
|
9739
|
-
results.push(await applyPreparedConfig(config,
|
|
9778
|
+
results.push(await applyPreparedConfig(config, effective));
|
|
9740
9779
|
} catch (error) {
|
|
9741
9780
|
failures.push({
|
|
9742
9781
|
config_id: config.id,
|
|
@@ -9776,7 +9815,27 @@ function prepareConfigBatch(configs, opts) {
|
|
|
9776
9815
|
}
|
|
9777
9816
|
return false;
|
|
9778
9817
|
});
|
|
9779
|
-
const
|
|
9818
|
+
const renderSafeConfigs = activeConfigs.filter((config) => {
|
|
9819
|
+
const behavior = canonicalConfigApplyBehavior(config, opts, activeConfigs);
|
|
9820
|
+
const targets = [
|
|
9821
|
+
...behavior.primary ? [{ path: behavior.primary.path, content: behavior.primary.content }] : [],
|
|
9822
|
+
...behavior.outputs.map((output) => ({ path: output.path, content: output.content }))
|
|
9823
|
+
];
|
|
9824
|
+
const blocked = [...new Set(targets.flatMap((target) => wouldDestroyACredential(target.path, target.content, config.format)))].sort();
|
|
9825
|
+
if (blocked.length === 0)
|
|
9826
|
+
return true;
|
|
9827
|
+
for (const target of targets) {
|
|
9828
|
+
skipped.push({
|
|
9829
|
+
config_id: config.id,
|
|
9830
|
+
config_slug: config.slug,
|
|
9831
|
+
path: target.path,
|
|
9832
|
+
owner: "unresolved-secret-placeholder",
|
|
9833
|
+
reason: `no value for ${blocked.map((name) => `{{${name}}}`).join(", ")} and the file holds something else there; writing the placeholder would overwrite a live credential`
|
|
9834
|
+
});
|
|
9835
|
+
}
|
|
9836
|
+
return false;
|
|
9837
|
+
});
|
|
9838
|
+
const { configs: deduplicated, duplicates } = deduplicateEquivalentProfileConfigs(renderSafeConfigs, opts);
|
|
9780
9839
|
for (const duplicate of duplicates) {
|
|
9781
9840
|
for (const target of configTargets(duplicate, opts, activeConfigs)) {
|
|
9782
9841
|
skipped.push({
|
|
@@ -11698,14 +11757,6 @@ function redactionPlaceholders(storedLine) {
|
|
|
11698
11757
|
}
|
|
11699
11758
|
return found;
|
|
11700
11759
|
}
|
|
11701
|
-
function redactFormatForTarget(targetPath, storedFormat) {
|
|
11702
|
-
const p = targetPath.toLowerCase();
|
|
11703
|
-
if (/(^|\/)\.(zshrc|zprofile|bashrc|bash_profile|profile|zshenv|env)$/.test(p) || p.endsWith(".env"))
|
|
11704
|
-
return "shell";
|
|
11705
|
-
if (/(^|\/)\.(npmrc|yarnrc|curlrc|netrc)$/.test(p))
|
|
11706
|
-
return "ini";
|
|
11707
|
-
return storedFormat;
|
|
11708
|
-
}
|
|
11709
11760
|
function storedPlaceholderIsLiteralOnDisk(storedLine, diskLine) {
|
|
11710
11761
|
return redactionPlaceholders(storedLine).some((p) => !diskLine.includes(p));
|
|
11711
11762
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-secret-placeholder-guard.test.d.ts","sourceRoot":"","sources":["../../src/lib/apply-secret-placeholder-guard.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-text-format-credential-guard.test.d.ts","sourceRoot":"","sources":["../../src/lib/apply-text-format-credential-guard.test.ts"],"names":[],"mappings":""}
|
package/dist/lib/apply.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface ConfigApplySkippedTarget {
|
|
|
23
23
|
config_id: string;
|
|
24
24
|
config_slug: string;
|
|
25
25
|
path: string;
|
|
26
|
-
owner: typeof SESSION_RENDERER_OWNER_ID | "equivalent-profile-config" | "retired-provider-config";
|
|
26
|
+
owner: typeof SESSION_RENDERER_OWNER_ID | "equivalent-profile-config" | "retired-provider-config" | "unresolved-secret-placeholder";
|
|
27
27
|
reason: string;
|
|
28
28
|
}
|
|
29
29
|
export interface ConfigApplyPreviewFailure {
|
package/dist/lib/apply.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/lib/apply.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/lib/apply.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAA8B,MAAM,mBAAmB,CAAC;AAEzF,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAQ1D,OAAO,EAGL,yBAAyB,EAC1B,MAAM,qBAAqB,CAAC;AAM7B,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK5C;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAsBrD;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9B;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,yBAAyB,GAAG,2BAA2B,GAAG,yBAAyB,GAAG,+BAA+B,CAAC;IACpI,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE,wBAAwB,EAAE,CAAC;IACpC,QAAQ,EAAE,yBAAyB,EAAE,CAAC;CACvC;AA+QD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,WAAW,CAAC,CA+BtB;AA2ED,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,WAAW,EAAE,CAAC,CAMxB;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,kBAAkB,CAAC,CAiC7B;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,GAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAM,GACtC,OAAO,CAAC,kBAAkB,CAAC,CAE7B"}
|
package/dist/lib/redact.d.ts
CHANGED
|
@@ -21,6 +21,30 @@ export interface RedactedVar {
|
|
|
21
21
|
reason: string;
|
|
22
22
|
}
|
|
23
23
|
export type RedactFormat = "shell" | "json" | "toml" | "ini" | "markdown" | "text" | "yaml";
|
|
24
|
+
/**
|
|
25
|
+
* Pick the redaction dialect for the file actually being read, from its PATH.
|
|
26
|
+
*
|
|
27
|
+
* `ConfigFormat` — what a stored row declares — is
|
|
28
|
+
* `text | json | toml | yaml | markdown | ini` and has NO `shell` member, while
|
|
29
|
+
* `RedactFormat` does. `detectFormat` returns `text` for any extensionless path,
|
|
30
|
+
* so `~/.zshrc`, `~/.bashrc` and `~/.npmrc` are all stored as `text`, and `text`
|
|
31
|
+
* routes to `redactGeneric` — which matches token SHAPES only and never key
|
|
32
|
+
* names. A credential whose key is secret-class but whose value has no
|
|
33
|
+
* recognisable shape is therefore invisible on exactly the files most likely to
|
|
34
|
+
* hold one.
|
|
35
|
+
*
|
|
36
|
+
* Resolving the dialect from the path closes that. It is deliberately
|
|
37
|
+
* PATH-KEYED rather than a widening of `ConfigFormat`: `.md` still resolves to
|
|
38
|
+
* `markdown`, so a rules file documenting `NPM_TOKEN=...` in prose is not
|
|
39
|
+
* mistaken for a shell assignment and frozen from ever shipping an edit.
|
|
40
|
+
*
|
|
41
|
+
* Exported so every caller that must choose a dialect shares ONE definition.
|
|
42
|
+
* Two surfaces need it and they must not drift: `diff`, the last read before a
|
|
43
|
+
* value reaches a transcript, and the `apply` guard, the last check before a
|
|
44
|
+
* value is overwritten. A per-surface copy is how one of them silently keeps the
|
|
45
|
+
* gap (todos e4d9c22e).
|
|
46
|
+
*/
|
|
47
|
+
export declare function redactFormatForTarget(targetPath: string, storedFormat: RedactFormat): RedactFormat;
|
|
24
48
|
export declare function redactContent(content: string, format: RedactFormat): RedactResult;
|
|
25
49
|
/** Detect secrets without modifying content. Returns list of findings. */
|
|
26
50
|
export declare function scanSecrets(content: string, format: RedactFormat): RedactedVar[];
|
package/dist/lib/redact.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../src/lib/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAgND,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5F,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,YAAY,CAQjF;AAED,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,WAAW,EAAE,CAGhF;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAEzE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD"}
|
|
1
|
+
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../src/lib/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAgND,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5F;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,GAAG,YAAY,CAKlG;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,YAAY,CAQjF;AAED,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,WAAW,EAAE,CAGhF;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAEzE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD"}
|
package/dist/lib/sync.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/lib/sync.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACrH,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAW/E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,eAAO,MAAM,qBAAqB,EAAE,YAAY,EAQ/C,CAAC;AAwDF,eAAO,MAAM,aAAa,EAAE,WAAW,EAwDtC,CAAC;AAIF,eAAO,MAAM,oBAAoB;;cAC2B,cAAc;WAAsB,WAAW;YAAwB,YAAY;GAe9I,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAiE/E;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,wBAAsB,SAAS,CAAC,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,CAqGhF;AAGD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,wBAAsB,UAAU,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAmClF;AAGD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/lib/sync.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACrH,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAW/E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,eAAO,MAAM,qBAAqB,EAAE,YAAY,EAQ/C,CAAC;AAwDF,eAAO,MAAM,aAAa,EAAE,WAAW,EAwDtC,CAAC;AAIF,eAAO,MAAM,oBAAoB;;cAC2B,cAAc;WAAsB,WAAW;YAAwB,YAAY;GAe9I,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAiE/E;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,wBAAsB,SAAS,CAAC,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,CAqGhF;AAGD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED,wBAAsB,UAAU,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAmClF;AAGD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAkJD,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CA+B9F;AAGD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAU/D;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAgBzD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAQ3D;AAGD,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -578,9 +578,6 @@ function templateizeMachineContent(content, machine) {
|
|
|
578
578
|
next = next.replace(/~\/workspace/g, "{{WORKSPACE_ROOT}}").replace(/~\/Workspace/g, "{{WORKSPACE_ROOT}}").replace(/\/opt\/homebrew\/bin\/bun/g, "{{BUN_PATH}}");
|
|
579
579
|
return { content: next, changed: next !== content };
|
|
580
580
|
}
|
|
581
|
-
function renderMachineAwareContent(content, variables) {
|
|
582
|
-
return isTemplate(content) ? renderTemplate(content, variables) : content;
|
|
583
|
-
}
|
|
584
581
|
function renderMachineAwareContentPreview(content, variables) {
|
|
585
582
|
return isTemplate(content) ? renderTemplatePreview(content, variables) : { content, unresolved: [] };
|
|
586
583
|
}
|
|
@@ -5169,6 +5166,7 @@ var init_zod = __esm(() => {
|
|
|
5169
5166
|
var exports_redact = {};
|
|
5170
5167
|
__export(exports_redact, {
|
|
5171
5168
|
scanSecrets: () => scanSecrets,
|
|
5169
|
+
redactFormatForTarget: () => redactFormatForTarget,
|
|
5172
5170
|
redactContent: () => redactContent,
|
|
5173
5171
|
isSecretVarName: () => isSecretVarName,
|
|
5174
5172
|
hasSecrets: () => hasSecrets
|
|
@@ -5323,6 +5321,14 @@ function reasonFor(key, value) {
|
|
|
5323
5321
|
function isReferenceValue(value) {
|
|
5324
5322
|
return /^\{\{[A-Z][A-Z0-9_]*\}\}$/.test(value) || /^\$\{[A-Z][A-Z0-9_]*\}$/.test(value) || /^\$[A-Z][A-Z0-9_]*$/.test(value) || /^%[A-Z][A-Z0-9_]*%$/.test(value);
|
|
5325
5323
|
}
|
|
5324
|
+
function redactFormatForTarget(targetPath, storedFormat) {
|
|
5325
|
+
const p = targetPath.toLowerCase();
|
|
5326
|
+
if (/(^|\/)\.(zshrc|zprofile|bashrc|bash_profile|profile|zshenv|env)$/.test(p) || p.endsWith(".env"))
|
|
5327
|
+
return "shell";
|
|
5328
|
+
if (/(^|\/)\.(npmrc|yarnrc|curlrc|netrc)$/.test(p))
|
|
5329
|
+
return "ini";
|
|
5330
|
+
return storedFormat;
|
|
5331
|
+
}
|
|
5326
5332
|
function redactContent(content, format) {
|
|
5327
5333
|
switch (format) {
|
|
5328
5334
|
case "shell":
|
|
@@ -5894,8 +5900,9 @@ function normalizeTargetPath(p) {
|
|
|
5894
5900
|
}
|
|
5895
5901
|
}
|
|
5896
5902
|
async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
|
|
5897
|
-
const
|
|
5898
|
-
const
|
|
5903
|
+
const variables = opts.vars ?? {};
|
|
5904
|
+
const renderedTarget = renderForApply(targetPath, variables);
|
|
5905
|
+
const rendered = renderForApply(content, variables);
|
|
5899
5906
|
const renderedTargetPath = renderedTarget.content;
|
|
5900
5907
|
const renderedContent = rendered.content;
|
|
5901
5908
|
const targetAgent = meta.agent ?? config.agent;
|
|
@@ -5934,13 +5941,42 @@ async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
|
|
|
5934
5941
|
...meta
|
|
5935
5942
|
};
|
|
5936
5943
|
}
|
|
5937
|
-
function renderForApply(content, variables
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
+
function renderForApply(content, variables) {
|
|
5945
|
+
return renderMachineAwareContentPreview(content, variables);
|
|
5946
|
+
}
|
|
5947
|
+
function wouldDestroyACredential(targetPath, renderedContent, format) {
|
|
5948
|
+
const secretTokens = parseTemplateVars(renderedContent).filter(isSecretVarName);
|
|
5949
|
+
if (secretTokens.length === 0)
|
|
5950
|
+
return [];
|
|
5951
|
+
let current;
|
|
5952
|
+
try {
|
|
5953
|
+
const path = expandPath(targetPath);
|
|
5954
|
+
if (!existsSync4(path))
|
|
5955
|
+
return [];
|
|
5956
|
+
current = readFileSync2(path, "utf-8");
|
|
5957
|
+
} catch {
|
|
5958
|
+
return secretTokens;
|
|
5959
|
+
}
|
|
5960
|
+
if (current === renderedContent)
|
|
5961
|
+
return [];
|
|
5962
|
+
if (scanSecrets(current, redactFormatForTarget(targetPath, format)).length > 0)
|
|
5963
|
+
return secretTokens;
|
|
5964
|
+
return secretTokens.filter((name) => countPlaceholder(current, name) < countPlaceholder(renderedContent, name));
|
|
5965
|
+
}
|
|
5966
|
+
function countPlaceholder(content, name) {
|
|
5967
|
+
return content.match(new RegExp(`\\{\\{${name}(?::[^}]*)?\\}\\}`, "g"))?.length ?? 0;
|
|
5968
|
+
}
|
|
5969
|
+
async function resolveApplyVariables(opts) {
|
|
5970
|
+
const machine = detectMachineContext();
|
|
5971
|
+
let base;
|
|
5972
|
+
try {
|
|
5973
|
+
const store = opts.store ?? resolveConfigStore();
|
|
5974
|
+
const profile = await store.resolveProfileForMachine(machine);
|
|
5975
|
+
base = resolveProfileVariables(profile, machine);
|
|
5976
|
+
} catch {
|
|
5977
|
+
base = machineContextToVariables(machine);
|
|
5978
|
+
}
|
|
5979
|
+
return { ...base, ...opts.vars ?? {} };
|
|
5944
5980
|
}
|
|
5945
5981
|
function isAntigravityRuleTarget(agent, targetPath) {
|
|
5946
5982
|
return agent === "antigravity" && /\.(md|mdc|markdown)$/i.test(targetPath);
|
|
@@ -6025,7 +6061,8 @@ async function applyConfigs(configs, opts = {}) {
|
|
|
6025
6061
|
return report.results;
|
|
6026
6062
|
}
|
|
6027
6063
|
async function applyConfigsWithReport(configs, opts = {}) {
|
|
6028
|
-
const
|
|
6064
|
+
const effective = { ...opts, vars: await resolveApplyVariables(opts) };
|
|
6065
|
+
const prepared = prepareConfigBatch(configs, effective);
|
|
6029
6066
|
if (prepared.failures.length > 0) {
|
|
6030
6067
|
return {
|
|
6031
6068
|
results: [],
|
|
@@ -6039,7 +6076,7 @@ async function applyConfigsWithReport(configs, opts = {}) {
|
|
|
6039
6076
|
if (config.kind === "reference" || isRetiredOrUnsupportedConfigAgent(config.agent))
|
|
6040
6077
|
continue;
|
|
6041
6078
|
try {
|
|
6042
|
-
results.push(await applyPreparedConfig(config,
|
|
6079
|
+
results.push(await applyPreparedConfig(config, effective));
|
|
6043
6080
|
} catch (error) {
|
|
6044
6081
|
failures.push({
|
|
6045
6082
|
config_id: config.id,
|
|
@@ -6079,7 +6116,27 @@ function prepareConfigBatch(configs, opts) {
|
|
|
6079
6116
|
}
|
|
6080
6117
|
return false;
|
|
6081
6118
|
});
|
|
6082
|
-
const
|
|
6119
|
+
const renderSafeConfigs = activeConfigs.filter((config) => {
|
|
6120
|
+
const behavior = canonicalConfigApplyBehavior(config, opts, activeConfigs);
|
|
6121
|
+
const targets = [
|
|
6122
|
+
...behavior.primary ? [{ path: behavior.primary.path, content: behavior.primary.content }] : [],
|
|
6123
|
+
...behavior.outputs.map((output) => ({ path: output.path, content: output.content }))
|
|
6124
|
+
];
|
|
6125
|
+
const blocked = [...new Set(targets.flatMap((target) => wouldDestroyACredential(target.path, target.content, config.format)))].sort();
|
|
6126
|
+
if (blocked.length === 0)
|
|
6127
|
+
return true;
|
|
6128
|
+
for (const target of targets) {
|
|
6129
|
+
skipped.push({
|
|
6130
|
+
config_id: config.id,
|
|
6131
|
+
config_slug: config.slug,
|
|
6132
|
+
path: target.path,
|
|
6133
|
+
owner: "unresolved-secret-placeholder",
|
|
6134
|
+
reason: `no value for ${blocked.map((name) => `{{${name}}}`).join(", ")} and the file holds something else there; writing the placeholder would overwrite a live credential`
|
|
6135
|
+
});
|
|
6136
|
+
}
|
|
6137
|
+
return false;
|
|
6138
|
+
});
|
|
6139
|
+
const { configs: deduplicated, duplicates } = deduplicateEquivalentProfileConfigs(renderSafeConfigs, opts);
|
|
6083
6140
|
for (const duplicate of duplicates) {
|
|
6084
6141
|
for (const target of configTargets(duplicate, opts, activeConfigs)) {
|
|
6085
6142
|
skipped.push({
|
|
@@ -6231,6 +6288,8 @@ var init_apply = __esm(() => {
|
|
|
6231
6288
|
init_machine();
|
|
6232
6289
|
init_session_render();
|
|
6233
6290
|
init_session_render_ownership();
|
|
6291
|
+
init_redact();
|
|
6292
|
+
init_template();
|
|
6234
6293
|
init_transforms();
|
|
6235
6294
|
});
|
|
6236
6295
|
|
|
@@ -6531,14 +6590,6 @@ function redactionPlaceholders(storedLine) {
|
|
|
6531
6590
|
}
|
|
6532
6591
|
return found;
|
|
6533
6592
|
}
|
|
6534
|
-
function redactFormatForTarget(targetPath, storedFormat) {
|
|
6535
|
-
const p = targetPath.toLowerCase();
|
|
6536
|
-
if (/(^|\/)\.(zshrc|zprofile|bashrc|bash_profile|profile|zshenv|env)$/.test(p) || p.endsWith(".env"))
|
|
6537
|
-
return "shell";
|
|
6538
|
-
if (/(^|\/)\.(npmrc|yarnrc|curlrc|netrc)$/.test(p))
|
|
6539
|
-
return "ini";
|
|
6540
|
-
return storedFormat;
|
|
6541
|
-
}
|
|
6542
6593
|
function storedPlaceholderIsLiteralOnDisk(storedLine, diskLine) {
|
|
6543
6594
|
return redactionPlaceholders(storedLine).some((p) => !diskLine.includes(p));
|
|
6544
6595
|
}
|
|
@@ -6858,7 +6909,7 @@ var init_sync_dir = __esm(() => {
|
|
|
6858
6909
|
var require_package = __commonJS((exports, module) => {
|
|
6859
6910
|
module.exports = {
|
|
6860
6911
|
name: "@hasna/instructions",
|
|
6861
|
-
version: "0.4.
|
|
6912
|
+
version: "0.4.16",
|
|
6862
6913
|
description: "AI coding agent instruction & configuration manager \u2014 store, version, apply, and share all your AI coding configs. CLI + MCP + HTTP API (instructions-serve) + generated SDK + Dashboard.",
|
|
6863
6914
|
type: "module",
|
|
6864
6915
|
main: "dist/index.js",
|
|
@@ -6897,7 +6948,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
6897
6948
|
"dev:mcp": "bun run src/mcp/index.ts",
|
|
6898
6949
|
"dev:serve": "bun run src/server/index.ts",
|
|
6899
6950
|
seed: "bun run scripts/seed.ts",
|
|
6900
|
-
prepublishOnly: "bun run build",
|
|
6951
|
+
prepublishOnly: "bun run scripts/check-publish-hold.ts && bun run build",
|
|
6901
6952
|
postinstall: "mkdir -p $HOME/.hasna/instructions $HOME/.hasna/instructions/backups 2>/dev/null || true"
|
|
6902
6953
|
},
|
|
6903
6954
|
keywords: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/instructions",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.16",
|
|
4
4
|
"description": "AI coding agent instruction & configuration manager \u2014 store, version, apply, and share all your AI coding configs. CLI + MCP + HTTP API (instructions-serve) + generated SDK + Dashboard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dev:mcp": "bun run src/mcp/index.ts",
|
|
40
40
|
"dev:serve": "bun run src/server/index.ts",
|
|
41
41
|
"seed": "bun run scripts/seed.ts",
|
|
42
|
-
"prepublishOnly": "bun run build",
|
|
42
|
+
"prepublishOnly": "bun run scripts/check-publish-hold.ts && bun run build",
|
|
43
43
|
"postinstall": "mkdir -p $HOME/.hasna/instructions $HOME/.hasna/instructions/backups 2>/dev/null || true"
|
|
44
44
|
},
|
|
45
45
|
"keywords": [
|