@hasna/instructions 0.4.18 → 0.4.20
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/README.md +12 -4
- package/dist/cli/add-reference-update.test.d.ts +2 -0
- package/dist/cli/add-reference-update.test.d.ts.map +1 -0
- package/dist/cli/doctor-reference-duplicates.test.d.ts +2 -0
- package/dist/cli/doctor-reference-duplicates.test.d.ts.map +1 -0
- package/dist/cli/index.js +193 -24
- package/dist/cli/profile-update.test.d.ts +2 -0
- package/dist/cli/profile-update.test.d.ts.map +1 -0
- package/dist/index.js +111 -18
- package/dist/lib/config-target-identity.d.ts +76 -0
- package/dist/lib/config-target-identity.d.ts.map +1 -1
- package/dist/lib/global-agent-rules-standard.d.ts +29 -10
- package/dist/lib/global-agent-rules-standard.d.ts.map +1 -1
- package/dist/lib/project-dashboard-standard.d.ts +1 -1
- package/dist/lib/project-dashboard-standard.d.ts.map +1 -1
- package/dist/lib/session-render-rule-currency-floor.test.d.ts +2 -0
- package/dist/lib/session-render-rule-currency-floor.test.d.ts.map +1 -0
- package/dist/lib/session-render.d.ts +5 -0
- package/dist/lib/session-render.d.ts.map +1 -1
- package/dist/mcp/index.js +16 -2
- package/dist/mcp/server.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -331,14 +331,22 @@ workflows:
|
|
|
331
331
|
- `{{PROJECT_DASHBOARD_DIR}}` -> `.hasna/project`
|
|
332
332
|
- `{{PROJECT_DASHBOARD_RENDER_MANIFEST}}` -> `.hasna/project/dashboard/render.json`
|
|
333
333
|
- `{{PROJECT_DASHBOARD_SNAPSHOTS_DIR}}` -> `.hasna/project/dashboard/snapshots`
|
|
334
|
-
- `{{PROJECT_CHANNEL_PREFIX}}` -> `
|
|
334
|
+
- `{{PROJECT_CHANNEL_PREFIX}}` -> `""` (no prefix; the channel is the normalized project slug)
|
|
335
|
+
|
|
336
|
+
Existing profiles can be migrated in place without deleting or recreating them:
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
instructions profile update linux-arm64 \
|
|
340
|
+
--var PROJECT_CHANNEL_PREFIX= \
|
|
341
|
+
--unset-var LEGACY_VARIABLE
|
|
342
|
+
```
|
|
335
343
|
|
|
336
344
|
`instructions init` and `bun run seed` seed the
|
|
337
345
|
`agent-managed-project-dashboard-standard` reference. It documents the standard
|
|
338
346
|
`.hasna/project` layout, `projects dashboard *` commands, provider panel
|
|
339
|
-
commands,
|
|
340
|
-
that dashboards must show ids/statuses/evidence refs instead of raw
|
|
341
|
-
documents or secrets.
|
|
347
|
+
commands, normalized project-slug channel naming, durable todos/goal workflow,
|
|
348
|
+
and the rule that dashboards must show ids/statuses/evidence refs instead of raw
|
|
349
|
+
private documents or secrets.
|
|
342
350
|
|
|
343
351
|
## License
|
|
344
352
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-reference-update.test.d.ts","sourceRoot":"","sources":["../../src/cli/add-reference-update.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-reference-duplicates.test.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-reference-duplicates.test.ts"],"names":[],"mappings":""}
|
package/dist/cli/index.js
CHANGED
|
@@ -10371,6 +10371,21 @@ function canonicalFingerprintValue(value) {
|
|
|
10371
10371
|
}
|
|
10372
10372
|
return value;
|
|
10373
10373
|
}
|
|
10374
|
+
function ruleAttestation(rule) {
|
|
10375
|
+
const metadata = rule.metadata ?? {};
|
|
10376
|
+
const read = (key) => {
|
|
10377
|
+
const value = metadata[key];
|
|
10378
|
+
return typeof value === "string" ? value : null;
|
|
10379
|
+
};
|
|
10380
|
+
const applied = metadata["payloadFloorApplied"];
|
|
10381
|
+
return {
|
|
10382
|
+
contentSha256: sha2563(rule.content ?? ""),
|
|
10383
|
+
payloadFloorApplied: typeof applied === "boolean" ? applied : null,
|
|
10384
|
+
flooredFromRulesVersion: read("flooredFromRulesVersion"),
|
|
10385
|
+
flooredFromPayloadSha256: read("flooredFromPayloadSha256"),
|
|
10386
|
+
payloadIntegrity: read("payloadIntegrity")
|
|
10387
|
+
};
|
|
10388
|
+
}
|
|
10374
10389
|
function sourceFingerprint(source) {
|
|
10375
10390
|
return {
|
|
10376
10391
|
id: source.id,
|
|
@@ -10469,6 +10484,27 @@ function applyAgentOperatingRulesFloor(source, content) {
|
|
|
10469
10484
|
metadata: { ...source.metadata ?? {}, ...payload.metadata, ...floored }
|
|
10470
10485
|
};
|
|
10471
10486
|
}
|
|
10487
|
+
function applyAgentOperatingRulesFloorToRule(source, rule, content) {
|
|
10488
|
+
const unchanged = { content, metadata: rule.metadata ?? null };
|
|
10489
|
+
if (!claimsAgentOperatingRulesPolicy(source, content))
|
|
10490
|
+
return unchanged;
|
|
10491
|
+
const payload = resolveAgentOperatingRulesPayload(content);
|
|
10492
|
+
if (payload.content === content) {
|
|
10493
|
+
return {
|
|
10494
|
+
content,
|
|
10495
|
+
metadata: { ...rule.metadata ?? {}, payloadIntegrity: payload.integrity }
|
|
10496
|
+
};
|
|
10497
|
+
}
|
|
10498
|
+
const floored = {
|
|
10499
|
+
payloadFloorApplied: true,
|
|
10500
|
+
flooredFromRulesVersion: parseAgentOperatingRulesVersion(content),
|
|
10501
|
+
flooredFromPayloadSha256: sha2563(content)
|
|
10502
|
+
};
|
|
10503
|
+
return {
|
|
10504
|
+
content: payload.content,
|
|
10505
|
+
metadata: { ...rule.metadata ?? {}, ...payload.metadata, ...floored }
|
|
10506
|
+
};
|
|
10507
|
+
}
|
|
10472
10508
|
function skippedSource(source, reason) {
|
|
10473
10509
|
return {
|
|
10474
10510
|
id: source.id,
|
|
@@ -10507,24 +10543,67 @@ function normalizeSources(sources, tool, allowEmptySources) {
|
|
|
10507
10543
|
rejectDuplicateRulePaths(ordered);
|
|
10508
10544
|
return { sources: ordered, skipped: deduplicated.skipped };
|
|
10509
10545
|
}
|
|
10546
|
+
function semanticPolicyIntegrity(body) {
|
|
10547
|
+
return sha2563(body) === AGENT_OPERATING_RULES_PAYLOAD_SHA256 ? "pinned-digest" : "unverified-self-declared";
|
|
10548
|
+
}
|
|
10549
|
+
function semanticPolicyDeclaration(source) {
|
|
10550
|
+
const normalize = (value) => value.replace(/\r\n/g, `
|
|
10551
|
+
`).trim();
|
|
10552
|
+
const sentinel = source.content.match(AGENT_OPERATING_RULES_SENTINEL_PATTERN);
|
|
10553
|
+
if (sentinel) {
|
|
10554
|
+
return {
|
|
10555
|
+
version: sentinel[1],
|
|
10556
|
+
normalizedContent: normalize(source.content),
|
|
10557
|
+
integrity: semanticPolicyIntegrity(source.content)
|
|
10558
|
+
};
|
|
10559
|
+
}
|
|
10560
|
+
for (const rule of source.resolvedRules) {
|
|
10561
|
+
const body = rule.content ?? "";
|
|
10562
|
+
if (!claimsAgentOperatingRulesPolicy(source, body))
|
|
10563
|
+
continue;
|
|
10564
|
+
const ruleSentinel = body.match(AGENT_OPERATING_RULES_SENTINEL_PATTERN);
|
|
10565
|
+
if (!ruleSentinel)
|
|
10566
|
+
continue;
|
|
10567
|
+
return {
|
|
10568
|
+
version: ruleSentinel[1],
|
|
10569
|
+
normalizedContent: normalize(body),
|
|
10570
|
+
integrity: semanticPolicyIntegrity(body)
|
|
10571
|
+
};
|
|
10572
|
+
}
|
|
10573
|
+
return null;
|
|
10574
|
+
}
|
|
10575
|
+
function withoutSemanticPolicyPayloads(source) {
|
|
10576
|
+
const content = AGENT_OPERATING_RULES_SENTINEL_PATTERN.test(source.content) ? "" : source.content;
|
|
10577
|
+
const resolvedRules = source.resolvedRules.filter((rule) => {
|
|
10578
|
+
const body = rule.content ?? "";
|
|
10579
|
+
return !(AGENT_OPERATING_RULES_SENTINEL_PATTERN.test(body) && claimsAgentOperatingRulesPolicy(source, body));
|
|
10580
|
+
});
|
|
10581
|
+
const hasPathReferences = (source.sourcePaths ?? []).length > 0;
|
|
10582
|
+
if (!content.trim() && resolvedRules.length === 0 && !hasPathReferences)
|
|
10583
|
+
return null;
|
|
10584
|
+
return { ...source, content, resolvedRules };
|
|
10585
|
+
}
|
|
10510
10586
|
function deduplicateSemanticPolicySources(sources) {
|
|
10511
10587
|
const selected = [];
|
|
10512
10588
|
const skipped = [];
|
|
10513
10589
|
const policySources = new Map;
|
|
10514
|
-
const collapseReason = (winner, key) => `superseded by "${winner.id}": sources declaring the semantic policy ${key} collapse to one so a single instruction home cannot carry two rule-set versions
|
|
10590
|
+
const collapseReason = (winner, key, partial, displacesVerified) => `superseded by "${winner.id}": sources declaring the semantic policy ${key} collapse to one so a single instruction home cannot carry two rule-set versions` + (partial ? "; only the policy payload was removed and this source's other instructions still render" : "") + (displacesVerified ? "; WARNING the surviving payload is unverified-self-declared and displaced a digest-verified one on its own version claim" : "");
|
|
10591
|
+
const discard = (loser, winner, key, displacesVerified) => {
|
|
10592
|
+
const remainder = withoutSemanticPolicyPayloads(loser);
|
|
10593
|
+
skipped.push(skippedSource(loser, collapseReason(winner, key, remainder !== null, displacesVerified)));
|
|
10594
|
+
return remainder;
|
|
10595
|
+
};
|
|
10515
10596
|
for (const source of sources) {
|
|
10516
|
-
const
|
|
10517
|
-
if (!
|
|
10597
|
+
const declaration = semanticPolicyDeclaration(source);
|
|
10598
|
+
if (!declaration) {
|
|
10518
10599
|
selected.push(source);
|
|
10519
10600
|
continue;
|
|
10520
10601
|
}
|
|
10521
|
-
const version =
|
|
10602
|
+
const { version, normalizedContent, integrity } = declaration;
|
|
10522
10603
|
const key = AGENT_OPERATING_RULES_SEMANTIC_POLICY_KEY;
|
|
10523
|
-
const normalizedContent = source.content.replace(/\r\n/g, `
|
|
10524
|
-
`).trim();
|
|
10525
10604
|
const existing = policySources.get(key);
|
|
10526
10605
|
if (!existing) {
|
|
10527
|
-
policySources.set(key, { index: selected.length, version, normalizedContent });
|
|
10606
|
+
policySources.set(key, { index: selected.length, version, normalizedContent, integrity });
|
|
10528
10607
|
selected.push(source);
|
|
10529
10608
|
continue;
|
|
10530
10609
|
}
|
|
@@ -10534,16 +10613,22 @@ function deduplicateSemanticPolicySources(sources) {
|
|
|
10534
10613
|
}
|
|
10535
10614
|
const current = selected[existing.index];
|
|
10536
10615
|
const priorityOrder = semanticPolicySourcePriority(source) - semanticPolicySourcePriority(current);
|
|
10537
|
-
|
|
10538
|
-
|
|
10616
|
+
const displacesVerified = existing.integrity === "pinned-digest" && integrity === "unverified-self-declared";
|
|
10617
|
+
const arrivingWins = priorityOrder > 0 || priorityOrder === 0 && versionOrder > 0;
|
|
10618
|
+
if (!arrivingWins) {
|
|
10619
|
+
const remainder2 = discard(source, current, key, false);
|
|
10620
|
+
if (remainder2)
|
|
10621
|
+
selected.push(remainder2);
|
|
10539
10622
|
continue;
|
|
10540
10623
|
}
|
|
10541
|
-
|
|
10624
|
+
const remainder = discard(current, source, key, displacesVerified);
|
|
10542
10625
|
selected[existing.index] = {
|
|
10543
10626
|
...source,
|
|
10544
10627
|
resolvedOrder: current.resolvedOrder
|
|
10545
10628
|
};
|
|
10546
|
-
|
|
10629
|
+
if (remainder)
|
|
10630
|
+
selected.push(remainder);
|
|
10631
|
+
policySources.set(key, { index: existing.index, version, normalizedContent, integrity });
|
|
10547
10632
|
}
|
|
10548
10633
|
return { selected, skipped };
|
|
10549
10634
|
}
|
|
@@ -10551,7 +10636,7 @@ function semanticPolicySourcePriority(source) {
|
|
|
10551
10636
|
let priority = 0;
|
|
10552
10637
|
if (source.nonOverridable)
|
|
10553
10638
|
priority += 4;
|
|
10554
|
-
if (source.id === GLOBAL_AGENT_RULES_STANDARD_SLUG)
|
|
10639
|
+
if (source.id === GLOBAL_AGENT_RULES_STANDARD_SLUG || source.id === AGENT_OPERATING_RULES_SOURCE_ID)
|
|
10555
10640
|
priority += 2;
|
|
10556
10641
|
if (source.metadata?.["role"] === AGENT_OPERATING_RULES_ROLE)
|
|
10557
10642
|
priority += 1;
|
|
@@ -11051,7 +11136,8 @@ function planSessionRender(input) {
|
|
|
11051
11136
|
label: rule.resolvedLabel,
|
|
11052
11137
|
path: rule.resolvedPath,
|
|
11053
11138
|
globs: rule.globs ?? [],
|
|
11054
|
-
hash: rule.hash ?? null
|
|
11139
|
+
hash: rule.hash ?? null,
|
|
11140
|
+
...ruleAttestation(rule)
|
|
11055
11141
|
})),
|
|
11056
11142
|
renderedPayloadSha256: sha2563(source.content),
|
|
11057
11143
|
provenance: source.provenance ?? null,
|
|
@@ -11172,7 +11258,8 @@ function normalizeInstructionRules(source, tool) {
|
|
|
11172
11258
|
return (source.rules ?? []).map((rule) => {
|
|
11173
11259
|
if (!rule.id.trim())
|
|
11174
11260
|
throw new Error(`Instruction rule id is required for source ${source.id}.`);
|
|
11175
|
-
const
|
|
11261
|
+
const floored = applyAgentOperatingRulesFloorToRule(source, rule, rule.content ?? "");
|
|
11262
|
+
const content = filterProviderOnlyBlocks(floored.content, tool);
|
|
11176
11263
|
if (!content.trim() && !rule.path)
|
|
11177
11264
|
throw new Error(`Instruction rule content or path is required for rule ${rule.id}.`);
|
|
11178
11265
|
const resolvedPath = normalizeRulePath(rule.path ?? `${slug(rule.id)}.md`);
|
|
@@ -11183,6 +11270,7 @@ function normalizeInstructionRules(source, tool) {
|
|
|
11183
11270
|
return {
|
|
11184
11271
|
...rule,
|
|
11185
11272
|
content,
|
|
11273
|
+
metadata: floored.metadata,
|
|
11186
11274
|
normalizedId: slug(rule.id),
|
|
11187
11275
|
resolvedLabel: rule.label ?? rule.id,
|
|
11188
11276
|
resolvedPath
|
|
@@ -13794,6 +13882,7 @@ import { basename as basename7, join as join15, resolve as resolve8 } from "path
|
|
|
13794
13882
|
|
|
13795
13883
|
// src/lib/config-target-identity.ts
|
|
13796
13884
|
init_apply();
|
|
13885
|
+
init_database();
|
|
13797
13886
|
function findConfigsByTargetPath(configs, targetPath) {
|
|
13798
13887
|
const wanted = normalizeTargetPath(targetPath);
|
|
13799
13888
|
return configs.filter((config) => {
|
|
@@ -13804,6 +13893,20 @@ function findConfigsByTargetPath(configs, targetPath) {
|
|
|
13804
13893
|
return normalizeTargetPath(config.target_path) === wanted;
|
|
13805
13894
|
});
|
|
13806
13895
|
}
|
|
13896
|
+
function findReferenceConfigsByName(configs, name) {
|
|
13897
|
+
const wantedSlug = slugify(name);
|
|
13898
|
+
return configs.filter((config) => config.kind === "reference" && (config.name === name || slugify(config.name) === wantedSlug));
|
|
13899
|
+
}
|
|
13900
|
+
function findDuplicateReferenceNameGroups(configs) {
|
|
13901
|
+
const groups = new Map;
|
|
13902
|
+
for (const config of configs) {
|
|
13903
|
+
if (config.kind !== "reference")
|
|
13904
|
+
continue;
|
|
13905
|
+
const key = slugify(config.name);
|
|
13906
|
+
groups.set(key, [...groups.get(key) ?? [], config]);
|
|
13907
|
+
}
|
|
13908
|
+
return [...groups.entries()].filter(([, rows]) => rows.length > 1).map(([, rows]) => ({ name: rows[0].name, configs: rows }));
|
|
13909
|
+
}
|
|
13807
13910
|
function findDuplicateTargetPathGroups(configs) {
|
|
13808
13911
|
const groups = new Map;
|
|
13809
13912
|
for (const config of configs) {
|
|
@@ -14833,7 +14936,7 @@ var PROJECT_DASHBOARD_PROFILE_VARIABLES = {
|
|
|
14833
14936
|
PROJECT_DASHBOARD_DIR: ".hasna/project",
|
|
14834
14937
|
PROJECT_DASHBOARD_RENDER_MANIFEST: ".hasna/project/dashboard/render.json",
|
|
14835
14938
|
PROJECT_DASHBOARD_SNAPSHOTS_DIR: ".hasna/project/dashboard/snapshots",
|
|
14836
|
-
PROJECT_CHANNEL_PREFIX: "
|
|
14939
|
+
PROJECT_CHANNEL_PREFIX: ""
|
|
14837
14940
|
};
|
|
14838
14941
|
var PROJECT_DASHBOARD_STANDARD_CONTENT = `# Agent-Managed Project Dashboard Standard
|
|
14839
14942
|
|
|
@@ -14888,8 +14991,8 @@ context.
|
|
|
14888
14991
|
|
|
14889
14992
|
## Coordination
|
|
14890
14993
|
|
|
14891
|
-
- Project conversation channels use
|
|
14892
|
-
displayed to humans as
|
|
14994
|
+
- Project conversation channels use the normalized project slug in the CLI and
|
|
14995
|
+
are displayed to humans as \`#<project-slug>\`.
|
|
14893
14996
|
- Todos tasks are the source of truth for work; messages are only coordination.
|
|
14894
14997
|
- Durable Codewith goal plans should own long-running implementation.
|
|
14895
14998
|
- New implementation/verification work should route through task-triggered fresh
|
|
@@ -14994,10 +15097,15 @@ function mergeProfileSelectors(preset, existing) {
|
|
|
14994
15097
|
};
|
|
14995
15098
|
}
|
|
14996
15099
|
function mergeProfileVariables(preset, existing) {
|
|
14997
|
-
|
|
15100
|
+
const variables = {
|
|
14998
15101
|
...preset ?? {},
|
|
14999
15102
|
...existing
|
|
15000
15103
|
};
|
|
15104
|
+
for (const [key, value] of Object.entries(preset ?? {})) {
|
|
15105
|
+
if (value === "")
|
|
15106
|
+
variables[key] = value;
|
|
15107
|
+
}
|
|
15108
|
+
return variables;
|
|
15001
15109
|
}
|
|
15002
15110
|
function mergeUnique(preset, existing) {
|
|
15003
15111
|
const values = [...new Set([...preset ?? [], ...existing ?? []])];
|
|
@@ -15577,6 +15685,15 @@ function parseVarArgs(values) {
|
|
|
15577
15685
|
}
|
|
15578
15686
|
return Object.keys(vars).length > 0 ? vars : undefined;
|
|
15579
15687
|
}
|
|
15688
|
+
function parseUnsetVarArgs(values) {
|
|
15689
|
+
if (!values || values.length === 0)
|
|
15690
|
+
return [];
|
|
15691
|
+
const keys = [...new Set(values.map((value) => value.trim()))];
|
|
15692
|
+
if (keys.some((key) => key.length === 0 || key.includes("="))) {
|
|
15693
|
+
throw new Error('Invalid --unset-var (expected variable names without "=")');
|
|
15694
|
+
}
|
|
15695
|
+
return keys;
|
|
15696
|
+
}
|
|
15580
15697
|
function parseProfileSelectors(opts) {
|
|
15581
15698
|
const selectors = {};
|
|
15582
15699
|
const os = splitCsv(opts.os);
|
|
@@ -15691,20 +15808,33 @@ program.command("add <path>").description("Ingest a file into the config DB").op
|
|
|
15691
15808
|
const targetPath = abs.startsWith(homedir7()) ? abs.replace(homedir7(), "~") : abs;
|
|
15692
15809
|
const name = opts.name || filePath.split("/").pop();
|
|
15693
15810
|
const store = resolveConfigStore();
|
|
15694
|
-
const
|
|
15811
|
+
const allConfigs = await store.listConfigs();
|
|
15812
|
+
const existingOwners = opts.kind === "reference" ? findReferenceConfigsByName(allConfigs, name) : findConfigsByTargetPath(allConfigs, targetPath);
|
|
15813
|
+
const isReference = opts.kind === "reference";
|
|
15814
|
+
const identityLabel = isReference ? `Reference config "${name}"` : targetPath;
|
|
15815
|
+
const identityNoun = isReference ? "name" : "path";
|
|
15695
15816
|
if (existingOwners.length > 0 && !opts.update) {
|
|
15696
15817
|
const owners = existingOwners.map((owner) => `${owner.slug} (${owner.id})`).join(", ");
|
|
15697
|
-
console.error(chalk.red(`${
|
|
15818
|
+
console.error(chalk.red(`${identityLabel} is already tracked by: ${owners}`));
|
|
15698
15819
|
if (existingOwners.length > 1) {
|
|
15699
|
-
console.error(chalk.red(` ${existingOwners.length} rows already collide on this
|
|
15820
|
+
console.error(chalk.red(` ${existingOwners.length} rows already collide on this ${identityNoun} \u2014 apply order between them is undefined.`));
|
|
15700
15821
|
}
|
|
15701
15822
|
console.error(chalk.dim(" Use `instructions add <path> --update` to refresh that row in place,"));
|
|
15702
|
-
|
|
15823
|
+
if (isReference) {
|
|
15824
|
+
console.error(chalk.dim(" or `instructions delete <id>` first."));
|
|
15825
|
+
} else {
|
|
15826
|
+
console.error(chalk.dim(" `instructions sync` to pull disk changes in, or `instructions delete <id>` first."));
|
|
15827
|
+
}
|
|
15703
15828
|
process.exit(1);
|
|
15704
15829
|
}
|
|
15705
15830
|
let config;
|
|
15706
15831
|
if (existingOwners.length > 0) {
|
|
15707
|
-
const
|
|
15832
|
+
const exactIndex = isReference ? existingOwners.findIndex((owner) => owner.name === name) : -1;
|
|
15833
|
+
const target = exactIndex >= 0 ? existingOwners[exactIndex] : existingOwners[0];
|
|
15834
|
+
const rest = existingOwners.filter((owner) => owner.id !== target.id);
|
|
15835
|
+
if (content !== target.content) {
|
|
15836
|
+
await store.createSnapshot(target.id, target.content, target.version);
|
|
15837
|
+
}
|
|
15708
15838
|
config = await store.updateConfig(target.id, {
|
|
15709
15839
|
content,
|
|
15710
15840
|
format: fmt,
|
|
@@ -15714,7 +15844,7 @@ program.command("add <path>").description("Ingest a file into the config DB").op
|
|
|
15714
15844
|
});
|
|
15715
15845
|
console.log(chalk.green("\u2713") + ` Updated: ${chalk.bold(config.name)} ${chalk.dim(`(${config.slug})`)}`);
|
|
15716
15846
|
if (rest.length > 0) {
|
|
15717
|
-
console.log(chalk.yellow(` \u26A0 ${rest.length} other row(s) still
|
|
15847
|
+
console.log(chalk.yellow(` \u26A0 ${rest.length} other row(s) still share this ${identityNoun}: ${rest.map((r) => r.slug).join(", ")}`));
|
|
15718
15848
|
console.log(chalk.yellow(" Apply order between them is undefined. Delete the extras."));
|
|
15719
15849
|
}
|
|
15720
15850
|
if (redacted.length > 0) {
|
|
@@ -15979,6 +16109,31 @@ profileCmd.command("create <name>").description("Create a new profile").option("
|
|
|
15979
16109
|
});
|
|
15980
16110
|
console.log(chalk.green("\u2713") + ` Created profile: ${chalk.bold(p.name)} ${chalk.dim(`(${p.slug})`)}`);
|
|
15981
16111
|
});
|
|
16112
|
+
profileCmd.command("update <id>").description("Update an existing profile's variables in one store operation").option("--var <vars...>", "set profile variable(s) as KEY=VALUE").option("--unset-var <keys...>", "remove profile variable(s) by key").action(async (id, opts) => {
|
|
16113
|
+
try {
|
|
16114
|
+
const setVariables = parseVarArgs(opts.var) ?? {};
|
|
16115
|
+
const unsetVariables = parseUnsetVarArgs(opts.unsetVar);
|
|
16116
|
+
const setKeys = new Set(Object.keys(setVariables));
|
|
16117
|
+
const conflicts = unsetVariables.filter((key) => setKeys.has(key));
|
|
16118
|
+
if (conflicts.length > 0) {
|
|
16119
|
+
throw new Error(`Variables cannot be both set and unset: ${conflicts.join(", ")}`);
|
|
16120
|
+
}
|
|
16121
|
+
if (Object.keys(setVariables).length === 0 && unsetVariables.length === 0) {
|
|
16122
|
+
throw new Error("Provide --var KEY=VALUE and/or --unset-var KEY");
|
|
16123
|
+
}
|
|
16124
|
+
const store = resolveConfigStore();
|
|
16125
|
+
const profile = await store.getProfile(id);
|
|
16126
|
+
const variables = { ...profile.variables };
|
|
16127
|
+
for (const key of unsetVariables)
|
|
16128
|
+
delete variables[key];
|
|
16129
|
+
Object.assign(variables, setVariables);
|
|
16130
|
+
const updated = await store.updateProfile(profile.id, { variables });
|
|
16131
|
+
console.log(chalk.green("\u2713") + ` Updated profile: ${chalk.bold(updated.name)} ${chalk.dim(`(${updated.slug})`)}`);
|
|
16132
|
+
} catch (e) {
|
|
16133
|
+
console.error(chalk.red(formatCliError(e)));
|
|
16134
|
+
process.exit(1);
|
|
16135
|
+
}
|
|
16136
|
+
});
|
|
15982
16137
|
profileCmd.command("show <id>").description("Show profile and its configs").option("--limit <n>", `max config rows (default ${DEFAULT_LIST_LIMIT})`).option("--cursor <n>", "zero-based pagination cursor").action(async (id, opts) => {
|
|
15983
16138
|
try {
|
|
15984
16139
|
const store = resolveConfigStore();
|
|
@@ -16755,6 +16910,20 @@ Stored configs (${allConfigs.length}):`));
|
|
|
16755
16910
|
}
|
|
16756
16911
|
console.log(chalk.dim(" Keep one row per path: `instructions delete <id>` for the extras."));
|
|
16757
16912
|
}
|
|
16913
|
+
const duplicateReferenceNames = findDuplicateReferenceNameGroups(allConfigs);
|
|
16914
|
+
if (duplicateReferenceNames.length === 0) {
|
|
16915
|
+
pass("No reference config name is claimed by more than one row");
|
|
16916
|
+
} else {
|
|
16917
|
+
const rowCount = duplicateReferenceNames.reduce((total, group) => total + group.configs.length, 0);
|
|
16918
|
+
fail(`${duplicateReferenceNames.length} reference name(s) claimed by more than one row (${rowCount} rows) \u2014 only one is live in the next render`);
|
|
16919
|
+
for (const group of duplicateReferenceNames) {
|
|
16920
|
+
console.log(chalk.yellow(` ${group.name}`));
|
|
16921
|
+
for (const c of group.configs) {
|
|
16922
|
+
console.log(chalk.dim(` ${c.slug} (${c.id}) updated ${c.updated_at}`));
|
|
16923
|
+
}
|
|
16924
|
+
}
|
|
16925
|
+
console.log(chalk.dim(" Keep one row per name: `instructions delete <id>` for the extras."));
|
|
16926
|
+
}
|
|
16758
16927
|
console.log(`
|
|
16759
16928
|
${issues === 0 ? chalk.green("\u2713 All checks passed") : chalk.yellow(`${issues} issue(s) found`)}`);
|
|
16760
16929
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-update.test.d.ts","sourceRoot":"","sources":["../../src/cli/profile-update.test.ts"],"names":[],"mappings":""}
|
package/dist/index.js
CHANGED
|
@@ -8442,6 +8442,21 @@ function canonicalFingerprintValue(value) {
|
|
|
8442
8442
|
}
|
|
8443
8443
|
return value;
|
|
8444
8444
|
}
|
|
8445
|
+
function ruleAttestation(rule) {
|
|
8446
|
+
const metadata = rule.metadata ?? {};
|
|
8447
|
+
const read = (key) => {
|
|
8448
|
+
const value = metadata[key];
|
|
8449
|
+
return typeof value === "string" ? value : null;
|
|
8450
|
+
};
|
|
8451
|
+
const applied = metadata["payloadFloorApplied"];
|
|
8452
|
+
return {
|
|
8453
|
+
contentSha256: sha2563(rule.content ?? ""),
|
|
8454
|
+
payloadFloorApplied: typeof applied === "boolean" ? applied : null,
|
|
8455
|
+
flooredFromRulesVersion: read("flooredFromRulesVersion"),
|
|
8456
|
+
flooredFromPayloadSha256: read("flooredFromPayloadSha256"),
|
|
8457
|
+
payloadIntegrity: read("payloadIntegrity")
|
|
8458
|
+
};
|
|
8459
|
+
}
|
|
8445
8460
|
function sourceFingerprint(source) {
|
|
8446
8461
|
return {
|
|
8447
8462
|
id: source.id,
|
|
@@ -8540,6 +8555,27 @@ function applyAgentOperatingRulesFloor(source, content) {
|
|
|
8540
8555
|
metadata: { ...source.metadata ?? {}, ...payload.metadata, ...floored }
|
|
8541
8556
|
};
|
|
8542
8557
|
}
|
|
8558
|
+
function applyAgentOperatingRulesFloorToRule(source, rule, content) {
|
|
8559
|
+
const unchanged = { content, metadata: rule.metadata ?? null };
|
|
8560
|
+
if (!claimsAgentOperatingRulesPolicy(source, content))
|
|
8561
|
+
return unchanged;
|
|
8562
|
+
const payload = resolveAgentOperatingRulesPayload(content);
|
|
8563
|
+
if (payload.content === content) {
|
|
8564
|
+
return {
|
|
8565
|
+
content,
|
|
8566
|
+
metadata: { ...rule.metadata ?? {}, payloadIntegrity: payload.integrity }
|
|
8567
|
+
};
|
|
8568
|
+
}
|
|
8569
|
+
const floored = {
|
|
8570
|
+
payloadFloorApplied: true,
|
|
8571
|
+
flooredFromRulesVersion: parseAgentOperatingRulesVersion(content),
|
|
8572
|
+
flooredFromPayloadSha256: sha2563(content)
|
|
8573
|
+
};
|
|
8574
|
+
return {
|
|
8575
|
+
content: payload.content,
|
|
8576
|
+
metadata: { ...rule.metadata ?? {}, ...payload.metadata, ...floored }
|
|
8577
|
+
};
|
|
8578
|
+
}
|
|
8543
8579
|
function skippedSource(source, reason) {
|
|
8544
8580
|
return {
|
|
8545
8581
|
id: source.id,
|
|
@@ -8578,24 +8614,67 @@ function normalizeSources(sources, tool, allowEmptySources) {
|
|
|
8578
8614
|
rejectDuplicateRulePaths(ordered);
|
|
8579
8615
|
return { sources: ordered, skipped: deduplicated.skipped };
|
|
8580
8616
|
}
|
|
8617
|
+
function semanticPolicyIntegrity(body) {
|
|
8618
|
+
return sha2563(body) === AGENT_OPERATING_RULES_PAYLOAD_SHA256 ? "pinned-digest" : "unverified-self-declared";
|
|
8619
|
+
}
|
|
8620
|
+
function semanticPolicyDeclaration(source) {
|
|
8621
|
+
const normalize = (value) => value.replace(/\r\n/g, `
|
|
8622
|
+
`).trim();
|
|
8623
|
+
const sentinel = source.content.match(AGENT_OPERATING_RULES_SENTINEL_PATTERN);
|
|
8624
|
+
if (sentinel) {
|
|
8625
|
+
return {
|
|
8626
|
+
version: sentinel[1],
|
|
8627
|
+
normalizedContent: normalize(source.content),
|
|
8628
|
+
integrity: semanticPolicyIntegrity(source.content)
|
|
8629
|
+
};
|
|
8630
|
+
}
|
|
8631
|
+
for (const rule of source.resolvedRules) {
|
|
8632
|
+
const body = rule.content ?? "";
|
|
8633
|
+
if (!claimsAgentOperatingRulesPolicy(source, body))
|
|
8634
|
+
continue;
|
|
8635
|
+
const ruleSentinel = body.match(AGENT_OPERATING_RULES_SENTINEL_PATTERN);
|
|
8636
|
+
if (!ruleSentinel)
|
|
8637
|
+
continue;
|
|
8638
|
+
return {
|
|
8639
|
+
version: ruleSentinel[1],
|
|
8640
|
+
normalizedContent: normalize(body),
|
|
8641
|
+
integrity: semanticPolicyIntegrity(body)
|
|
8642
|
+
};
|
|
8643
|
+
}
|
|
8644
|
+
return null;
|
|
8645
|
+
}
|
|
8646
|
+
function withoutSemanticPolicyPayloads(source) {
|
|
8647
|
+
const content = AGENT_OPERATING_RULES_SENTINEL_PATTERN.test(source.content) ? "" : source.content;
|
|
8648
|
+
const resolvedRules = source.resolvedRules.filter((rule) => {
|
|
8649
|
+
const body = rule.content ?? "";
|
|
8650
|
+
return !(AGENT_OPERATING_RULES_SENTINEL_PATTERN.test(body) && claimsAgentOperatingRulesPolicy(source, body));
|
|
8651
|
+
});
|
|
8652
|
+
const hasPathReferences = (source.sourcePaths ?? []).length > 0;
|
|
8653
|
+
if (!content.trim() && resolvedRules.length === 0 && !hasPathReferences)
|
|
8654
|
+
return null;
|
|
8655
|
+
return { ...source, content, resolvedRules };
|
|
8656
|
+
}
|
|
8581
8657
|
function deduplicateSemanticPolicySources(sources) {
|
|
8582
8658
|
const selected = [];
|
|
8583
8659
|
const skipped = [];
|
|
8584
8660
|
const policySources = new Map;
|
|
8585
|
-
const collapseReason = (winner, key) => `superseded by "${winner.id}": sources declaring the semantic policy ${key} collapse to one so a single instruction home cannot carry two rule-set versions
|
|
8661
|
+
const collapseReason = (winner, key, partial, displacesVerified) => `superseded by "${winner.id}": sources declaring the semantic policy ${key} collapse to one so a single instruction home cannot carry two rule-set versions` + (partial ? "; only the policy payload was removed and this source's other instructions still render" : "") + (displacesVerified ? "; WARNING the surviving payload is unverified-self-declared and displaced a digest-verified one on its own version claim" : "");
|
|
8662
|
+
const discard = (loser, winner, key, displacesVerified) => {
|
|
8663
|
+
const remainder = withoutSemanticPolicyPayloads(loser);
|
|
8664
|
+
skipped.push(skippedSource(loser, collapseReason(winner, key, remainder !== null, displacesVerified)));
|
|
8665
|
+
return remainder;
|
|
8666
|
+
};
|
|
8586
8667
|
for (const source of sources) {
|
|
8587
|
-
const
|
|
8588
|
-
if (!
|
|
8668
|
+
const declaration = semanticPolicyDeclaration(source);
|
|
8669
|
+
if (!declaration) {
|
|
8589
8670
|
selected.push(source);
|
|
8590
8671
|
continue;
|
|
8591
8672
|
}
|
|
8592
|
-
const version =
|
|
8673
|
+
const { version, normalizedContent, integrity } = declaration;
|
|
8593
8674
|
const key = AGENT_OPERATING_RULES_SEMANTIC_POLICY_KEY;
|
|
8594
|
-
const normalizedContent = source.content.replace(/\r\n/g, `
|
|
8595
|
-
`).trim();
|
|
8596
8675
|
const existing = policySources.get(key);
|
|
8597
8676
|
if (!existing) {
|
|
8598
|
-
policySources.set(key, { index: selected.length, version, normalizedContent });
|
|
8677
|
+
policySources.set(key, { index: selected.length, version, normalizedContent, integrity });
|
|
8599
8678
|
selected.push(source);
|
|
8600
8679
|
continue;
|
|
8601
8680
|
}
|
|
@@ -8605,16 +8684,22 @@ function deduplicateSemanticPolicySources(sources) {
|
|
|
8605
8684
|
}
|
|
8606
8685
|
const current = selected[existing.index];
|
|
8607
8686
|
const priorityOrder = semanticPolicySourcePriority(source) - semanticPolicySourcePriority(current);
|
|
8608
|
-
|
|
8609
|
-
|
|
8687
|
+
const displacesVerified = existing.integrity === "pinned-digest" && integrity === "unverified-self-declared";
|
|
8688
|
+
const arrivingWins = priorityOrder > 0 || priorityOrder === 0 && versionOrder > 0;
|
|
8689
|
+
if (!arrivingWins) {
|
|
8690
|
+
const remainder2 = discard(source, current, key, false);
|
|
8691
|
+
if (remainder2)
|
|
8692
|
+
selected.push(remainder2);
|
|
8610
8693
|
continue;
|
|
8611
8694
|
}
|
|
8612
|
-
|
|
8695
|
+
const remainder = discard(current, source, key, displacesVerified);
|
|
8613
8696
|
selected[existing.index] = {
|
|
8614
8697
|
...source,
|
|
8615
8698
|
resolvedOrder: current.resolvedOrder
|
|
8616
8699
|
};
|
|
8617
|
-
|
|
8700
|
+
if (remainder)
|
|
8701
|
+
selected.push(remainder);
|
|
8702
|
+
policySources.set(key, { index: existing.index, version, normalizedContent, integrity });
|
|
8618
8703
|
}
|
|
8619
8704
|
return { selected, skipped };
|
|
8620
8705
|
}
|
|
@@ -8622,7 +8707,7 @@ function semanticPolicySourcePriority(source) {
|
|
|
8622
8707
|
let priority = 0;
|
|
8623
8708
|
if (source.nonOverridable)
|
|
8624
8709
|
priority += 4;
|
|
8625
|
-
if (source.id === GLOBAL_AGENT_RULES_STANDARD_SLUG)
|
|
8710
|
+
if (source.id === GLOBAL_AGENT_RULES_STANDARD_SLUG || source.id === AGENT_OPERATING_RULES_SOURCE_ID)
|
|
8626
8711
|
priority += 2;
|
|
8627
8712
|
if (source.metadata?.["role"] === AGENT_OPERATING_RULES_ROLE)
|
|
8628
8713
|
priority += 1;
|
|
@@ -9122,7 +9207,8 @@ function planSessionRender(input) {
|
|
|
9122
9207
|
label: rule.resolvedLabel,
|
|
9123
9208
|
path: rule.resolvedPath,
|
|
9124
9209
|
globs: rule.globs ?? [],
|
|
9125
|
-
hash: rule.hash ?? null
|
|
9210
|
+
hash: rule.hash ?? null,
|
|
9211
|
+
...ruleAttestation(rule)
|
|
9126
9212
|
})),
|
|
9127
9213
|
renderedPayloadSha256: sha2563(source.content),
|
|
9128
9214
|
provenance: source.provenance ?? null,
|
|
@@ -9344,7 +9430,8 @@ function normalizeInstructionRules(source, tool) {
|
|
|
9344
9430
|
return (source.rules ?? []).map((rule) => {
|
|
9345
9431
|
if (!rule.id.trim())
|
|
9346
9432
|
throw new Error(`Instruction rule id is required for source ${source.id}.`);
|
|
9347
|
-
const
|
|
9433
|
+
const floored = applyAgentOperatingRulesFloorToRule(source, rule, rule.content ?? "");
|
|
9434
|
+
const content = filterProviderOnlyBlocks(floored.content, tool);
|
|
9348
9435
|
if (!content.trim() && !rule.path)
|
|
9349
9436
|
throw new Error(`Instruction rule content or path is required for rule ${rule.id}.`);
|
|
9350
9437
|
const resolvedPath = normalizeRulePath(rule.path ?? `${slug(rule.id)}.md`);
|
|
@@ -9355,6 +9442,7 @@ function normalizeInstructionRules(source, tool) {
|
|
|
9355
9442
|
return {
|
|
9356
9443
|
...rule,
|
|
9357
9444
|
content,
|
|
9445
|
+
metadata: floored.metadata,
|
|
9358
9446
|
normalizedId: slug(rule.id),
|
|
9359
9447
|
resolvedLabel: rule.label ?? rule.id,
|
|
9360
9448
|
resolvedPath
|
|
@@ -11163,7 +11251,7 @@ var PROJECT_DASHBOARD_PROFILE_VARIABLES = {
|
|
|
11163
11251
|
PROJECT_DASHBOARD_DIR: ".hasna/project",
|
|
11164
11252
|
PROJECT_DASHBOARD_RENDER_MANIFEST: ".hasna/project/dashboard/render.json",
|
|
11165
11253
|
PROJECT_DASHBOARD_SNAPSHOTS_DIR: ".hasna/project/dashboard/snapshots",
|
|
11166
|
-
PROJECT_CHANNEL_PREFIX: "
|
|
11254
|
+
PROJECT_CHANNEL_PREFIX: ""
|
|
11167
11255
|
};
|
|
11168
11256
|
var PROJECT_DASHBOARD_STANDARD_CONTENT = `# Agent-Managed Project Dashboard Standard
|
|
11169
11257
|
|
|
@@ -11218,8 +11306,8 @@ context.
|
|
|
11218
11306
|
|
|
11219
11307
|
## Coordination
|
|
11220
11308
|
|
|
11221
|
-
- Project conversation channels use
|
|
11222
|
-
displayed to humans as
|
|
11309
|
+
- Project conversation channels use the normalized project slug in the CLI and
|
|
11310
|
+
are displayed to humans as \`#<project-slug>\`.
|
|
11223
11311
|
- Todos tasks are the source of truth for work; messages are only coordination.
|
|
11224
11312
|
- Durable Codewith goal plans should own long-running implementation.
|
|
11225
11313
|
- New implementation/verification work should route through task-triggered fresh
|
|
@@ -11324,10 +11412,15 @@ function mergeProfileSelectors(preset, existing) {
|
|
|
11324
11412
|
};
|
|
11325
11413
|
}
|
|
11326
11414
|
function mergeProfileVariables(preset, existing) {
|
|
11327
|
-
|
|
11415
|
+
const variables = {
|
|
11328
11416
|
...preset ?? {},
|
|
11329
11417
|
...existing
|
|
11330
11418
|
};
|
|
11419
|
+
for (const [key, value] of Object.entries(preset ?? {})) {
|
|
11420
|
+
if (value === "")
|
|
11421
|
+
variables[key] = value;
|
|
11422
|
+
}
|
|
11423
|
+
return variables;
|
|
11331
11424
|
}
|
|
11332
11425
|
function mergeUnique(preset, existing) {
|
|
11333
11426
|
const values = [...new Set([...preset ?? [], ...existing ?? []])];
|
|
@@ -15,6 +15,82 @@ import type { Config } from "../types/index.js";
|
|
|
15
15
|
* Reference configs (`kind: "reference"`) own no target path and never match.
|
|
16
16
|
*/
|
|
17
17
|
export declare function findConfigsByTargetPath(configs: Config[], targetPath: string): Config[];
|
|
18
|
+
/**
|
|
19
|
+
* Every reference-kind row already ingested under `name`.
|
|
20
|
+
*
|
|
21
|
+
* A reference config (`kind: "reference"`) owns no target_path — it is not
|
|
22
|
+
* mirrored 1:1 onto one file on disk, so `findConfigsByTargetPath` can never
|
|
23
|
+
* find it, by design (see that function's own doc comment). That left
|
|
24
|
+
* `add <path> --kind reference --update` with no identity signal at all: every
|
|
25
|
+
* re-ingest of a reference config's content minted a fresh row instead of
|
|
26
|
+
* updating the one that already existed, at every `--update` setting, because
|
|
27
|
+
* there was nothing to match on. Measured live 2026-08-04, todos 757cefdb: 20
|
|
28
|
+
* of 20 reference-kind rows in the fleet store had target_path=null.
|
|
29
|
+
*
|
|
30
|
+
* For a reference config, `name` IS the identity, in exactly the same sense a
|
|
31
|
+
* file-kind config's target_path is its identity: re-ingest with the same
|
|
32
|
+
* name, get the same row; re-ingest with a different name, get a different
|
|
33
|
+
* (or new) row. Two comparisons, both needed:
|
|
34
|
+
*
|
|
35
|
+
* - EXACT name match. `uniqueSlug` (db/database.ts) only de-duplicates the
|
|
36
|
+
* SLUG column, which carries a DB-level UNIQUE constraint — it never
|
|
37
|
+
* touches `name`, which carries no such constraint. So every prior
|
|
38
|
+
* duplicate this bug already produced still has the identical `name` and a
|
|
39
|
+
* `-1`, `-2`, ... suffixed slug. Measured live 2026-08-04 in the fleet
|
|
40
|
+
* store: 8 reference rows all named "Global Agent Rules Standard"
|
|
41
|
+
* (`global-agent-rules-standard-1` through `-8`), one identical SHA-256
|
|
42
|
+
* content hash across all 8, ingested on 6 different days — the exact
|
|
43
|
+
* shape this function exists to stop.
|
|
44
|
+
* - Slugified match, for a re-ingest whose `--name` differs only in case or
|
|
45
|
+
* punctuation from an existing row's name.
|
|
46
|
+
*
|
|
47
|
+
* CORRECTED 2026-08-04 (todos 195272ae, Finding 1): this used to compare
|
|
48
|
+
* the query's slug against each candidate's STORED `.slug` COLUMN
|
|
49
|
+
* (`config.slug === wantedSlug`). That is sound only for a candidate whose
|
|
50
|
+
* own slug was never disambiguated — the moment two rows already collide
|
|
51
|
+
* and `uniqueSlug` has suffixed one of them (`sample-rule-1`), its stored
|
|
52
|
+
* slug no longer equals what re-slugifying its OWN name produces, so the
|
|
53
|
+
* old comparison went blind to it. Reproduced live: row A "Sample Rule"
|
|
54
|
+
* (slug "sample-rule"), row B "sample rule" (slug disambiguated to
|
|
55
|
+
* "sample-rule-1" because A already held the base slug) — querying "Sample
|
|
56
|
+
* Rule" found only A. `add --update` then updated A, reported
|
|
57
|
+
* `rest.length === 0` (no "N other rows share this name" warning), and
|
|
58
|
+
* left B — the exact row a human would call a duplicate of A — untouched
|
|
59
|
+
* and unmentioned. This is the one population the slug clause exists to
|
|
60
|
+
* catch: it is impossible for a fresh, non-colliding row to need it, since
|
|
61
|
+
* an un-disambiguated slug already matches via `slugify(name)` trivially.
|
|
62
|
+
* Comparing against `slugify(config.name)` instead — recomputed from the
|
|
63
|
+
* candidate's own name rather than trusted from its (possibly
|
|
64
|
+
* disambiguated) stored column — fixes this without weakening the EXACT
|
|
65
|
+
* name clause above, which still independently catches the byte-identical
|
|
66
|
+
* case regardless: it can only ADD matches the old comparison missed, not
|
|
67
|
+
* remove any a query's name literally shares.
|
|
68
|
+
*/
|
|
69
|
+
export declare function findReferenceConfigsByName(configs: Config[], name: string): Config[];
|
|
70
|
+
/**
|
|
71
|
+
* Groups of reference-kind rows that collide on identity, the mirror image of
|
|
72
|
+
* `findDuplicateTargetPathGroups` for the identity axis reference configs
|
|
73
|
+
* actually use. Only groups with more than one member are returned, so an
|
|
74
|
+
* empty result means the store is clean.
|
|
75
|
+
*
|
|
76
|
+
* CORRECTED 2026-08-04 (todos 195272ae, Finding 1): grouping used to key on
|
|
77
|
+
* the raw, exact `config.name` string. `doctor` (which calls this) therefore
|
|
78
|
+
* reported a store CLEAN for two rows whose names differ only in case or
|
|
79
|
+
* punctuation — precisely the pair `findReferenceConfigsByName` above treats
|
|
80
|
+
* as one identity (see its doc comment for the reproduction). The two
|
|
81
|
+
* functions disagreeing about what "the same reference config" means was the
|
|
82
|
+
* same defect class PR #57 fixed one level up, one file down: `doctor` a
|
|
83
|
+
* store clean, `add --update` half-fixing it. Keying on `slugify(config.name)`
|
|
84
|
+
* instead makes this agree with `findReferenceConfigsByName`'s identity
|
|
85
|
+
* notion — a case/punctuation variant is now reported as a duplicate group
|
|
86
|
+
* too, not only a byte-identical one. The reported `name` is the first
|
|
87
|
+
* colliding row's own (human-authored) name, for display — the grouping key
|
|
88
|
+
* itself is never surfaced.
|
|
89
|
+
*/
|
|
90
|
+
export declare function findDuplicateReferenceNameGroups(configs: Config[]): Array<{
|
|
91
|
+
name: string;
|
|
92
|
+
configs: Config[];
|
|
93
|
+
}>;
|
|
18
94
|
/**
|
|
19
95
|
* Groups of rows that collide on one normalized target path. Only groups with
|
|
20
96
|
* more than one member are returned, so an empty result means the store is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-target-identity.d.ts","sourceRoot":"","sources":["../../src/lib/config-target-identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"config-target-identity.d.ts","sourceRoot":"","sources":["../../src/lib/config-target-identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAIhD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAOvF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAKpF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAU9G;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAUlH"}
|
|
@@ -127,7 +127,17 @@ export declare function compareAgentOperatingRulesVersions(left: string, right:
|
|
|
127
127
|
* ties on priority in `deduplicateSemanticPolicySources` and then WINS on version,
|
|
128
128
|
* EVICTING the genuine baseline from the same render; the collapse happens before
|
|
129
129
|
* `rejectDuplicateSourceSlugs` runs, so the duplicate-slug guard never sees the
|
|
130
|
-
* collision.
|
|
130
|
+
* collision. That eviction was REACHABLE and is now narrowed, not closed: the managed
|
|
131
|
+
* source id `hasna-agent-operating-rules` earns precedence in
|
|
132
|
+
* `semanticPolicySourcePriority` alongside the managed slug, so the canonical source no
|
|
133
|
+
* longer merely ties with any export that sets `nonOverridable`, and an eviction by an
|
|
134
|
+
* unverified payload is reported in `skippedSources` and in `warnings` instead of
|
|
135
|
+
* passing as a routine collapse. An export that also mimics a canonical id still ties
|
|
136
|
+
* and still wins on version. Ordering by `payloadIntegrity` instead was tried and
|
|
137
|
+
* rejected: the pinned digest describes the EMBEDDED snapshot, so preferring it would
|
|
138
|
+
* freeze a home carrying that snapshot beside a newly published rules document — the
|
|
139
|
+
* same downgrade this floor exists to prevent, arriving by the selection path.
|
|
140
|
+
* Nothing in these bytes distinguishes a genuine future rules version from
|
|
131
141
|
* an inflated one. Rejecting
|
|
132
142
|
* above-baseline versions was considered and deliberately NOT done: the canonical
|
|
133
143
|
* rules document ships from `@hasna/identities`, which legitimately runs ahead of the
|
|
@@ -138,15 +148,24 @@ export declare function compareAgentOperatingRulesVersions(left: string, right:
|
|
|
138
148
|
* channel), not a comparison. Until then the choice is recorded rather than hidden:
|
|
139
149
|
* every payload carries `payloadIntegrity`, which is `unverified-self-declared`
|
|
140
150
|
* whenever bytes were accepted on their version claim alone.
|
|
141
|
-
* 2. This function guards only the payloads routed through it
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
151
|
+
* 2. This function guards only the payloads routed through it. The render pipeline routes
|
|
152
|
+
* BOTH `source.content` and `source.rules[].content`: `normalizeSources` floors the
|
|
153
|
+
* first and `normalizeInstructionRules` floors the second through
|
|
154
|
+
* `applyAgentOperatingRulesFloorToRule`, both before provider filtering, and
|
|
155
|
+
* `deduplicateSemanticPolicySources` reads a declaration from either field. A claiming
|
|
156
|
+
* source or rule is therefore covered whether it came from the config store, an
|
|
157
|
+
* identity export, or a file.
|
|
158
|
+
*
|
|
159
|
+
* The rule half was NOT covered until hasna/instructions#54, and this note used to say
|
|
160
|
+
* so in present tense. Until then a sentinel carried inside a RULE was neither floored
|
|
161
|
+
* nor deduped nor attested on the same untrusted export transport this floor otherwise
|
|
162
|
+
* defends, so an export installed a below-baseline NON-OVERRIDABLE rules document by
|
|
163
|
+
* putting it in `rules[]` instead of `content`.
|
|
164
|
+
*
|
|
165
|
+
* What remains uncovered is narrower and is stated so the choke point is not read as
|
|
166
|
+
* total: an unprivileged rule that merely QUOTES the rules mid-body is deliberately not
|
|
167
|
+
* floored (the F2 false positive), and a rule under a privileged parent IS floored even
|
|
168
|
+
* when it only quotes them.
|
|
150
169
|
*
|
|
151
170
|
* The attestation is also PER-RENDER, not durable: a repair is recorded in the manifest
|
|
152
171
|
* of the render that performed it, so fleet-wide auditing needs those manifests
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"global-agent-rules-standard.d.ts","sourceRoot":"","sources":["../../src/lib/global-agent-rules-standard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE/E,eAAO,MAAM,gCAAgC,gCAAgC,CAAC;AAE9E,eAAO,MAAM,mCAAmC,EAAG,mCAA4C,CAAC;AAChG,eAAO,MAAM,+BAA+B,EAAG,6BAAsC,CAAC;AACtF,yFAAyF;AACzF,eAAO,MAAM,0BAA0B,EAAG,uBAAgC,CAAC;AAC3E,eAAO,MAAM,6BAA6B,EAAG,OAAgB,CAAC;AAC9D,eAAO,MAAM,wCAAwC,EAAG,YAAqB,CAAC;AAC9E,eAAO,MAAM,8BAA8B,EAAG,8CAAuD,CAAC;AACtG;;;;;GAKG;AACH,eAAO,MAAM,yCAAyC,EAAG,6BAAsC,CAAC;AAChG,6FAA6F;AAC7F,eAAO,MAAM,sCAAsC,QAA2E,CAAC;AAC/H;;;;;;;GAOG;AACH,eAAO,MAAM,qCAAqC,QAAsG,CAAC;AACzJ,eAAO,MAAM,oCAAoC,EAAG,kEAA2E,CAAC;AAChI,eAAO,MAAM,oCAAoC,oEAAuC,CAAC;AACzF,eAAO,MAAM,0CAA0C,EAAG,kEAA2E,CAAC;AACtI,eAAO,MAAM,2CAA2C,EAAG,2DAAoE,CAAC;AAEhI,eAAO,MAAM,8BAA8B;;;;CAIjC,CAAC;AAEX,eAAO,MAAM,iCAAiC;;;;;;;CAOpC,CAAC;AAEX,eAAO,MAAM,gCAAgC;;;;;;;;;;;;CAYnC,CAAC;AAEX,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;CAejC,CAAC;AAEX,eAAO,MAAM,0BAA0B,8ZAA8Z,CAAC;AAEtc,eAAO,MAAM,mCAAmC,QA+B7B,CAAC;AAEpB,iFAAiF;AACjF,MAAM,MAAM,gCAAgC,GAAG,eAAe,GAAG,mBAAmB,CAAC;AAErF;;;;;;;;GAQG;AACH,MAAM,MAAM,mCAAmC,GAAG,eAAe,GAAG,0BAA0B,CAAC;AAE/F,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,gCAAgC,CAAC;IACzC,iFAAiF;IACjF,uBAAuB,EAAE,OAAO,CAAC;IACjC,gFAAgF;IAChF,SAAS,EAAE,mCAAmC,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,2EAA2E;AAC3E,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAEjG;AAED,qDAAqD;AACrD,wBAAgB,kCAAkC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQtF;AAmBD
|
|
1
|
+
{"version":3,"file":"global-agent-rules-standard.d.ts","sourceRoot":"","sources":["../../src/lib/global-agent-rules-standard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE/E,eAAO,MAAM,gCAAgC,gCAAgC,CAAC;AAE9E,eAAO,MAAM,mCAAmC,EAAG,mCAA4C,CAAC;AAChG,eAAO,MAAM,+BAA+B,EAAG,6BAAsC,CAAC;AACtF,yFAAyF;AACzF,eAAO,MAAM,0BAA0B,EAAG,uBAAgC,CAAC;AAC3E,eAAO,MAAM,6BAA6B,EAAG,OAAgB,CAAC;AAC9D,eAAO,MAAM,wCAAwC,EAAG,YAAqB,CAAC;AAC9E,eAAO,MAAM,8BAA8B,EAAG,8CAAuD,CAAC;AACtG;;;;;GAKG;AACH,eAAO,MAAM,yCAAyC,EAAG,6BAAsC,CAAC;AAChG,6FAA6F;AAC7F,eAAO,MAAM,sCAAsC,QAA2E,CAAC;AAC/H;;;;;;;GAOG;AACH,eAAO,MAAM,qCAAqC,QAAsG,CAAC;AACzJ,eAAO,MAAM,oCAAoC,EAAG,kEAA2E,CAAC;AAChI,eAAO,MAAM,oCAAoC,oEAAuC,CAAC;AACzF,eAAO,MAAM,0CAA0C,EAAG,kEAA2E,CAAC;AACtI,eAAO,MAAM,2CAA2C,EAAG,2DAAoE,CAAC;AAEhI,eAAO,MAAM,8BAA8B;;;;CAIjC,CAAC;AAEX,eAAO,MAAM,iCAAiC;;;;;;;CAOpC,CAAC;AAEX,eAAO,MAAM,gCAAgC;;;;;;;;;;;;CAYnC,CAAC;AAEX,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;CAejC,CAAC;AAEX,eAAO,MAAM,0BAA0B,8ZAA8Z,CAAC;AAEtc,eAAO,MAAM,mCAAmC,QA+B7B,CAAC;AAEpB,iFAAiF;AACjF,MAAM,MAAM,gCAAgC,GAAG,eAAe,GAAG,mBAAmB,CAAC;AAErF;;;;;;;;GAQG;AACH,MAAM,MAAM,mCAAmC,GAAG,eAAe,GAAG,0BAA0B,CAAC;AAE/F,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,gCAAgC,CAAC;IACzC,iFAAiF;IACjF,uBAAuB,EAAE,OAAO,CAAC;IACjC,gFAAgF;IAChF,SAAS,EAAE,mCAAmC,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,2EAA2E;AAC3E,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAEjG;AAED,qDAAqD;AACrD,wBAAgB,kCAAkC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQtF;AAmBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AACH,wBAAgB,iCAAiC,CAC/C,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACvC,0BAA0B,CA0E5B;AAwBD;;;;;;GAMG;AACH,wBAAsB,oCAAoC,CAAC,KAAK,GAAE,WAAkC,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBrH"}
|
|
@@ -2,6 +2,6 @@ import type { Config, ProfileVariables } from "../types/index.js";
|
|
|
2
2
|
import { type ConfigStore } from "../data/config-store.js";
|
|
3
3
|
export declare const PROJECT_DASHBOARD_STANDARD_SLUG = "agent-managed-project-dashboard-standard";
|
|
4
4
|
export declare const PROJECT_DASHBOARD_PROFILE_VARIABLES: ProfileVariables;
|
|
5
|
-
export declare const PROJECT_DASHBOARD_STANDARD_CONTENT = "# Agent-Managed Project Dashboard Standard\n\nThis standard applies to Hasna work projects under `Workspace/<division>/project/<slug>`.\nHumans do not work directly inside these folders; agents keep structure,\nevidence, tasks, knowledge, and dashboard output consistent.\n\n## Canonical Files\n\n- Project manifest root: `.hasna/project/`\n- Dashboard render manifest: `.hasna/project/dashboard/render.json`\n- Latest snapshot: `.hasna/project/dashboard/snapshots/latest.snapshot.json`\n- Dashboard schema ids come from `@hasna/contracts`.\n- Project folders may contain private documents, but render JSON must contain\n only ids, counts, statuses, resource refs, evidence refs, and redacted\n summaries.\n\n## Viewer Commands\n\nUse the Projects-owned viewer. Do not invent a separate per-project app unless\n`open-projects` cannot express the surface.\n\n```bash\nprojects dashboard snapshot <project> --write --json\nprojects dashboard render <project> --json\nprojects dashboard validate <project> --json\nPROJECTS_DASHBOARD_TOKEN=<token> projects dashboard serve <project> --host 0.0.0.0 --port <port>\n```\n\nNon-loopback serving must use `--token`, `PROJECTS_DASHBOARD_TOKEN`, or an\nexplicit `--trust-network` choice. Never put the token in a URL, task\nevidence, render spec, or report.\n\n## Provider Panels\n\nProvider CLIs emit bounded `hasna.project_panel.v1` summaries:\n\n```bash\ntodos project-panel --project <project> --json --contract\nfiles project-panel --project <project> --json --contract\nmailery project-panel --project <project> --limit 20 --json --contract\nconversations project-panel --project <project> --limit 30 --json --contract\nknowledge project-panel --project <project> --scope project --limit 30 --json --contract\nmementos --json project-panel --project <project> --contract\nreports project-panel --project <project> --json --contract\n```\n\nProviders must degrade to unavailable/error panels instead of dumping raw\ncontent. Mailery is workspace-scoped until explicit project-email mapping is\nconfigured; Knowledge must run from the project cwd or with the correct store\ncontext.\n\n## Coordination\n\n- Project conversation channels use
|
|
5
|
+
export declare const PROJECT_DASHBOARD_STANDARD_CONTENT = "# Agent-Managed Project Dashboard Standard\n\nThis standard applies to Hasna work projects under `Workspace/<division>/project/<slug>`.\nHumans do not work directly inside these folders; agents keep structure,\nevidence, tasks, knowledge, and dashboard output consistent.\n\n## Canonical Files\n\n- Project manifest root: `.hasna/project/`\n- Dashboard render manifest: `.hasna/project/dashboard/render.json`\n- Latest snapshot: `.hasna/project/dashboard/snapshots/latest.snapshot.json`\n- Dashboard schema ids come from `@hasna/contracts`.\n- Project folders may contain private documents, but render JSON must contain\n only ids, counts, statuses, resource refs, evidence refs, and redacted\n summaries.\n\n## Viewer Commands\n\nUse the Projects-owned viewer. Do not invent a separate per-project app unless\n`open-projects` cannot express the surface.\n\n```bash\nprojects dashboard snapshot <project> --write --json\nprojects dashboard render <project> --json\nprojects dashboard validate <project> --json\nPROJECTS_DASHBOARD_TOKEN=<token> projects dashboard serve <project> --host 0.0.0.0 --port <port>\n```\n\nNon-loopback serving must use `--token`, `PROJECTS_DASHBOARD_TOKEN`, or an\nexplicit `--trust-network` choice. Never put the token in a URL, task\nevidence, render spec, or report.\n\n## Provider Panels\n\nProvider CLIs emit bounded `hasna.project_panel.v1` summaries:\n\n```bash\ntodos project-panel --project <project> --json --contract\nfiles project-panel --project <project> --json --contract\nmailery project-panel --project <project> --limit 20 --json --contract\nconversations project-panel --project <project> --limit 30 --json --contract\nknowledge project-panel --project <project> --scope project --limit 30 --json --contract\nmementos --json project-panel --project <project> --contract\nreports project-panel --project <project> --json --contract\n```\n\nProviders must degrade to unavailable/error panels instead of dumping raw\ncontent. Mailery is workspace-scoped until explicit project-email mapping is\nconfigured; Knowledge must run from the project cwd or with the correct store\ncontext.\n\n## Coordination\n\n- Project conversation channels use the normalized project slug in the CLI and\n are displayed to humans as `#<project-slug>`.\n- Todos tasks are the source of truth for work; messages are only coordination.\n- Durable Codewith goal plans should own long-running implementation.\n- New implementation/verification work should route through task-triggered fresh\n agent runs, not by opening or pasting into existing tmux panes.\n- Agent handoff should reference task ids, project ids, commit ids, evidence\n paths, and dashboard URLs without exposing secrets or raw private documents.\n\n## Report Rules\n\nReports and dashboards should use JSON Render/React Flow through\n`projects dashboard render`. Include decisions, open questions, bank/document\nids, tasks, and evidence refs. Exclude raw email bodies, account numbers, tax\nids, passport numbers, credentials, and contract clauses unless an explicit\napproved storage policy exists.\n";
|
|
6
6
|
export declare function ensureProjectDashboardStandardConfig(store?: ConfigStore): Promise<Config>;
|
|
7
7
|
//# sourceMappingURL=project-dashboard-standard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-dashboard-standard.d.ts","sourceRoot":"","sources":["../../src/lib/project-dashboard-standard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE/E,eAAO,MAAM,+BAA+B,6CAA6C,CAAC;AAE1F,eAAO,MAAM,mCAAmC,EAAE,gBAKjD,CAAC;AAEF,eAAO,MAAM,kCAAkC,
|
|
1
|
+
{"version":3,"file":"project-dashboard-standard.d.ts","sourceRoot":"","sources":["../../src/lib/project-dashboard-standard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE/E,eAAO,MAAM,+BAA+B,6CAA6C,CAAC;AAE1F,eAAO,MAAM,mCAAmC,EAAE,gBAKjD,CAAC;AAEF,eAAO,MAAM,kCAAkC,0hGAqE9C,CAAC;AAEF,wBAAsB,oCAAoC,CAAC,KAAK,GAAE,WAAkC,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BrH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-render-rule-currency-floor.test.d.ts","sourceRoot":"","sources":["../../src/lib/session-render-rule-currency-floor.test.ts"],"names":[],"mappings":""}
|
|
@@ -150,6 +150,11 @@ export interface SessionRenderManifest {
|
|
|
150
150
|
path: string;
|
|
151
151
|
globs: string[];
|
|
152
152
|
hash: string | null;
|
|
153
|
+
contentSha256: string;
|
|
154
|
+
payloadFloorApplied: boolean | null;
|
|
155
|
+
flooredFromRulesVersion: string | null;
|
|
156
|
+
flooredFromPayloadSha256: string | null;
|
|
157
|
+
payloadIntegrity: string | null;
|
|
153
158
|
}>;
|
|
154
159
|
renderedPayloadSha256: string;
|
|
155
160
|
provenance: Record<string, unknown> | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-render.d.ts","sourceRoot":"","sources":["../../src/lib/session-render.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"session-render.d.ts","sourceRoot":"","sources":["../../src/lib/session-render.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -6957,7 +6957,7 @@ var init_sync_dir = __esm(() => {
|
|
|
6957
6957
|
var require_package = __commonJS((exports, module) => {
|
|
6958
6958
|
module.exports = {
|
|
6959
6959
|
name: "@hasna/instructions",
|
|
6960
|
-
version: "0.4.
|
|
6960
|
+
version: "0.4.20",
|
|
6961
6961
|
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.",
|
|
6962
6962
|
type: "module",
|
|
6963
6963
|
main: "dist/index.js",
|
|
@@ -7062,6 +7062,7 @@ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprot
|
|
|
7062
7062
|
|
|
7063
7063
|
// src/lib/config-target-identity.ts
|
|
7064
7064
|
init_apply();
|
|
7065
|
+
init_database();
|
|
7065
7066
|
function findConfigsByTargetPath(configs, targetPath) {
|
|
7066
7067
|
const wanted = normalizeTargetPath(targetPath);
|
|
7067
7068
|
return configs.filter((config) => {
|
|
@@ -7072,6 +7073,10 @@ function findConfigsByTargetPath(configs, targetPath) {
|
|
|
7072
7073
|
return normalizeTargetPath(config.target_path) === wanted;
|
|
7073
7074
|
});
|
|
7074
7075
|
}
|
|
7076
|
+
function findReferenceConfigsByName(configs, name) {
|
|
7077
|
+
const wantedSlug = slugify(name);
|
|
7078
|
+
return configs.filter((config) => config.kind === "reference" && (config.name === name || slugify(config.name) === wantedSlug));
|
|
7079
|
+
}
|
|
7075
7080
|
|
|
7076
7081
|
// src/mcp/server.ts
|
|
7077
7082
|
init_sync_dir();
|
|
@@ -7178,7 +7183,7 @@ function summarizeApplyResult(result) {
|
|
|
7178
7183
|
var TOOL_DOCS = {
|
|
7179
7184
|
list_configs: "List configs. Params: category?, agent?, kind?, search?, limit?, cursor?, verbose?. Defaults to a paged compact envelope without content; use get_config for full content.",
|
|
7180
7185
|
get_config: "Get a config by id or slug. Returns full config including content.",
|
|
7181
|
-
create_config: "Create a new config. Required: name, content, category. Optional: agent, target_path, outputs, kind, format, tags, description, is_template. Refuses when target_path is already tracked by another config (one target path, one row) \u2014 use update_config on the owning row, or delete_config first. kind:'reference' owns no target path and is exempt.",
|
|
7186
|
+
create_config: "Create a new config. Required: name, content, category. Optional: agent, target_path, outputs, kind, format, tags, description, is_template. Refuses when target_path is already tracked by another config (one target path, one row) \u2014 use update_config on the owning row, or delete_config first. kind:'reference' owns no target path and is exempt from that check, but is instead refused when its name (or a case/punctuation variant of it) already tracks another reference config.",
|
|
7182
7187
|
update_config: "Update a config by id or slug. Optional: content, name, tags, description, category, agent, target_path, outputs.",
|
|
7183
7188
|
apply_config: "Apply a config through the shared ownership gate. Params: id_or_slug, dry_run?, verbose?. Returns results plus session-renderer-owned targets that were skipped.",
|
|
7184
7189
|
sync_directory: "Sync a directory with the DB. Params: dir, direction ('from_disk'|'to_disk'). Returns sync result.",
|
|
@@ -7269,6 +7274,15 @@ function buildServer() {
|
|
|
7269
7274
|
return err(`${targetPath} is already tracked by: ${named}.${collision}` + ` Use update_config on that row to refresh it in place, or delete_config first.`);
|
|
7270
7275
|
}
|
|
7271
7276
|
}
|
|
7277
|
+
if (kind === "reference") {
|
|
7278
|
+
const name2 = args["name"];
|
|
7279
|
+
const owners = findReferenceConfigsByName(await store.listConfigs(), name2);
|
|
7280
|
+
if (owners.length > 0) {
|
|
7281
|
+
const named = owners.map((owner) => `${owner.slug} (${owner.id})`).join(", ");
|
|
7282
|
+
const collision = owners.length > 1 ? ` ${owners.length} rows already collide on this name \u2014 apply order between them is undefined.` : "";
|
|
7283
|
+
return err(`Reference config "${name2}" is already tracked by: ${named}.${collision}` + ` Use update_config on that row to refresh it in place, or delete_config first.`);
|
|
7284
|
+
}
|
|
7285
|
+
}
|
|
7272
7286
|
const c = await store.createConfig({
|
|
7273
7287
|
name: args["name"],
|
|
7274
7288
|
content: args["content"],
|
package/dist/mcp/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AA4EnE,wBAAgB,WAAW,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AA4EnE,wBAAgB,WAAW,IAAI,MAAM,CAyVpC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/instructions",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.20",
|
|
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",
|