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.
Files changed (87) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +524 -0
  3. package/dist/atom/types.d.ts +618 -0
  4. package/dist/atom/types.d.ts.map +1 -0
  5. package/dist/atom/types.js +2 -0
  6. package/dist/atom/types.js.map +1 -0
  7. package/dist/graph/builder.d.ts +31 -0
  8. package/dist/graph/builder.d.ts.map +1 -0
  9. package/dist/graph/builder.js +165 -0
  10. package/dist/graph/builder.js.map +1 -0
  11. package/dist/graph/guards.d.ts +31 -0
  12. package/dist/graph/guards.d.ts.map +1 -0
  13. package/dist/graph/guards.js +94 -0
  14. package/dist/graph/guards.js.map +1 -0
  15. package/dist/graph/skill-deps.d.ts +20 -0
  16. package/dist/graph/skill-deps.d.ts.map +1 -0
  17. package/dist/graph/skill-deps.js +15 -0
  18. package/dist/graph/skill-deps.js.map +1 -0
  19. package/dist/index.d.ts +49 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +42 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/mcp.d.ts +16 -0
  24. package/dist/mcp.d.ts.map +1 -0
  25. package/dist/mcp.js +15 -0
  26. package/dist/mcp.js.map +1 -0
  27. package/dist/presence/presence.d.ts +50 -0
  28. package/dist/presence/presence.d.ts.map +1 -0
  29. package/dist/presence/presence.js +126 -0
  30. package/dist/presence/presence.js.map +1 -0
  31. package/dist/registry/registry.d.ts +53 -0
  32. package/dist/registry/registry.d.ts.map +1 -0
  33. package/dist/registry/registry.js +76 -0
  34. package/dist/registry/registry.js.map +1 -0
  35. package/dist/serve/mcp-server.d.ts +40 -0
  36. package/dist/serve/mcp-server.d.ts.map +1 -0
  37. package/dist/serve/mcp-server.js +72 -0
  38. package/dist/serve/mcp-server.js.map +1 -0
  39. package/dist/serve/mcp.d.ts +12 -0
  40. package/dist/serve/mcp.d.ts.map +1 -0
  41. package/dist/serve/mcp.js +62 -0
  42. package/dist/serve/mcp.js.map +1 -0
  43. package/dist/serve/modes.d.ts +66 -0
  44. package/dist/serve/modes.d.ts.map +1 -0
  45. package/dist/serve/modes.js +347 -0
  46. package/dist/serve/modes.js.map +1 -0
  47. package/dist/testing/harness.d.ts +156 -0
  48. package/dist/testing/harness.d.ts.map +1 -0
  49. package/dist/testing/harness.js +416 -0
  50. package/dist/testing/harness.js.map +1 -0
  51. package/dist/testing/index.d.ts +35 -0
  52. package/dist/testing/index.d.ts.map +1 -0
  53. package/dist/testing/index.js +32 -0
  54. package/dist/testing/index.js.map +1 -0
  55. package/dist/testing/lint.d.ts +20 -0
  56. package/dist/testing/lint.d.ts.map +1 -0
  57. package/dist/testing/lint.js +18 -0
  58. package/dist/testing/lint.js.map +1 -0
  59. package/dist/testing/model/check.d.ts +30 -0
  60. package/dist/testing/model/check.d.ts.map +1 -0
  61. package/dist/testing/model/check.js +89 -0
  62. package/dist/testing/model/check.js.map +1 -0
  63. package/dist/testing/model/lint.d.ts +54 -0
  64. package/dist/testing/model/lint.d.ts.map +1 -0
  65. package/dist/testing/model/lint.js +235 -0
  66. package/dist/testing/model/lint.js.map +1 -0
  67. package/dist/testing/model/satisfiable.d.ts +25 -0
  68. package/dist/testing/model/satisfiable.d.ts.map +1 -0
  69. package/dist/testing/model/satisfiable.js +101 -0
  70. package/dist/testing/model/satisfiable.js.map +1 -0
  71. package/dist/traverse/nav-session.d.ts +108 -0
  72. package/dist/traverse/nav-session.d.ts.map +1 -0
  73. package/dist/traverse/nav-session.js +637 -0
  74. package/dist/traverse/nav-session.js.map +1 -0
  75. package/dist/traverse/session.d.ts +239 -0
  76. package/dist/traverse/session.d.ts.map +1 -0
  77. package/dist/traverse/session.js +1305 -0
  78. package/dist/traverse/session.js.map +1 -0
  79. package/dist/tree/appmap.d.ts +8 -0
  80. package/dist/tree/appmap.d.ts.map +1 -0
  81. package/dist/tree/appmap.js +259 -0
  82. package/dist/tree/appmap.js.map +1 -0
  83. package/dist/tree/types.d.ts +151 -0
  84. package/dist/tree/types.d.ts.map +1 -0
  85. package/dist/tree/types.js +2 -0
  86. package/dist/tree/types.js.map +1 -0
  87. 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":"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"}
@@ -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"}
@@ -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
@@ -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"}