@pathmode/mcp-server 1.14.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +405 -10
- package/dist/intent-compiler.d.ts.map +1 -1
- package/dist/local-reader.d.ts +24 -0
- package/dist/local-reader.d.ts.map +1 -1
- package/dist/readiness.d.ts +65 -0
- package/dist/readiness.d.ts.map +1 -1
- package/manifest.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34476,6 +34476,41 @@ function formatIntentMd(spec, opts = {}) {
|
|
|
34476
34476
|
sections.push(`- [ ] ${renderCheckLine(c)}`);
|
|
34477
34477
|
}
|
|
34478
34478
|
}
|
|
34479
|
+
// `## Confirmations` is emitted LAST so it never sits between the fields a reader is
|
|
34480
|
+
// comparing, and so appending one cannot shift any other section's parse. Derived fields
|
|
34481
|
+
// (assurance, source) are NOT written: anything read from a file is local-unverified.
|
|
34482
|
+
const rawConfirmations = spec.confirmations;
|
|
34483
|
+
const confirmations = Array.isArray(rawConfirmations)
|
|
34484
|
+
? rawConfirmations
|
|
34485
|
+
: [];
|
|
34486
|
+
// Filter BEFORE emitting the heading: a spec whose only confirmation targets an
|
|
34487
|
+
// unwaivable dimension must not leave an empty `## Confirmations` section behind.
|
|
34488
|
+
const emittable = confirmations.filter((c) => {
|
|
34489
|
+
const dim = String(c.dimension ?? '').toLowerCase();
|
|
34490
|
+
const kind = String(c.kind ?? '').toLowerCase();
|
|
34491
|
+
const by = String(c.by ?? '').toLowerCase();
|
|
34492
|
+
return ['objective', 'outcomes'].includes(dim)
|
|
34493
|
+
&& ['confirmed', 'waived'].includes(kind)
|
|
34494
|
+
&& ['agent', 'human'].includes(by);
|
|
34495
|
+
});
|
|
34496
|
+
if (emittable.length) {
|
|
34497
|
+
sections.push('');
|
|
34498
|
+
sections.push('## Confirmations');
|
|
34499
|
+
for (const c of emittable) {
|
|
34500
|
+
const dim = String(c.dimension ?? '').toLowerCase();
|
|
34501
|
+
const kind = String(c.kind ?? '').toLowerCase();
|
|
34502
|
+
const by = String(c.by ?? '').toLowerCase();
|
|
34503
|
+
sections.push('');
|
|
34504
|
+
sections.push(`**${dim}** — ${kind} by ${by}`);
|
|
34505
|
+
for (const key of ['actor', 'problem', 'outcome', 'observable', 'reason', 'anchor', 'at']) {
|
|
34506
|
+
const v = c[key];
|
|
34507
|
+
if (typeof v !== 'string' || !v.trim())
|
|
34508
|
+
continue;
|
|
34509
|
+
// Values are single-line by contract; the writer flattens rather than escaping.
|
|
34510
|
+
sections.push(`- ${key}: ${v.replace(/\s+/g, ' ').trim()}`);
|
|
34511
|
+
}
|
|
34512
|
+
}
|
|
34513
|
+
}
|
|
34479
34514
|
sections.push('');
|
|
34480
34515
|
return sections.join('\n');
|
|
34481
34516
|
}
|
|
@@ -34890,6 +34925,43 @@ exports.parseIntentMarkdown = parseIntentMarkdown;
|
|
|
34890
34925
|
const fs_1 = __importDefault(__nccwpck_require__(9896));
|
|
34891
34926
|
const path_1 = __importDefault(__nccwpck_require__(6928));
|
|
34892
34927
|
const gray_matter_1 = __importDefault(__nccwpck_require__(9599));
|
|
34928
|
+
const CONFIRMATION_HEADER_RE = /^\*\*(objective|outcomes)\*\*\s*[—–-]\s*(confirmed|waived)\s+by\s+(agent|human)\s*$/i;
|
|
34929
|
+
const CONFIRMATION_FIELD_RE = /^\s*[-*]\s+(actor|problem|outcome|observable|reason|anchor|at)\s*:\s*(.+)$/i;
|
|
34930
|
+
/**
|
|
34931
|
+
* Parse `## Confirmations` permissively; the gate validates.
|
|
34932
|
+
*
|
|
34933
|
+
* A block missing its anchor still parses and is reported by the gate as `malformed` or `stale`
|
|
34934
|
+
* rather than vanishing here. Silent drops at parse time are what make "my confirmation did
|
|
34935
|
+
* nothing" undebuggable, which is the precedent this deliberately does not copy.
|
|
34936
|
+
*
|
|
34937
|
+
* A value runs to end of line, so it may contain colons, dashes and quotes without escaping.
|
|
34938
|
+
* A duplicate key inside one block is last-wins, matching splitSections' duplicate-heading rule.
|
|
34939
|
+
* A line matching neither shape is ignored, so stray prose cannot open a block.
|
|
34940
|
+
*/
|
|
34941
|
+
function extractConfirmations(sections) {
|
|
34942
|
+
const out = [];
|
|
34943
|
+
let current = null;
|
|
34944
|
+
for (const line of sections.get('Confirmations') ?? []) {
|
|
34945
|
+
const header = line.trim().match(CONFIRMATION_HEADER_RE);
|
|
34946
|
+
if (header) {
|
|
34947
|
+
current = {
|
|
34948
|
+
dimension: header[1].toLowerCase(),
|
|
34949
|
+
kind: header[2].toLowerCase(),
|
|
34950
|
+
by: header[3].toLowerCase(),
|
|
34951
|
+
assurance: 'local-unverified',
|
|
34952
|
+
source: 'file',
|
|
34953
|
+
};
|
|
34954
|
+
out.push(current);
|
|
34955
|
+
continue;
|
|
34956
|
+
}
|
|
34957
|
+
if (!current)
|
|
34958
|
+
continue;
|
|
34959
|
+
const field = line.match(CONFIRMATION_FIELD_RE);
|
|
34960
|
+
if (field)
|
|
34961
|
+
current[field[1].toLowerCase()] = field[2].trim();
|
|
34962
|
+
}
|
|
34963
|
+
return out;
|
|
34964
|
+
}
|
|
34893
34965
|
const DECISIONS_HEADING = 'Decisions & Ruled-Out Alternatives';
|
|
34894
34966
|
/**
|
|
34895
34967
|
* Read all intent.md files from the current directory and subdirectories (1 level deep).
|
|
@@ -34957,7 +35029,8 @@ function readIntentFile(filePath) {
|
|
|
34957
35029
|
* (lib/intentMdParse.ts) to this implementation's behavior on gate-relevant fields.
|
|
34958
35030
|
*/
|
|
34959
35031
|
function parseIntentMarkdown(content, fallbackId = 'intent') {
|
|
34960
|
-
const { data, content:
|
|
35032
|
+
const { data, content: rawBody } = (0, gray_matter_1.default)(content);
|
|
35033
|
+
const body = stripFencedBlocks(rawBody);
|
|
34961
35034
|
const sections = splitSections(body);
|
|
34962
35035
|
const parsedVerification = extractVerification(sections);
|
|
34963
35036
|
const frontmatterVerification = data.verification && typeof data.verification === 'object'
|
|
@@ -34984,6 +35057,7 @@ function parseIntentMarkdown(content, fallbackId = 'intent') {
|
|
|
34984
35057
|
healthMetrics: extractListSection(sections, 'Health Metrics'),
|
|
34985
35058
|
scope: extractScope(sections) || undefined,
|
|
34986
35059
|
verification,
|
|
35060
|
+
confirmations: extractConfirmations(sections),
|
|
34987
35061
|
source: 'local',
|
|
34988
35062
|
};
|
|
34989
35063
|
}
|
|
@@ -34995,6 +35069,46 @@ function parseIntentMarkdown(content, fallbackId = 'intent') {
|
|
|
34995
35069
|
* wins. `###` is not a section boundary (`^##\s+` cannot match `### `), so sub-headings stay
|
|
34996
35070
|
* inside their parent section.
|
|
34997
35071
|
*/
|
|
35072
|
+
/**
|
|
35073
|
+
* Remove fenced code blocks before any structural parsing.
|
|
35074
|
+
*
|
|
35075
|
+
* A spec's fenced blocks are examples and payloads, never spec structure, but the
|
|
35076
|
+
* section walker is line-based: a `## ` inside a fence opens a bogus section, and
|
|
35077
|
+
* `isListItem` matches `^\s*[-*]\s`, so a C comment line (` * @brief ...`) or a YAML
|
|
35078
|
+
* list inside a fence becomes an outcome. Measured in the wild: one OpenSpec change
|
|
35079
|
+
* contributed 21 Doxygen `@brief` lines as "outcomes" and passed a gate a reviewer
|
|
35080
|
+
* fails it on (docs/research/openspec-corpus-audit.md).
|
|
35081
|
+
*
|
|
35082
|
+
* Fenced content is DROPPED, not kept-and-ignored. Nothing downstream reads a fence as
|
|
35083
|
+
* a check (verification takes list items only), so keeping it would only feed code
|
|
35084
|
+
* noise to the lexical gates that read the prose fields.
|
|
35085
|
+
*
|
|
35086
|
+
* Indented (4-space) code blocks are deliberately NOT handled: they are
|
|
35087
|
+
* indistinguishable from indented list continuations, and dropping those would lose
|
|
35088
|
+
* real content. An unclosed fence swallows the rest of the document, which is what a
|
|
35089
|
+
* markdown renderer does, so the parser reads what the author sees.
|
|
35090
|
+
*/
|
|
35091
|
+
function stripFencedBlocks(body) {
|
|
35092
|
+
const out = [];
|
|
35093
|
+
let fence = null;
|
|
35094
|
+
for (const line of body.split('\n')) {
|
|
35095
|
+
const marker = line.match(/^\s*(`{3,}|~{3,})/);
|
|
35096
|
+
if (marker) {
|
|
35097
|
+
const char = marker[1][0];
|
|
35098
|
+
const len = marker[1].length;
|
|
35099
|
+
if (!fence) {
|
|
35100
|
+
fence = { char, len };
|
|
35101
|
+
continue;
|
|
35102
|
+
}
|
|
35103
|
+
if (char === fence.char && len >= fence.len)
|
|
35104
|
+
fence = null;
|
|
35105
|
+
continue;
|
|
35106
|
+
}
|
|
35107
|
+
if (!fence)
|
|
35108
|
+
out.push(line);
|
|
35109
|
+
}
|
|
35110
|
+
return out.join('\n');
|
|
35111
|
+
}
|
|
34998
35112
|
function splitSections(body) {
|
|
34999
35113
|
const sections = new Map();
|
|
35000
35114
|
let current = null;
|
|
@@ -35506,6 +35620,8 @@ exports.isConstraintConcrete = isConstraintConcrete;
|
|
|
35506
35620
|
exports.isVerificationCheckSubstantive = isVerificationCheckSubstantive;
|
|
35507
35621
|
exports.isObjectiveSpecific = isObjectiveSpecific;
|
|
35508
35622
|
exports.isOutcomeMeasurable = isOutcomeMeasurable;
|
|
35623
|
+
exports.normalizeAnchor = normalizeAnchor;
|
|
35624
|
+
exports.fieldDigest = fieldDigest;
|
|
35509
35625
|
exports.computeReadinessVerdict = computeReadinessVerdict;
|
|
35510
35626
|
exports.formatReadinessFrontmatter = formatReadinessFrontmatter;
|
|
35511
35627
|
exports.formatReadinessVerdict = formatReadinessVerdict;
|
|
@@ -35624,6 +35740,114 @@ exports.READINESS_BLOCKER_DESCRIPTIONS = {
|
|
|
35624
35740
|
verification: 'No concrete verification — describe at least one check specific enough to run.',
|
|
35625
35741
|
};
|
|
35626
35742
|
/** Display order for the gate strip (title first, matching the Preflight page). */
|
|
35743
|
+
// ── Confirmation anchoring ──────────────────────────────────────────────────
|
|
35744
|
+
/**
|
|
35745
|
+
* Fold away everything that is a rewrite of the same claim, and nothing that is a change to it.
|
|
35746
|
+
* NFC because one glyph has two encodings; soft hyphens because editors inject them invisibly;
|
|
35747
|
+
* quote/dash folding and markdown emphasis because adding `**` around a word is formatting, not
|
|
35748
|
+
* a reword. Lowercased and whitespace-collapsed last.
|
|
35749
|
+
*/
|
|
35750
|
+
function normalizeAnchor(value) {
|
|
35751
|
+
return coerceText(value)
|
|
35752
|
+
.normalize('NFC')
|
|
35753
|
+
.replace(//g, '')
|
|
35754
|
+
.replace(/[‘’ʼ]/g, "'")
|
|
35755
|
+
.replace(/[“”]/g, '"')
|
|
35756
|
+
.replace(/[–—]/g, '-')
|
|
35757
|
+
.replace(/\*/g, '')
|
|
35758
|
+
.replace(/\s+/g, ' ')
|
|
35759
|
+
.trim()
|
|
35760
|
+
.toLowerCase();
|
|
35761
|
+
}
|
|
35762
|
+
/**
|
|
35763
|
+
* 64-bit FNV-1a over the normalized field text, as 16 lowercase hex chars.
|
|
35764
|
+
*
|
|
35765
|
+
* NOT sha256, and deliberately not node:crypto. lib/intentReadiness.ts is imported by
|
|
35766
|
+
* 'use client' components (PreflightVerdictDemo, SpecPanel, DraftWorkspace), so the app-side
|
|
35767
|
+
* half of this parity pair runs in the browser, where node crypto does not exist and
|
|
35768
|
+
* crypto.subtle is async while this gate is synchronous and pure. Do not "upgrade" this to
|
|
35769
|
+
* sha256 without checking that constraint first.
|
|
35770
|
+
*
|
|
35771
|
+
* A weak hash is adequate because this is change detection, not a security boundary: anyone
|
|
35772
|
+
* who can forge a confirmation can edit the digest beside it. Accidental collision over 64 bits
|
|
35773
|
+
* is negligible, and a collision only means a confirmation outlives an edit it should not have.
|
|
35774
|
+
*/
|
|
35775
|
+
function fieldDigest(text) {
|
|
35776
|
+
const s = normalizeAnchor(text);
|
|
35777
|
+
let h = 0xcbf29ce484222325n;
|
|
35778
|
+
const prime = 0x100000001b3n;
|
|
35779
|
+
const mask = 0xffffffffffffffffn;
|
|
35780
|
+
for (let i = 0; i < s.length; i++) {
|
|
35781
|
+
h = (h ^ BigInt(s.charCodeAt(i))) * prime & mask;
|
|
35782
|
+
}
|
|
35783
|
+
return h.toString(16).padStart(16, '0');
|
|
35784
|
+
}
|
|
35785
|
+
/** Only these two are waivable or confirmable. goal and verification are unrepresentable here. */
|
|
35786
|
+
const CONFIRMABLE = ['objective', 'outcomes'];
|
|
35787
|
+
/**
|
|
35788
|
+
* Apply confirmations to the dimensions the gate could not confirm lexically.
|
|
35789
|
+
*
|
|
35790
|
+
* Structural checks ONLY: the gate never reads the prose of `actor`, `problem` or `reason`, it
|
|
35791
|
+
* only checks that they are present and that the anchor still matches the field it was made
|
|
35792
|
+
* against. Interpreting them is the consumer's job, which is the whole point of the split.
|
|
35793
|
+
*
|
|
35794
|
+
* The uniform rule is `anchor === fieldDigest(current field text)`. It covers both kinds and
|
|
35795
|
+
* both directions: editing a confirmed objective kills the confirmation, and filling in an
|
|
35796
|
+
* objective that was waived as absent kills the waiver, because '' and the new text digest
|
|
35797
|
+
* differently.
|
|
35798
|
+
*/
|
|
35799
|
+
function applyConfirmations(detail, digests, raw) {
|
|
35800
|
+
const rejected = [];
|
|
35801
|
+
for (const entry of asArray(raw)) {
|
|
35802
|
+
const c = (entry ?? {});
|
|
35803
|
+
const dim = coerceText(c.dimension).trim();
|
|
35804
|
+
const kind = coerceText(c.kind).trim();
|
|
35805
|
+
const by = coerceText(c.by).trim();
|
|
35806
|
+
if (!CONFIRMABLE.includes(dim)) {
|
|
35807
|
+
rejected.push({ code: 'unknown-dimension', dimension: dim || '(none)' });
|
|
35808
|
+
continue;
|
|
35809
|
+
}
|
|
35810
|
+
const d = detail[dim];
|
|
35811
|
+
if (kind === 'waived') {
|
|
35812
|
+
// Amendment A: a waiver is a human decision. An agent may propose one; only a human
|
|
35813
|
+
// may make it. Without this an agent's cheapest route to a green gate is one call.
|
|
35814
|
+
if (by !== 'human') {
|
|
35815
|
+
rejected.push({ code: 'waiver-requires-human', dimension: dim });
|
|
35816
|
+
continue;
|
|
35817
|
+
}
|
|
35818
|
+
if (!coerceText(c.reason).trim()) {
|
|
35819
|
+
rejected.push({ code: 'malformed', dimension: dim });
|
|
35820
|
+
continue;
|
|
35821
|
+
}
|
|
35822
|
+
}
|
|
35823
|
+
else if (kind === 'confirmed') {
|
|
35824
|
+
const filled = dim === 'objective'
|
|
35825
|
+
? coerceText(c.actor).trim() && coerceText(c.problem).trim()
|
|
35826
|
+
: coerceText(c.outcome).trim() && coerceText(c.observable).trim();
|
|
35827
|
+
if (!filled) {
|
|
35828
|
+
rejected.push({ code: 'malformed', dimension: dim });
|
|
35829
|
+
continue;
|
|
35830
|
+
}
|
|
35831
|
+
// M3: there is no path from a blank spec to a pass. Absent is unconfirmable;
|
|
35832
|
+
// waiving it is the honest move and stays available above.
|
|
35833
|
+
if (d?.state === 'absent') {
|
|
35834
|
+
rejected.push({ code: 'nothing-to-confirm', dimension: dim });
|
|
35835
|
+
continue;
|
|
35836
|
+
}
|
|
35837
|
+
}
|
|
35838
|
+
else {
|
|
35839
|
+
rejected.push({ code: 'malformed', dimension: dim });
|
|
35840
|
+
continue;
|
|
35841
|
+
}
|
|
35842
|
+
if (coerceText(c.anchor).trim() !== digests[dim]) {
|
|
35843
|
+
rejected.push({ code: 'stale', dimension: dim });
|
|
35844
|
+
continue;
|
|
35845
|
+
}
|
|
35846
|
+
if (d && d.state !== 'pass')
|
|
35847
|
+
d.state = kind === 'waived' ? 'not_applicable' : 'pass';
|
|
35848
|
+
}
|
|
35849
|
+
return rejected;
|
|
35850
|
+
}
|
|
35627
35851
|
exports.READINESS_GATE_ORDER = ['goal', 'objective', 'outcomes', 'constraints', 'edgeCases', 'verification'];
|
|
35628
35852
|
/** Blocker emission order — byte-identical to lib/intentReadiness computeReviewSignals. */
|
|
35629
35853
|
const BLOCKER_ORDER = ['objective', 'goal', 'outcomes', 'constraints', 'edgeCases', 'verification'];
|
|
@@ -35669,7 +35893,41 @@ function computeReadinessVerdict(spec) {
|
|
|
35669
35893
|
const failingBlockers = BLOCKER_ORDER
|
|
35670
35894
|
.filter(k => !signals[k])
|
|
35671
35895
|
.map(k => exports.READINESS_BLOCKER_DESCRIPTIONS[k]);
|
|
35672
|
-
|
|
35896
|
+
// What the reader read, per dimension, independent of whether the heuristic accepted it.
|
|
35897
|
+
// Placeholder text is deliberately not extracted: no path from a blank spec to confirmable.
|
|
35898
|
+
const objectiveText = coerceText(spec.objective).trim();
|
|
35899
|
+
const titleText = coerceText(spec.title).trim();
|
|
35900
|
+
const extractedBy = {
|
|
35901
|
+
goal: isLikelyPlaceholderText(titleText) ? '' : titleText,
|
|
35902
|
+
objective: isLikelyPlaceholderText(objectiveText) ? '' : objectiveText,
|
|
35903
|
+
outcomes: nonEmptyOutcomes.join('; '),
|
|
35904
|
+
constraints: asArray(spec.constraints).map(c => coerceText(c).trim()).filter(Boolean).join('; '),
|
|
35905
|
+
edgeCases: asArray(spec.edgeCases)
|
|
35906
|
+
.map((ec) => coerceText(ec?.scenario).trim())
|
|
35907
|
+
.filter(Boolean).join('; '),
|
|
35908
|
+
verification: verificationDescriptions(spec.verification).join('; '),
|
|
35909
|
+
};
|
|
35910
|
+
const detail = {};
|
|
35911
|
+
for (const key of exports.READINESS_GATE_ORDER) {
|
|
35912
|
+
const text = extractedBy[key] ?? '';
|
|
35913
|
+
detail[key] = signals[key]
|
|
35914
|
+
? { state: 'pass', ...(text ? { extracted: text } : {}) }
|
|
35915
|
+
: text
|
|
35916
|
+
? { state: 'unconfirmed', extracted: text }
|
|
35917
|
+
: { state: 'absent' };
|
|
35918
|
+
}
|
|
35919
|
+
// Confirmations only ever move a dimension the heuristics already failed; `signals` is never
|
|
35920
|
+
// mutated, so the lexical verdict stays visible underneath.
|
|
35921
|
+
const anchorDigests = {
|
|
35922
|
+
objective: fieldDigest(extractedBy.objective),
|
|
35923
|
+
outcomes: fieldDigest(extractedBy.outcomes),
|
|
35924
|
+
};
|
|
35925
|
+
const rejectedConfirmations = applyConfirmations(detail, anchorDigests, spec.confirmations);
|
|
35926
|
+
const confirmedReady = exports.READINESS_GATE_ORDER.every(k => signals[k] || detail[k]?.state === 'pass' || detail[k]?.state === 'not_applicable');
|
|
35927
|
+
return {
|
|
35928
|
+
ready: failingBlockers.length === 0,
|
|
35929
|
+
signals, failingBlockers, detail, rejectedConfirmations, confirmedReady,
|
|
35930
|
+
};
|
|
35673
35931
|
}
|
|
35674
35932
|
const GATE_LABELS = {
|
|
35675
35933
|
goal: 'Title',
|
|
@@ -35702,6 +35960,24 @@ function formatReadinessFrontmatter(verdict) {
|
|
|
35702
35960
|
const blocking = exports.READINESS_GATE_ORDER.filter((k) => !verdict.signals[k]).map((k) => FRONTMATTER_GATE_LABELS[k]);
|
|
35703
35961
|
return `failed ${passed}/${total} — blocking: ${blocking.join(', ')}`;
|
|
35704
35962
|
}
|
|
35963
|
+
/**
|
|
35964
|
+
* The extra line an `unconfirmed` dimension earns: what was read, and an honest statement of
|
|
35965
|
+
* what the check could not find in it.
|
|
35966
|
+
*
|
|
35967
|
+
* Only objective and outcomes appear here, and that scoping is the finding, not caution. The
|
|
35968
|
+
* audit measured that most failures on those two are false negatives from a fixed English
|
|
35969
|
+
* vocabulary. Verification's measured misses were all extraction failures, so quoting text
|
|
35970
|
+
* back there would imply a confidence the evidence does not support.
|
|
35971
|
+
*/
|
|
35972
|
+
const UNCONFIRMED_HINT = {
|
|
35973
|
+
objective: 'Read this, but could not confirm an affected actor and a concrete problem in it. If it already names them, this check reads a fixed vocabulary and may be missing valid phrasing:',
|
|
35974
|
+
outcomes: 'Read these, but could not confirm an observable threshold in enough of them. If they are already observable, this check reads a fixed vocabulary and may be missing valid phrasing:',
|
|
35975
|
+
};
|
|
35976
|
+
/** Keep a quoted extraction to one readable line; the full text is in verdict.detail. */
|
|
35977
|
+
function truncateForQuote(text, max = 160) {
|
|
35978
|
+
const flat = text.replace(/\s+/g, ' ').trim();
|
|
35979
|
+
return flat.length <= max ? flat : `${flat.slice(0, max - 1)}…`;
|
|
35980
|
+
}
|
|
35705
35981
|
/** Human/agent-readable verdict block, stable enough to parse by line prefix. */
|
|
35706
35982
|
function formatReadinessVerdict(verdict, specTitle) {
|
|
35707
35983
|
const lines = [];
|
|
@@ -35711,8 +35987,21 @@ function formatReadinessVerdict(verdict, specTitle) {
|
|
|
35711
35987
|
}
|
|
35712
35988
|
else {
|
|
35713
35989
|
lines.push(`✗ Preflight failed${name ? ` for "${name}"` : ''}. ${verdict.failingBlockers.length}/6 checks blocking.`);
|
|
35714
|
-
|
|
35715
|
-
|
|
35990
|
+
// Blocker lines stay byte-identical and in order; an unconfirmed dimension gets an
|
|
35991
|
+
// extra indented line quoting what was actually read. Without it the verdict says
|
|
35992
|
+
// "name the actor" to an author who named one in words this vocabulary misses, which
|
|
35993
|
+
// an audit of 80 real specs measured as the majority of these failures
|
|
35994
|
+
// (docs/research/openspec-corpus-audit.md).
|
|
35995
|
+
for (const key of BLOCKER_ORDER) {
|
|
35996
|
+
if (verdict.signals[key])
|
|
35997
|
+
continue;
|
|
35998
|
+
lines.push(` ✗ ${exports.READINESS_BLOCKER_DESCRIPTIONS[key]}`);
|
|
35999
|
+
const d = verdict.detail?.[key];
|
|
36000
|
+
if (d?.state === 'unconfirmed' && d.extracted && UNCONFIRMED_HINT[key]) {
|
|
36001
|
+
lines.push(` ↳ ${UNCONFIRMED_HINT[key]}`);
|
|
36002
|
+
lines.push(` "${truncateForQuote(d.extracted)}"`);
|
|
36003
|
+
}
|
|
36004
|
+
}
|
|
35716
36005
|
}
|
|
35717
36006
|
lines.push('');
|
|
35718
36007
|
lines.push(exports.READINESS_GATE_ORDER.map(k => `${verdict.signals[k] ? '✓' : '·'} ${GATE_LABELS[k]}`).join(' '));
|
|
@@ -65652,7 +65941,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"$schema":"http://json-schema.org/dra
|
|
|
65652
65941
|
/***/ ((module) => {
|
|
65653
65942
|
|
|
65654
65943
|
"use strict";
|
|
65655
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@pathmode/mcp-server","version":"1.
|
|
65944
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@pathmode/mcp-server","version":"1.15.0","publishConfig":{"access":"public"},"mcpName":"io.github.pathmodeio/mcp-server","description":"Deterministic intent preflight before your agent builds: six calibrated gates, keyless, no model call. Draft and sharpen specs in conversation, or connect a Pathmode workspace to sync intent and evidence across a team.","main":"dist/index.js","bin":{"pathmode-mcp":"dist/index.js"},"files":["dist/","manifest.json","icon.svg","README.md","skills/"],"scripts":{"build":"rm -rf dist && ncc build src/index.ts -o dist","dev":"ts-node src/index.ts","prepublishOnly":"npm run build"},"keywords":["pathmode","mcp","model-context-protocol","claude-code","claude-code-skills","agent-skills","cursor","windsurf","intent-engineering","intent-compiler","ai-agents","product-development","dependency-graph","strategic-planning"],"author":"Pathmode","license":"MIT","type":"commonjs","engines":{"node":">=18.0.0"},"homepage":"https://pathmode.io","dependencies":{"@modelcontextprotocol/sdk":"^1.12.1","gray-matter":"^4.0.3","zod":"^3.24.0"},"devDependencies":{"@types/node":"^25.1.0","@vercel/ncc":"^0.38.4","ts-node":"^10.9.2","typescript":"^5.9.3"}}');
|
|
65656
65945
|
|
|
65657
65946
|
/***/ })
|
|
65658
65947
|
|
|
@@ -65994,7 +66283,13 @@ function startMcpServer() {
|
|
|
65994
66283
|
return { content: [{ type: 'text', text: 'No intents found in workspace.' }] };
|
|
65995
66284
|
}
|
|
65996
66285
|
}
|
|
65997
|
-
const
|
|
66286
|
+
const listed = pickCurrentIntent(intents);
|
|
66287
|
+
// The list projection omits intent_spec_edge_cases. Serving it as "the full IntentSpec"
|
|
66288
|
+
// hands the implementing agent a spec with every failure mode silently missing — the
|
|
66289
|
+
// one part of a spec it would not have invented on its own. Re-read the whole record.
|
|
66290
|
+
const current = listed?.id
|
|
66291
|
+
? (await cloud.getIntent(listed.id).catch(() => listed))
|
|
66292
|
+
: listed;
|
|
65998
66293
|
// Default: a fetch-free coverage summary (no extra API call). On request: the cited
|
|
65999
66294
|
// evidence content, fetched once for the product and filtered to this intent's citations.
|
|
66000
66295
|
const evidenceSummary = summarizeCitedEvidence(current);
|
|
@@ -66356,7 +66651,12 @@ function startMcpServer() {
|
|
|
66356
66651
|
const cloud = requireCloudClient();
|
|
66357
66652
|
const intent = intentId
|
|
66358
66653
|
? await cloud.getIntent(intentId)
|
|
66359
|
-
:
|
|
66654
|
+
: await (async () => {
|
|
66655
|
+
// Same list-projection caveat: the rubric must be derived from the whole
|
|
66656
|
+
// spec, edge cases included, or it grades against a partial contract.
|
|
66657
|
+
const listed = pickCurrentIntent(await cloud.listIntents('approved')) || pickCurrentIntent(await cloud.listIntents());
|
|
66658
|
+
return listed?.id ? await cloud.getIntent(listed.id).catch(() => listed) : listed;
|
|
66659
|
+
})();
|
|
66360
66660
|
if (!intent) {
|
|
66361
66661
|
return { content: [{ type: 'text', text: 'No intent found to export. Pass an intentId, or create an approved intent first.' }] };
|
|
66362
66662
|
}
|
|
@@ -66990,8 +67290,15 @@ function startMcpServer() {
|
|
|
66990
67290
|
}
|
|
66991
67291
|
else {
|
|
66992
67292
|
const cloud = requireCloudClient();
|
|
66993
|
-
|
|
66994
|
-
|
|
67293
|
+
// The list projection (INTENT_LIST_SELECT) omits intent_spec_edge_cases, so
|
|
67294
|
+
// grading a listed row fails the edge-case gate unconditionally — no saved
|
|
67295
|
+
// cloud intent could ever pass its own preflight. Re-read the full record
|
|
67296
|
+
// before grading; readiness is only deterministic over the whole spec.
|
|
67297
|
+
const listed = intentId ? undefined : pickCurrentIntent(await cloud.listIntents());
|
|
67298
|
+
const targetId = intentId || listed?.id;
|
|
67299
|
+
subject = targetId
|
|
67300
|
+
? await cloud.getIntent(targetId).catch(() => undefined)
|
|
67301
|
+
: undefined;
|
|
66995
67302
|
sourceNote = intentId ? `intent ${intentId}` : 'current intent';
|
|
66996
67303
|
if (!subject) {
|
|
66997
67304
|
return {
|
|
@@ -67134,6 +67441,92 @@ function startMcpServer() {
|
|
|
67134
67441
|
}],
|
|
67135
67442
|
};
|
|
67136
67443
|
});
|
|
67444
|
+
/**
|
|
67445
|
+
* Confirm or waive a readiness dimension the deterministic gate could not confirm on its own.
|
|
67446
|
+
*
|
|
67447
|
+
* M1 (a confirmation must not be minted in the write that authored the field) is enforced by the
|
|
67448
|
+
* TOOL BOUNDARY, not by tracking state: `intent_save` has no `confirmations` parameter, so the
|
|
67449
|
+
* only way a confirmation exists is a separate call against a file a previous write produced.
|
|
67450
|
+
* Keep it that way. Adding confirmations to intent_save would let an agent author a field and
|
|
67451
|
+
* vouch for it in one breath, which is the rubber stamp this whole mechanism exists to price.
|
|
67452
|
+
*
|
|
67453
|
+
* The tool stamps `by: agent` for a confirmation and never accepts a `by` parameter. A waiver is
|
|
67454
|
+
* a human decision (contract amendment A) and requires `humanApproved`, which the agent may only
|
|
67455
|
+
* set after the user has actually said so. That is forgeable, and so is every other byte of a
|
|
67456
|
+
* local file; what it buys is that the shortcut is not an official one-call path to a green gate.
|
|
67457
|
+
*/
|
|
67458
|
+
server.registerTool('confirm_intent_dimension', {
|
|
67459
|
+
title: 'Confirm or waive a readiness dimension',
|
|
67460
|
+
description: 'Resolve an "unconfirmed" readiness dimension in a local intent.md. Use this when check_intent_readiness reports that it READ your objective or outcomes but could not confirm them: the gate matches a fixed English vocabulary and misses valid phrasing, including other languages. ' +
|
|
67461
|
+
'confirm: state who is affected and what goes wrong for them, in your own words, and the dimension passes. ' +
|
|
67462
|
+
'waive: mark the dimension as not applicable to this change (a pure refactor has no product outcome). A waiver is a HUMAN decision, so set humanApproved only after the user has explicitly agreed. ' +
|
|
67463
|
+
'The confirmation is bound to the exact text it was made against and dies automatically if that text is edited. You cannot confirm a dimension the gate read nothing for; write the field first, save, then confirm.',
|
|
67464
|
+
inputSchema: {
|
|
67465
|
+
dimension: zod_1.z.enum(['objective', 'outcomes']).describe('Only these two are confirmable. Title and verification are never waivable.'),
|
|
67466
|
+
action: zod_1.z.enum(['confirm', 'waive']).describe('confirm: vouch that the text names what the gate could not find. waive: this dimension does not apply to this change.'),
|
|
67467
|
+
actor: zod_1.z.string().optional().describe('confirm + objective: who is affected, in your words.'),
|
|
67468
|
+
problem: zod_1.z.string().optional().describe('confirm + objective: what goes wrong for them today.'),
|
|
67469
|
+
outcome: zod_1.z.string().optional().describe('confirm + outcomes: the observable change.'),
|
|
67470
|
+
observable: zod_1.z.string().optional().describe('confirm + outcomes: how you would see it.'),
|
|
67471
|
+
reason: zod_1.z.string().optional().describe('waive: why this dimension does not apply.'),
|
|
67472
|
+
humanApproved: zod_1.z.boolean().optional().describe('waive only. Set ONLY after the user has explicitly approved the waiver. Recorded as a human decision that this environment cannot verify.'),
|
|
67473
|
+
path: zod_1.z.string().optional().describe('Path to the intent file. Defaults to intent.md.'),
|
|
67474
|
+
},
|
|
67475
|
+
}, async ({ dimension, action, actor, problem, outcome, observable, reason, humanApproved, path }) => {
|
|
67476
|
+
const filePath = resolveWithinProject(path || 'intent.md');
|
|
67477
|
+
const existing = (0, local_reader_1.readIntentFile)(filePath);
|
|
67478
|
+
if (!existing) {
|
|
67479
|
+
return { content: [{ type: 'text', text: `✗ No intent file at ${filePath}. Save one with intent_save first, then confirm.` }] };
|
|
67480
|
+
}
|
|
67481
|
+
const verdict = (0, readiness_1.computeReadinessVerdict)({ ...existing, confirmations: existing.confirmations });
|
|
67482
|
+
const state = verdict.detail[dimension]?.state;
|
|
67483
|
+
if (state === 'pass') {
|
|
67484
|
+
return { content: [{ type: 'text', text: `· ${dimension} already passes on its own. Nothing to confirm.` }] };
|
|
67485
|
+
}
|
|
67486
|
+
if (action === 'confirm' && state === 'absent') {
|
|
67487
|
+
return { content: [{ type: 'text', text: `✗ Cannot confirm ${dimension}: the reader found nothing there. Write the field, save with intent_save, then confirm. If it genuinely does not apply to this change, waive it instead.` }] };
|
|
67488
|
+
}
|
|
67489
|
+
if (action === 'waive' && !humanApproved) {
|
|
67490
|
+
return { content: [{ type: 'text', text: `✗ A waiver is a human decision. Ask the user whether ${dimension} genuinely does not apply to this change, and call again with humanApproved once they have said so.` }] };
|
|
67491
|
+
}
|
|
67492
|
+
if (action === 'confirm') {
|
|
67493
|
+
const missing = dimension === 'objective'
|
|
67494
|
+
? (!actor?.trim() || !problem?.trim()) && 'actor and problem'
|
|
67495
|
+
: (!outcome?.trim() || !observable?.trim()) && 'outcome and observable';
|
|
67496
|
+
if (missing)
|
|
67497
|
+
return { content: [{ type: 'text', text: `✗ A confirmation must name the ${missing}. A bare yes is not a confirmation.` }] };
|
|
67498
|
+
}
|
|
67499
|
+
if (action === 'waive' && !reason?.trim()) {
|
|
67500
|
+
return { content: [{ type: 'text', text: '✗ A waiver must carry a reason.' }] };
|
|
67501
|
+
}
|
|
67502
|
+
// Anchor to exactly what the gate read for this dimension, so an edit invalidates it.
|
|
67503
|
+
const anchor = (0, readiness_1.fieldDigest)(verdict.detail[dimension]?.extracted ?? '');
|
|
67504
|
+
const record = action === 'waive'
|
|
67505
|
+
? { dimension, kind: 'waived', by: 'human', reason: reason.trim(), anchor }
|
|
67506
|
+
: {
|
|
67507
|
+
dimension, kind: 'confirmed', by: 'agent', anchor,
|
|
67508
|
+
...(dimension === 'objective'
|
|
67509
|
+
? { actor: actor.trim(), problem: problem.trim() }
|
|
67510
|
+
: { outcome: outcome.trim(), observable: observable.trim() }),
|
|
67511
|
+
};
|
|
67512
|
+
// One live record per dimension: a re-confirmation replaces rather than accumulates.
|
|
67513
|
+
const kept = existing.confirmations.filter(c => c.dimension !== dimension);
|
|
67514
|
+
const content = (0, intent_compiler_1.formatIntentMd)({ ...existing, confirmations: [...kept, record] });
|
|
67515
|
+
(0, fs_1.writeFileSync)(filePath, content, 'utf-8');
|
|
67516
|
+
const after = (0, readiness_1.computeReadinessVerdict)({ ...existing, confirmations: [...kept, record] });
|
|
67517
|
+
return {
|
|
67518
|
+
content: [{
|
|
67519
|
+
type: 'text',
|
|
67520
|
+
text: [
|
|
67521
|
+
`✓ ${dimension} ${action === 'waive' ? 'waived' : 'confirmed'} in ${filePath}`,
|
|
67522
|
+
` ${after.detail[dimension]?.state === 'not_applicable' ? 'not applicable to this change' : 'confirmed against the current text'} · anchor ${anchor}`,
|
|
67523
|
+
action === 'waive' ? ' Recorded as a human decision this environment cannot verify.' : '',
|
|
67524
|
+
'',
|
|
67525
|
+
(0, readiness_1.formatReadinessVerdict)(after),
|
|
67526
|
+
].filter(Boolean).join('\n'),
|
|
67527
|
+
}],
|
|
67528
|
+
};
|
|
67529
|
+
});
|
|
67137
67530
|
server.tool('intent_export', 'Export an intent spec as .cursorrules, a CLAUDE.md or AGENTS.md section, or a Claude Managed Agents Outcomes rubric for AI agent consumption. Use agents-md for Codex, Cursor, and other AGENTS.md-aware agents.', {
|
|
67138
67531
|
format: zod_1.z.enum(['cursorrules', 'claude-md', 'agents-md', 'outcome-rubric']).describe('Export format'),
|
|
67139
67532
|
spec: zod_1.z.object(intentSpecSchema),
|
|
@@ -67204,7 +67597,9 @@ function startMcpServer() {
|
|
|
67204
67597
|
try {
|
|
67205
67598
|
const cloud = requireCloudClient();
|
|
67206
67599
|
const intents = await cloud.listIntents('approved');
|
|
67207
|
-
const
|
|
67600
|
+
const listed = intents[0] || (await cloud.listIntents())[0] || null;
|
|
67601
|
+
// List projection omits edge cases; this resource is read as the whole spec.
|
|
67602
|
+
const current = listed?.id ? await cloud.getIntent(listed.id).catch(() => listed) : listed;
|
|
67208
67603
|
return {
|
|
67209
67604
|
contents: [{
|
|
67210
67605
|
uri: uri.href,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"","sourceRoot":"","sources":["file:///Users/jannelammi/code/Pathmode/packages/mcp-server/src/intent-compiler.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"","sourceRoot":"","sources":["file:///Users/jannelammi/code/Pathmode/packages/mcp-server/src/intent-compiler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,MAAM,WAAW,cAAc;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAOD,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,QAAQ,GAAG,gBAAgB,GAAG,kBAAkB,GAAG,MAAM,CAAC;AAC1G,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AACxE,MAAM,WAAW,iBAAiB;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,qBAAqB,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAsDD,MAAM,WAAW,YAAY;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB;;iCAE6B;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,CAAC,MAAM,GAAG;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;KAAE,CAAC,EAAE,CAAC;IAC7F,6GAA6G;IAC7G,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC7D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACtD,YAAY,CAAC,EAAE;QACX,8GAA8G;QAC9G,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;QAC7B,kDAAkD;QAClD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;IACF;;;;0EAIsE;IACtE,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC;sFACkF;IAClF,qBAAqB,CAAC,EAAE;QACpB,oFAAoF;QACpF,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;QAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,aAAa,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QACnD,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;KACtC,GAAG,IAAI,CAAC;CACZ;AAwDD;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CA4D/C;AAoBD,kGAAkG;AAClG,MAAM,WAAW,eAAe;IAC5B,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mGAAmG;IACnG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;gFAI4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAiDD,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,GAAE,eAAoB,GAAG,MAAM,CA+IrF;AAOD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAwF5D;AAOD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CA4DhE;AAOD,MAAM,WAAW,oBAAoB;IACjC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AA2MD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,GAAE,oBAAyB,GAAG,MAAM,CAmC/F"}
|
package/dist/local-reader.d.ts
CHANGED
|
@@ -28,6 +28,28 @@ export interface LocalVerification {
|
|
|
28
28
|
unitTests?: string[];
|
|
29
29
|
e2eTests?: string[];
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* A confirmation or waiver as it sits in `## Confirmations`.
|
|
33
|
+
*
|
|
34
|
+
* `assurance` and `source` are DERIVED, never written in the file: anything read out of a local
|
|
35
|
+
* file is `local-unverified` from `file`, whatever the `by` line claims. A hand-edited block
|
|
36
|
+
* asserting `by: human` is still a human claim we cannot check, and every surface must render it
|
|
37
|
+
* as such (contract amendments C and M4).
|
|
38
|
+
*/
|
|
39
|
+
export interface LocalConfirmation {
|
|
40
|
+
dimension: string;
|
|
41
|
+
kind: string;
|
|
42
|
+
by: string;
|
|
43
|
+
assurance: 'local-unverified';
|
|
44
|
+
source: 'file';
|
|
45
|
+
actor?: string;
|
|
46
|
+
problem?: string;
|
|
47
|
+
outcome?: string;
|
|
48
|
+
observable?: string;
|
|
49
|
+
reason?: string;
|
|
50
|
+
anchor?: string;
|
|
51
|
+
at?: string;
|
|
52
|
+
}
|
|
31
53
|
export interface LocalIntent {
|
|
32
54
|
id: string;
|
|
33
55
|
status: string;
|
|
@@ -55,6 +77,8 @@ export interface LocalIntent {
|
|
|
55
77
|
outOfScope?: string[];
|
|
56
78
|
};
|
|
57
79
|
verification: LocalVerification;
|
|
80
|
+
/** From `## Confirmations`; validated by the readiness gate, not here. */
|
|
81
|
+
confirmations: LocalConfirmation[];
|
|
58
82
|
source: 'local';
|
|
59
83
|
}
|
|
60
84
|
/** Frontmatter identity of an existing intent.md, for non-destructive saves. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"","sourceRoot":"","sources":["file:///Users/jannelammi/code/Pathmode/packages/mcp-server/src/local-reader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,QAAQ,GAAG,gBAAgB,GAAG,kBAAkB,GAAG,MAAM,CAAC;AAE1G,MAAM,WAAW,sBAAsB;IACnC,IAAI,EAAE,qBAAqB,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wGAAwG;AACxG,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAC9B,MAAM,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAClC,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;iDAE6C;IAC7C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5D,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACtD,YAAY,EAAE,iBAAiB,CAAC;IAChC,MAAM,EAAE,OAAO,CAAC;CACnB;AAED,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC5B,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;6EACyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAID;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,EAAE,CAmBhD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAevE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAUnE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,SAAW,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"","sourceRoot":"","sources":["file:///Users/jannelammi/code/Pathmode/packages/mcp-server/src/local-reader.ts"],"names":[],"mappings":"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"}
|
package/dist/readiness.d.ts
CHANGED
|
@@ -21,6 +21,44 @@ export declare function isObjectiveSpecific(objective: string | null | undefined
|
|
|
21
21
|
export declare function isOutcomeMeasurable(text: string): boolean;
|
|
22
22
|
export declare const READINESS_BLOCKER_DESCRIPTIONS: Record<string, string>;
|
|
23
23
|
/** Display order for the gate strip (title first, matching the Preflight page). */
|
|
24
|
+
/**
|
|
25
|
+
* Fold away everything that is a rewrite of the same claim, and nothing that is a change to it.
|
|
26
|
+
* NFC because one glyph has two encodings; soft hyphens because editors inject them invisibly;
|
|
27
|
+
* quote/dash folding and markdown emphasis because adding `**` around a word is formatting, not
|
|
28
|
+
* a reword. Lowercased and whitespace-collapsed last.
|
|
29
|
+
*/
|
|
30
|
+
export declare function normalizeAnchor(value: unknown): string;
|
|
31
|
+
/**
|
|
32
|
+
* 64-bit FNV-1a over the normalized field text, as 16 lowercase hex chars.
|
|
33
|
+
*
|
|
34
|
+
* NOT sha256, and deliberately not node:crypto. lib/intentReadiness.ts is imported by
|
|
35
|
+
* 'use client' components (PreflightVerdictDemo, SpecPanel, DraftWorkspace), so the app-side
|
|
36
|
+
* half of this parity pair runs in the browser, where node crypto does not exist and
|
|
37
|
+
* crypto.subtle is async while this gate is synchronous and pure. Do not "upgrade" this to
|
|
38
|
+
* sha256 without checking that constraint first.
|
|
39
|
+
*
|
|
40
|
+
* A weak hash is adequate because this is change detection, not a security boundary: anyone
|
|
41
|
+
* who can forge a confirmation can edit the digest beside it. Accidental collision over 64 bits
|
|
42
|
+
* is negligible, and a collision only means a confirmation outlives an edit it should not have.
|
|
43
|
+
*/
|
|
44
|
+
export declare function fieldDigest(text: unknown): string;
|
|
45
|
+
/** A confirmation or waiver as it arrives, before any structural validation. */
|
|
46
|
+
export interface ConfirmationRecord {
|
|
47
|
+
dimension?: unknown;
|
|
48
|
+
kind?: unknown;
|
|
49
|
+
by?: unknown;
|
|
50
|
+
anchor?: unknown;
|
|
51
|
+
actor?: unknown;
|
|
52
|
+
problem?: unknown;
|
|
53
|
+
outcome?: unknown;
|
|
54
|
+
observable?: unknown;
|
|
55
|
+
reason?: unknown;
|
|
56
|
+
}
|
|
57
|
+
export interface RejectedConfirmation {
|
|
58
|
+
/** Stable machine code; nothing is ever dropped silently. */
|
|
59
|
+
code: 'unknown-dimension' | 'malformed' | 'stale' | 'waiver-requires-human' | 'nothing-to-confirm';
|
|
60
|
+
dimension: string;
|
|
61
|
+
}
|
|
24
62
|
export declare const READINESS_GATE_ORDER: readonly ["goal", "objective", "outcomes", "constraints", "edgeCases", "verification"];
|
|
25
63
|
/** Loose spec shape: covers LocalIntent, cloud intent JSON, and hand-built specs. */
|
|
26
64
|
export interface ReadinessSpecInput {
|
|
@@ -30,11 +68,38 @@ export interface ReadinessSpecInput {
|
|
|
30
68
|
constraints?: unknown;
|
|
31
69
|
edgeCases?: unknown;
|
|
32
70
|
verification?: unknown;
|
|
71
|
+
/** Confirmations and waivers; see docs/READINESS_CONFIRMATION_CONTRACT.md. */
|
|
72
|
+
confirmations?: unknown;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Why a dimension is not passing, which is not the same question as whether it passes.
|
|
76
|
+
* MIRROR of DimensionState in lib/intentReadiness.ts; see that file for the full rationale.
|
|
77
|
+
*
|
|
78
|
+
* `absent` means nothing substantive was extracted and the blocker copy is fair.
|
|
79
|
+
* `unconfirmed` means text WAS extracted and the lexical test rejected it, which on real
|
|
80
|
+
* in-the-wild specs is usually OUR error: an audit of 80 changes found ~80% of objective
|
|
81
|
+
* failures and ~94% of outcome failures are false negatives, most of them extracted
|
|
82
|
+
* correctly and then discarded by the word lists (docs/research/openspec-corpus-audit.md).
|
|
83
|
+
*/
|
|
84
|
+
export type DimensionState = 'pass' | 'unconfirmed' | 'absent' | 'not_applicable';
|
|
85
|
+
export interface DimensionDetail {
|
|
86
|
+
state: DimensionState;
|
|
87
|
+
/** What the reader actually read for this dimension, for quoting back. */
|
|
88
|
+
extracted?: string;
|
|
33
89
|
}
|
|
34
90
|
export interface ReadinessVerdict {
|
|
35
91
|
ready: boolean;
|
|
36
92
|
signals: Record<string, boolean>;
|
|
37
93
|
failingBlockers: string[];
|
|
94
|
+
/** Additive: failingBlockers stays byte-identical, richer messaging is opt-in. */
|
|
95
|
+
detail: Record<string, DimensionDetail>;
|
|
96
|
+
/** Confirmations that did not apply, with a reason. Nothing is ever dropped silently. */
|
|
97
|
+
rejectedConfirmations: RejectedConfirmation[];
|
|
98
|
+
/**
|
|
99
|
+
* Ready once confirmations and waivers are counted. `ready` stays the pure lexical verdict
|
|
100
|
+
* so a surface can distinguish what was earned from what was vouched for.
|
|
101
|
+
*/
|
|
102
|
+
confirmedReady: boolean;
|
|
38
103
|
}
|
|
39
104
|
/**
|
|
40
105
|
* The preflight: six deterministic gates over an intent spec. Mirrors
|
package/dist/readiness.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"","sourceRoot":"","sources":["file:///Users/jannelammi/code/Pathmode/packages/mcp-server/src/readiness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQjD;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,EAAE,CAIjE;AAoCD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAQ3E;AAID,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAI5D;AAED,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAI9F;AAQD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAOjF;AAQD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKzD;AAID,eAAO,MAAM,8BAA8B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOjE,CAAC;AAEF,mFAAmF;
|
|
1
|
+
{"version":3,"file":"","sourceRoot":"","sources":["file:///Users/jannelammi/code/Pathmode/packages/mcp-server/src/readiness.ts"],"names":[],"mappings":"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"}
|
package/manifest.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"manifest_version": "0.3",
|
|
3
3
|
"name": "pathmode",
|
|
4
4
|
"display_name": "Pathmode",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.15.0",
|
|
6
6
|
"description": "Deterministic preflight for the intent you hand to a coding agent: six calibrated gates, the exact blockers named, no model call, no key needed.",
|
|
7
7
|
"long_description": "Pathmode MCP Server runs a deterministic preflight before your coding agent builds: check_intent_readiness scores an intent spec against six calibrated gates (title, objective, outcomes, constraints, edge cases, verification) and names the exact blockers, with no model call and no account. Keyless local mode works out of the box; specs live in intent.md in your repo, plain markdown you own, and skills for drafting, pressure-testing, and handing off intent ride along. Connect a Pathmode workspace with an API key to sync intent and evidence across a team, analyze dependency graphs, and verify pull requests against the outcomes you agreed to.",
|
|
8
8
|
"author": {
|