@gramatr/mcp 0.7.10 → 0.7.13

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 (99) hide show
  1. package/dist/__mocks__/bun-sqlite.d.ts +35 -0
  2. package/dist/__mocks__/bun-sqlite.d.ts.map +1 -0
  3. package/dist/__mocks__/bun-sqlite.js +89 -0
  4. package/dist/__mocks__/bun-sqlite.js.map +1 -0
  5. package/dist/bin/build-mcpb.d.ts +2 -5
  6. package/dist/bin/build-mcpb.d.ts.map +1 -1
  7. package/dist/bin/build-mcpb.js +20 -43
  8. package/dist/bin/build-mcpb.js.map +1 -1
  9. package/dist/bin/gramatr-mcp.d.ts +10 -2
  10. package/dist/bin/gramatr-mcp.d.ts.map +1 -1
  11. package/dist/bin/gramatr-mcp.js +73 -15
  12. package/dist/bin/gramatr-mcp.js.map +1 -1
  13. package/dist/bin/login.d.ts.map +1 -1
  14. package/dist/bin/login.js +5 -0
  15. package/dist/bin/login.js.map +1 -1
  16. package/dist/bin/setup.d.ts +12 -10
  17. package/dist/bin/setup.d.ts.map +1 -1
  18. package/dist/bin/setup.js +56 -40
  19. package/dist/bin/setup.js.map +1 -1
  20. package/dist/cache/lru-cache.js +1 -1
  21. package/dist/config-runtime.d.ts +13 -0
  22. package/dist/config-runtime.d.ts.map +1 -1
  23. package/dist/config-runtime.js +24 -0
  24. package/dist/config-runtime.js.map +1 -1
  25. package/dist/gramatr +0 -0
  26. package/dist/hooks/input-validator.d.ts.map +1 -1
  27. package/dist/hooks/input-validator.js +27 -9
  28. package/dist/hooks/input-validator.js.map +1 -1
  29. package/dist/hooks/lib/client-runtime.d.ts +7 -0
  30. package/dist/hooks/lib/client-runtime.d.ts.map +1 -0
  31. package/dist/hooks/lib/client-runtime.js +22 -0
  32. package/dist/hooks/lib/client-runtime.js.map +1 -0
  33. package/dist/hooks/lib/hook-state.d.ts +7 -2
  34. package/dist/hooks/lib/hook-state.d.ts.map +1 -1
  35. package/dist/hooks/lib/hook-state.js +56 -35
  36. package/dist/hooks/lib/hook-state.js.map +1 -1
  37. package/dist/hooks/lib/intelligence.d.ts.map +1 -1
  38. package/dist/hooks/lib/intelligence.js +229 -427
  39. package/dist/hooks/lib/intelligence.js.map +1 -1
  40. package/dist/hooks/lib/routing.d.ts +6 -1
  41. package/dist/hooks/lib/routing.d.ts.map +1 -1
  42. package/dist/hooks/lib/routing.js +35 -11
  43. package/dist/hooks/lib/routing.js.map +1 -1
  44. package/dist/hooks/lib/session.d.ts.map +1 -1
  45. package/dist/hooks/lib/session.js +3 -4
  46. package/dist/hooks/lib/session.js.map +1 -1
  47. package/dist/hooks/lib/tool-envelope.d.ts +9 -0
  48. package/dist/hooks/lib/tool-envelope.d.ts.map +1 -0
  49. package/dist/hooks/lib/tool-envelope.js +24 -0
  50. package/dist/hooks/lib/tool-envelope.js.map +1 -0
  51. package/dist/hooks/lib/types.d.ts +7 -0
  52. package/dist/hooks/lib/types.d.ts.map +1 -1
  53. package/dist/hooks/lib/version.d.ts.map +1 -1
  54. package/dist/hooks/lib/version.js +3 -0
  55. package/dist/hooks/lib/version.js.map +1 -1
  56. package/dist/hooks/rating-capture.d.ts.map +1 -1
  57. package/dist/hooks/rating-capture.js +7 -2
  58. package/dist/hooks/rating-capture.js.map +1 -1
  59. package/dist/hooks/session-end.d.ts.map +1 -1
  60. package/dist/hooks/session-end.js +8 -6
  61. package/dist/hooks/session-end.js.map +1 -1
  62. package/dist/hooks/session-start.d.ts.map +1 -1
  63. package/dist/hooks/session-start.js +39 -13
  64. package/dist/hooks/session-start.js.map +1 -1
  65. package/dist/hooks/stop.d.ts.map +1 -1
  66. package/dist/hooks/stop.js +18 -6
  67. package/dist/hooks/stop.js.map +1 -1
  68. package/dist/hooks/user-prompt-submit.d.ts.map +1 -1
  69. package/dist/hooks/user-prompt-submit.js +24 -11
  70. package/dist/hooks/user-prompt-submit.js.map +1 -1
  71. package/dist/intelligence/packet2-fetcher.d.ts +2 -2
  72. package/dist/intelligence/packet2-fetcher.d.ts.map +1 -1
  73. package/dist/intelligence/packet2-fetcher.js +24 -5
  74. package/dist/intelligence/packet2-fetcher.js.map +1 -1
  75. package/dist/intelligence/session-manager.d.ts.map +1 -1
  76. package/dist/intelligence/session-manager.js +25 -1
  77. package/dist/intelligence/session-manager.js.map +1 -1
  78. package/dist/proxy/tool-proxy.d.ts.map +1 -1
  79. package/dist/proxy/tool-proxy.js +57 -11
  80. package/dist/proxy/tool-proxy.js.map +1 -1
  81. package/dist/server/server.d.ts.map +1 -1
  82. package/dist/server/server.js +8 -9
  83. package/dist/server/server.js.map +1 -1
  84. package/dist/setup/instructions.d.ts +2 -2
  85. package/dist/setup/instructions.d.ts.map +1 -1
  86. package/dist/setup/instructions.js +33 -11
  87. package/dist/setup/instructions.js.map +1 -1
  88. package/dist/setup/integrations.d.ts +1 -1
  89. package/dist/setup/integrations.d.ts.map +1 -1
  90. package/dist/setup/integrations.js +7 -4
  91. package/dist/setup/integrations.js.map +1 -1
  92. package/dist/setup/targets.d.ts +1 -1
  93. package/dist/setup/targets.d.ts.map +1 -1
  94. package/dist/setup/targets.js +2 -3
  95. package/dist/setup/targets.js.map +1 -1
  96. package/dist/setup/web-connector.d.ts.map +1 -1
  97. package/dist/setup/web-connector.js +3 -1
  98. package/dist/setup/web-connector.js.map +1 -1
  99. package/package.json +10 -7
@@ -1,43 +1,65 @@
1
+ function toAgentHint(agent) {
2
+ if (!agent || typeof agent !== 'object')
3
+ return null;
4
+ const a = agent;
5
+ const displayName = typeof a.display_name === 'string'
6
+ ? a.display_name
7
+ : typeof a.displayName === 'string'
8
+ ? a.displayName
9
+ : null;
10
+ const model = typeof a.model === 'string'
11
+ ? a.model
12
+ : typeof a.model_preference === 'string'
13
+ ? a.model_preference
14
+ : null;
15
+ return {
16
+ name: typeof a.name === 'string' ? a.name : null,
17
+ display_name: displayName,
18
+ model,
19
+ reason: typeof a.reason === 'string' ? a.reason : null,
20
+ };
21
+ }
22
+ function hasAgentIdentity(hint) {
23
+ return !!hint && !!(hint.name || hint.display_name || hint.model || hint.reason);
24
+ }
25
+ function toRecommendationMeta(value) {
26
+ if (!value || typeof value !== 'object')
27
+ return null;
28
+ const r = value;
29
+ return {
30
+ type: typeof r.type === 'string' ? r.type : null,
31
+ source: typeof r.source === 'string' ? r.source : null,
32
+ confidence: typeof r.confidence === 'number' ? r.confidence : null,
33
+ };
34
+ }
35
+ function renderContractBlock(payload) {
36
+ return ['```json', JSON.stringify(payload, null, 2), '```'].join('\n');
37
+ }
38
+ function cloneContractPayload(payload) {
39
+ return JSON.parse(JSON.stringify(payload));
40
+ }
1
41
  export function formatFailureWarning(failure) {
2
- const lines = [];
3
- lines.push('⚠️ [gramatr intelligence — failed]');
4
- lines.push('');
5
- switch (failure.reason) {
6
- case 'auth':
7
- lines.push('🔒 AUTHENTICATION FAILURE — gramatr decision router cannot authenticate.');
8
- lines.push(`Detail: ${failure.detail}`);
9
- lines.push('');
10
- lines.push('FIX: Set GRAMATR_TOKEN in your environment (AIOS_MCP_TOKEN remains a legacy alias)');
11
- lines.push('Without this, NO pre-classification happens. The Algorithm runs without intelligence.');
12
- break;
13
- case 'timeout':
14
- lines.push('⏱️ TIMEOUT — gramatr decision router did not respond in time.');
15
- lines.push(`Detail: ${failure.detail}`);
16
- lines.push('');
17
- lines.push('The classifier may be overloaded or the server may be slow.');
18
- break;
19
- case 'server_down':
20
- lines.push('🔴 SERVER UNREACHABLE cannot connect to gramatr server.');
21
- lines.push(`Detail: ${failure.detail}`);
22
- lines.push('');
23
- lines.push('Check: Is the server running? Is the URL correct? Is there a network issue?');
24
- break;
25
- case 'server_error':
26
- lines.push('💥 SERVER ERROR — gramatr server returned an error.');
27
- lines.push(`Detail: ${failure.detail}`);
28
- break;
29
- case 'parse_error':
30
- lines.push('🔧 PARSE ERROR — could not understand the server response.');
31
- lines.push(`Detail: ${failure.detail}`);
32
- break;
33
- default:
34
- lines.push('❓ UNKNOWN ERROR — gramatr enrichment failed.');
35
- lines.push(`Detail: ${failure.detail}`);
36
- }
37
- lines.push('');
38
- lines.push('IMPORTANT: Tell the user about this error. Do not silently proceed without intelligence.');
39
- lines.push('You should still follow the Algorithm from CLAUDE.md, but note that pre-classification is unavailable.');
40
- return lines.join('\n');
42
+ const titleMap = {
43
+ auth: 'AUTHENTICATION FAILURE',
44
+ timeout: 'TIMEOUT',
45
+ server_down: 'SERVER UNREACHABLE',
46
+ server_error: 'SERVER ERROR',
47
+ parse_error: 'PARSE ERROR',
48
+ unknown: 'UNKNOWN ERROR',
49
+ };
50
+ return renderContractBlock({
51
+ schema: 'gmtr.intelligence.error.v1',
52
+ error: {
53
+ reason: failure.reason,
54
+ title: titleMap[failure.reason],
55
+ detail: failure.detail,
56
+ },
57
+ required_actions: [
58
+ 'Tell the user intelligence pre-classification failed.',
59
+ 'Do not pretend intelligence packet delivery succeeded.',
60
+ 'Continue with degraded flow only after surfacing the failure.',
61
+ ],
62
+ });
41
63
  }
42
64
  export function mergeEnrichmentIntoRoute(route, enrichment) {
43
65
  const packet2 = enrichment?.packet_2 || enrichment;
@@ -63,400 +85,180 @@ function normalizeClassifierHeadScores(value) {
63
85
  return [];
64
86
  return Array.isArray(value) ? value : [value];
65
87
  }
88
+ function normalizeMatchedSkillNames(packet1, classification) {
89
+ const fromClassification = Array.isArray(classification.matched_skills)
90
+ ? classification.matched_skills.filter((skill) => typeof skill === 'string')
91
+ : [];
92
+ if (fromClassification.length > 0)
93
+ return fromClassification;
94
+ const matched = packet1.skills?.routing?.matched_skills || [];
95
+ return matched
96
+ .map((skill) => skill.name || skill.id)
97
+ .filter((name) => typeof name === 'string');
98
+ }
99
+ function normalizeRoutingSignals(value) {
100
+ if (!value || typeof value !== 'object')
101
+ return null;
102
+ const raw = value;
103
+ const { bert_entity_scope, bert_entity_category, bert_entity_type_suggestion, classifier_entity_scope, classifier_entity_category, classifier_entity_type_suggestion, ...rest } = raw;
104
+ return {
105
+ ...rest,
106
+ classifier_entity_scope: classifier_entity_scope ?? bert_entity_scope ?? null,
107
+ classifier_entity_category: classifier_entity_category ?? bert_entity_category ?? null,
108
+ classifier_entity_type_suggestion: classifier_entity_type_suggestion ?? bert_entity_type_suggestion ?? null,
109
+ };
110
+ }
111
+ function normalizeClassifierSignals(classifierHeads, routingSignals) {
112
+ const normalizedHeads = classifierHeads
113
+ ? Object.fromEntries(Object.entries(classifierHeads).map(([head, value]) => [
114
+ head,
115
+ normalizeClassifierHeadScores(value),
116
+ ]))
117
+ : null;
118
+ const entityClassification = {
119
+ scope: routingSignals?.classifier_entity_scope ?? null,
120
+ category: routingSignals?.classifier_entity_category ?? null,
121
+ type_suggestion: routingSignals?.classifier_entity_type_suggestion ?? null,
122
+ };
123
+ if (!normalizedHeads && !entityClassification.scope && !entityClassification.category && !entityClassification.type_suggestion) {
124
+ return null;
125
+ }
126
+ return {
127
+ heads: normalizedHeads,
128
+ entity_classification: entityClassification,
129
+ };
130
+ }
131
+ function buildRequiredActions(packet2Status, enrichmentId) {
132
+ return packet2Status === 'required' && enrichmentId
133
+ ? [`Call gramatr_get_packet_two with enrichment_id="${enrichmentId}" before proceeding.`]
134
+ : [];
135
+ }
136
+ function normalizeFullContractPayload(data) {
137
+ const payload = cloneContractPayload(data);
138
+ const packet1 = (payload.packet_1 || {});
139
+ const manifest = (packet1.manifest || {});
140
+ const unifiedPacket = (payload.unified_packet || null);
141
+ const packet2 = (payload.packet_2 || {});
142
+ const packet2Status = manifest.packet_2_status
143
+ || packet2.status
144
+ || payload.packet_2_status
145
+ || 'not_applicable';
146
+ const enrichmentId = manifest.enrichment_id
147
+ || packet2.enrichment_id
148
+ || payload.enrichment_id
149
+ || null;
150
+ const packet1RoutingSignals = normalizeRoutingSignals(packet1.routing_signals);
151
+ if (packet1RoutingSignals) {
152
+ packet1.routing_signals = packet1RoutingSignals;
153
+ }
154
+ const packet1ClassifierHeads = packet1.classifier_heads;
155
+ const packet1ClassifierSignals = normalizeClassifierSignals(packet1ClassifierHeads, packet1RoutingSignals);
156
+ if (packet1ClassifierSignals) {
157
+ packet1.classifier_signals = packet1ClassifierSignals;
158
+ }
159
+ if (unifiedPacket) {
160
+ const unifiedRoutingSignals = normalizeRoutingSignals(unifiedPacket.routing_signals);
161
+ if (unifiedRoutingSignals) {
162
+ unifiedPacket.routing_signals = unifiedRoutingSignals;
163
+ }
164
+ const unifiedClassifierSignals = normalizeClassifierSignals(packet1ClassifierHeads, unifiedRoutingSignals);
165
+ if (unifiedClassifierSignals) {
166
+ unifiedPacket.classifier_signals = unifiedClassifierSignals;
167
+ }
168
+ }
169
+ if (Object.keys(packet2).length > 0) {
170
+ packet2.fetch_tool = packet2.fetch_tool || 'gramatr_get_packet_two';
171
+ packet2.required = packet2.required ?? (packet2Status === 'required');
172
+ packet2.enrichment_id = packet2.enrichment_id ?? enrichmentId;
173
+ }
174
+ payload.required_actions = buildRequiredActions(packet2Status, enrichmentId);
175
+ return payload;
176
+ }
66
177
  export function formatIntelligence(data, enrichment) {
178
+ if (data.schema === 'gmtr.intelligence.unified.v1' || data.contract_shape === 'full' || data.unified_packet) {
179
+ return renderContractBlock(normalizeFullContractPayload(data));
180
+ }
67
181
  const packet1 = data.packet_1 || {};
68
182
  const manifest = packet1.manifest;
69
- const packet1Contents = manifest?.contents || data.packet_1_contents;
70
- const packet2Contents = manifest?.packet_2_contents || data.packet_2_contents;
71
- const packet2Status = manifest?.packet_2_status || data.packet_2_status;
72
- const enrichmentId = manifest?.enrichment_id ?? data.enrichment_id;
183
+ const packet2Status = manifest?.packet_2_status || data.packet_2_status || 'not_applicable';
184
+ const enrichmentId = manifest?.enrichment_id ?? data.enrichment_id ?? null;
73
185
  const c = packet1.classification || data.classification || {};
74
- const ts = packet1.token_savings || data.token_savings || {};
75
186
  const es = packet1.execution_summary || data.execution_summary || {};
76
- const lines = [];
77
- lines.push(`[gramatr intelligence pre-classified by ${es.classifier_model || 'gramatr'}]`);
78
- const ps = packet1.project_state || data.project_state;
79
- if (ps && ps.project_id) {
80
- lines.push('');
81
- lines.push('ACTIVE PROJECT STATE:');
82
- if (ps.active_prd_title) {
83
- lines.push(` PRD: ${ps.active_prd_title}${ps.active_prd_id ? ` (${ps.active_prd_id})` : ''}`);
84
- }
85
- if (ps.current_phase) {
86
- lines.push(` Phase: ${ps.current_phase}`);
87
- }
88
- if (ps.isc_summary && ps.isc_summary.total && ps.isc_summary.total > 0) {
89
- const s = ps.isc_summary;
90
- lines.push(` ISC: ${s.passing || 0}/${s.total} passing, ${s.failing || 0} failing, ${s.pending || 0} pending`);
91
- }
92
- if (ps.session_history_summary) {
93
- lines.push(` Last session: "${ps.session_history_summary}"`);
94
- }
95
- if (ps.current_phase && ps.current_phase !== 'OBSERVE') {
96
- lines.push(` ⚠️ RESUME from ${ps.current_phase} phase — do NOT restart OBSERVE`);
97
- }
98
- lines.push('');
99
- }
100
- const meta = [];
101
- if (c.effort_level)
102
- meta.push(`Effort: ${c.effort_level}`);
103
- if (c.intent_type)
104
- meta.push(`Intent: ${c.intent_type}`);
105
- if (c.confidence)
106
- meta.push(`Confidence: ${Math.round(c.confidence * 100)}%`);
107
- if (c.memory_scope)
108
- meta.push(`Scope: ${c.memory_scope}`);
109
- if (meta.length)
110
- lines.push(meta.join(' | '));
111
- if (c.matched_skills?.length) {
112
- lines.push(`Matched skills: ${c.matched_skills.join(', ')}`);
113
- }
114
- const re = c.reverse_engineering;
115
- if (re) {
116
- if (re.explicit_wants?.length) {
117
- lines.push('What user explicitly wants:');
118
- for (const w of re.explicit_wants)
119
- lines.push(` - ${w}`);
120
- }
121
- if (re.implicit_wants?.length) {
122
- lines.push('What is implied but not stated:');
123
- for (const w of re.implicit_wants)
124
- lines.push(` - ${w}`);
125
- }
126
- if (re.explicit_dont_wants?.length) {
127
- lines.push('What user explicitly does NOT want:');
128
- for (const w of re.explicit_dont_wants)
129
- lines.push(` - ${w}`);
130
- }
131
- if (re.implicit_dont_wants?.length) {
132
- lines.push('What user would clearly NOT want:');
133
- for (const w of re.implicit_dont_wants)
134
- lines.push(` - ${w}`);
135
- }
136
- if (re.gotchas?.length) {
137
- lines.push('Gotchas and edge cases:');
138
- for (const g of re.gotchas)
139
- lines.push(` - ${g}`);
140
- }
141
- }
142
- if (c.suggested_capabilities?.length) {
143
- lines.push(`Suggested capabilities: ${c.suggested_capabilities.join(', ')}`);
144
- }
145
- if (c.isc_scaffold?.length) {
146
- lines.push('ISC Scaffold (preliminary Ideal State Criteria):');
147
- for (let i = 0; i < c.isc_scaffold.length; i++) {
148
- lines.push(` ${i + 1}. ${c.isc_scaffold[i]}`);
149
- }
150
- }
151
- if (c.constraints_extracted?.length) {
152
- lines.push(`Constraints: ${c.constraints_extracted.join('; ')}`);
153
- }
154
- const audit = packet1.capability_audit || data.capability_audit;
155
- if (audit?.formatted_summary) {
156
- lines.push('');
157
- lines.push(audit.formatted_summary);
158
- }
159
- const qg = packet1.quality_gate_config || data.quality_gate_config;
160
- if (qg?.rules?.length) {
161
- lines.push('');
162
- lines.push(`ISC Quality Gate: min ${qg.min_criteria || 4} criteria, ${qg.anti_required ? 'anti-criteria required' : 'anti-criteria optional'}, ${qg.word_range?.min || 8}-${qg.word_range?.max || 12} words each`);
163
- const effortGated = qg.rules.filter((r) => r.min_effort);
164
- if (effortGated.length) {
165
- lines.push(` Effort-gated rules: ${effortGated.map((r) => `${r.id} (${r.min_effort}+)`).join(', ')}`);
166
- }
167
- }
168
- const preload = packet1.context_pre_load_plan || data.context_pre_load_plan;
169
- if (preload?.entity_types?.length) {
170
- lines.push(`Context pre-load: ${preload.entity_types.join(', ')}`);
171
- }
172
- const memoryPlan = packet1.memory_plan || data.memory_plan;
173
- if (memoryPlan?.strategy) {
174
- lines.push(`Memory plan: strategy=${memoryPlan.strategy}${memoryPlan.memory_scope ? ` | scope=${memoryPlan.memory_scope}` : ''}${memoryPlan.domain_class ? ` | domain=${memoryPlan.domain_class}` : ''}${memoryPlan.entity_type_filter ? ` | filter=${memoryPlan.entity_type_filter}` : ''}${typeof memoryPlan.top_k === 'number' ? ` | top_k=${memoryPlan.top_k}` : ''}`);
175
- }
176
- const directives = packet1.behavioral_directives || data.behavioral_directives;
177
- if (directives?.length) {
178
- lines.push('');
179
- lines.push('BEHAVIORAL DIRECTIVES (from gramatr steering rules — follow these):');
180
- for (const d of directives)
181
- lines.push(` - ${d}`);
182
- }
183
- if (packet1Contents?.length || packet2Contents?.length || packet2Status || enrichmentId) {
184
- lines.push('');
185
- if (packet1Contents?.length) {
186
- lines.push(`PACKET 1 CONTENTS: ${packet1Contents.join(', ')}`);
187
- }
188
- const packet2Parts = [
189
- packet2Status ? `status=${packet2Status}` : '',
190
- packet2Contents?.length ? `contents=${packet2Contents.join(', ')}` : '',
191
- enrichmentId ? `enrichment_id=${enrichmentId}` : '',
192
- ].filter(Boolean);
193
- if (packet2Parts.length) {
194
- lines.push(`PACKET 2: ${packet2Parts.join(' | ')}`);
195
- }
196
- }
197
- const formatSpec = packet1.format_spec || data.format_spec;
198
- if (formatSpec?.mode || formatSpec?.phases?.length || formatSpec?.response_contract?.length) {
199
- lines.push('');
200
- lines.push(`FORMAT SPEC: ${[
201
- formatSpec.mode ? `mode=${formatSpec.mode}` : '',
202
- formatSpec.phases?.length ? `phases=${formatSpec.phases.join('→')}` : '',
203
- formatSpec.response_contract?.length ? `contract=${formatSpec.response_contract.join(', ')}` : '',
204
- ].filter(Boolean).join(' | ')}`);
205
- }
206
- const classifierHeads = packet1.classifier_heads || data.classifier_heads;
207
- if (classifierHeads) {
208
- const entries = Object.entries(classifierHeads).slice(0, 4);
209
- if (entries.length) {
210
- lines.push('');
211
- lines.push('CLASSIFIER HEADS:');
212
- for (const [head, rawScores] of entries) {
213
- const top = normalizeClassifierHeadScores(rawScores)
214
- .slice(0, 2)
215
- .map((score) => {
216
- const numericScore = typeof score.score === 'number'
217
- ? score.score
218
- : typeof score.confidence === 'number'
219
- ? score.confidence
220
- : null;
221
- const pct = typeof numericScore === 'number' ? `${Math.round(numericScore * 100)}%` : '';
222
- return [score.label, pct].filter(Boolean).join(' ');
223
- })
224
- .filter(Boolean)
225
- .join(', ');
226
- lines.push(` - ${head}: ${top || 'present'}`);
227
- }
228
- }
229
- }
230
- const routingSignals = packet1.routing_signals || data.routing_signals;
231
- if (routingSignals) {
232
- const parts = [
233
- routingSignals.complexity ? `complexity=${routingSignals.complexity}` : '',
234
- routingSignals.crud_operation ? `crud=${routingSignals.crud_operation}` : '',
235
- routingSignals.conversation_phase ? `phase=${routingSignals.conversation_phase}` : '',
236
- routingSignals.memory_scope ? `scope=${routingSignals.memory_scope}` : '',
237
- routingSignals.memory_priority ? `memory=${routingSignals.memory_priority}` : '',
238
- typeof routingSignals.retrieval_needed === 'boolean' ? `retrieval=${routingSignals.retrieval_needed}` : '',
239
- typeof routingSignals.is_read_only === 'boolean' ? `read_only=${routingSignals.is_read_only}` : '',
240
- typeof routingSignals.requires_approval === 'boolean' ? `approval=${routingSignals.requires_approval}` : '',
241
- typeof routingSignals.escalation_recommended === 'boolean' ? `escalate=${routingSignals.escalation_recommended}` : '',
242
- ].filter(Boolean);
243
- if (parts.length || routingSignals.safety_flags?.length) {
244
- lines.push('');
245
- lines.push(`ROUTING SIGNALS: ${parts.join(' | ')}`);
246
- if (routingSignals.entity_type_suggestion?.top) {
247
- lines.push(` Entity suggestion: ${routingSignals.entity_type_suggestion.top}`);
248
- }
249
- if (routingSignals.safety_flags?.length) {
250
- lines.push(` Safety flags: ${routingSignals.safety_flags.join(', ')}`);
251
- }
252
- }
253
- }
254
- const skillRouting = packet1.skills?.routing || packet1.skill_routing || data.skill_routing;
255
- if (skillRouting) {
256
- const matched = (skillRouting.matched_skills || []).map((skill) => skill.name || skill.id).filter(Boolean);
257
- const stats = [
258
- typeof skillRouting.use_count === 'number' ? `use=${skillRouting.use_count}` : '',
259
- typeof skillRouting.decline_count === 'number' ? `decline=${skillRouting.decline_count}` : '',
260
- typeof skillRouting.na_count === 'number' ? `na=${skillRouting.na_count}` : '',
261
- typeof skillRouting.pattern_boost_applied === 'boolean' ? `pattern_boost=${skillRouting.pattern_boost_applied}` : '',
262
- ].filter(Boolean);
263
- if (matched.length || stats.length) {
264
- lines.push('');
265
- if (matched.length)
266
- lines.push(`SKILL ROUTING: ${matched.join(', ')}`);
267
- if (stats.length)
268
- lines.push(` Stats: ${stats.join(' | ')}`);
269
- }
270
- }
271
- const activeSkill = packet1.skills?.active || packet1.active_skill || data.active_skill;
272
- if (activeSkill?.directives?.length) {
273
- lines.push('');
274
- lines.push(`ACTIVE SKILL: ${activeSkill.title || activeSkill.name} (phase: ${activeSkill.phase || 'ALL'})`);
275
- for (const d of activeSkill.directives)
276
- lines.push(` - ${d}`);
277
- }
278
- const rules = packet1.behavioral_rules || data.behavioral_rules;
279
- const effort = c.effort_level || 'standard';
280
- const routingMemoryPlan = packet1.memory_plan || data.memory_plan;
281
- const memoryScope = c.memory_scope || routingSignals?.memory_scope || null;
282
- if (rules) {
283
- lines.push('');
284
- lines.push(`ALGORITHM: ${(rules.algorithm_phases || []).join(' → ')}`);
285
- if (rules.hard_gates) {
286
- lines.push('');
287
- lines.push('HARD GATES:');
288
- for (const value of Object.values(rules.hard_gates)) {
289
- lines.push(` - ${value}`);
290
- }
291
- }
292
- if (rules.verification_rules?.length) {
293
- lines.push('');
294
- lines.push('VERIFICATION RULES:');
295
- for (const r of rules.verification_rules)
296
- lines.push(` - ${r}`);
297
- }
298
- if (rules.code_rules?.length) {
299
- lines.push('');
300
- lines.push('CODE RULES:');
301
- for (const r of rules.code_rules)
302
- lines.push(` - ${r}`);
303
- }
304
- if (rules.safety_rules?.length) {
305
- lines.push('');
306
- lines.push('SAFETY RULES:');
307
- for (const r of rules.safety_rules)
308
- lines.push(` - ${r}`);
309
- }
310
- }
311
- if (routingMemoryPlan?.semantic_search_enabled || memoryScope) {
312
- lines.push('');
313
- lines.push('═══ MANDATORY: QUERY GRAMATR MEMORY BEFORE ANY WORK ═══');
314
- lines.push(`${memoryScope ? `Memory scope: ${memoryScope} | ` : ''}Use search_results from Packet 1 first. Only call search_semantic for follow-up queries beyond the returned packet.`);
315
- lines.push('Do NOT answer from stale local markdown alone. gramatr has the live knowledge graph.');
316
- }
317
- lines.push('');
318
- lines.push('═══ MANDATORY: CREATE ISC VIA TaskCreate BEFORE ANY WORK ═══');
319
- lines.push('You MUST call the TaskCreate tool for each criterion below. This creates visible tracked tasks.');
320
- lines.push('NEVER write criteria as manual text/tables. ALWAYS use TaskCreate + TaskList tools.');
321
- lines.push('ALWAYS prefix task subjects with "ISC-C{N}: " for criteria or "ISC-A{N}: " for anti-criteria.');
322
- lines.push('The ISC prefix is REQUIRED — it signals to the user that gramatr intelligence is driving the criteria.');
323
- lines.push('This is a HARD GATE — do NOT proceed to any work until TaskCreate calls are complete.');
324
- lines.push('');
325
- lines.push('When presenting gramatr intelligence (ISC scaffolds, search results, agent recommendations, summaries), prefix with **grā:** in bold. This distinguishes server-pre-computed content from your own reasoning. Example: "**grā:** ISC scaffold suggests 6 criteria for this migration task."');
326
- if (effort === 'instant') {
327
- lines.push('');
328
- lines.push('FORMAT (instant effort — minimal): State, do, confirm.');
329
- }
330
- else if (effort === 'fast') {
331
- lines.push('');
332
- lines.push('FORMAT (fast effort — compressed):');
333
- lines.push(' 1. "Understanding: [wants] | Avoiding: [don\'t wants]"');
334
- if (c.isc_scaffold?.length) {
335
- lines.push(' 2. MANDATORY — call TaskCreate for each:');
336
- for (let i = 0; i < c.isc_scaffold.length; i++) {
337
- lines.push(` [INVOKE TaskCreate: subject="ISC-C${i + 1}: ${c.isc_scaffold[i]}", description="Binary testable: PASS or FAIL."]`);
338
- }
339
- lines.push(' 3. [INVOKE TaskList to display criteria to user]');
340
- lines.push(' 4. Do the work');
341
- lines.push(' 5. [INVOKE TaskList], then [INVOKE TaskUpdate] each with PASS/FAIL + evidence');
342
- }
343
- else {
344
- lines.push(' 2. [INVOKE TaskCreate for at least 4 criteria you identify]');
345
- lines.push(' 3. [INVOKE TaskList to display criteria to user]');
346
- lines.push(' 4. Do the work');
347
- lines.push(' 5. [INVOKE TaskList], then [INVOKE TaskUpdate] each with PASS/FAIL + evidence');
348
- }
349
- }
350
- else {
351
- lines.push('');
352
- lines.push(`FORMAT (${effort} effort — full phases)`);
353
- const agents = packet1.agents?.suggested || packet1.suggested_agents || data.packet_2?.agents?.suggested || data.packet_2?.suggested_agents || data.suggested_agents;
354
- if (agents?.length) {
355
- lines.push('');
356
- lines.push('Suggested agents:');
357
- for (const a of agents) {
358
- lines.push(` - ${a.display_name || a.name || 'agent'} (${a.model || 'default'}) — ${a.reason || ''}`);
359
- }
360
- }
361
- }
362
- const mem = packet1.memory_context || data.memory_context;
363
- if (mem?.results?.length) {
364
- lines.push('');
365
- lines.push(`RELEVANT MEMORY (${mem.total_count} matches from gramatr knowledge graph):`);
366
- for (const r of mem.results.slice(0, 5)) {
367
- const sim = r.similarity ? ` (${Math.round(r.similarity * 100)}% match)` : '';
368
- lines.push(` - [${r.entity_type || 'unknown'}] ${r.entity_name || 'unnamed'}${sim}: ${((r.summary || r.content) || '').substring(0, 150)}`);
369
- }
370
- }
187
+ const routingSignals = normalizeRoutingSignals(packet1.routing_signals || data.routing_signals);
188
+ const classifierHeads = (packet1.classifier_heads || data.classifier_heads);
189
+ const classifierSignals = normalizeClassifierSignals(classifierHeads, routingSignals);
190
+ const memory = packet1.memory_context || data.memory_context;
371
191
  const searchResults = packet1.search_results || data.search_results;
372
- if (searchResults?.results?.length) {
373
- lines.push('');
374
- lines.push(`SEARCH RESULTS (${searchResults.count || searchResults.results.length} pre-loaded):`);
375
- for (const r of searchResults.results.slice(0, 3)) {
376
- const label = [r.entity_name, r.entity_type].filter(Boolean).join(' / ');
377
- lines.push(` - ${[label, ((r.summary || r.snippet) || '').substring(0, 150)].filter(Boolean).join(': ')}`);
378
- }
379
- }
380
- const diaryCompact = packet1.diary_compact || data.diary_compact;
381
- if (diaryCompact?.summary || diaryCompact?.current_focus) {
382
- lines.push('');
383
- lines.push('DIARY COMPACT:');
384
- if (diaryCompact.summary)
385
- lines.push(` ${diaryCompact.summary}`);
386
- if (diaryCompact.current_focus)
387
- lines.push(` Focus: ${diaryCompact.current_focus}`);
388
- }
389
- const agentRecommendation = packet1.agents?.recommendation || packet1.agent_recommendation || data.agent_recommendation;
390
- if (agentRecommendation?.type || agentRecommendation?.source) {
391
- lines.push('');
392
- lines.push(`AGENT RECOMMENDATION: ${[
393
- agentRecommendation.type ? `type=${agentRecommendation.type}` : '',
394
- agentRecommendation.source ? `source=${agentRecommendation.source}` : '',
395
- typeof agentRecommendation.confidence === 'number'
396
- ? `confidence=${Math.round(agentRecommendation.confidence * 100)}%`
397
- : '',
398
- ].filter(Boolean).join(' | ')}`);
399
- }
400
- const activeTask = packet1.active_task || data.active_task;
401
- if (activeTask?.id || activeTask?.title || activeTask?.phase || activeTask?.status) {
402
- lines.push('');
403
- lines.push(`ACTIVE TASK: ${[
404
- activeTask.id ? `id=${activeTask.id}` : '',
405
- activeTask.title ? `title=${activeTask.title}` : '',
406
- activeTask.phase ? `phase=${activeTask.phase}` : '',
407
- activeTask.status ? `status=${activeTask.status}` : '',
408
- ].filter(Boolean).join(' | ')}`);
409
- }
410
- const composed = packet1.agents?.composed || packet1.composed_agents || data.composed_agents;
411
- if (composed?.length) {
412
- lines.push('');
413
- lines.push('gramatr composed agent (specialized for this task — USE THIS):');
414
- for (const ca of composed) {
415
- lines.push(` Agent: ${ca.display_name || ca.name || 'specialist'}`);
416
- lines.push(` Domain: ${ca.task_domain || 'general'} | Expertise: ${(ca.expertise_areas || []).join(', ')}`);
417
- lines.push(` Model: ${ca.model_preference || 'default'}`);
418
- lines.push(` Context: ${ca.context_summary || 'memory-aware'}`);
419
- lines.push(' ACTION: Use the Task tool with subagent_type="general-purpose" and inject this system prompt:');
420
- lines.push(' --- AGENT SYSTEM PROMPT START ---');
421
- const promptPreview = (ca.system_prompt || '').substring(0, 800);
422
- lines.push(` ${promptPreview}${(ca.system_prompt || '').length > 800 ? '... [truncated — use gramatr_invoke_agent for full prompt]' : ''}`);
423
- lines.push(' --- AGENT SYSTEM PROMPT END ---');
424
- }
425
- }
426
- const saved = ts.total_saved || ts.tokens_saved || 0;
427
- if (saved > 0) {
428
- lines.push(`[Token savings: ${saved.toLocaleString()} tokens saved per request (CLAUDE.md: ${(ts.claude_md_reduction || 0).toLocaleString()}, OBSERVE offload: ${(ts.observe_work_offloaded || 0).toLocaleString()})]`);
429
- }
430
- const curatedContext = packet1.curated_context || data.curated_context;
431
- if (curatedContext) {
432
- lines.push('');
433
- lines.push('CURATED CONTEXT:');
434
- lines.push(curatedContext.trim());
435
- }
436
- const diagnostics = packet1.packet_diagnostics || data.packet_diagnostics;
437
- if (diagnostics?.memory_context?.status === 'error' || diagnostics?.project_state?.status === 'error') {
438
- lines.push('');
439
- lines.push('PACKET DIAGNOSTICS:');
440
- if (diagnostics.memory_context?.status === 'error') {
441
- lines.push(` - Memory pre-load degraded: ${diagnostics.memory_context.error || 'unknown error'}`);
442
- }
443
- if (diagnostics.project_state?.status === 'error') {
444
- lines.push(` - Project state degraded: ${diagnostics.project_state.error || 'unknown error'}`);
445
- }
446
- }
447
- const degraded = es.degraded_components?.filter((component) => component.startsWith('classification.')) || [];
448
- if (degraded.length > 0) {
449
- lines.push('');
450
- lines.push('CLASSIFIER DIAGNOSTICS:');
451
- for (const component of degraded) {
452
- lines.push(` - ${component.replace('classification.', '').replace(/_/g, ' ')} degraded`);
453
- }
454
- }
455
- if (!enrichment && packet2Status === 'required' && enrichmentId) {
456
- lines.push('');
457
- lines.push(`Packet 2 (reverse engineering + ISC scaffold) is required but still generating. Call gramatr_get_enrichment with enrichment_id="${enrichmentId}" before proceeding.`);
458
- }
459
- return lines.join('\n');
192
+ const agentRecommendation = packet1.agents?.recommendation || packet1.agent_recommendation || data.agent_recommendation || null;
193
+ const suggestedAgents = packet1.agents?.suggested || packet1.suggested_agents || data.suggested_agents || [];
194
+ const selectedAgent = suggestedAgents[0] || null;
195
+ const recommendationHint = toAgentHint(agentRecommendation);
196
+ const selectedHint = toAgentHint(selectedAgent);
197
+ const recommendationMeta = toRecommendationMeta(agentRecommendation);
198
+ const matchedSkillNames = normalizeMatchedSkillNames(packet1, c);
199
+ const activeSkill = packet1.skills?.active?.name || packet1.active_skill?.name || null;
200
+ const skillStats = packet1.skills?.routing
201
+ ? {
202
+ use_count: packet1.skills.routing.use_count ?? null,
203
+ decline_count: packet1.skills.routing.decline_count ?? null,
204
+ na_count: packet1.skills.routing.na_count ?? null,
205
+ }
206
+ : null;
207
+ const envelope = {
208
+ schema: 'gmtr.intelligence.envelope.v1',
209
+ source: 'gramatr',
210
+ consumer_instructions: {
211
+ protocol: 'Process packet_1 first. Treat packet_1 as deterministic contract input.',
212
+ packet_1: [
213
+ 'Use classification + routing_signals to decide immediate response mode.',
214
+ 'Use memory_context/search_results directly; do not re-summarize with LLM in packet one.',
215
+ 'Execute required_actions exactly when present.',
216
+ ],
217
+ packet_2: [
218
+ 'If packet_2.required is true, call fetch_tool with enrichment_id before deep reasoning.',
219
+ 'Merge packet_2 reasoning into your plan, then continue implementation.',
220
+ ],
221
+ },
222
+ packet_1: {
223
+ manifest: {
224
+ packet_2_status: packet2Status,
225
+ packet_2_required: packet2Status === 'required',
226
+ enrichment_id: enrichmentId,
227
+ },
228
+ classification: {
229
+ effort_level: c.effort_level || null,
230
+ intent_type: c.intent_type || null,
231
+ confidence: c.confidence ?? null,
232
+ memory_scope: c.memory_scope || routingSignals?.memory_scope || null,
233
+ matched_skills: matchedSkillNames,
234
+ constraints_extracted: c.constraints_extracted || [],
235
+ },
236
+ routing_signals: routingSignals || null,
237
+ classifier_signals: classifierSignals,
238
+ memory_context: memory || null,
239
+ search_results: searchResults || null,
240
+ skills: {
241
+ active: activeSkill,
242
+ matched: matchedSkillNames,
243
+ stats: skillStats,
244
+ },
245
+ agents: {
246
+ recommendation: hasAgentIdentity(recommendationHint) ? recommendationHint : null,
247
+ recommendation_meta: recommendationMeta,
248
+ selected: selectedHint,
249
+ suggested: selectedHint ? [selectedHint] : [],
250
+ suggested_count: suggestedAgents.length,
251
+ },
252
+ },
253
+ packet_2: {
254
+ status: packet2Status,
255
+ required: packet2Status === 'required',
256
+ enrichment_id: enrichmentId,
257
+ fetch_tool: 'gramatr_get_packet_two',
258
+ },
259
+ required_actions: buildRequiredActions(packet2Status, enrichmentId),
260
+ };
261
+ return renderContractBlock(envelope);
460
262
  }
461
263
  export function emitStatus(data, elapsed, lastFailure) {
462
264
  if (!data) {