hcifootprint 0.2.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/LICENSE +20 -0
- package/README.md +524 -0
- package/dist/atom/types.d.ts +618 -0
- package/dist/atom/types.d.ts.map +1 -0
- package/dist/atom/types.js +2 -0
- package/dist/atom/types.js.map +1 -0
- package/dist/graph/builder.d.ts +31 -0
- package/dist/graph/builder.d.ts.map +1 -0
- package/dist/graph/builder.js +165 -0
- package/dist/graph/builder.js.map +1 -0
- package/dist/graph/guards.d.ts +31 -0
- package/dist/graph/guards.d.ts.map +1 -0
- package/dist/graph/guards.js +94 -0
- package/dist/graph/guards.js.map +1 -0
- package/dist/graph/skill-deps.d.ts +20 -0
- package/dist/graph/skill-deps.d.ts.map +1 -0
- package/dist/graph/skill-deps.js +15 -0
- package/dist/graph/skill-deps.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.d.ts +16 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +15 -0
- package/dist/mcp.js.map +1 -0
- package/dist/presence/presence.d.ts +50 -0
- package/dist/presence/presence.d.ts.map +1 -0
- package/dist/presence/presence.js +126 -0
- package/dist/presence/presence.js.map +1 -0
- package/dist/registry/registry.d.ts +53 -0
- package/dist/registry/registry.d.ts.map +1 -0
- package/dist/registry/registry.js +76 -0
- package/dist/registry/registry.js.map +1 -0
- package/dist/serve/mcp-server.d.ts +40 -0
- package/dist/serve/mcp-server.d.ts.map +1 -0
- package/dist/serve/mcp-server.js +72 -0
- package/dist/serve/mcp-server.js.map +1 -0
- package/dist/serve/mcp.d.ts +12 -0
- package/dist/serve/mcp.d.ts.map +1 -0
- package/dist/serve/mcp.js +62 -0
- package/dist/serve/mcp.js.map +1 -0
- package/dist/serve/modes.d.ts +66 -0
- package/dist/serve/modes.d.ts.map +1 -0
- package/dist/serve/modes.js +347 -0
- package/dist/serve/modes.js.map +1 -0
- package/dist/testing/harness.d.ts +156 -0
- package/dist/testing/harness.d.ts.map +1 -0
- package/dist/testing/harness.js +416 -0
- package/dist/testing/harness.js.map +1 -0
- package/dist/testing/index.d.ts +35 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +32 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/lint.d.ts +20 -0
- package/dist/testing/lint.d.ts.map +1 -0
- package/dist/testing/lint.js +18 -0
- package/dist/testing/lint.js.map +1 -0
- package/dist/testing/model/check.d.ts +30 -0
- package/dist/testing/model/check.d.ts.map +1 -0
- package/dist/testing/model/check.js +89 -0
- package/dist/testing/model/check.js.map +1 -0
- package/dist/testing/model/lint.d.ts +54 -0
- package/dist/testing/model/lint.d.ts.map +1 -0
- package/dist/testing/model/lint.js +235 -0
- package/dist/testing/model/lint.js.map +1 -0
- package/dist/testing/model/satisfiable.d.ts +25 -0
- package/dist/testing/model/satisfiable.d.ts.map +1 -0
- package/dist/testing/model/satisfiable.js +101 -0
- package/dist/testing/model/satisfiable.js.map +1 -0
- package/dist/traverse/nav-session.d.ts +108 -0
- package/dist/traverse/nav-session.d.ts.map +1 -0
- package/dist/traverse/nav-session.js +637 -0
- package/dist/traverse/nav-session.js.map +1 -0
- package/dist/traverse/session.d.ts +239 -0
- package/dist/traverse/session.d.ts.map +1 -0
- package/dist/traverse/session.js +1305 -0
- package/dist/traverse/session.js.map +1 -0
- package/dist/tree/appmap.d.ts +8 -0
- package/dist/tree/appmap.d.ts.map +1 -0
- package/dist/tree/appmap.js +259 -0
- package/dist/tree/appmap.js.map +1 -0
- package/dist/tree/types.d.ts +151 -0
- package/dist/tree/types.d.ts.map +1 -0
- package/dist/tree/types.js +2 -0
- package/dist/tree/types.js.map +1 -0
- package/package.json +90 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skillGraph() — the fluent authoring surface.
|
|
3
|
+
*
|
|
4
|
+
* Authoring is the primary acquisition mode by design: guards and intent are
|
|
5
|
+
* semantic and unrecoverable from passive observation. The builder's job is
|
|
6
|
+
* the enforcement spine — every referential or shape mistake fails LOUDLY at
|
|
7
|
+
* build() so the graph can't silently drift into lying to a planner.
|
|
8
|
+
*/
|
|
9
|
+
import { detectSchema } from 'footprintjs';
|
|
10
|
+
import { Session } from '../traverse/session.js';
|
|
11
|
+
import { SkillGraphValidationError, guardStateKeys, validateGuardShape } from './guards.js';
|
|
12
|
+
export { SkillGraphValidationError } from './guards.js';
|
|
13
|
+
export function skillGraph(id, opts) {
|
|
14
|
+
return new SkillGraphBuilder(id, opts?.description);
|
|
15
|
+
}
|
|
16
|
+
export class SkillGraphBuilder {
|
|
17
|
+
#id;
|
|
18
|
+
#description;
|
|
19
|
+
#pages = new Map();
|
|
20
|
+
#affordances = new Map();
|
|
21
|
+
#skills = new Map();
|
|
22
|
+
constructor(id, description) {
|
|
23
|
+
if (!id || !id.trim())
|
|
24
|
+
throw new SkillGraphValidationError('skillGraph(id) requires a non-empty id.');
|
|
25
|
+
this.#id = id;
|
|
26
|
+
this.#description = description;
|
|
27
|
+
}
|
|
28
|
+
page(id, def = {}) {
|
|
29
|
+
if (this.#pages.has(id))
|
|
30
|
+
throw new SkillGraphValidationError(`duplicate page id '${id}'.`);
|
|
31
|
+
this.#pages.set(id, def);
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
affordance(id, def) {
|
|
35
|
+
if (id === 'leave-skill') {
|
|
36
|
+
throw new SkillGraphValidationError(`affordance id 'leave-skill' is reserved — it is the synthetic escape tool served while a skill frame is open.`);
|
|
37
|
+
}
|
|
38
|
+
if (this.#affordances.has(id))
|
|
39
|
+
throw new SkillGraphValidationError(`duplicate affordance id '${id}'.`);
|
|
40
|
+
if (!def.description || !def.description.trim()) {
|
|
41
|
+
throw new SkillGraphValidationError(`affordance '${id}' needs a description — it is the planner-facing text an LLM sees.`);
|
|
42
|
+
}
|
|
43
|
+
if (def.guard && Object.keys(def.guard).length === 0) {
|
|
44
|
+
throw new SkillGraphValidationError(`affordance '${id}' has an empty guard {} — footprint's evaluator deliberately NEVER matches ` +
|
|
45
|
+
`an empty filter (anti-vacuous-truth). Omit 'guard' entirely for an always-offered affordance.`);
|
|
46
|
+
}
|
|
47
|
+
if (def.guard)
|
|
48
|
+
this.#validateGuardShape(`affordance '${id}' guard`, def.guard);
|
|
49
|
+
if (Array.isArray(def.on) && def.on.length === 0) {
|
|
50
|
+
throw new SkillGraphValidationError(`affordance '${id}' has on: [] — it would never be offered anywhere. List at least one page.`);
|
|
51
|
+
}
|
|
52
|
+
if (def.schema !== undefined && detectSchema(def.schema) === 'none') {
|
|
53
|
+
throw new SkillGraphValidationError(`affordance '${id}' has an unrecognized schema — pass a Zod schema, a JSON Schema object, ` +
|
|
54
|
+
`or a validator with .safeParse/.parse.`);
|
|
55
|
+
}
|
|
56
|
+
this.#affordances.set(id, def);
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
skill(id, def) {
|
|
60
|
+
if (this.#skills.has(id))
|
|
61
|
+
throw new SkillGraphValidationError(`duplicate skill id '${id}'.`);
|
|
62
|
+
if (!def.description || !def.description.trim()) {
|
|
63
|
+
throw new SkillGraphValidationError(`skill '${id}' needs a description (planner-facing text).`);
|
|
64
|
+
}
|
|
65
|
+
if (!def.steps || def.steps.length === 0) {
|
|
66
|
+
throw new SkillGraphValidationError(`skill '${id}' needs at least one step (affordance id).`);
|
|
67
|
+
}
|
|
68
|
+
if (def.precondition && Object.keys(def.precondition).length === 0) {
|
|
69
|
+
throw new SkillGraphValidationError(`skill '${id}' has an empty precondition {} — it would never pass. Omit it instead.`);
|
|
70
|
+
}
|
|
71
|
+
if (def.precondition) {
|
|
72
|
+
this.#validateGuardShape(`skill '${id}' precondition`, def.precondition);
|
|
73
|
+
}
|
|
74
|
+
this.#skills.set(id, def);
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
build() {
|
|
78
|
+
if (this.#pages.size === 0) {
|
|
79
|
+
throw new SkillGraphValidationError(`graph '${this.#id}' has no pages — add at least one .page().`);
|
|
80
|
+
}
|
|
81
|
+
const pages = {};
|
|
82
|
+
for (const [id, def] of this.#pages)
|
|
83
|
+
pages[id] = { id, ...def };
|
|
84
|
+
const affordances = {};
|
|
85
|
+
for (const [id, def] of this.#affordances) {
|
|
86
|
+
const on = Array.isArray(def.on) ? [...def.on] : [def.on];
|
|
87
|
+
for (const pageId of on) {
|
|
88
|
+
if (!pages[pageId]) {
|
|
89
|
+
throw new SkillGraphValidationError(`affordance '${id}' is offered on unknown page '${pageId}'. Known pages: ${[...this.#pages.keys()].join(', ')}.`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (def.effect?.navigatesTo && !pages[def.effect.navigatesTo]) {
|
|
93
|
+
throw new SkillGraphValidationError(`affordance '${id}' declares navigatesTo unknown page '${def.effect.navigatesTo}'.`);
|
|
94
|
+
}
|
|
95
|
+
// Clone + deep-freeze plain data so the compiled graph is decoupled from
|
|
96
|
+
// the author's live objects (post-build mutation must not silently change
|
|
97
|
+
// what a session offers). `schema` is the one exception: validators hold
|
|
98
|
+
// functions, so it stays by reference and MCP emission clones on the way out.
|
|
99
|
+
affordances[id] = deepFreeze({
|
|
100
|
+
id,
|
|
101
|
+
on,
|
|
102
|
+
description: def.description,
|
|
103
|
+
binding: structuredClone(def.binding),
|
|
104
|
+
guard: def.guard ? structuredClone(def.guard) : undefined,
|
|
105
|
+
effect: def.effect ? structuredClone(def.effect) : undefined,
|
|
106
|
+
schema: def.schema,
|
|
107
|
+
highEffect: def.highEffect ?? false,
|
|
108
|
+
role: deriveRole(def),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const skills = {};
|
|
112
|
+
for (const [id, def] of this.#skills) {
|
|
113
|
+
for (const step of def.steps) {
|
|
114
|
+
if (!affordances[step]) {
|
|
115
|
+
throw new SkillGraphValidationError(`skill '${id}' step '${step}' is not a known affordance. Known: ${[...this.#affordances.keys()].join(', ')}.`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
skills[id] = deepFreeze({
|
|
119
|
+
id,
|
|
120
|
+
description: def.description,
|
|
121
|
+
steps: [...def.steps],
|
|
122
|
+
precondition: def.precondition ? structuredClone(def.precondition) : undefined,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
for (const page of Object.values(pages))
|
|
126
|
+
Object.freeze(page);
|
|
127
|
+
const spec = Object.freeze({
|
|
128
|
+
id: this.#id,
|
|
129
|
+
description: this.#description,
|
|
130
|
+
pages: Object.freeze(pages),
|
|
131
|
+
affordances: Object.freeze(affordances),
|
|
132
|
+
skills: Object.freeze(skills),
|
|
133
|
+
});
|
|
134
|
+
return {
|
|
135
|
+
spec,
|
|
136
|
+
createSession: (opts) => new Session(spec, opts),
|
|
137
|
+
requiredStateKeys: () => guardStateKeys([
|
|
138
|
+
...Object.values(spec.affordances).map((aff) => aff.guard),
|
|
139
|
+
...Object.values(spec.skills).map((skill) => skill.precondition),
|
|
140
|
+
]),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/** Catch shape mistakes at build time — shared spine with appMap() (guards.ts). */
|
|
144
|
+
#validateGuardShape(owner, guard) {
|
|
145
|
+
validateGuardShape(owner, guard);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function deriveRole(def) {
|
|
149
|
+
if (def.role)
|
|
150
|
+
return def.role;
|
|
151
|
+
if (def.effect?.navigatesTo)
|
|
152
|
+
return 'next';
|
|
153
|
+
return 'action';
|
|
154
|
+
}
|
|
155
|
+
/** Freeze an object and every plain nested object/array. Skips the (unfrozen) `schema` field. */
|
|
156
|
+
function deepFreeze(value) {
|
|
157
|
+
for (const [key, child] of Object.entries(value)) {
|
|
158
|
+
if (key === 'schema')
|
|
159
|
+
continue;
|
|
160
|
+
if (child && typeof child === 'object')
|
|
161
|
+
deepFreeze(child);
|
|
162
|
+
}
|
|
163
|
+
return Object.freeze(value);
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/graph/builder.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAY3C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,yBAAyB,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAE5F,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAmBxD,MAAM,UAAU,UAAU,CAAC,EAAU,EAAE,IAA+B;IACpE,OAAO,IAAI,iBAAiB,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,OAAO,iBAAiB;IACnB,GAAG,CAAS;IACZ,YAAY,CAAU;IACtB,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAC;IACpC,YAAY,GAAG,IAAI,GAAG,EAAyB,CAAC;IAChD,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE/C,YAAY,EAAU,EAAE,WAAoB;QAC1C,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE;YAAE,MAAM,IAAI,yBAAyB,CAAC,yCAAyC,CAAC,CAAC;QACtG,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QACd,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC;IAClC,CAAC;IAED,IAAI,CAAC,EAAU,EAAE,MAAe,EAAE;QAChC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,yBAAyB,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAC;QAC3F,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,UAAU,CAAC,EAAU,EAAE,GAAkB;QACvC,IAAI,EAAE,KAAK,aAAa,EAAE,CAAC;YACzB,MAAM,IAAI,yBAAyB,CACjC,+GAA+G,CAChH,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,yBAAyB,CAAC,4BAA4B,EAAE,IAAI,CAAC,CAAC;QACvG,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC;YAChD,MAAM,IAAI,yBAAyB,CACjC,eAAe,EAAE,oEAAoE,CACtF,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,yBAAyB,CACjC,eAAe,EAAE,6EAA6E;gBAC5F,+FAA+F,CAClG,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,KAAK;YAAE,IAAI,CAAC,mBAAmB,CAAC,eAAe,EAAE,SAAS,EAAE,GAAG,CAAC,KAAgC,CAAC,CAAC;QAC1G,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,yBAAyB,CACjC,eAAe,EAAE,4EAA4E,CAC9F,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,MAAM,EAAE,CAAC;YACpE,MAAM,IAAI,yBAAyB,CACjC,eAAe,EAAE,0EAA0E;gBACzF,wCAAwC,CAC3C,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,EAAU,EAAE,GAAa;QAC7B,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,yBAAyB,CAAC,uBAAuB,EAAE,IAAI,CAAC,CAAC;QAC7F,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC;YAChD,MAAM,IAAI,yBAAyB,CAAC,UAAU,EAAE,8CAA8C,CAAC,CAAC;QAClG,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,yBAAyB,CAAC,UAAU,EAAE,4CAA4C,CAAC,CAAC;QAChG,CAAC;QACD,IAAI,GAAG,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnE,MAAM,IAAI,yBAAyB,CACjC,UAAU,EAAE,wEAAwE,CACrF,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,YAAY,EAAE,CAAC;YACrB,IAAI,CAAC,mBAAmB,CAAC,UAAU,EAAE,gBAAgB,EAAE,GAAG,CAAC,YAAuC,CAAC,CAAC;QACtG,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,yBAAyB,CAAC,UAAU,IAAI,CAAC,GAAG,4CAA4C,CAAC,CAAC;QACtG,CAAC;QAED,MAAM,KAAK,GAAyB,EAAE,CAAC;QACvC,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,GAAG,EAAE,CAAC;QAEhE,MAAM,WAAW,GAA+B,EAAE,CAAC;QACnD,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YAC1C,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC1D,KAAK,MAAM,MAAM,IAAI,EAAE,EAAE,CAAC;gBACxB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;oBACnB,MAAM,IAAI,yBAAyB,CACjC,eAAe,EAAE,iCAAiC,MAAM,mBAAmB,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACjH,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC9D,MAAM,IAAI,yBAAyB,CACjC,eAAe,EAAE,wCAAwC,GAAG,CAAC,MAAM,CAAC,WAAW,IAAI,CACpF,CAAC;YACJ,CAAC;YACD,yEAAyE;YACzE,0EAA0E;YAC1E,yEAAyE;YACzE,8EAA8E;YAC9E,WAAW,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC;gBAC3B,EAAE;gBACF,EAAE;gBACF,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC;gBACrC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;gBACzD,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;gBAC5D,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,KAAK;gBACnC,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC;aACtB,CAAe,CAAC;QACnB,CAAC;QAED,MAAM,MAAM,GAA0B,EAAE,CAAC;QACzC,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACrC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;gBAC7B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvB,MAAM,IAAI,yBAAyB,CACjC,UAAU,EAAE,WAAW,IAAI,uCAAuC,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC9G,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,MAAM,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC;gBACtB,EAAE;gBACF,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,KAAK,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC;gBACrB,YAAY,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS;aAC/E,CAAU,CAAC;QACd,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAmB,MAAM,CAAC,MAAM,CAAC;YACzC,EAAE,EAAE,IAAI,CAAC,GAAG;YACZ,WAAW,EAAE,IAAI,CAAC,YAAY;YAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YAC3B,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC;YACvC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;SAC9B,CAAC,CAAC;QAEH,OAAO;YACL,IAAI;YACJ,aAAa,EAAE,CAAC,IAAoB,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC;YAChE,iBAAiB,EAAE,GAAG,EAAE,CACtB,cAAc,CAAC;gBACb,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC;gBAC1D,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC;aACjE,CAAC;SACL,CAAC;IACJ,CAAC;IAED,mFAAmF;IACnF,mBAAmB,CAAC,KAAa,EAAE,KAA8B;QAC/D,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC;CACF;AAED,SAAS,UAAU,CAAC,GAAkB;IACpC,IAAI,GAAG,CAAC,IAAI;QAAE,OAAO,GAAG,CAAC,IAAI,CAAC;IAC9B,IAAI,GAAG,CAAC,MAAM,EAAE,WAAW;QAAE,OAAO,MAAM,CAAC;IAC3C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,iGAAiG;AACjG,SAAS,UAAU,CAAmB,KAAQ;IAC5C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,GAAG,KAAK,QAAQ;YAAE,SAAS;QAC/B,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,UAAU,CAAC,KAAe,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared guard-shape enforcement — one spine for BOTH authoring surfaces
|
|
3
|
+
* (the v1 fluent skillGraph() and the D18 appMap() object literal).
|
|
4
|
+
*
|
|
5
|
+
* footprint's evaluator fails shape mistakes SILENTLY at runtime (unknown
|
|
6
|
+
* operators are ignored; denied keys never match). Authoring is where they
|
|
7
|
+
* must die loudly.
|
|
8
|
+
*/
|
|
9
|
+
export declare const FILTER_OPERATORS: Set<string>;
|
|
10
|
+
/** Mirrors footprint evaluator's DENIED_KEYS — guards on these silently never match at runtime. */
|
|
11
|
+
export declare const DENIED_GUARD_KEYS: Set<string>;
|
|
12
|
+
export declare class SkillGraphValidationError extends Error {
|
|
13
|
+
constructor(message: string);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* AND-compose a guard chain (root → leaf → own). Children may only NARROW:
|
|
17
|
+
* the same key+operator appearing twice with different values is a
|
|
18
|
+
* contradiction the author must resolve, not a silent override.
|
|
19
|
+
*/
|
|
20
|
+
export declare function composeGuards(owner: string, layers: Record<string, unknown>[]): Record<string, unknown> | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* The sorted, deduped set of top-level state keys a collection of guards
|
|
23
|
+
* (WhereFilters) reads. A WhereFilter is a FLAT `key → { op: value }` map, so
|
|
24
|
+
* its own-enumerable keys ARE the state keys the evaluator looks up — the same
|
|
25
|
+
* `Object.keys(guard)` set #evalGuard tests for presence before deciding. Both
|
|
26
|
+
* authoring surfaces build their `requiredStateKeys()` on this.
|
|
27
|
+
*/
|
|
28
|
+
export declare function guardStateKeys(guards: Iterable<Record<string, unknown> | undefined>): string[];
|
|
29
|
+
/** Catch shape mistakes at authoring time — the evaluator fails them silently at runtime. */
|
|
30
|
+
export declare function validateGuardShape(owner: string, guard: Record<string, unknown>): void;
|
|
31
|
+
//# sourceMappingURL=guards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../src/graph/guards.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,eAAO,MAAM,gBAAgB,aAAiE,CAAC;AAE/F,mGAAmG;AACnG,eAAO,MAAM,iBAAiB,aAa5B,CAAC;AAEH,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAChC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAiBrC;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,GAAG,MAAM,EAAE,CAO9F;AAED,6FAA6F;AAC7F,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAiCtF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared guard-shape enforcement — one spine for BOTH authoring surfaces
|
|
3
|
+
* (the v1 fluent skillGraph() and the D18 appMap() object literal).
|
|
4
|
+
*
|
|
5
|
+
* footprint's evaluator fails shape mistakes SILENTLY at runtime (unknown
|
|
6
|
+
* operators are ignored; denied keys never match). Authoring is where they
|
|
7
|
+
* must die loudly.
|
|
8
|
+
*/
|
|
9
|
+
export const FILTER_OPERATORS = new Set(['eq', 'ne', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn']);
|
|
10
|
+
/** Mirrors footprint evaluator's DENIED_KEYS — guards on these silently never match at runtime. */
|
|
11
|
+
export const DENIED_GUARD_KEYS = new Set([
|
|
12
|
+
'__proto__',
|
|
13
|
+
'constructor',
|
|
14
|
+
'prototype',
|
|
15
|
+
'toString',
|
|
16
|
+
'valueOf',
|
|
17
|
+
'hasOwnProperty',
|
|
18
|
+
'isPrototypeOf',
|
|
19
|
+
'propertyIsEnumerable',
|
|
20
|
+
'__defineGetter__',
|
|
21
|
+
'__defineSetter__',
|
|
22
|
+
'__lookupGetter__',
|
|
23
|
+
'__lookupSetter__',
|
|
24
|
+
]);
|
|
25
|
+
export class SkillGraphValidationError extends Error {
|
|
26
|
+
constructor(message) {
|
|
27
|
+
super(`hcifootprint: ${message}`);
|
|
28
|
+
this.name = 'SkillGraphValidationError';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* AND-compose a guard chain (root → leaf → own). Children may only NARROW:
|
|
33
|
+
* the same key+operator appearing twice with different values is a
|
|
34
|
+
* contradiction the author must resolve, not a silent override.
|
|
35
|
+
*/
|
|
36
|
+
export function composeGuards(owner, layers) {
|
|
37
|
+
const merged = {};
|
|
38
|
+
for (const layer of layers) {
|
|
39
|
+
for (const [key, ops] of Object.entries(layer)) {
|
|
40
|
+
const target = (merged[key] ??= {});
|
|
41
|
+
for (const [op, value] of Object.entries(ops)) {
|
|
42
|
+
if (op in target && JSON.stringify(target[op]) !== JSON.stringify(value)) {
|
|
43
|
+
throw new SkillGraphValidationError(`tool '${owner}': ancestor and descendant guards disagree on '${key}.${op}' ` +
|
|
44
|
+
`(${JSON.stringify(target[op])} vs ${JSON.stringify(value)}) — children can only narrow.`);
|
|
45
|
+
}
|
|
46
|
+
target[op] = structuredClone(value);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The sorted, deduped set of top-level state keys a collection of guards
|
|
54
|
+
* (WhereFilters) reads. A WhereFilter is a FLAT `key → { op: value }` map, so
|
|
55
|
+
* its own-enumerable keys ARE the state keys the evaluator looks up — the same
|
|
56
|
+
* `Object.keys(guard)` set #evalGuard tests for presence before deciding. Both
|
|
57
|
+
* authoring surfaces build their `requiredStateKeys()` on this.
|
|
58
|
+
*/
|
|
59
|
+
export function guardStateKeys(guards) {
|
|
60
|
+
const keys = new Set();
|
|
61
|
+
for (const guard of guards) {
|
|
62
|
+
if (!guard)
|
|
63
|
+
continue;
|
|
64
|
+
for (const key of Object.keys(guard))
|
|
65
|
+
keys.add(key);
|
|
66
|
+
}
|
|
67
|
+
return [...keys].sort();
|
|
68
|
+
}
|
|
69
|
+
/** Catch shape mistakes at authoring time — the evaluator fails them silently at runtime. */
|
|
70
|
+
export function validateGuardShape(owner, guard) {
|
|
71
|
+
for (const [key, ops] of Object.entries(guard)) {
|
|
72
|
+
if (DENIED_GUARD_KEYS.has(key)) {
|
|
73
|
+
throw new SkillGraphValidationError(`${owner} key '${key}' is on footprint's denied list — it would silently never match at runtime.`);
|
|
74
|
+
}
|
|
75
|
+
if (!ops || typeof ops !== 'object' || Array.isArray(ops)) {
|
|
76
|
+
throw new SkillGraphValidationError(`${owner} key '${key}' must map to an operator object like { eq: value } ` +
|
|
77
|
+
`(operators: ${[...FILTER_OPERATORS].join(', ')}).`);
|
|
78
|
+
}
|
|
79
|
+
if (Object.keys(ops).length === 0) {
|
|
80
|
+
throw new SkillGraphValidationError(`${owner} key '${key}' has an empty operator object {} — the evaluator would silently ignore it ` +
|
|
81
|
+
`(or never match if it is the only key). Give it an operator like { eq: value } or remove the key.`);
|
|
82
|
+
}
|
|
83
|
+
for (const [op, value] of Object.entries(ops)) {
|
|
84
|
+
if (!FILTER_OPERATORS.has(op)) {
|
|
85
|
+
throw new SkillGraphValidationError(`${owner} key '${key}' uses unknown operator '${op}' (valid: ${[...FILTER_OPERATORS].join(', ')}).`);
|
|
86
|
+
}
|
|
87
|
+
if ((op === 'in' || op === 'notIn') && !Array.isArray(value)) {
|
|
88
|
+
throw new SkillGraphValidationError(`${owner} key '${key}' operator '${op}' needs an ARRAY (got ${typeof value}) — ` +
|
|
89
|
+
`a non-array compiles but silently never matches at runtime.`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=guards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/graph/guards.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The intra-skill dependency rule, in ONE place.
|
|
3
|
+
*
|
|
4
|
+
* Step B depends on step A when A's declared `effect.writes` overlap B's guard
|
|
5
|
+
* keys — the guard×effect atoms already encode the ordering, so the dependency
|
|
6
|
+
* DAG is DERIVED, never authored, and cannot drift from the graph.
|
|
7
|
+
*
|
|
8
|
+
* This is shared on purpose: Session.skillPlan() computes the live DAG from it,
|
|
9
|
+
* and the testing linter (hcifootprint/testing) reasons about skill
|
|
10
|
+
* completability from the SAME rule. If they used two copies, the linter could
|
|
11
|
+
* green-light a skill the runtime then reports as blocked (or vice versa) — the
|
|
12
|
+
* exact drift this library exists to catch. One function, no disagreement.
|
|
13
|
+
*/
|
|
14
|
+
import type { Affordance, DependencyEdge } from '../atom/types.js';
|
|
15
|
+
/**
|
|
16
|
+
* The steps that must run before `stepId` for its guard to be satisfiable by
|
|
17
|
+
* in-skill writes — each with the specific keys that create the dependency.
|
|
18
|
+
*/
|
|
19
|
+
export declare function stepDependencies(affordances: Record<string, Affordance>, steps: readonly string[], stepId: string): DependencyEdge[];
|
|
20
|
+
//# sourceMappingURL=skill-deps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-deps.d.ts","sourceRoot":"","sources":["../../src/graph/skill-deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEnE;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,EACvC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,MAAM,EAAE,MAAM,GACb,cAAc,EAAE,CAWlB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The steps that must run before `stepId` for its guard to be satisfiable by
|
|
3
|
+
* in-skill writes — each with the specific keys that create the dependency.
|
|
4
|
+
*/
|
|
5
|
+
export function stepDependencies(affordances, steps, stepId) {
|
|
6
|
+
const guardKeys = Object.keys(affordances[stepId]?.guard ?? {});
|
|
7
|
+
return steps
|
|
8
|
+
.filter((otherId) => otherId !== stepId)
|
|
9
|
+
.map((otherId) => {
|
|
10
|
+
const viaKeys = (affordances[otherId]?.effect?.writes ?? []).filter((key) => guardKeys.includes(key));
|
|
11
|
+
return { affordanceId: otherId, viaKeys };
|
|
12
|
+
})
|
|
13
|
+
.filter((dep) => dep.viaKeys.length > 0);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=skill-deps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-deps.js","sourceRoot":"","sources":["../../src/graph/skill-deps.ts"],"names":[],"mappings":"AAeA;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,WAAuC,EACvC,KAAwB,EACxB,MAAc;IAEd,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;IAChE,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,MAAM,CAAC;SACvC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QACf,MAAM,OAAO,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAC1E,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CACxB,CAAC;QACF,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAC5C,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC7C,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hcifootprint — turn a web app's interaction surface into a typed,
|
|
3
|
+
* traversable skill graph an LLM can plan over.
|
|
4
|
+
*
|
|
5
|
+
* The frontend sibling of footprintjs (backend flowcharts) and agentfootprint
|
|
6
|
+
* (self-explaining agents): one self-explaining trace substrate underneath.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { buildNavigationGraph } from 'hcifootprint';
|
|
10
|
+
*
|
|
11
|
+
* const graph = buildNavigationGraph('shop', {
|
|
12
|
+
* pages: {
|
|
13
|
+
* catalog: {
|
|
14
|
+
* tools: {
|
|
15
|
+
* 'add-to-cart': { does: 'Add the open dress to the cart', when: { authenticated: { eq: true } }, writes: ['cart'] },
|
|
16
|
+
* },
|
|
17
|
+
* },
|
|
18
|
+
* },
|
|
19
|
+
* skills: { purchase: { does: 'Buy a dress end to end', steps: ['add-to-cart'] } },
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* const session = graph.createSession({ node: 'catalog', state: { authenticated: true } });
|
|
23
|
+
* session.available(); // → guard-passing edges = the LLM's action space
|
|
24
|
+
* session.registerToolGroup('catalog', { handlers: { 'add-to-cart': (i) => shop.add(i) } });
|
|
25
|
+
* session.fire('catalog.add-to-cart', { source: 'agent' }); // → settlement: 'awaiting-state'
|
|
26
|
+
* session.updateState({ cart: 1 }); // your store tap settles the pending write
|
|
27
|
+
* session.why('cart'); // footprint backward slice over the session
|
|
28
|
+
*
|
|
29
|
+
* // v1 skillGraph() — the fluent builder — remains as legacy sugar.
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export { skillGraph, SkillGraphBuilder, SkillGraphValidationError } from './graph/builder.js';
|
|
33
|
+
export type { SkillGraph } from './graph/builder.js';
|
|
34
|
+
export { Session } from './traverse/session.js';
|
|
35
|
+
export type { RegisteredTools, RegisterToolsOptions } from './traverse/session.js';
|
|
36
|
+
export { buildNavigationGraph } from './tree/appmap.js';
|
|
37
|
+
export type { NavigationGraph, NavigationGraphDef, NodePathsOf, MapNode, ModalDef, NodeDef, NodeKind, PageNodeDef, SkillDef2, ToolDef, } from './tree/types.js';
|
|
38
|
+
export { InteractionSession } from './traverse/nav-session.js';
|
|
39
|
+
export type { RegisterToolGroupOptions, ToolGroupHandle, RegisteredToolDef, InteractionSessionOptions, } from './traverse/nav-session.js';
|
|
40
|
+
export type { SessionEventName, SessionEvents, ToolGroup, ToolHandle } from './atom/types.js';
|
|
41
|
+
export { PresenceIndex } from './presence/presence.js';
|
|
42
|
+
export type { PresenceHandle } from './presence/presence.js';
|
|
43
|
+
export { ToolRegistry } from './registry/registry.js';
|
|
44
|
+
export type { Registration, ToolHandler } from './registry/registry.js';
|
|
45
|
+
export { edgesToMCPTools, leaveSkillTool } from './serve/mcp.js';
|
|
46
|
+
export { skillsAsTools } from './serve/modes.js';
|
|
47
|
+
export type { DoActionArgs, ServeResult, SkillCallArgs, SkillToolsOptions, SkillToolsPort, } from './serve/modes.js';
|
|
48
|
+
export type { ActivationLevel, Actuation, Affordance, AffordanceDef, AvailableEdge, AvailableSkill, AvailableSlice, Binding, CanonicalRole, Cause, CommitSkillResult, ContextBrief, ContextBriefOptions, DependencyEdge, Effect, ElementLocator, Explanation, FireOptions, FireResult, FrameStatus, GapReason, GapRecord, ReportGapOptions, Page, PageDef, PendingInfo, Principal, SessionOptions, Settlement, Skill, SkillDef, SkillFrame, SkillGraphSpec, SkillPlan, SkillPlanStep, StepStatus, StimulusKind, SyncResult, TransitionRecord, UpdateOptions, UpdateResult, } from './atom/types.js';
|
|
49
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC9F,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAEnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,OAAO,EACP,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,WAAW,EACX,SAAS,EACT,OAAO,GACR,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EACV,wBAAwB,EACxB,eAAe,EACf,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AAEnC,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EACV,YAAY,EACZ,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,eAAe,EACf,SAAS,EACT,UAAU,EACV,aAAa,EACb,aAAa,EACb,cAAc,EACd,cAAc,EACd,OAAO,EACP,aAAa,EACb,KAAK,EACL,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,MAAM,EACN,cAAc,EACd,WAAW,EACX,WAAW,EACX,UAAU,EACV,WAAW,EACX,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,IAAI,EACJ,OAAO,EACP,WAAW,EACX,SAAS,EACT,cAAc,EACd,UAAU,EACV,KAAK,EACL,QAAQ,EACR,UAAU,EACV,cAAc,EACd,SAAS,EACT,aAAa,EACb,UAAU,EACV,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,YAAY,GACb,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hcifootprint — turn a web app's interaction surface into a typed,
|
|
3
|
+
* traversable skill graph an LLM can plan over.
|
|
4
|
+
*
|
|
5
|
+
* The frontend sibling of footprintjs (backend flowcharts) and agentfootprint
|
|
6
|
+
* (self-explaining agents): one self-explaining trace substrate underneath.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { buildNavigationGraph } from 'hcifootprint';
|
|
10
|
+
*
|
|
11
|
+
* const graph = buildNavigationGraph('shop', {
|
|
12
|
+
* pages: {
|
|
13
|
+
* catalog: {
|
|
14
|
+
* tools: {
|
|
15
|
+
* 'add-to-cart': { does: 'Add the open dress to the cart', when: { authenticated: { eq: true } }, writes: ['cart'] },
|
|
16
|
+
* },
|
|
17
|
+
* },
|
|
18
|
+
* },
|
|
19
|
+
* skills: { purchase: { does: 'Buy a dress end to end', steps: ['add-to-cart'] } },
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* const session = graph.createSession({ node: 'catalog', state: { authenticated: true } });
|
|
23
|
+
* session.available(); // → guard-passing edges = the LLM's action space
|
|
24
|
+
* session.registerToolGroup('catalog', { handlers: { 'add-to-cart': (i) => shop.add(i) } });
|
|
25
|
+
* session.fire('catalog.add-to-cart', { source: 'agent' }); // → settlement: 'awaiting-state'
|
|
26
|
+
* session.updateState({ cart: 1 }); // your store tap settles the pending write
|
|
27
|
+
* session.why('cart'); // footprint backward slice over the session
|
|
28
|
+
*
|
|
29
|
+
* // v1 skillGraph() — the fluent builder — remains as legacy sugar.
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export { skillGraph, SkillGraphBuilder, SkillGraphValidationError } from './graph/builder.js';
|
|
33
|
+
export { Session } from './traverse/session.js';
|
|
34
|
+
// The navigation graph: buildNavigationGraph() authoring, InteractionSession runtime
|
|
35
|
+
export { buildNavigationGraph } from './tree/appmap.js';
|
|
36
|
+
export { InteractionSession } from './traverse/nav-session.js';
|
|
37
|
+
export { PresenceIndex } from './presence/presence.js';
|
|
38
|
+
export { ToolRegistry } from './registry/registry.js';
|
|
39
|
+
export { edgesToMCPTools, leaveSkillTool } from './serve/mcp.js';
|
|
40
|
+
// D18 serving modes — Mode B: skills as fixed tools, disclosure in results
|
|
41
|
+
export { skillsAsTools } from './serve/modes.js';
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAE9F,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,qFAAqF;AACrF,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAaxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAS/D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACjE,2EAA2E;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hcifootprint/mcp — the OPTIONAL Model Context Protocol surface.
|
|
3
|
+
*
|
|
4
|
+
* Import from here (not the main entry) to expose a session as a real MCP
|
|
5
|
+
* server. This subpath is the ONLY place `@modelcontextprotocol/sdk` — an
|
|
6
|
+
* optional peer dependency — is imported, so the core entry stays zero-dep and
|
|
7
|
+
* anyone who does not need MCP never pulls the SDK.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { skillsAsTools } from 'hcifootprint'; // primitive — bind to any framework, zero deps
|
|
11
|
+
* import { mcpServer } from 'hcifootprint/mcp'; // full MCP server — needs the SDK peer dep
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export { mcpServer } from './serve/mcp-server.js';
|
|
15
|
+
export type { McpServerOptions } from './serve/mcp-server.js';
|
|
16
|
+
//# sourceMappingURL=mcp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hcifootprint/mcp — the OPTIONAL Model Context Protocol surface.
|
|
3
|
+
*
|
|
4
|
+
* Import from here (not the main entry) to expose a session as a real MCP
|
|
5
|
+
* server. This subpath is the ONLY place `@modelcontextprotocol/sdk` — an
|
|
6
|
+
* optional peer dependency — is imported, so the core entry stays zero-dep and
|
|
7
|
+
* anyone who does not need MCP never pulls the SDK.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { skillsAsTools } from 'hcifootprint'; // primitive — bind to any framework, zero deps
|
|
11
|
+
* import { mcpServer } from 'hcifootprint/mcp'; // full MCP server — needs the SDK peer dep
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export { mcpServer } from './serve/mcp-server.js';
|
|
15
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PresenceIndex — the pure presence sensor (D18).
|
|
3
|
+
*
|
|
4
|
+
* Registration observes MOUNTED, nothing more. This index is deliberately a
|
|
5
|
+
* plain refcounted data structure that knows nothing about sessions, trees,
|
|
6
|
+
* routers, or footprint — the meaning of presence (dormancy below the router,
|
|
7
|
+
* overlay masking, tab exclusivity, assumed-active defaults) lives one layer
|
|
8
|
+
* up in NavSession, which COMPOSES this with the authored tree.
|
|
9
|
+
*
|
|
10
|
+
* Contract points that make React StrictMode/HMR safe by construction:
|
|
11
|
+
* - Handles are identities: open() returns a token, close(token) is
|
|
12
|
+
* idempotent per token. setup→cleanup→setup nets to one open handle.
|
|
13
|
+
* - Instance handles (repeats containers) are tracked separately and are
|
|
14
|
+
* EXCLUDED from the fingerprint — a scrolling virtualized list must never
|
|
15
|
+
* look like world motion (that scoping rule is enforced here, at the
|
|
16
|
+
* lowest layer that can).
|
|
17
|
+
* - Visibility is an EXPLICIT signal store (set by show()/setVisible()/the
|
|
18
|
+
* `visible:` mount option). No amount of mount-counting can see CSS; when
|
|
19
|
+
* no signal exists the layer above serves honesty markers instead of
|
|
20
|
+
* guessing.
|
|
21
|
+
*/
|
|
22
|
+
export interface PresenceHandle {
|
|
23
|
+
readonly node: string;
|
|
24
|
+
readonly instance?: string;
|
|
25
|
+
/** Idempotent. */
|
|
26
|
+
release(): void;
|
|
27
|
+
}
|
|
28
|
+
export declare class PresenceIndex {
|
|
29
|
+
#private;
|
|
30
|
+
open(node: string, instance?: string): PresenceHandle;
|
|
31
|
+
/** A node is present when at least one NODE handle is open on it. */
|
|
32
|
+
isPresent(node: string): boolean;
|
|
33
|
+
presentNodes(): string[];
|
|
34
|
+
/** Mounted instance keys of a repeats node (the mounted WINDOW, not existence). */
|
|
35
|
+
instancesOf(node: string): string[];
|
|
36
|
+
hasInstance(node: string, instance: string): boolean;
|
|
37
|
+
/** True when ANY node handle is open — the signal that presence is in use at all. */
|
|
38
|
+
hasAnyHandles(): boolean;
|
|
39
|
+
/** True when ANY handle (node OR instance) is open — "the mount layer is in use". */
|
|
40
|
+
hasAny(): boolean;
|
|
41
|
+
setVisible(node: string, visible: boolean): void;
|
|
42
|
+
/** The explicit signal, or undefined when none was ever given (→ honesty markers above). */
|
|
43
|
+
visibility(node: string): boolean | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* The served-structure identity used for coalesced world-motion detection:
|
|
46
|
+
* node presence + visibility signals. Instance churn is EXCLUDED by design.
|
|
47
|
+
*/
|
|
48
|
+
fingerprint(): string;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=presence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../../src/presence/presence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB;IAClB,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,qBAAa,aAAa;;IAWxB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,cAAc;IA8CrD,qEAAqE;IACrE,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIhC,YAAY,IAAI,MAAM,EAAE;IAIxB,mFAAmF;IACnF,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAInC,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIpD,qFAAqF;IACrF,aAAa,IAAI,OAAO;IAIxB,qFAAqF;IACrF,MAAM,IAAI,OAAO;IAIjB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAIhD,4FAA4F;IAC5F,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAI7C;;;OAGG;IACH,WAAW,IAAI,MAAM;CAQtB"}
|