fraim-framework 2.0.101 → 2.0.102

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.
@@ -594,7 +594,7 @@ const runSetup = async (options) => {
594
594
  console.log(chalk_1.default.cyan('\nšŸ“ For future projects:'));
595
595
  console.log(chalk_1.default.cyan(' 1. cd into any project directory'));
596
596
  console.log(chalk_1.default.cyan(' 2. Run: fraim init-project'));
597
- console.log(chalk_1.default.cyan(' 3. Tell your AI agent: "Onboard this project"'));
597
+ console.log(chalk_1.default.cyan(' 3. Ask your AI agent: "FRAIM was just installed. Read the FRAIM docs, explain what it can do for me, then run project-onboarding."'));
598
598
  if (mode === 'integrated') {
599
599
  const allProviderIds = await (0, provider_registry_1.getAllProviderIds)();
600
600
  const unconfiguredProviders = allProviderIds.filter(id => !tokens[id]);
@@ -10,6 +10,7 @@ const project_fraim_paths_1 = require("../../core/utils/project-fraim-paths");
10
10
  const START_MARKER = '<!-- FRAIM_AGENT_ADAPTER_START -->';
11
11
  const END_MARKER = '<!-- FRAIM_AGENT_ADAPTER_END -->';
12
12
  const CURSOR_RULE_PATH = path_1.default.join('.cursor', 'rules', 'fraim.mdc');
13
+ const CLAUDE_FRAIM_COMMAND_PATH = path_1.default.join('.claude', 'commands', 'fraim.md');
13
14
  const CURSOR_FRONTMATTER = `---
14
15
  description: FRAIM discovery and execution contract
15
16
  alwaysApply: true
@@ -59,9 +60,13 @@ This repository uses FRAIM.
59
60
  - Skills under \`${employeeSkillsPath}/\` are reusable capabilities that jobs compose.
60
61
  - Rules under \`${employeeRulesPath}/\` are always-on constraints and conventions.
61
62
  - Repo-specific overrides and learning artifacts live under \`${personalizedRootPath}/\` and take precedence over synced baseline content.
62
- - Use stub filenames and summaries to discover what to invoke. Once you identify a relevant job, call \`get_fraim_job({ job: "<job-name>" })\`.
63
+ - Before acting on any user request, scan the job stubs under \`${employeeJobsPath}/\` and \`${managerJobsPath}/\` to identify the most appropriate job. Read stub filenames and their Intent/Outcome sections to match the request to the right job.
64
+ - Once you identify the relevant job, call \`get_fraim_job({ job: "<job-name>" })\` to get the full phased instructions.
63
65
  - For deeper capability detail, call \`get_fraim_file({ path: "skills/<category>/<skill-name>.md" })\` or \`get_fraim_file({ path: "rules/<category>/<rule-name>.md" })\`.
64
66
  - Read \`${projectRulesPath}\` if it exists before doing work.
67
+
68
+ > [!IMPORTANT]
69
+ > **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.
65
70
  `);
66
71
  const cursorManagedBody = buildManagedSection(`
67
72
  Use FRAIM as the repo's execution framework.
@@ -72,6 +77,7 @@ Use FRAIM as the repo's execution framework.
72
77
  - Rules are always-on constraints.
73
78
  - Repo-specific overrides and learnings under \`${personalizedRootPath}/\` take precedence.
74
79
  - Choose a relevant job from the stubs, then call \`get_fraim_job(...)\` for the full phased instructions.
80
+ - **Job stubs are for discovery only.** Never execute a job from stub content — always call \`get_fraim_job({ job: "<job-name>" })\` first.
75
81
  `);
76
82
  const copilotBody = buildManagedSection(`
77
83
  ## FRAIM
@@ -82,6 +88,7 @@ Use FRAIM as the repo's execution framework.
82
88
  - FRAIM rules are always-on constraints and conventions.
83
89
  - Repo-specific overrides and learnings live under \`${personalizedRootPath}/\`.
84
90
  - Use the stubs to identify which job to invoke before fetching full content with FRAIM MCP tools.
91
+ - **Job stubs are for discovery only.** Never execute a job from stub content — always call \`get_fraim_job({ job: "<job-name>" })\` first.
85
92
  `);
86
93
  const fraimReadme = `# FRAIM Catalog
87
94
 
@@ -94,13 +101,26 @@ This directory is the repository-visible FRAIM surface.
94
101
  - \`personalized-employee/\`: repo-specific overrides and learnings
95
102
 
96
103
  Use the stubs here to discover which FRAIM job, skill, or rule is relevant, then load the full content through FRAIM MCP tools.
104
+ `;
105
+ const claudeCommand = `The user wants to run FRAIM. The requested job or topic is: $ARGUMENTS
106
+
107
+ Follow this process:
108
+
109
+ 1. **If no argument was given** (the line above ends with ": "): scan all stub files under \`${employeeJobsPath}/\` and \`${managerJobsPath}/\`. List each by filename and its Intent line. Ask the user which job they want to run, then proceed to step 2.
110
+
111
+ 2. **Find the job**: search \`${employeeJobsPath}/\` and \`${managerJobsPath}/\` for a stub whose filename (without \`.md\`) matches or closely resembles the argument. Read the stub's Intent/Outcome to confirm it matches what the user wants.
112
+
113
+ 3. **Load the full job**: call \`get_fraim_job({ job: "<matched-job-name>" })\` — never execute from stub content.
114
+
115
+ 4. **Execute**: follow the phased instructions returned by \`get_fraim_job\`, using \`seekMentoring\` at phase transitions where indicated.
97
116
  `;
98
117
  return [
99
118
  { path: 'AGENTS.md', content: markdownBody },
100
119
  { path: 'CLAUDE.md', content: markdownBody },
101
120
  { path: path_1.default.join('.github', 'copilot-instructions.md'), content: copilotBody },
102
121
  { path: CURSOR_RULE_PATH, content: cursorManagedBody },
103
- { path: path_1.default.join(project_fraim_paths_1.WORKSPACE_FRAIM_DIRNAME, 'README.md'), content: fraimReadme }
122
+ { path: path_1.default.join(project_fraim_paths_1.WORKSPACE_FRAIM_DIRNAME, 'README.md'), content: fraimReadme },
123
+ { path: CLAUDE_FRAIM_COMMAND_PATH, content: claudeCommand }
104
124
  ];
105
125
  }
106
126
  function ensureAgentAdapterFiles(projectRoot) {
@@ -114,7 +134,7 @@ function ensureAgentAdapterFiles(projectRoot) {
114
134
  const existing = fs_1.default.existsSync(fullPath) ? fs_1.default.readFileSync(fullPath, 'utf8') : '';
115
135
  const next = file.path === CURSOR_RULE_PATH
116
136
  ? mergeCursorRule(existing, file.content)
117
- : file.path.endsWith('README.md')
137
+ : file.path.endsWith('README.md') || file.path === CLAUDE_FRAIM_COMMAND_PATH
118
138
  ? file.content
119
139
  : mergeManagedSection(existing, file.content);
120
140
  if (existing !== next) {
@@ -10,12 +10,11 @@ function getFraimVersion() {
10
10
  // Try reliable paths to find package.json relative to this file
11
11
  // locally: src/cli/utils/version-utils.ts -> package.json is ../../../package.json
12
12
  // dist: dist/src/cli/utils/version-utils.js -> package.json is ../../../../package.json
13
- const possiblePaths = [
14
- path_1.default.join(__dirname, '../../../package.json'), // Local dev (src)
15
- path_1.default.join(__dirname, '../../../../package.json'), // Dist (dist/src)
16
- path_1.default.join(process.cwd(), 'package.json') // Fallback to CWD
17
- ];
18
- for (const pkgPath of possiblePaths) {
13
+ // Traverse up from __dirname until we find fraim-framework's package.json.
14
+ // Fixed relative paths break when npx cache layouts differ across OS/npm versions.
15
+ let dir = __dirname;
16
+ for (let i = 0; i < 10; i++) {
17
+ const pkgPath = path_1.default.join(dir, 'package.json');
19
18
  if (fs_1.default.existsSync(pkgPath)) {
20
19
  try {
21
20
  const pkg = JSON.parse(fs_1.default.readFileSync(pkgPath, 'utf-8'));
@@ -27,6 +26,10 @@ function getFraimVersion() {
27
26
  // Ignore parsing errors
28
27
  }
29
28
  }
29
+ const parent = path_1.default.dirname(dir);
30
+ if (parent === dir)
31
+ break; // Reached filesystem root
32
+ dir = parent;
30
33
  }
31
- return '1.0.0'; // Fallback
34
+ return 'unknown'; // Do not return a fake version — unknown is safer than misleading
32
35
  }
@@ -4,11 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.UsageCollector = void 0;
7
- const mongodb_1 = require("mongodb");
8
7
  const axios_1 = __importDefault(require("axios"));
9
- // A placeholder ObjectId used when the real API key ID is not yet known.
10
- // The server will override this with the correct ID from the authenticated API key.
11
- const PLACEHOLDER_API_KEY_ID = new mongodb_1.ObjectId('000000000000000000000000');
12
8
  /**
13
9
  * UsageCollector is responsible for collecting usage events from MCP tools
14
10
  * and formatting them for the analytics system.
@@ -16,7 +12,7 @@ const PLACEHOLDER_API_KEY_ID = new mongodb_1.ObjectId('000000000000000000000000'
16
12
  class UsageCollector {
17
13
  constructor() {
18
14
  this.events = [];
19
- this.apiKeyId = null;
15
+ this.userId = null;
20
16
  }
21
17
  static resolveMentoringJobName(args) {
22
18
  if (!args || typeof args !== 'object') {
@@ -35,10 +31,10 @@ class UsageCollector {
35
31
  return 'unknown';
36
32
  }
37
33
  /**
38
- * Set the API key ID for this session
34
+ * Set the user ID for this session
39
35
  */
40
- setApiKeyId(apiKeyId) {
41
- this.apiKeyId = apiKeyId;
36
+ setUserId(userId) {
37
+ this.userId = userId;
42
38
  }
43
39
  /**
44
40
  * Collect MCP tool call event
@@ -61,9 +57,8 @@ class UsageCollector {
61
57
  const event = {
62
58
  type: parsed.type,
63
59
  name: parsed.name,
64
- // Use set apiKeyId if available, otherwise a placeholder.
65
- // The server will override this with the correct ID from the authenticated API key.
66
- apiKeyId: this.apiKeyId || PLACEHOLDER_API_KEY_ID,
60
+ // Use set userId if available; the server will override with the authenticated userId.
61
+ userId: this.userId || 'unknown',
67
62
  sessionId,
68
63
  success,
69
64
  category: parsed.category,
@@ -83,9 +78,7 @@ class UsageCollector {
83
78
  type,
84
79
  name,
85
80
  category,
86
- // Use set apiKeyId if available, otherwise a placeholder.
87
- // The server will override this with the correct value from the auth token.
88
- apiKeyId: this.apiKeyId || PLACEHOLDER_API_KEY_ID,
81
+ userId: this.userId || 'unknown',
89
82
  sessionId,
90
83
  success,
91
84
  args
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fraim-framework",
3
- "version": "2.0.101",
3
+ "version": "2.0.102",
4
4
  "description": "FRAIM v2: Framework for Rigor-based AI Management - Transform from solo developer to AI manager orchestrating production-ready code with enterprise-grade discipline",
5
5
  "main": "index.js",
6
6
  "bin": {