fraim 2.0.240 → 2.0.242

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,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CODEX_SKILL_FRONTMATTER = exports.FRAIM_INVOCATION_BODY = exports.FRAIM_DEFERRED_TOOL_PRELOAD = exports.CURSOR_MDC_FRONTMATTER = exports.FRAIM_LAUNCH_PHRASE = void 0;
3
+ exports.CODEX_SKILL_FRONTMATTER = exports.FRAIM_INVOCATION_BODY = exports.FRAIM_MCP_UNAVAILABLE_MANAGER_GUIDANCE = exports.FRAIM_DEFERRED_TOOL_PRELOAD = exports.CURSOR_MDC_FRONTMATTER = exports.FRAIM_LAUNCH_PHRASE = void 0;
4
4
  exports.buildFraimInvocationBody = buildFraimInvocationBody;
5
5
  exports.buildClaudeSkillContent = buildClaudeSkillContent;
6
6
  exports.buildClaudeCommandShimContent = buildClaudeCommandShimContent;
@@ -25,6 +25,12 @@ exports.FRAIM_DEFERRED_TOOL_PRELOAD = [
25
25
  'get_fraim_file',
26
26
  'seekMentoring'
27
27
  ];
28
+ exports.FRAIM_MCP_UNAVAILABLE_MANAGER_GUIDANCE = [
29
+ 'If required FRAIM MCP tools remain unavailable after the deferred-tool preload/retry step, stop the FRAIM job.',
30
+ 'Do not continue from memory, local stubs, cached instructions, or prior context.',
31
+ 'In the blocker sentence, state only the work-focused blocker and what outcome is blocked; do not narrate ToolSearch/tool_search, individual tool names, server internals, or retry mechanics.',
32
+ 'Always help troubleshoot the unavailable FRAIM MCP connection: tell the user to reconnect or enable the FRAIM MCP server in their IDE/agent, restart or refresh the agent session, retry the FRAIM job, and if it still fails run `fraim doctor --test-mcp` and share the failing check output.'
33
+ ].join(' ');
28
34
  function buildDeferredToolBootstrapSection(profile) {
29
35
  if (profile === 'none') {
30
36
  return '';
@@ -72,6 +78,7 @@ ${buildDeferredToolBootstrapSection(profile)}1. **Confirm FRAIM activation**:
72
78
  5. **Execute**:
73
79
  - For jobs, follow the phased instructions and use \`seekMentoring\` when the job requires phase transitions.
74
80
  - For skills, apply the skill steps directly to the user's current context.
81
+ - ${exports.FRAIM_MCP_UNAVAILABLE_MANAGER_GUIDANCE}
75
82
  `;
76
83
  }
77
84
  exports.FRAIM_INVOCATION_BODY = buildFraimInvocationBody();
@@ -78,6 +78,7 @@ This repository uses FRAIM.
78
78
  - For deeper capability detail, call \`get_fraim_file({ path: "skills/<category>/<skill-name>.md" })\` or \`get_fraim_file({ path: "rules/<category>/<rule-name>.md" })\`.
79
79
  - Read \`${projectRulesPath}\` if it exists before doing work.
80
80
  - When users ask for next step recommendations, use recommend-next-job skill under \`${employeeSkillsPath}/\` to gather context before suggesting jobs.
81
+ - ${ide_invocation_surfaces_1.FRAIM_MCP_UNAVAILABLE_MANAGER_GUIDANCE}
81
82
 
82
83
  > [!IMPORTANT]
83
84
  > **Job stubs are for discovery only.** When a user mentions or references any file under \`${employeeJobsPath}/\` or \`${managerJobsPath}/\`, do NOT attempt to execute the job from the stub content. The stub only shows intent and phase names. Always call \`get_fraim_job({ job: "<job-name>" })\` first to get the full phased instructions before doing any work.
@@ -101,6 +102,7 @@ ${(0, ide_invocation_surfaces_1.buildFraimInvocationBody)('generic-tool-discover
101
102
  - When FRAIM routing is active but the job is not exact, use local stubs to identify which job to invoke before fetching full content with FRAIM MCP tools.
102
103
  - If no exact or high-confidence job match exists, say that no FRAIM job matches and continue with normal tools or ask one concise clarification.
103
104
  - **Job stubs are for discovery only.** Never execute a job from stub content - always call \`get_fraim_job({ job: "<job-name>" })\` first.
105
+ - ${ide_invocation_surfaces_1.FRAIM_MCP_UNAVAILABLE_MANAGER_GUIDANCE}
104
106
  `);
105
107
  const fraimReadme = `# FRAIM Catalog
106
108
 
@@ -152,6 +152,38 @@ function validateDelegationLedger(value) {
152
152
  else if (!Array.isArray(obj.tasks)) {
153
153
  errors.push('evidence.delegationLedger.tasks must be an array');
154
154
  }
155
+ else {
156
+ // Issue #1021: validate each task, not just the array's existence. A task naming
157
+ // no job used to pass here and then be skipped by a bare `continue` in
158
+ // maybeStartDelegatedChildRuns, so a whole workstream could vanish with nothing
159
+ // manager-visible. Rejecting at emission lets the agent retry in one round.
160
+ //
161
+ // Deliberately NOT required: `taskId`. normalizeDelegationLedger synthesizes one
162
+ // from the title, so requiring it would reject ledgers the runtime handles fine.
163
+ // The title requirement accepts `briefing`/`instructions` because the group schema
164
+ // supplies those instead — this mirrors exactly what the normalizer needs to keep
165
+ // a task, so the contract can no longer be weaker than the parser.
166
+ obj.tasks.forEach((task, index) => {
167
+ const label = `evidence.delegationLedger.tasks[${index}]`;
168
+ if (!task || typeof task !== 'object' || Array.isArray(task)) {
169
+ errors.push(`${label} must be an object`);
170
+ return;
171
+ }
172
+ const entry = task;
173
+ const nonEmpty = (value) => typeof value === 'string' && value.trim().length > 0;
174
+ if (!nonEmpty(entry.title) && !nonEmpty(entry.briefing) && !nonEmpty(entry.instructions)) {
175
+ errors.push(`${label} needs a title (or briefing/instructions to derive one from)`);
176
+ }
177
+ if (!nonEmpty(entry.jobId) && !nonEmpty(entry.job) && !nonEmpty(entry.job_id)) {
178
+ errors.push(`${label}.jobId is missing; every delegated task must name an existing FRAIM job`);
179
+ }
180
+ const issueNumber = entry.issueNumber ?? entry.issue_number ?? entry.issue;
181
+ if (issueNumber !== undefined && issueNumber !== null
182
+ && typeof issueNumber !== 'string' && typeof issueNumber !== 'number') {
183
+ errors.push(`${label}.issueNumber must be a string or number when present (got ${typeof issueNumber})`);
184
+ }
185
+ });
186
+ }
155
187
  return errors.length > 0 ? errors : null;
156
188
  }
157
189
  // ---------------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fraim",
3
- "version": "2.0.240",
3
+ "version": "2.0.242",
4
4
  "description": "FRAIM core CLI and MCP package.",
5
5
  "main": "index.js",
6
6
  "bin": {