@shrkcrft/context 0.1.0-alpha.2 → 0.1.0-alpha.21

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.
@@ -1 +1 @@
1
- {"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../src/context-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAA2B,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG1D,OAAO,EAAE,qBAAqB,EAAqB,MAAM,2BAA2B,CAAC;AASrF,wBAAgB,YAAY,CAC1B,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,OAAO,EAAE,eAAe,GACvB,cAAc,CAiGhB;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
1
+ {"version":3,"file":"context-builder.d.ts","sourceRoot":"","sources":["../src/context-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAA2B,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG1D,OAAO,EAAE,qBAAqB,EAAqB,MAAM,2BAA2B,CAAC;AAcrF,wBAAgB,YAAY,CAC1B,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,OAAO,EAAE,eAAe,GACvB,cAAc,CA4GhB;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
@@ -38,6 +38,18 @@ export function buildContext(allEntries, request) {
38
38
  if (r.includeDocs) {
39
39
  sectionPlans.push({ title: 'Reference Docs', priority: 10, entries: buckets.docs });
40
40
  }
41
+ // Agent Actions: aggregate action hints (recommended MCP tools / CLI commands
42
+ // / forbidden actions / verification commands / human-review points) from
43
+ // every included entry into ONE composite section. Register it in the SAME
44
+ // priority-sorted pipeline with a HIGH priority so it survives budget pruning
45
+ // — it is the most agent-actionable section and was previously appended after
46
+ // the loop with leftover budget, so it was the first thing dropped.
47
+ const allIncludedEntries = sectionPlans.flatMap((p) => p.entries);
48
+ const aggregated = aggregateActionHints(allIncludedEntries);
49
+ const hintsBody = formatAggregatedHints(aggregated, { level: '###', compact: true });
50
+ if (hintsBody && hintsBody.length > 0) {
51
+ sectionPlans.push({ title: 'Agent Actions', priority: 92, entries: [], body: hintsBody });
52
+ }
41
53
  sectionPlans.sort((a, b) => b.priority - a.priority);
42
54
  const sections = [];
43
55
  const omitted = [];
@@ -65,6 +77,13 @@ export function buildContext(allEntries, request) {
65
77
  tryAddSection('Project Overview', r.projectOverview.trim(), []);
66
78
  continue;
67
79
  }
80
+ // Composite section with a precomputed body (e.g. Agent Actions) — added in
81
+ // priority order with its contributing-entry ids.
82
+ if (plan.body !== undefined) {
83
+ if (plan.body.length > 0)
84
+ tryAddSection(plan.title, plan.body, aggregated.contributingEntries);
85
+ continue;
86
+ }
68
87
  if (plan.entries.length === 0)
69
88
  continue;
70
89
  const body = formatSectionBody(plan.entries, {
@@ -74,14 +93,6 @@ export function buildContext(allEntries, request) {
74
93
  const ids = plan.entries.map((e) => e.id);
75
94
  tryAddSection(plan.title, body, ids);
76
95
  }
77
- // Action hints: aggregate from every included entry and emit a single
78
- // composite "Agent Actions" section. Skipped when no entry contributes.
79
- const allIncludedEntries = sectionPlans.flatMap((p) => p.entries);
80
- const aggregated = aggregateActionHints(allIncludedEntries);
81
- const hintsBody = formatAggregatedHints(aggregated, { level: '###', compact: true });
82
- if (hintsBody && hintsBody.length > 0) {
83
- tryAddSection('Agent Actions', hintsBody, aggregated.contributingEntries);
84
- }
85
96
  const fullBody = sections
86
97
  .map((s) => `## ${s.title}${s.truncated ? ' (truncated)' : ''}\n\n${s.body}`)
87
98
  .join('\n\n');
@@ -92,6 +103,7 @@ export function buildContext(allEntries, request) {
92
103
  maxTokens,
93
104
  omittedSections: omitted,
94
105
  body: fullBody,
106
+ actionHints: aggregated,
95
107
  };
96
108
  }
97
109
  export { formatEntryForContext };
@@ -1,3 +1,4 @@
1
+ import type { IAggregatedActionHints } from '@shrkcrft/knowledge';
1
2
  import type { IContextSection } from './context-section.js';
2
3
  import type { IContextRequest } from './context-request.js';
3
4
  export interface IContextResult {
@@ -8,5 +9,13 @@ export interface IContextResult {
8
9
  omittedSections: readonly string[];
9
10
  /** Combined render of all sections (in order). */
10
11
  body: string;
12
+ /**
13
+ * Aggregated action hints from every included entry — the same structured
14
+ * bundle `shrk task` exposes (preferredFlow / forbiddenActions /
15
+ * verificationCommands / writePolicy / …). Also rendered into `body` as the
16
+ * "Agent Actions" section, but exposed here so JSON consumers don't have to
17
+ * parse markdown to recover it.
18
+ */
19
+ actionHints: IAggregatedActionHints;
11
20
  }
12
21
  //# sourceMappingURL=context-result.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-result.d.ts","sourceRoot":"","sources":["../src/context-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;CACd"}
1
+ {"version":3,"file":"context-result.d.ts","sourceRoot":"","sources":["../src/context-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,eAAe,CAAC;IACzB,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,WAAW,EAAE,sBAAsB,CAAC;CACrC"}
@@ -0,0 +1,2 @@
1
+ export declare function deriveAppliesWhen(task: string): string[];
2
+ //# sourceMappingURL=derive-applies-when.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive-applies-when.d.ts","sourceRoot":"","sources":["../src/derive-applies-when.ts"],"names":[],"mappings":"AAqCA,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAWxD"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Derive `appliesWhen` tokens from a free-text task string.
3
+ *
4
+ * `shrk context` ranks knowledge entries via a lexical scorer. Foundational
5
+ * rules (e.g. `architecture.layer-order`) declare an `appliesWhen` like
6
+ * `generate-code` but share no surface tokens with a task such as "add a new
7
+ * plugin command" — so without a derived `appliesWhen` signal they earn no
8
+ * match reason and are dropped before priority is even considered.
9
+ *
10
+ * This maps task verbs/domains to the same canonical `appliesWhen` vocabulary
11
+ * the inspector task-ranker uses, so the rule that *governs* the work surfaces
12
+ * even when the wording doesn't overlap. Deterministic; no model in the loop.
13
+ *
14
+ * NOTE: the verb/domain vocabulary mirrors
15
+ * `packages/inspector/src/task-ranker.ts`. The context layer cannot import the
16
+ * higher inspector layer, so the small map is duplicated here on purpose — keep
17
+ * the two in sync if either grows.
18
+ */
19
+ const VERB_APPLIES_WHEN = [
20
+ {
21
+ regex: /\b(create|add|implement|generate|new|build|introduce|provide)\b/,
22
+ appliesWhen: ['generate-code', 'generate-service', 'generate-utility', 'generate-template', 'create-feature'],
23
+ },
24
+ { regex: /\b(refactor|rewrite|migrate|extract|rename)\b/, appliesWhen: ['refactor'] },
25
+ { regex: /\b(test|spec|coverage)\b/, appliesWhen: ['generate-test'] },
26
+ { regex: /\b(fix|bug|broken|crash)\b/, appliesWhen: ['fix-bug'] },
27
+ { regex: /\b(review|audit|inspect)\b/, appliesWhen: ['review-pr', 'review-code', 'check-boundaries'] },
28
+ ];
29
+ const DOMAIN_APPLIES_WHEN = [
30
+ { token: 'service', appliesWhen: ['generate-service'] },
31
+ { token: 'utility', appliesWhen: ['generate-utility'] },
32
+ { token: 'utilities', appliesWhen: ['generate-utility'] },
33
+ { token: 'pipeline', appliesWhen: ['create-pipeline'] },
34
+ { token: 'route', appliesWhen: ['generate-route'] },
35
+ ];
36
+ export function deriveAppliesWhen(task) {
37
+ const text = task.toLowerCase();
38
+ const out = new Set();
39
+ for (const v of VERB_APPLIES_WHEN) {
40
+ if (v.regex.test(text))
41
+ for (const a of v.appliesWhen)
42
+ out.add(a);
43
+ }
44
+ const tokens = new Set(text.split(/[^a-z0-9]+/).filter((t) => t.length >= 3));
45
+ for (const d of DOMAIN_APPLIES_WHEN) {
46
+ if (tokens.has(d.token))
47
+ for (const a of d.appliesWhen)
48
+ out.add(a);
49
+ }
50
+ return [...out].sort();
51
+ }
package/dist/index.d.ts CHANGED
@@ -4,5 +4,6 @@ export * from './context-section.js';
4
4
  export * from './context-builder.js';
5
5
  export * from './token-estimator.js';
6
6
  export * from './relevance-selector.js';
7
+ export * from './derive-applies-when.js';
7
8
  export * from './ai-context-formatter.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -4,4 +4,5 @@ export * from "./context-section.js";
4
4
  export * from "./context-builder.js";
5
5
  export * from "./token-estimator.js";
6
6
  export * from "./relevance-selector.js";
7
+ export * from "./derive-applies-when.js";
7
8
  export * from "./ai-context-formatter.js";
@@ -1 +1 @@
1
- {"version":3,"file":"relevance-selector.d.ts","sourceRoot":"","sources":["../src/relevance-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,YAAY,EAAE,eAAe,EAAE,CAAC;IAChC,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAeD,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,OAAO,EAAE,eAAe,EACxB,eAAe,SAAI,GAClB,eAAe,CAuCjB"}
1
+ {"version":3,"file":"relevance-selector.d.ts","sourceRoot":"","sources":["../src/relevance-selector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,YAAY,EAAE,eAAe,EAAE,CAAC;IAChC,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAeD,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,OAAO,EAAE,eAAe,EACxB,eAAe,SAAI,GAClB,eAAe,CAgDjB"}
@@ -1,4 +1,5 @@
1
1
  import { KnowledgeIndex } from '@shrkcrft/knowledge';
2
+ import { deriveAppliesWhen } from "./derive-applies-when.js";
2
3
  const TYPE_BUCKETS = {
3
4
  rule: 'rules',
4
5
  path: 'paths',
@@ -19,11 +20,19 @@ export function selectRelevantEntries(allEntries, request, limitPerSection = 5)
19
20
  scope.push(request.framework);
20
21
  if (request.area)
21
22
  scope.push(request.area);
23
+ // Merge any explicit appliesWhen with tokens derived from the task verbs /
24
+ // domain so foundational rules that key on `appliesWhen` (e.g.
25
+ // architecture.layer-order on 'generate-code') earn a match reason for a task
26
+ // whose wording doesn't overlap the rule. Without this they score 0 reasons
27
+ // and are dropped before priority matters.
28
+ const appliesWhen = [
29
+ ...new Set([...(request.appliesWhen ?? []), ...deriveAppliesWhen(request.task)]),
30
+ ];
22
31
  const searchAll = index.search({
23
32
  query: request.task,
24
33
  scope,
25
34
  tags,
26
- appliesWhen: request.appliesWhen,
35
+ appliesWhen,
27
36
  });
28
37
  const buckets = {
29
38
  rules: [],
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@shrkcrft/context",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "0.1.0-alpha.21",
4
4
  "description": "SharkCraft AI context builder: token-budgeted relevance retrieval for tasks.",
5
5
  "license": "MIT",
6
6
  "author": "SharkCraft contributors",
7
7
  "type": "module",
8
8
  "main": "./dist/index.js",
9
- "types": "./dist/index.d.d.ts",
9
+ "types": "./dist/index.d.ts",
10
10
  "exports": {
11
11
  ".": {
12
12
  "types": "./dist/index.d.ts",
@@ -44,11 +44,11 @@
44
44
  "typecheck": "tsc --noEmit -p tsconfig.json"
45
45
  },
46
46
  "dependencies": {
47
- "@shrkcrft/core": "^0.1.0-alpha.2",
48
- "@shrkcrft/knowledge": "^0.1.0-alpha.2",
49
- "@shrkcrft/rules": "^0.1.0-alpha.2",
50
- "@shrkcrft/paths": "^0.1.0-alpha.2",
51
- "@shrkcrft/templates": "^0.1.0-alpha.2"
47
+ "@shrkcrft/core": "^0.1.0-alpha.21",
48
+ "@shrkcrft/knowledge": "^0.1.0-alpha.21",
49
+ "@shrkcrft/rules": "^0.1.0-alpha.21",
50
+ "@shrkcrft/paths": "^0.1.0-alpha.21",
51
+ "@shrkcrft/templates": "^0.1.0-alpha.21"
52
52
  },
53
53
  "publishConfig": {
54
54
  "access": "public"