@hasna/instructions 0.4.10 → 0.4.12
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 +84 -10
- package/dist/index.js +73 -5
- package/dist/lib/diff-redaction.test.d.ts +2 -0
- package/dist/lib/diff-redaction.test.d.ts.map +1 -0
- package/dist/lib/redact.d.ts +9 -0
- package/dist/lib/redact.d.ts.map +1 -1
- package/dist/lib/sync.d.ts +10 -0
- package/dist/lib/sync.d.ts.map +1 -1
- package/dist/mcp/index.js +74 -7
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -7550,6 +7550,9 @@ function scanSecrets(content, format) {
|
|
|
7550
7550
|
const r = redactContent(content, format);
|
|
7551
7551
|
return r.redacted;
|
|
7552
7552
|
}
|
|
7553
|
+
function isSecretVarName(name) {
|
|
7554
|
+
return SECRET_KEY_PATTERN.test(name);
|
|
7555
|
+
}
|
|
7553
7556
|
var SECRET_KEY_PATTERN, VALUE_PATTERNS, MIN_SECRET_VALUE_LEN = 8;
|
|
7554
7557
|
var init_redact = __esm(() => {
|
|
7555
7558
|
SECRET_KEY_PATTERN = /^(.*_?API_?KEY|.*_?TOKEN|.*_?SECRET|.*_?PASSWORD|.*_?PASSWD|.*_?CREDENTIAL|.*_?AUTH(?:_TOKEN|_KEY|ORIZATION)?|.*_?PRIVATE_?KEY|.*_?ACCESS_?KEY|.*_?CLIENT_?SECRET|.*_?SIGNING_?KEY|.*_?ENCRYPTION_?KEY|.*_AUTH_TOKEN)$/i;
|
|
@@ -11048,8 +11051,10 @@ function sourcesFromIdentityExport(value, options = {}) {
|
|
|
11048
11051
|
function requireIdentityExportShape(record) {
|
|
11049
11052
|
if (record["contract"] === "hasna.identities.configs-instructions/v1")
|
|
11050
11053
|
return "configs-contract";
|
|
11051
|
-
|
|
11054
|
+
const packageName = record["package"];
|
|
11055
|
+
if (record["version"] === 1 && typeof packageName === "string" && CANONICAL_IDENTITY_EXPORT_PACKAGES.has(packageName)) {
|
|
11052
11056
|
return "canonical-open-identities";
|
|
11057
|
+
}
|
|
11053
11058
|
throw new Error("Unsupported identity instruction export contract.");
|
|
11054
11059
|
}
|
|
11055
11060
|
function normalizeInstructionRules(source, tool) {
|
|
@@ -11308,7 +11313,7 @@ function asStringArray(value) {
|
|
|
11308
11313
|
return [];
|
|
11309
11314
|
return value.filter((item) => typeof item === "string");
|
|
11310
11315
|
}
|
|
11311
|
-
var RAW_STORE_ROOT_ENV = "HASNA_CONFIGS_HOME", ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000, SESSION_RENDERER_OWNER_ID = "instructions-session-renderer", SESSION_RENDER_TOOLS, SESSION_RENDER_PROFILE_ENTRYPOINTS, SESSION_RENDER_OWNED_CONFIG_TARGETS, CODEWITH_FLATTENED_ADAPTER, CODEWITH_NATIVE_ADAPTER, SESSION_TOOL_ADAPTERS, SESSION_RENDER_MANAGED_DIRS, SESSION_RENDER_SHARED_MANAGED_DIRS, SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS, SESSION_LAYER_RANK;
|
|
11316
|
+
var RAW_STORE_ROOT_ENV = "HASNA_CONFIGS_HOME", ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000, SESSION_RENDERER_OWNER_ID = "instructions-session-renderer", SESSION_RENDER_TOOLS, SESSION_RENDER_PROFILE_ENTRYPOINTS, SESSION_RENDER_OWNED_CONFIG_TARGETS, CODEWITH_FLATTENED_ADAPTER, CODEWITH_NATIVE_ADAPTER, SESSION_TOOL_ADAPTERS, SESSION_RENDER_MANAGED_DIRS, SESSION_RENDER_SHARED_MANAGED_DIRS, SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS, SESSION_LAYER_RANK, CANONICAL_IDENTITY_EXPORT_PACKAGES;
|
|
11312
11317
|
var init_session_render = __esm(() => {
|
|
11313
11318
|
init_global_agent_rules_standard();
|
|
11314
11319
|
init_project_context();
|
|
@@ -11444,6 +11449,10 @@ var init_session_render = __esm(() => {
|
|
|
11444
11449
|
session: 100,
|
|
11445
11450
|
local: 110
|
|
11446
11451
|
};
|
|
11452
|
+
CANONICAL_IDENTITY_EXPORT_PACKAGES = new Set([
|
|
11453
|
+
"@hasna/identities",
|
|
11454
|
+
"@hasna/personas"
|
|
11455
|
+
]);
|
|
11447
11456
|
});
|
|
11448
11457
|
|
|
11449
11458
|
// src/lib/session-render-ownership.ts
|
|
@@ -12283,30 +12292,86 @@ async function syncToDisk(opts = {}) {
|
|
|
12283
12292
|
}
|
|
12284
12293
|
return result;
|
|
12285
12294
|
}
|
|
12286
|
-
function
|
|
12295
|
+
function redactionPlaceholders(storedLine) {
|
|
12296
|
+
const found = [...storedLine.match(CERTAIN_PLACEHOLDER_RE) ?? []];
|
|
12297
|
+
const assigned = storedLine.match(ASSIGNED_PLACEHOLDER_RE);
|
|
12298
|
+
if (assigned) {
|
|
12299
|
+
const name = assigned[3] ?? assigned[4] ?? assigned[5];
|
|
12300
|
+
if (name && isSecretVarName(name))
|
|
12301
|
+
found.push(assigned[2]);
|
|
12302
|
+
}
|
|
12303
|
+
return found;
|
|
12304
|
+
}
|
|
12305
|
+
function redactFormatForTarget(targetPath, storedFormat) {
|
|
12306
|
+
const p = targetPath.toLowerCase();
|
|
12307
|
+
if (/(^|\/)\.(zshrc|zprofile|bashrc|bash_profile|profile|zshenv|env)$/.test(p) || p.endsWith(".env"))
|
|
12308
|
+
return "shell";
|
|
12309
|
+
if (/(^|\/)\.(npmrc|yarnrc|curlrc|netrc)$/.test(p))
|
|
12310
|
+
return "ini";
|
|
12311
|
+
return storedFormat;
|
|
12312
|
+
}
|
|
12313
|
+
function storedPlaceholderIsLiteralOnDisk(storedLine, diskLine) {
|
|
12314
|
+
return redactionPlaceholders(storedLine).some((p) => !diskLine.includes(p));
|
|
12315
|
+
}
|
|
12316
|
+
function buildDiff(expectedContent, targetPath, storedFormat, showSecrets) {
|
|
12287
12317
|
const path = expandPath(targetPath);
|
|
12288
12318
|
if (!existsSync9(path))
|
|
12289
12319
|
return `(file not found on disk: ${path})`;
|
|
12290
12320
|
const diskContent = readFileSync6(path, "utf-8");
|
|
12291
12321
|
if (diskContent === expectedContent)
|
|
12292
12322
|
return "(no diff \u2014 identical)";
|
|
12323
|
+
const format = redactFormatForTarget(targetPath, storedFormat);
|
|
12293
12324
|
const stored = expectedContent.split(`
|
|
12294
12325
|
`);
|
|
12295
12326
|
const disk = diskContent.split(`
|
|
12296
12327
|
`);
|
|
12328
|
+
const { content: redactedDiskContent, redacted } = showSecrets ? { content: diskContent, redacted: [] } : redactContent(diskContent, format);
|
|
12329
|
+
const redactedDisk = redactedDiskContent.split(`
|
|
12330
|
+
`);
|
|
12331
|
+
const reasonByLine = new Map;
|
|
12332
|
+
for (const r of redacted)
|
|
12333
|
+
if (!reasonByLine.has(r.line))
|
|
12334
|
+
reasonByLine.set(r.line, r.reason);
|
|
12297
12335
|
const lines = [`--- stored (DB)`, `+++ disk (${path})`];
|
|
12298
12336
|
const maxLen = Math.max(stored.length, disk.length);
|
|
12299
12337
|
for (let i = 0;i < maxLen; i++) {
|
|
12338
|
+
const lineNo = i + 1;
|
|
12300
12339
|
const s = stored[i];
|
|
12301
12340
|
const dk = disk[i];
|
|
12302
12341
|
if (s === dk) {
|
|
12303
12342
|
if (s !== undefined)
|
|
12304
12343
|
lines.push(` ${s}`);
|
|
12305
|
-
|
|
12344
|
+
continue;
|
|
12345
|
+
}
|
|
12346
|
+
if (showSecrets || dk === undefined) {
|
|
12306
12347
|
if (s !== undefined)
|
|
12307
12348
|
lines.push(`-${s}`);
|
|
12308
12349
|
if (dk !== undefined)
|
|
12309
12350
|
lines.push(`+${dk}`);
|
|
12351
|
+
continue;
|
|
12352
|
+
}
|
|
12353
|
+
const structural = s !== undefined && storedPlaceholderIsLiteralOnDisk(s, dk);
|
|
12354
|
+
const patterned = reasonByLine.has(lineNo);
|
|
12355
|
+
if (!structural && !patterned) {
|
|
12356
|
+
if (s !== undefined)
|
|
12357
|
+
lines.push(`-${s}`);
|
|
12358
|
+
lines.push(`+${dk}`);
|
|
12359
|
+
continue;
|
|
12360
|
+
}
|
|
12361
|
+
if (structural) {
|
|
12362
|
+
const placeholder = redactionPlaceholders(s).find((p) => !dk.includes(p)) ?? "a placeholder";
|
|
12363
|
+
lines.push(`~line ${lineNo} differs: stored \`${s}\`, disk holds a literal value for ${placeholder} \u2014 redacted (use --show-secrets on a TTY to reveal)`);
|
|
12364
|
+
continue;
|
|
12365
|
+
}
|
|
12366
|
+
const safe = redactedDisk[i] ?? "";
|
|
12367
|
+
const reason = reasonByLine.get(lineNo);
|
|
12368
|
+
if (s !== undefined && safe === s) {
|
|
12369
|
+
lines.push(`~line ${lineNo} differs: stored \`${s}\`, disk holds a literal value (${reason}) \u2014 redacted (use --show-secrets on a TTY to reveal)`);
|
|
12370
|
+
} else {
|
|
12371
|
+
if (s !== undefined)
|
|
12372
|
+
lines.push(`-${s}`);
|
|
12373
|
+
lines.push(`+${safe}`);
|
|
12374
|
+
lines.push(`~line ${lineNo}: disk value redacted (${reason}) \u2014 use --show-secrets on a TTY to reveal`);
|
|
12310
12375
|
}
|
|
12311
12376
|
}
|
|
12312
12377
|
return lines.join(`
|
|
@@ -12321,15 +12386,16 @@ async function diffConfig(config, opts = {}) {
|
|
|
12321
12386
|
if (isGeneratedOutputTarget2(config, outputOwnerIdsByTarget(contextConfigs))) {
|
|
12322
12387
|
return "(generated output \u2014 managed by fan-out)";
|
|
12323
12388
|
}
|
|
12389
|
+
const showSecrets = opts.showSecrets ?? false;
|
|
12324
12390
|
if (config.target_path) {
|
|
12325
|
-
const diff = buildDiff(config.content, config.target_path);
|
|
12391
|
+
const diff = buildDiff(config.content, config.target_path, config.format, showSecrets);
|
|
12326
12392
|
if (!diff.includes("no diff"))
|
|
12327
12393
|
diffs.push(diff);
|
|
12328
12394
|
}
|
|
12329
12395
|
if (config.outputs.length > 0) {
|
|
12330
12396
|
for (const output of config.outputs) {
|
|
12331
12397
|
const expected = applyTransform(config, output, { configs: contextConfigs });
|
|
12332
|
-
const diff = buildDiff(expected, output.target_path);
|
|
12398
|
+
const diff = buildDiff(expected, output.target_path, detectFormat(output.target_path), showSecrets);
|
|
12333
12399
|
if (!diff.includes("no diff"))
|
|
12334
12400
|
diffs.push(diff);
|
|
12335
12401
|
}
|
|
@@ -12400,7 +12466,7 @@ function detectFormat(filePath) {
|
|
|
12400
12466
|
return "ini";
|
|
12401
12467
|
return "text";
|
|
12402
12468
|
}
|
|
12403
|
-
var CLAUDE_PROMPT_OUTPUTS, KNOWN_CONFIGS, PROJECT_CONFIG_FILES;
|
|
12469
|
+
var CLAUDE_PROMPT_OUTPUTS, KNOWN_CONFIGS, PROJECT_CONFIG_FILES, CERTAIN_PLACEHOLDER_RE, ASSIGNED_PLACEHOLDER_RE;
|
|
12404
12470
|
var init_sync = __esm(() => {
|
|
12405
12471
|
init_config_store();
|
|
12406
12472
|
init_apply();
|
|
@@ -12464,6 +12530,8 @@ var init_sync = __esm(() => {
|
|
|
12464
12530
|
{ file: ".agents/mcp_config.json", category: "mcp", agent: "antigravity", format: "json" },
|
|
12465
12531
|
{ file: ".qwen/settings.json", category: "agent", agent: "qwen", format: "json" }
|
|
12466
12532
|
];
|
|
12533
|
+
CERTAIN_PLACEHOLDER_RE = /\{\{[A-Za-z_][A-Za-z0-9_]*\}\}/g;
|
|
12534
|
+
ASSIGNED_PLACEHOLDER_RE = /[=:]\s*(["']?)(\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Z][A-Z0-9_]*)|%([A-Za-z_][A-Za-z0-9_]*)%)\1\s*,?\s*$/;
|
|
12467
12535
|
});
|
|
12468
12536
|
|
|
12469
12537
|
// src/lib/package-manager-guard.ts
|
|
@@ -15424,12 +15492,18 @@ program.command("apply <id>").description("Apply a config to its target_path and
|
|
|
15424
15492
|
process.exit(1);
|
|
15425
15493
|
}
|
|
15426
15494
|
});
|
|
15427
|
-
program.command("diff [id]").description("Show diff between stored config and disk (omit id for --all)").option("--all", "diff every known config against disk").action(async (id, opts) => {
|
|
15495
|
+
program.command("diff [id]").description("Show diff between stored config and disk (omit id for --all). Credential values on disk are redacted.").option("--all", "diff every known config against disk").option("--show-secrets", "render credential values from disk verbatim (interactive TTY only)").action(async (id, opts) => {
|
|
15428
15496
|
try {
|
|
15497
|
+
if (opts.showSecrets && !process.stdout.isTTY) {
|
|
15498
|
+
console.error(chalk.red("--show-secrets refuses to run on a non-TTY: the output would be captured verbatim into a log or transcript."));
|
|
15499
|
+
console.error(chalk.dim("Run it in an interactive terminal, or use the redacted default."));
|
|
15500
|
+
process.exit(1);
|
|
15501
|
+
}
|
|
15502
|
+
const showSecrets = Boolean(opts.showSecrets);
|
|
15429
15503
|
const store = resolveConfigStore();
|
|
15430
15504
|
if (id) {
|
|
15431
15505
|
const config = await store.getConfig(id);
|
|
15432
|
-
console.log(await diffConfig(config, { store }));
|
|
15506
|
+
console.log(await diffConfig(config, { store, showSecrets }));
|
|
15433
15507
|
return;
|
|
15434
15508
|
}
|
|
15435
15509
|
const configs = await store.listConfigs({ kind: "file" });
|
|
@@ -15437,7 +15511,7 @@ program.command("diff [id]").description("Show diff between stored config and di
|
|
|
15437
15511
|
for (const c of configs) {
|
|
15438
15512
|
if (!c.target_path)
|
|
15439
15513
|
continue;
|
|
15440
|
-
const diff = await diffConfig(c, { store });
|
|
15514
|
+
const diff = await diffConfig(c, { store, showSecrets });
|
|
15441
15515
|
if (diff.includes("no diff") || diff.includes("not found"))
|
|
15442
15516
|
continue;
|
|
15443
15517
|
drifted++;
|
package/dist/index.js
CHANGED
|
@@ -5515,6 +5515,9 @@ function scanSecrets(content, format) {
|
|
|
5515
5515
|
function hasSecrets(content, format) {
|
|
5516
5516
|
return scanSecrets(content, format).length > 0;
|
|
5517
5517
|
}
|
|
5518
|
+
function isSecretVarName(name) {
|
|
5519
|
+
return SECRET_KEY_PATTERN.test(name);
|
|
5520
|
+
}
|
|
5518
5521
|
|
|
5519
5522
|
// src/lib/session-render-contract.ts
|
|
5520
5523
|
var CODEWITH_NATIVE_IMPORTS_ENV = "HASNA_CONFIGS_CODEWITH_NATIVE_IMPORTS";
|
|
@@ -9212,11 +9215,17 @@ function sourcesFromIdentityExport(value, options = {}) {
|
|
|
9212
9215
|
exportShape: shape
|
|
9213
9216
|
})).filter((source) => source !== null);
|
|
9214
9217
|
}
|
|
9218
|
+
var CANONICAL_IDENTITY_EXPORT_PACKAGES = new Set([
|
|
9219
|
+
"@hasna/identities",
|
|
9220
|
+
"@hasna/personas"
|
|
9221
|
+
]);
|
|
9215
9222
|
function requireIdentityExportShape(record) {
|
|
9216
9223
|
if (record["contract"] === "hasna.identities.configs-instructions/v1")
|
|
9217
9224
|
return "configs-contract";
|
|
9218
|
-
|
|
9225
|
+
const packageName = record["package"];
|
|
9226
|
+
if (record["version"] === 1 && typeof packageName === "string" && CANONICAL_IDENTITY_EXPORT_PACKAGES.has(packageName)) {
|
|
9219
9227
|
return "canonical-open-identities";
|
|
9228
|
+
}
|
|
9220
9229
|
throw new Error("Unsupported identity instruction export contract.");
|
|
9221
9230
|
}
|
|
9222
9231
|
function normalizeInstructionRules(source, tool) {
|
|
@@ -11674,30 +11683,88 @@ async function syncToDisk(opts = {}) {
|
|
|
11674
11683
|
}
|
|
11675
11684
|
return result;
|
|
11676
11685
|
}
|
|
11677
|
-
|
|
11686
|
+
var CERTAIN_PLACEHOLDER_RE = /\{\{[A-Za-z_][A-Za-z0-9_]*\}\}/g;
|
|
11687
|
+
var ASSIGNED_PLACEHOLDER_RE = /[=:]\s*(["']?)(\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Z][A-Z0-9_]*)|%([A-Za-z_][A-Za-z0-9_]*)%)\1\s*,?\s*$/;
|
|
11688
|
+
function redactionPlaceholders(storedLine) {
|
|
11689
|
+
const found = [...storedLine.match(CERTAIN_PLACEHOLDER_RE) ?? []];
|
|
11690
|
+
const assigned = storedLine.match(ASSIGNED_PLACEHOLDER_RE);
|
|
11691
|
+
if (assigned) {
|
|
11692
|
+
const name = assigned[3] ?? assigned[4] ?? assigned[5];
|
|
11693
|
+
if (name && isSecretVarName(name))
|
|
11694
|
+
found.push(assigned[2]);
|
|
11695
|
+
}
|
|
11696
|
+
return found;
|
|
11697
|
+
}
|
|
11698
|
+
function redactFormatForTarget(targetPath, storedFormat) {
|
|
11699
|
+
const p = targetPath.toLowerCase();
|
|
11700
|
+
if (/(^|\/)\.(zshrc|zprofile|bashrc|bash_profile|profile|zshenv|env)$/.test(p) || p.endsWith(".env"))
|
|
11701
|
+
return "shell";
|
|
11702
|
+
if (/(^|\/)\.(npmrc|yarnrc|curlrc|netrc)$/.test(p))
|
|
11703
|
+
return "ini";
|
|
11704
|
+
return storedFormat;
|
|
11705
|
+
}
|
|
11706
|
+
function storedPlaceholderIsLiteralOnDisk(storedLine, diskLine) {
|
|
11707
|
+
return redactionPlaceholders(storedLine).some((p) => !diskLine.includes(p));
|
|
11708
|
+
}
|
|
11709
|
+
function buildDiff(expectedContent, targetPath, storedFormat, showSecrets) {
|
|
11678
11710
|
const path = expandPath(targetPath);
|
|
11679
11711
|
if (!existsSync11(path))
|
|
11680
11712
|
return `(file not found on disk: ${path})`;
|
|
11681
11713
|
const diskContent = readFileSync9(path, "utf-8");
|
|
11682
11714
|
if (diskContent === expectedContent)
|
|
11683
11715
|
return "(no diff \u2014 identical)";
|
|
11716
|
+
const format = redactFormatForTarget(targetPath, storedFormat);
|
|
11684
11717
|
const stored = expectedContent.split(`
|
|
11685
11718
|
`);
|
|
11686
11719
|
const disk = diskContent.split(`
|
|
11687
11720
|
`);
|
|
11721
|
+
const { content: redactedDiskContent, redacted } = showSecrets ? { content: diskContent, redacted: [] } : redactContent(diskContent, format);
|
|
11722
|
+
const redactedDisk = redactedDiskContent.split(`
|
|
11723
|
+
`);
|
|
11724
|
+
const reasonByLine = new Map;
|
|
11725
|
+
for (const r of redacted)
|
|
11726
|
+
if (!reasonByLine.has(r.line))
|
|
11727
|
+
reasonByLine.set(r.line, r.reason);
|
|
11688
11728
|
const lines = [`--- stored (DB)`, `+++ disk (${path})`];
|
|
11689
11729
|
const maxLen = Math.max(stored.length, disk.length);
|
|
11690
11730
|
for (let i = 0;i < maxLen; i++) {
|
|
11731
|
+
const lineNo = i + 1;
|
|
11691
11732
|
const s = stored[i];
|
|
11692
11733
|
const dk = disk[i];
|
|
11693
11734
|
if (s === dk) {
|
|
11694
11735
|
if (s !== undefined)
|
|
11695
11736
|
lines.push(` ${s}`);
|
|
11696
|
-
|
|
11737
|
+
continue;
|
|
11738
|
+
}
|
|
11739
|
+
if (showSecrets || dk === undefined) {
|
|
11697
11740
|
if (s !== undefined)
|
|
11698
11741
|
lines.push(`-${s}`);
|
|
11699
11742
|
if (dk !== undefined)
|
|
11700
11743
|
lines.push(`+${dk}`);
|
|
11744
|
+
continue;
|
|
11745
|
+
}
|
|
11746
|
+
const structural = s !== undefined && storedPlaceholderIsLiteralOnDisk(s, dk);
|
|
11747
|
+
const patterned = reasonByLine.has(lineNo);
|
|
11748
|
+
if (!structural && !patterned) {
|
|
11749
|
+
if (s !== undefined)
|
|
11750
|
+
lines.push(`-${s}`);
|
|
11751
|
+
lines.push(`+${dk}`);
|
|
11752
|
+
continue;
|
|
11753
|
+
}
|
|
11754
|
+
if (structural) {
|
|
11755
|
+
const placeholder = redactionPlaceholders(s).find((p) => !dk.includes(p)) ?? "a placeholder";
|
|
11756
|
+
lines.push(`~line ${lineNo} differs: stored \`${s}\`, disk holds a literal value for ${placeholder} \u2014 redacted (use --show-secrets on a TTY to reveal)`);
|
|
11757
|
+
continue;
|
|
11758
|
+
}
|
|
11759
|
+
const safe = redactedDisk[i] ?? "";
|
|
11760
|
+
const reason = reasonByLine.get(lineNo);
|
|
11761
|
+
if (s !== undefined && safe === s) {
|
|
11762
|
+
lines.push(`~line ${lineNo} differs: stored \`${s}\`, disk holds a literal value (${reason}) \u2014 redacted (use --show-secrets on a TTY to reveal)`);
|
|
11763
|
+
} else {
|
|
11764
|
+
if (s !== undefined)
|
|
11765
|
+
lines.push(`-${s}`);
|
|
11766
|
+
lines.push(`+${safe}`);
|
|
11767
|
+
lines.push(`~line ${lineNo}: disk value redacted (${reason}) \u2014 use --show-secrets on a TTY to reveal`);
|
|
11701
11768
|
}
|
|
11702
11769
|
}
|
|
11703
11770
|
return lines.join(`
|
|
@@ -11712,15 +11779,16 @@ async function diffConfig(config, opts = {}) {
|
|
|
11712
11779
|
if (isGeneratedOutputTarget2(config, outputOwnerIdsByTarget(contextConfigs))) {
|
|
11713
11780
|
return "(generated output \u2014 managed by fan-out)";
|
|
11714
11781
|
}
|
|
11782
|
+
const showSecrets = opts.showSecrets ?? false;
|
|
11715
11783
|
if (config.target_path) {
|
|
11716
|
-
const diff = buildDiff(config.content, config.target_path);
|
|
11784
|
+
const diff = buildDiff(config.content, config.target_path, config.format, showSecrets);
|
|
11717
11785
|
if (!diff.includes("no diff"))
|
|
11718
11786
|
diffs.push(diff);
|
|
11719
11787
|
}
|
|
11720
11788
|
if (config.outputs.length > 0) {
|
|
11721
11789
|
for (const output of config.outputs) {
|
|
11722
11790
|
const expected = applyTransform(config, output, { configs: contextConfigs });
|
|
11723
|
-
const diff = buildDiff(expected, output.target_path);
|
|
11791
|
+
const diff = buildDiff(expected, output.target_path, detectFormat(output.target_path), showSecrets);
|
|
11724
11792
|
if (!diff.includes("no diff"))
|
|
11725
11793
|
diffs.push(diff);
|
|
11726
11794
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-redaction.test.d.ts","sourceRoot":"","sources":["../../src/lib/diff-redaction.test.ts"],"names":[],"mappings":""}
|
package/dist/lib/redact.d.ts
CHANGED
|
@@ -26,4 +26,13 @@ export declare function redactContent(content: string, format: RedactFormat): Re
|
|
|
26
26
|
export declare function scanSecrets(content: string, format: RedactFormat): RedactedVar[];
|
|
27
27
|
/** Returns true if content contains any detectable secrets. */
|
|
28
28
|
export declare function hasSecrets(content: string, format: RedactFormat): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Is this variable NAME secret-shaped? (`NPM_TOKEN` yes, `PATH`/`HOME` no.)
|
|
31
|
+
*
|
|
32
|
+
* Exported so callers reasoning about placeholder names — notably the diff
|
|
33
|
+
* renderer, which must tell a redaction artefact from an ordinary shell
|
|
34
|
+
* variable — share this module's single definition of "secret-shaped" instead
|
|
35
|
+
* of duplicating the pattern and drifting from it.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isSecretVarName(name: string): boolean;
|
|
29
38
|
//# sourceMappingURL=redact.d.ts.map
|
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"}
|
|
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"}
|
package/dist/lib/sync.d.ts
CHANGED
|
@@ -43,6 +43,16 @@ export interface SyncToDiskOptions {
|
|
|
43
43
|
export declare function syncToDisk(opts?: SyncToDiskOptions): Promise<SyncResult>;
|
|
44
44
|
export interface DiffConfigOptions {
|
|
45
45
|
store?: ConfigStore;
|
|
46
|
+
/**
|
|
47
|
+
* Render the raw disk content, INCLUDING any credential values it holds.
|
|
48
|
+
*
|
|
49
|
+
* Off by default and deliberately hard to reach: the CLI refuses it on a
|
|
50
|
+
* non-TTY, mirroring `secrets get --show`. Everything a tool prints is
|
|
51
|
+
* persisted verbatim into the session transcript, and agent output is also
|
|
52
|
+
* served as run evidence — so an unredacted diff writes a live credential
|
|
53
|
+
* into a durable, fetchable artefact.
|
|
54
|
+
*/
|
|
55
|
+
showSecrets?: boolean;
|
|
46
56
|
}
|
|
47
57
|
export declare function diffConfig(config: Config, opts?: DiffConfigOptions): Promise<string>;
|
|
48
58
|
export declare function detectCategory(filePath: string): ConfigCategory;
|
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;GAc9I,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,CAgE/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;
|
|
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;GAc9I,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,CAgE/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;AA8JD,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
|
@@ -5170,6 +5170,7 @@ var exports_redact = {};
|
|
|
5170
5170
|
__export(exports_redact, {
|
|
5171
5171
|
scanSecrets: () => scanSecrets,
|
|
5172
5172
|
redactContent: () => redactContent,
|
|
5173
|
+
isSecretVarName: () => isSecretVarName,
|
|
5173
5174
|
hasSecrets: () => hasSecrets
|
|
5174
5175
|
});
|
|
5175
5176
|
function redactShell(content) {
|
|
@@ -5343,6 +5344,9 @@ function scanSecrets(content, format) {
|
|
|
5343
5344
|
function hasSecrets(content, format) {
|
|
5344
5345
|
return scanSecrets(content, format).length > 0;
|
|
5345
5346
|
}
|
|
5347
|
+
function isSecretVarName(name) {
|
|
5348
|
+
return SECRET_KEY_PATTERN.test(name);
|
|
5349
|
+
}
|
|
5346
5350
|
var SECRET_KEY_PATTERN, VALUE_PATTERNS, MIN_SECRET_VALUE_LEN = 8;
|
|
5347
5351
|
var init_redact = __esm(() => {
|
|
5348
5352
|
SECRET_KEY_PATTERN = /^(.*_?API_?KEY|.*_?TOKEN|.*_?SECRET|.*_?PASSWORD|.*_?PASSWD|.*_?CREDENTIAL|.*_?AUTH(?:_TOKEN|_KEY|ORIZATION)?|.*_?PRIVATE_?KEY|.*_?ACCESS_?KEY|.*_?CLIENT_?SECRET|.*_?SIGNING_?KEY|.*_?ENCRYPTION_?KEY|.*_AUTH_TOKEN)$/i;
|
|
@@ -5649,7 +5653,7 @@ function applyTransform(source, output, context = {}) {
|
|
|
5649
5653
|
var init_transforms = () => {};
|
|
5650
5654
|
|
|
5651
5655
|
// src/lib/session-render.ts
|
|
5652
|
-
var ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000, SESSION_RENDERER_OWNER_ID = "instructions-session-renderer", SESSION_RENDER_PROFILE_ENTRYPOINTS, SESSION_RENDER_OWNED_CONFIG_TARGETS, CODEWITH_FLATTENED_ADAPTER, CODEWITH_NATIVE_ADAPTER, SESSION_TOOL_ADAPTERS, SESSION_RENDER_MANAGED_DIRS, SESSION_RENDER_SHARED_MANAGED_DIRS, SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS;
|
|
5656
|
+
var ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000, SESSION_RENDERER_OWNER_ID = "instructions-session-renderer", SESSION_RENDER_PROFILE_ENTRYPOINTS, SESSION_RENDER_OWNED_CONFIG_TARGETS, CODEWITH_FLATTENED_ADAPTER, CODEWITH_NATIVE_ADAPTER, SESSION_TOOL_ADAPTERS, SESSION_RENDER_MANAGED_DIRS, SESSION_RENDER_SHARED_MANAGED_DIRS, SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS, CANONICAL_IDENTITY_EXPORT_PACKAGES;
|
|
5653
5657
|
var init_session_render = __esm(() => {
|
|
5654
5658
|
init_global_agent_rules_standard();
|
|
5655
5659
|
init_project_context();
|
|
@@ -5762,6 +5766,10 @@ var init_session_render = __esm(() => {
|
|
|
5762
5766
|
SESSION_RENDER_MANIFEST_RELATIVE_PATH,
|
|
5763
5767
|
SESSION_RENDER_SNAPSHOT_RELATIVE_DIR
|
|
5764
5768
|
];
|
|
5769
|
+
CANONICAL_IDENTITY_EXPORT_PACKAGES = new Set([
|
|
5770
|
+
"@hasna/identities",
|
|
5771
|
+
"@hasna/personas"
|
|
5772
|
+
]);
|
|
5765
5773
|
});
|
|
5766
5774
|
|
|
5767
5775
|
// src/lib/session-render-ownership.ts
|
|
@@ -6511,30 +6519,86 @@ async function syncToDisk(opts = {}) {
|
|
|
6511
6519
|
}
|
|
6512
6520
|
return result;
|
|
6513
6521
|
}
|
|
6514
|
-
function
|
|
6522
|
+
function redactionPlaceholders(storedLine) {
|
|
6523
|
+
const found = [...storedLine.match(CERTAIN_PLACEHOLDER_RE) ?? []];
|
|
6524
|
+
const assigned = storedLine.match(ASSIGNED_PLACEHOLDER_RE);
|
|
6525
|
+
if (assigned) {
|
|
6526
|
+
const name = assigned[3] ?? assigned[4] ?? assigned[5];
|
|
6527
|
+
if (name && isSecretVarName(name))
|
|
6528
|
+
found.push(assigned[2]);
|
|
6529
|
+
}
|
|
6530
|
+
return found;
|
|
6531
|
+
}
|
|
6532
|
+
function redactFormatForTarget(targetPath, storedFormat) {
|
|
6533
|
+
const p = targetPath.toLowerCase();
|
|
6534
|
+
if (/(^|\/)\.(zshrc|zprofile|bashrc|bash_profile|profile|zshenv|env)$/.test(p) || p.endsWith(".env"))
|
|
6535
|
+
return "shell";
|
|
6536
|
+
if (/(^|\/)\.(npmrc|yarnrc|curlrc|netrc)$/.test(p))
|
|
6537
|
+
return "ini";
|
|
6538
|
+
return storedFormat;
|
|
6539
|
+
}
|
|
6540
|
+
function storedPlaceholderIsLiteralOnDisk(storedLine, diskLine) {
|
|
6541
|
+
return redactionPlaceholders(storedLine).some((p) => !diskLine.includes(p));
|
|
6542
|
+
}
|
|
6543
|
+
function buildDiff(expectedContent, targetPath, storedFormat, showSecrets) {
|
|
6515
6544
|
const path = expandPath(targetPath);
|
|
6516
6545
|
if (!existsSync5(path))
|
|
6517
6546
|
return `(file not found on disk: ${path})`;
|
|
6518
6547
|
const diskContent = readFileSync3(path, "utf-8");
|
|
6519
6548
|
if (diskContent === expectedContent)
|
|
6520
6549
|
return "(no diff \u2014 identical)";
|
|
6550
|
+
const format = redactFormatForTarget(targetPath, storedFormat);
|
|
6521
6551
|
const stored = expectedContent.split(`
|
|
6522
6552
|
`);
|
|
6523
6553
|
const disk = diskContent.split(`
|
|
6524
6554
|
`);
|
|
6555
|
+
const { content: redactedDiskContent, redacted } = showSecrets ? { content: diskContent, redacted: [] } : redactContent(diskContent, format);
|
|
6556
|
+
const redactedDisk = redactedDiskContent.split(`
|
|
6557
|
+
`);
|
|
6558
|
+
const reasonByLine = new Map;
|
|
6559
|
+
for (const r of redacted)
|
|
6560
|
+
if (!reasonByLine.has(r.line))
|
|
6561
|
+
reasonByLine.set(r.line, r.reason);
|
|
6525
6562
|
const lines = [`--- stored (DB)`, `+++ disk (${path})`];
|
|
6526
6563
|
const maxLen = Math.max(stored.length, disk.length);
|
|
6527
6564
|
for (let i = 0;i < maxLen; i++) {
|
|
6565
|
+
const lineNo = i + 1;
|
|
6528
6566
|
const s = stored[i];
|
|
6529
6567
|
const dk = disk[i];
|
|
6530
6568
|
if (s === dk) {
|
|
6531
6569
|
if (s !== undefined)
|
|
6532
6570
|
lines.push(` ${s}`);
|
|
6533
|
-
|
|
6571
|
+
continue;
|
|
6572
|
+
}
|
|
6573
|
+
if (showSecrets || dk === undefined) {
|
|
6534
6574
|
if (s !== undefined)
|
|
6535
6575
|
lines.push(`-${s}`);
|
|
6536
6576
|
if (dk !== undefined)
|
|
6537
6577
|
lines.push(`+${dk}`);
|
|
6578
|
+
continue;
|
|
6579
|
+
}
|
|
6580
|
+
const structural = s !== undefined && storedPlaceholderIsLiteralOnDisk(s, dk);
|
|
6581
|
+
const patterned = reasonByLine.has(lineNo);
|
|
6582
|
+
if (!structural && !patterned) {
|
|
6583
|
+
if (s !== undefined)
|
|
6584
|
+
lines.push(`-${s}`);
|
|
6585
|
+
lines.push(`+${dk}`);
|
|
6586
|
+
continue;
|
|
6587
|
+
}
|
|
6588
|
+
if (structural) {
|
|
6589
|
+
const placeholder = redactionPlaceholders(s).find((p) => !dk.includes(p)) ?? "a placeholder";
|
|
6590
|
+
lines.push(`~line ${lineNo} differs: stored \`${s}\`, disk holds a literal value for ${placeholder} \u2014 redacted (use --show-secrets on a TTY to reveal)`);
|
|
6591
|
+
continue;
|
|
6592
|
+
}
|
|
6593
|
+
const safe = redactedDisk[i] ?? "";
|
|
6594
|
+
const reason = reasonByLine.get(lineNo);
|
|
6595
|
+
if (s !== undefined && safe === s) {
|
|
6596
|
+
lines.push(`~line ${lineNo} differs: stored \`${s}\`, disk holds a literal value (${reason}) \u2014 redacted (use --show-secrets on a TTY to reveal)`);
|
|
6597
|
+
} else {
|
|
6598
|
+
if (s !== undefined)
|
|
6599
|
+
lines.push(`-${s}`);
|
|
6600
|
+
lines.push(`+${safe}`);
|
|
6601
|
+
lines.push(`~line ${lineNo}: disk value redacted (${reason}) \u2014 use --show-secrets on a TTY to reveal`);
|
|
6538
6602
|
}
|
|
6539
6603
|
}
|
|
6540
6604
|
return lines.join(`
|
|
@@ -6549,15 +6613,16 @@ async function diffConfig(config, opts = {}) {
|
|
|
6549
6613
|
if (isGeneratedOutputTarget2(config, outputOwnerIdsByTarget(contextConfigs))) {
|
|
6550
6614
|
return "(generated output \u2014 managed by fan-out)";
|
|
6551
6615
|
}
|
|
6616
|
+
const showSecrets = opts.showSecrets ?? false;
|
|
6552
6617
|
if (config.target_path) {
|
|
6553
|
-
const diff = buildDiff(config.content, config.target_path);
|
|
6618
|
+
const diff = buildDiff(config.content, config.target_path, config.format, showSecrets);
|
|
6554
6619
|
if (!diff.includes("no diff"))
|
|
6555
6620
|
diffs.push(diff);
|
|
6556
6621
|
}
|
|
6557
6622
|
if (config.outputs.length > 0) {
|
|
6558
6623
|
for (const output of config.outputs) {
|
|
6559
6624
|
const expected = applyTransform(config, output, { configs: contextConfigs });
|
|
6560
|
-
const diff = buildDiff(expected, output.target_path);
|
|
6625
|
+
const diff = buildDiff(expected, output.target_path, detectFormat(output.target_path), showSecrets);
|
|
6561
6626
|
if (!diff.includes("no diff"))
|
|
6562
6627
|
diffs.push(diff);
|
|
6563
6628
|
}
|
|
@@ -6628,7 +6693,7 @@ function detectFormat(filePath) {
|
|
|
6628
6693
|
return "ini";
|
|
6629
6694
|
return "text";
|
|
6630
6695
|
}
|
|
6631
|
-
var CLAUDE_PROMPT_OUTPUTS, KNOWN_CONFIGS, PROJECT_CONFIG_FILES;
|
|
6696
|
+
var CLAUDE_PROMPT_OUTPUTS, KNOWN_CONFIGS, PROJECT_CONFIG_FILES, CERTAIN_PLACEHOLDER_RE, ASSIGNED_PLACEHOLDER_RE;
|
|
6632
6697
|
var init_sync = __esm(() => {
|
|
6633
6698
|
init_config_store();
|
|
6634
6699
|
init_apply();
|
|
@@ -6692,6 +6757,8 @@ var init_sync = __esm(() => {
|
|
|
6692
6757
|
{ file: ".agents/mcp_config.json", category: "mcp", agent: "antigravity", format: "json" },
|
|
6693
6758
|
{ file: ".qwen/settings.json", category: "agent", agent: "qwen", format: "json" }
|
|
6694
6759
|
];
|
|
6760
|
+
CERTAIN_PLACEHOLDER_RE = /\{\{[A-Za-z_][A-Za-z0-9_]*\}\}/g;
|
|
6761
|
+
ASSIGNED_PLACEHOLDER_RE = /[=:]\s*(["']?)(\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Z][A-Z0-9_]*)|%([A-Za-z_][A-Za-z0-9_]*)%)\1\s*,?\s*$/;
|
|
6695
6762
|
});
|
|
6696
6763
|
|
|
6697
6764
|
// src/lib/sync-dir.ts
|
|
@@ -6788,7 +6855,7 @@ var init_sync_dir = __esm(() => {
|
|
|
6788
6855
|
var require_package = __commonJS((exports, module) => {
|
|
6789
6856
|
module.exports = {
|
|
6790
6857
|
name: "@hasna/instructions",
|
|
6791
|
-
version: "0.4.
|
|
6858
|
+
version: "0.4.12",
|
|
6792
6859
|
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.",
|
|
6793
6860
|
type: "module",
|
|
6794
6861
|
main: "dist/index.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/instructions",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.12",
|
|
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",
|