fraim 2.0.342 → 2.0.344
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.
- package/dist/registry/scripts/artifact-paths.js +108 -0
- package/dist/registry/scripts/learning/completion-state.js +205 -5
- package/dist/registry/scripts/learning-usage/local-runtime.js +217 -0
- package/dist/src/cli/commands/init-project.js +2 -12
- package/dist/src/cli/commands/sync.js +36 -162
- package/dist/src/cli/setup/ide-invocation-surfaces.js +3 -3
- package/dist/src/cli/setup/user-level-sync.js +3 -3
- package/dist/src/cli/utils/agent-adapters.js +12 -12
- package/dist/src/cli/utils/fraim-gitignore.js +28 -3
- package/dist/src/cli/utils/pack-home.js +10 -0
- package/dist/src/cli/utils/project-catalog-cleanup.js +62 -0
- package/dist/src/cli/utils/remote-sync.js +26 -2
- package/dist/src/config/persona-hiring.js +7 -1
- package/dist/src/core/ai-mentor.js +42 -11
- package/dist/src/core/config-loader.js +4 -0
- package/dist/src/core/fraim-config-schema.generated.js +22 -0
- package/dist/src/core/handoff-contracts.js +8 -3
- package/dist/src/core/utils/local-registry-resolver.js +33 -57
- package/dist/src/fraim/db-service.js +127 -118
- package/dist/src/local-mcp-server/artifact-retention-cleanup.js +79 -6
- package/dist/src/local-mcp-server/learning-context-builder.js +101 -105
- package/dist/src/local-mcp-server/learning-source-record.js +122 -0
- package/dist/src/local-mcp-server/learning-usage-attestation.js +66 -56
- package/dist/src/local-mcp-server/learning-usage-command.js +5 -4
- package/dist/src/local-mcp-server/stdio-server.js +10 -7
- package/dist/src/local-mcp-server/usage-collector.js +2 -0
- package/dist/src/mcp/tool-schemas.js +5 -1
- package/dist/src/services/mcp-service.js +6 -4
- package/dist/src/services/usage-analytics-service.js +1 -0
- package/package.json +3 -1
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.extractLegacyTitle = exports.parseFiringSection = void 0;
|
|
4
4
|
exports.recordAttestationsFromRetrospective = recordAttestationsFromRetrospective;
|
|
5
|
+
exports.readRetrospectiveForAttestation = readRetrospectiveForAttestation;
|
|
5
6
|
exports.runBackfill = runBackfill;
|
|
7
|
+
const artifact_paths_1 = require("../../registry/scripts/artifact-paths");
|
|
6
8
|
/**
|
|
7
9
|
* Issue #1103 — turning an attestation into a usage record.
|
|
8
10
|
*
|
|
@@ -18,6 +20,7 @@ exports.runBackfill = runBackfill;
|
|
|
18
20
|
*/
|
|
19
21
|
const fs_1 = require("fs");
|
|
20
22
|
const path_1 = require("path");
|
|
23
|
+
const learning_source_record_1 = require("./learning-source-record");
|
|
21
24
|
const learning_usage_store_1 = require("./learning-usage-store");
|
|
22
25
|
const learning_firing_parser_1 = require("./learning-firing-parser");
|
|
23
26
|
const learning_context_builder_1 = require("./learning-context-builder");
|
|
@@ -160,69 +163,76 @@ function recordAttestationsFromRetrospective(workspaceRoot, userId, options) {
|
|
|
160
163
|
rejected: parsed.rejected,
|
|
161
164
|
};
|
|
162
165
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
+
// ── R15: backfill ────────────────────────────────────────────────────────────
|
|
167
|
+
/** Resolve live attestation against its recorded home and immutable accounting identity. */
|
|
168
|
+
function readRetrospectiveForAttestation(workspaceRoot, userId, filePath) {
|
|
169
|
+
let reason = 'Retrospective is outside configured learning homes';
|
|
170
|
+
for (const home of (0, learning_context_builder_1.getLearningInputHomes)(workspaceRoot)) {
|
|
171
|
+
const result = (0, learning_context_builder_1.readLearningSourceFile)((0, path_1.resolve)(filePath), home.root, home.contentRoot);
|
|
172
|
+
if (result.status !== 'valid') {
|
|
173
|
+
reason = result.reason;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (result.record.kind !== 'retrospective' || result.record.author !== userId) {
|
|
177
|
+
throw new Error('Retrospective kind or author does not match this attestation');
|
|
178
|
+
}
|
|
179
|
+
return { content: result.content, record: result.record };
|
|
180
|
+
}
|
|
181
|
+
throw new Error(`Invalid learning retrospective: ${reason}`);
|
|
166
182
|
}
|
|
167
|
-
/**
|
|
168
|
-
* Read every retrospective and apply the firings it attests.
|
|
169
|
-
*
|
|
170
|
-
* Best effort by design (R15): only an id or an exact title resolves, and the
|
|
171
|
-
* unmatched count is reported rather than resolved by fuzzy matching. A low match
|
|
172
|
-
* rate is an expected outcome to state, not a failure to hide — only a small
|
|
173
|
-
* fraction of the existing attestations name a machine-matchable identifier.
|
|
174
|
-
*
|
|
175
|
-
* A retrospective already stamped `synthesized` is still read: being synthesized
|
|
176
|
-
* for learning content is not the same as having contributed usage data.
|
|
177
|
-
*/
|
|
183
|
+
/** Read only typed future reflections, including archives, with stable accounting identity. */
|
|
178
184
|
function runBackfill(workspaceRoot, userId, options) {
|
|
179
185
|
const limits = options.limits ?? (0, learning_usage_store_1.resolveUsageLimits)(workspaceRoot);
|
|
180
|
-
const dir = options.retrospectivesDir ?? (0, path_1.join)(workspaceRoot, 'docs', 'retrospectives');
|
|
181
186
|
const report = {
|
|
182
187
|
filesScanned: 0, filesWithSection: 0, itemsRead: 0, applied: 0,
|
|
183
|
-
alreadyRecorded: 0, unmatched: [], rejected: [], synthesizedFilesRead: 0,
|
|
188
|
+
alreadyRecorded: 0, unmatched: [], rejected: [], synthesizedFilesRead: 0, invalidRecords: [],
|
|
184
189
|
};
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
190
|
+
const seen = new Set();
|
|
191
|
+
for (const home of (0, learning_context_builder_1.getLearningInputHomes)(workspaceRoot)) {
|
|
192
|
+
const paths = (0, artifact_paths_1.resolveLearningPaths)(home.root, home.contentRoot);
|
|
193
|
+
for (const dir of [paths.retrospectives, paths.archiveRetrospectives]) {
|
|
194
|
+
if (options.retrospectivesDir && (0, learning_source_record_1.normalizeLearningSourcePath)(dir) !== (0, learning_source_record_1.normalizeLearningSourcePath)(options.retrospectivesDir))
|
|
195
|
+
continue;
|
|
196
|
+
let files;
|
|
197
|
+
try {
|
|
198
|
+
if ((0, fs_1.lstatSync)(dir).isSymbolicLink())
|
|
199
|
+
continue;
|
|
200
|
+
files = (0, fs_1.readdirSync)(dir).filter(f => f.endsWith('.md'));
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
for (const file of files) {
|
|
206
|
+
const filePath = (0, path_1.join)(dir, file);
|
|
207
|
+
const parsed = (0, learning_context_builder_1.readLearningSourceFile)(filePath, home.root, home.contentRoot);
|
|
208
|
+
if (parsed.status !== 'valid') {
|
|
209
|
+
if (parsed.status === 'invalid')
|
|
210
|
+
report.invalidRecords.push({ path: filePath, reason: parsed.reason });
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const { record } = parsed;
|
|
214
|
+
if (record.kind !== 'retrospective' || record.author !== userId)
|
|
215
|
+
continue;
|
|
216
|
+
if (seen.has(record.usageSourceRef))
|
|
217
|
+
continue;
|
|
218
|
+
seen.add(record.usageSourceRef);
|
|
219
|
+
report.filesScanned++;
|
|
220
|
+
if (record.synthesized)
|
|
221
|
+
report.synthesizedFilesRead++;
|
|
222
|
+
const result = recordAttestationsFromRetrospective(workspaceRoot, userId, {
|
|
223
|
+
content: parsed.content, source: record.usageSourceRef, job: record.job, date: record.date,
|
|
224
|
+
agent: options.agent, model: options.model, legacy: false,
|
|
225
|
+
limits, now: options.now, storePath: options.storePath, integrityMode: 'flag',
|
|
226
|
+
});
|
|
227
|
+
if (result.sectionState !== 'absent')
|
|
228
|
+
report.filesWithSection++;
|
|
229
|
+
report.itemsRead += result.itemsRead;
|
|
230
|
+
report.applied += result.applied;
|
|
231
|
+
report.alreadyRecorded += result.alreadyRecorded;
|
|
232
|
+
report.unmatched.push(...result.unmatched);
|
|
233
|
+
report.rejected.push(...result.rejected);
|
|
234
|
+
}
|
|
201
235
|
}
|
|
202
|
-
report.filesScanned += 1;
|
|
203
|
-
if (/^synthesized:\s*\S/m.test(content))
|
|
204
|
-
report.synthesizedFilesRead += 1;
|
|
205
|
-
const result = recordAttestationsFromRetrospective(workspaceRoot, userId, {
|
|
206
|
-
content,
|
|
207
|
-
source: `docs/retrospectives/${file}`,
|
|
208
|
-
job: jobFromFrontmatter(content),
|
|
209
|
-
agent: options.agent,
|
|
210
|
-
model: options.model,
|
|
211
|
-
legacy: true,
|
|
212
|
-
limits,
|
|
213
|
-
now: options.now,
|
|
214
|
-
storePath: options.storePath,
|
|
215
|
-
// A backfill reconciles hundreds of retrospectives at once, so a single
|
|
216
|
-
// stranded-offer entry must not refuse the whole run.
|
|
217
|
-
integrityMode: 'flag',
|
|
218
|
-
});
|
|
219
|
-
if (result.sectionState !== 'absent')
|
|
220
|
-
report.filesWithSection += 1;
|
|
221
|
-
report.itemsRead += result.itemsRead;
|
|
222
|
-
report.applied += result.applied;
|
|
223
|
-
report.alreadyRecorded += result.alreadyRecorded;
|
|
224
|
-
report.unmatched.push(...result.unmatched);
|
|
225
|
-
report.rejected.push(...result.rejected);
|
|
226
236
|
}
|
|
227
237
|
return report;
|
|
228
238
|
}
|
|
@@ -134,12 +134,13 @@ const recordFiringsCommand = addCommonOptions(new commander_1.Command('record-fi
|
|
|
134
134
|
if (!node_fs_1.default.existsSync(filePath)) {
|
|
135
135
|
throw new Error(`Retrospective not found: ${filePath}`);
|
|
136
136
|
}
|
|
137
|
-
const content =
|
|
138
|
-
const source =
|
|
137
|
+
const { content, record } = (0, learning_usage_attestation_1.readRetrospectiveForAttestation)(workspaceRoot, user, filePath);
|
|
138
|
+
const source = record.usageSourceRef;
|
|
139
139
|
const result = (0, learning_usage_attestation_1.recordAttestationsFromRetrospective)(workspaceRoot, user, {
|
|
140
140
|
content,
|
|
141
141
|
source,
|
|
142
|
-
job:
|
|
142
|
+
job: record.job,
|
|
143
|
+
date: record.date,
|
|
143
144
|
agent: options.agent ?? null,
|
|
144
145
|
model: options.model ?? null,
|
|
145
146
|
legacy: Boolean(options.legacy),
|
|
@@ -387,7 +388,7 @@ function defaultStampDirs(workspaceRoot) {
|
|
|
387
388
|
const dirs = [node_path_1.default.join(workspaceRoot, 'fraim', 'personalized-employee', 'learnings')];
|
|
388
389
|
for (const level of ['org', 'manager']) {
|
|
389
390
|
try {
|
|
390
|
-
dirs.push(node_path_1.default.join((0, pack_home_1.resolvePackHome)(level).contentRoot, 'learnings'));
|
|
391
|
+
dirs.push(node_path_1.default.join((0, pack_home_1.resolvePackHome)(level, { migrateLegacy: false }).contentRoot, 'learnings'));
|
|
391
392
|
}
|
|
392
393
|
catch {
|
|
393
394
|
// A pack home that does not resolve is simply not stamped. Reported by the
|
|
@@ -59,6 +59,7 @@ const path_1 = require("path");
|
|
|
59
59
|
const os_1 = require("os");
|
|
60
60
|
const child_process_1 = require("child_process");
|
|
61
61
|
const crypto_1 = require("crypto");
|
|
62
|
+
const local_runtime_1 = require("../../registry/scripts/learning-usage/local-runtime");
|
|
62
63
|
const axios_1 = __importDefault(require("axios"));
|
|
63
64
|
const provider_utils_1 = require("../core/utils/provider-utils");
|
|
64
65
|
const object_utils_1 = require("../core/utils/object-utils");
|
|
@@ -79,6 +80,7 @@ const learning_context_builder_js_1 = require("./learning-context-builder.js");
|
|
|
79
80
|
const learning_usage_store_js_1 = require("./learning-usage-store.js");
|
|
80
81
|
const learning_domains_js_1 = require("../config/learning-domains.js");
|
|
81
82
|
const skill_include_dedup_js_1 = require("./skill-include-dedup.js");
|
|
83
|
+
const git_utils_1 = require("../core/utils/git-utils");
|
|
82
84
|
/**
|
|
83
85
|
* Handle template substitution logic separately for better testability
|
|
84
86
|
*/
|
|
@@ -171,7 +173,7 @@ class FraimTemplateEngine {
|
|
|
171
173
|
try {
|
|
172
174
|
const configPath = (0, path_1.join)(this.projectRoot, 'fraim', 'config.json');
|
|
173
175
|
if ((0, fs_1.existsSync)(configPath)) {
|
|
174
|
-
this.config =
|
|
176
|
+
this.config = (0, local_runtime_1.readJsonIfObject)(configPath, { strict: true });
|
|
175
177
|
this.configLoadAttempted = true;
|
|
176
178
|
return this.config;
|
|
177
179
|
}
|
|
@@ -742,8 +744,7 @@ class FraimLocalMCPServer {
|
|
|
742
744
|
const configPath = (0, project_fraim_paths_1.getWorkspaceConfigPath)(projectDir);
|
|
743
745
|
this.log(`🔍 Looking for config at: ${configPath}`);
|
|
744
746
|
if ((0, fs_1.existsSync)(configPath)) {
|
|
745
|
-
|
|
746
|
-
this.config = JSON.parse(configContent);
|
|
747
|
+
this.config = (0, local_runtime_1.readJsonIfObject)(configPath, { strict: true });
|
|
747
748
|
this.log(`Loaded local ${(0, project_fraim_paths_1.getWorkspaceFraimDisplayPath)('config.json')}`);
|
|
748
749
|
}
|
|
749
750
|
else {
|
|
@@ -1119,7 +1120,7 @@ class FraimLocalMCPServer {
|
|
|
1119
1120
|
catch {
|
|
1120
1121
|
branch = '';
|
|
1121
1122
|
}
|
|
1122
|
-
const defaultBranch = this.config?.repository?.defaultBranch || '';
|
|
1123
|
+
const defaultBranch = this.config?.repository?.defaultBranch || (0, git_utils_1.getDefaultBranch)(projectDir) || '';
|
|
1123
1124
|
const repoInfo = {
|
|
1124
1125
|
url: repoUrl,
|
|
1125
1126
|
name: name || 'unknown',
|
|
@@ -1301,7 +1302,9 @@ class FraimLocalMCPServer {
|
|
|
1301
1302
|
}
|
|
1302
1303
|
const timestamp = new Date().toISOString();
|
|
1303
1304
|
const accepted = acceptedNext !== undefined;
|
|
1304
|
-
const
|
|
1305
|
+
const recoveringTerminalReview = previous?.status === 'waiting_review' && previous.currentPhase === null
|
|
1306
|
+
&& (args.status === 'starting' || args.status === 'incomplete');
|
|
1307
|
+
const currentPhase = recoveringTerminalReview ? null : accepted
|
|
1305
1308
|
? (args.status === 'complete' ? acceptedNext.nextPhase : acceptedNext.nextPhase || args.currentPhase)
|
|
1306
1309
|
: previous ? previous.currentPhase : args.currentPhase;
|
|
1307
1310
|
const completedPhases = previous?.completedPhases || [];
|
|
@@ -1371,7 +1374,7 @@ class FraimLocalMCPServer {
|
|
|
1371
1374
|
updated.phaseInstances = updated.phaseInstances?.filter((instance) => instance.jobId && instance.jobId !== args.jobId);
|
|
1372
1375
|
}
|
|
1373
1376
|
this.writeRunStateMarker(sessionId, args.jobName, updated);
|
|
1374
|
-
return (inspection.missingStart ? (0, handoff_contracts_1.buildPhaseStartWarning)(args.currentPhase) : '')
|
|
1377
|
+
return (inspection.missingStart ? (0, handoff_contracts_1.buildPhaseStartWarning)(args.currentPhase, nextPhase ?? undefined) : '')
|
|
1375
1378
|
+ (!args.jobId ? `Run-tracking notice: phase ${args.currentPhase} has no jobId; matching used the session, job name and phase.\n\n` : '');
|
|
1376
1379
|
}
|
|
1377
1380
|
readCachedTemplateFile(filename) {
|
|
@@ -3109,7 +3112,7 @@ class FraimLocalMCPServer {
|
|
|
3109
3112
|
const requestId = request.id;
|
|
3110
3113
|
const cached = this.jobStartCache.get(requestId);
|
|
3111
3114
|
if (cached) {
|
|
3112
|
-
args = { ...args, jobId: cached.jobId, action: 'start' };
|
|
3115
|
+
args = { ...args, jobId: cached.jobId, action: 'start', isReload: false };
|
|
3113
3116
|
this.jobStartCache.delete(requestId);
|
|
3114
3117
|
this.log(`📊 Enriched get_fraim_job args with jobId=${cached.jobId}, action=start`);
|
|
3115
3118
|
}
|
|
@@ -147,6 +147,8 @@ class UsageCollector {
|
|
|
147
147
|
analyticsArgs.job = args.job;
|
|
148
148
|
if (args.action)
|
|
149
149
|
analyticsArgs.action = args.action;
|
|
150
|
+
if (typeof args.isReload === 'boolean')
|
|
151
|
+
analyticsArgs.isReload = args.isReload;
|
|
150
152
|
break;
|
|
151
153
|
case 'fraim_connect':
|
|
152
154
|
if (args.agent?.name)
|
|
@@ -343,13 +343,17 @@ Do not use this tool for other repositories or external project issue trackers.`
|
|
|
343
343
|
},
|
|
344
344
|
currentPhase: {
|
|
345
345
|
type: 'string',
|
|
346
|
-
description: 'The phase you are currently in or have just finished (e.g., "implement-scoping"). For initial workflow start,
|
|
346
|
+
description: 'The phase you are currently in or have just finished (e.g., "implement-scoping"). For initial workflow start, pass "starting" as a one-time bootstrap — this is distinct from the per-phase status:"starting" on-arrival call you make at the beginning of every phase.'
|
|
347
347
|
},
|
|
348
348
|
status: {
|
|
349
349
|
type: 'string',
|
|
350
350
|
description: 'Status of your work in the current phase.',
|
|
351
351
|
enum: ['starting', 'complete', 'incomplete', 'failure']
|
|
352
352
|
},
|
|
353
|
+
requestInstructions: {
|
|
354
|
+
type: 'boolean',
|
|
355
|
+
description: 'On a starting call, pass true to restore full phase and skill instructions after context loss. Ordinary arrivals acknowledge the phase without repeating instructions already delivered by the previous response. Initial and recurring entry still deliver instructions.'
|
|
356
|
+
},
|
|
353
357
|
findings: {
|
|
354
358
|
type: 'object',
|
|
355
359
|
description: 'Your findings, summaries, or results from the current phase (required for status="complete")',
|
|
@@ -548,9 +548,9 @@ class McpService {
|
|
|
548
548
|
'- Use FRAIM when the user explicitly invokes FRAIM, names a FRAIM job, asks what FRAIM job to run, or the active surface has already selected a FRAIM job.',
|
|
549
549
|
'- For ordinary requests, answer or work normally. Do not scan FRAIM stubs first.',
|
|
550
550
|
'- If the user already named a job, call `get_fraim_job({ job: "<job-name>" })` directly.',
|
|
551
|
-
'- If routing is active and
|
|
551
|
+
'- If routing is active and no exact job is named, read `~/.fraim/ai-employee/jobs/INDEX.md` and `~/.fraim/ai-manager/jobs/INDEX.md` first (name, one-line intent, and category per job) to choose the best job; open an individual stub only to confirm a shortlisted candidate, or fall back to scanning stubs in those machine directories if an index is missing or stale. Project baseline catalog directories are not required.',
|
|
552
552
|
'- Also check `fraim/personalized-employee/jobs/` (and its own `INDEX.md`, if present) for local job overrides or repo-specific jobs when routing is active.',
|
|
553
|
-
'- If
|
|
553
|
+
'- If machine stubs are missing, you cannot inspect local files, or the user asks for available jobs, call `list_fraim_jobs()` to view the full catalog.',
|
|
554
554
|
'- 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.',
|
|
555
555
|
'- Use `get_fraim_file(...)` only for the specific skills or rules needed for the current task.',
|
|
556
556
|
'- Once a phased job starts, use `seekMentoring` for phase-specific instructions and transitions.'
|
|
@@ -712,7 +712,8 @@ class McpService {
|
|
|
712
712
|
currentPhase: args.currentPhase,
|
|
713
713
|
status: args.status,
|
|
714
714
|
evidence: args.evidence,
|
|
715
|
-
findings: args.findings
|
|
715
|
+
findings: args.findings,
|
|
716
|
+
requestInstructions: args.requestInstructions
|
|
716
717
|
});
|
|
717
718
|
// Handoff contract enforcement (Issue #916/#1157/#1276) fall-through
|
|
718
719
|
// safety net, matching the quality-enforcement note just below.
|
|
@@ -824,7 +825,7 @@ class McpService {
|
|
|
824
825
|
else if (isPhaseCompletion) {
|
|
825
826
|
const inspection = (0, handoff_contracts_1.inspectPhaseCompletion)(marker, context);
|
|
826
827
|
if (inspection.missingStart)
|
|
827
|
-
phaseStartWarning = (0, handoff_contracts_1.buildPhaseStartWarning)(args.currentPhase);
|
|
828
|
+
phaseStartWarning = (0, handoff_contracts_1.buildPhaseStartWarning)(args.currentPhase, result.nextPhase ?? undefined);
|
|
828
829
|
const completed = (0, handoff_contracts_1.commitPhaseCompletion)(marker, inspection, { ...context, timestamp });
|
|
829
830
|
this.phaseStartMarkers.set(markerKey, completed);
|
|
830
831
|
if (args.status === 'complete' && result.nextPhase === null) {
|
|
@@ -924,6 +925,7 @@ class McpService {
|
|
|
924
925
|
status: args.status,
|
|
925
926
|
evidence: args.evidence,
|
|
926
927
|
findings: args.findings,
|
|
928
|
+
requestInstructions: args.requestInstructions,
|
|
927
929
|
skipIncludes: true // ← the key difference: raw, no include resolution
|
|
928
930
|
});
|
|
929
931
|
return { content: [{ type: 'text', text: result.message }] };
|
|
@@ -254,6 +254,7 @@ class UsageAnalyticsService {
|
|
|
254
254
|
async logJobStart(jobId, jobName, userId, sessionId, issueNumber) {
|
|
255
255
|
const jobStartEvent = UsageAnalyticsService.createUsageEvent('job', jobName, userId, sessionId, true, {
|
|
256
256
|
action: 'start',
|
|
257
|
+
isReload: false,
|
|
257
258
|
issueNumber,
|
|
258
259
|
jobId
|
|
259
260
|
}, await this.resolveCategory(jobName), jobId);
|
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fraim",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.344",
|
|
4
4
|
"description": "FRAIM core CLI and MCP package.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"fraim": "bin/fraim.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
|
+
"dist/registry/scripts/artifact-paths.js",
|
|
11
|
+
"dist/registry/scripts/learning-usage/local-runtime.js",
|
|
10
12
|
"dist/registry/scripts/learning/learning-domains.json",
|
|
11
13
|
"dist/registry/scripts/learning/entry-format.js",
|
|
12
14
|
"dist/registry/scripts/learning/completion-state.js",
|