@renseiai/agentfactory 0.8.15 → 0.8.17
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/src/orchestrator/completion-contracts.js +1 -1
- package/dist/src/orchestrator/completion-contracts.test.js +3 -3
- package/dist/src/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/src/orchestrator/orchestrator.js +21 -1
- package/dist/src/orchestrator/session-backstop.d.ts.map +1 -1
- package/dist/src/orchestrator/session-backstop.js +113 -0
- package/dist/src/orchestrator/session-backstop.test.js +65 -0
- package/dist/src/providers/claude-provider.d.ts.map +1 -1
- package/dist/src/providers/claude-provider.js +8 -1
- package/package.json +2 -2
|
@@ -89,7 +89,7 @@ describe('validateCompletion', () => {
|
|
|
89
89
|
expect(result.missingFields).toContain('branch_pushed');
|
|
90
90
|
expect(result.backstopRecoverable).toContain('branch_pushed');
|
|
91
91
|
});
|
|
92
|
-
it('marks commits_present as
|
|
92
|
+
it('marks commits_present as backstop-capable', () => {
|
|
93
93
|
const contract = getCompletionContract('development');
|
|
94
94
|
const outputs = {
|
|
95
95
|
prUrl: 'https://github.com/org/repo/pull/1',
|
|
@@ -98,8 +98,8 @@ describe('validateCompletion', () => {
|
|
|
98
98
|
};
|
|
99
99
|
const result = validateCompletion(contract, outputs);
|
|
100
100
|
expect(result.satisfied).toBe(false);
|
|
101
|
-
expect(result.
|
|
102
|
-
expect(result.
|
|
101
|
+
expect(result.backstopRecoverable).toContain('commits_present');
|
|
102
|
+
expect(result.manualRequired).not.toContain('commits_present');
|
|
103
103
|
});
|
|
104
104
|
it('marks satisfied for QA with work result passed', () => {
|
|
105
105
|
const contract = getCompletionContract('qa');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/orchestrator.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1604,6 +1604,19 @@ export class AgentOrchestrator {
|
|
|
1604
1604
|
// Ignore
|
|
1605
1605
|
}
|
|
1606
1606
|
}
|
|
1607
|
+
// Clean up leftover directory shells (e.g., dirs with only .agent/ remaining
|
|
1608
|
+
// after git worktree remove succeeded but the directory wasn't fully deleted)
|
|
1609
|
+
if (existsSync(worktreePath)) {
|
|
1610
|
+
try {
|
|
1611
|
+
const entries = readdirSync(worktreePath).filter(e => e !== '.agent');
|
|
1612
|
+
if (entries.length === 0) {
|
|
1613
|
+
rmSync(worktreePath, { recursive: true, force: true });
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
catch {
|
|
1617
|
+
// Best-effort cleanup
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1607
1620
|
}
|
|
1608
1621
|
/**
|
|
1609
1622
|
* Write helper scripts into the worktree's .agent/ directory.
|
|
@@ -2448,8 +2461,15 @@ ORCHESTRATOR_INSTALL=1 exec pnpm add "$@"
|
|
|
2448
2461
|
if (agent.status === 'completed' && agent.worktreePath) {
|
|
2449
2462
|
const shouldPreserve = this.config.preserveWorkOnPrFailure ?? DEFAULT_CONFIG.preserveWorkOnPrFailure;
|
|
2450
2463
|
let shouldCleanup = true;
|
|
2464
|
+
// Only check for incomplete work on code-producing work types.
|
|
2465
|
+
// Non-code work types (research, backlog-creation, QA, refinement, etc.) use
|
|
2466
|
+
// worktrees for codebase exploration but don't produce commits/PRs. Checking
|
|
2467
|
+
// them triggers false "work not persisted" warnings from bootstrapped .agent/ files.
|
|
2468
|
+
const codeProducingWorkTypes = new Set(['development', 'inflight', 'coordination', 'inflight-coordination']);
|
|
2469
|
+
const agentWorkType = agent.workType ?? 'development';
|
|
2470
|
+
const isCodeProducingAgent = codeProducingWorkTypes.has(agentWorkType);
|
|
2451
2471
|
// Validate that PR was created or work was fully pushed before cleanup
|
|
2452
|
-
if (shouldPreserve) {
|
|
2472
|
+
if (shouldPreserve && isCodeProducingAgent) {
|
|
2453
2473
|
if (!agent.pullRequestUrl) {
|
|
2454
2474
|
// No PR detected - check for uncommitted/unpushed work
|
|
2455
2475
|
const incompleteCheck = checkForIncompleteWork(agent.worktreePath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-backstop.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/session-backstop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,OAAO,KAAK,EAEV,cAAc,EACd,kBAAkB,EAClB,0BAA0B,EAC1B,cAAc,EACf,MAAM,2BAA2B,CAAA;AAWlC,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,YAAY,CAAA;IACnB,iEAAiE;IACjE,aAAa,EAAE,OAAO,CAAA;IACtB,sDAAsD;IACtD,YAAY,EAAE,OAAO,CAAA;IACrB,2CAA2C;IAC3C,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,cAAc,GAAG,cAAc,CA8BzE;AAMD,uCAAuC;AACvC,MAAM,WAAW,eAAe;IAC9B,iFAAiF;IACjF,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,qEAAqE;IACrE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,cAAc,EACnB,OAAO,CAAC,EAAE,eAAe,GACxB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"session-backstop.d.ts","sourceRoot":"","sources":["../../../src/orchestrator/session-backstop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,OAAO,KAAK,EAEV,cAAc,EACd,kBAAkB,EAClB,0BAA0B,EAC1B,cAAc,EACf,MAAM,2BAA2B,CAAA;AAWlC,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,YAAY,CAAA;IACnB,iEAAiE;IACjE,aAAa,EAAE,OAAO,CAAA;IACtB,sDAAsD;IACtD,YAAY,EAAE,OAAO,CAAA;IACrB,2CAA2C;IAC3C,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,cAAc,GAAG,cAAc,CA8BzE;AAMD,uCAAuC;AACvC,MAAM,WAAW,eAAe;IAC9B,iFAAiF;IACjF,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,qEAAqE;IACrE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,cAAc,EACnB,OAAO,CAAC,EAAE,eAAe,GACxB,iBAAiB,CAwHnB;AAED,oCAAoC;AACpC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAA;IACnC,OAAO,EAAE,cAAc,CAAA;IACvB,UAAU,EAAE,0BAA0B,GAAG,IAAI,CAAA;IAC7C,QAAQ,EAAE,cAAc,CAAA;IACxB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC;AAyUD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI,CA8C9E"}
|
|
@@ -91,6 +91,27 @@ export function runBackstop(ctx, options) {
|
|
|
91
91
|
const actions = [];
|
|
92
92
|
for (const fieldType of validation.backstopRecoverable) {
|
|
93
93
|
switch (fieldType) {
|
|
94
|
+
case 'commits_present': {
|
|
95
|
+
// Auto-commit uncommitted changes for code-producing work types only
|
|
96
|
+
if (!ctx.agent.worktreePath) {
|
|
97
|
+
actions.push({
|
|
98
|
+
field: 'commits_present',
|
|
99
|
+
action: 'skipped — no worktree path',
|
|
100
|
+
success: false,
|
|
101
|
+
});
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
if (options?.dryRun) {
|
|
105
|
+
actions.push({ field: 'commits_present', action: 'would auto-commit uncommitted changes', success: false, detail: 'dry-run' });
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
const commitResult = backstopCommitChanges(ctx.agent.worktreePath, ctx.agent.identifier);
|
|
109
|
+
actions.push(commitResult);
|
|
110
|
+
if (commitResult.success) {
|
|
111
|
+
outputs.commitsPresent = true;
|
|
112
|
+
}
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
94
115
|
case 'branch_pushed': {
|
|
95
116
|
if (options?.dryRun) {
|
|
96
117
|
actions.push({ field: 'branch_pushed', action: 'would push branch', success: false, detail: 'dry-run' });
|
|
@@ -262,10 +283,102 @@ function backstopPushBranch(worktreePath) {
|
|
|
262
283
|
};
|
|
263
284
|
}
|
|
264
285
|
catch (error) {
|
|
286
|
+
// If push failed due to diverged history (e.g., agent rewrote commits),
|
|
287
|
+
// retry with --force-with-lease on feature branches. This is safe because
|
|
288
|
+
// force-with-lease won't overwrite commits pushed by others.
|
|
289
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
290
|
+
if (/non-fast-forward|rejected/.test(errorMsg)) {
|
|
291
|
+
try {
|
|
292
|
+
const currentBranch = execSync('git branch --show-current', {
|
|
293
|
+
cwd: worktreePath,
|
|
294
|
+
encoding: 'utf-8',
|
|
295
|
+
timeout: 10000,
|
|
296
|
+
}).trim();
|
|
297
|
+
// Verify we have local commits ahead of main (genuine rewrite, not empty branch)
|
|
298
|
+
const aheadCount = execSync('git rev-list --count main..HEAD', {
|
|
299
|
+
cwd: worktreePath,
|
|
300
|
+
encoding: 'utf-8',
|
|
301
|
+
timeout: 10000,
|
|
302
|
+
}).trim();
|
|
303
|
+
if (parseInt(aheadCount, 10) > 0 && currentBranch !== 'main' && currentBranch !== 'master') {
|
|
304
|
+
execSync(`git push --force-with-lease -u origin ${currentBranch}`, {
|
|
305
|
+
cwd: worktreePath,
|
|
306
|
+
encoding: 'utf-8',
|
|
307
|
+
timeout: 60000,
|
|
308
|
+
});
|
|
309
|
+
return {
|
|
310
|
+
field: 'branch_pushed',
|
|
311
|
+
action: 'force-pushed branch (diverged history recovered via --force-with-lease)',
|
|
312
|
+
success: true,
|
|
313
|
+
detail: currentBranch,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
catch (retryError) {
|
|
318
|
+
return {
|
|
319
|
+
field: 'branch_pushed',
|
|
320
|
+
action: 'failed to push branch (force-with-lease retry also failed)',
|
|
321
|
+
success: false,
|
|
322
|
+
detail: retryError instanceof Error ? retryError.message : String(retryError),
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
}
|
|
265
326
|
return {
|
|
266
327
|
field: 'branch_pushed',
|
|
267
328
|
action: 'failed to push branch',
|
|
268
329
|
success: false,
|
|
330
|
+
detail: errorMsg,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function backstopCommitChanges(worktreePath, identifier) {
|
|
335
|
+
try {
|
|
336
|
+
// Check if there are actually uncommitted changes
|
|
337
|
+
const status = execSync('git status --porcelain', {
|
|
338
|
+
cwd: worktreePath,
|
|
339
|
+
encoding: 'utf-8',
|
|
340
|
+
timeout: 10000,
|
|
341
|
+
}).trim();
|
|
342
|
+
if (status.length === 0) {
|
|
343
|
+
return {
|
|
344
|
+
field: 'commits_present',
|
|
345
|
+
action: 'skipped — no uncommitted changes to commit',
|
|
346
|
+
success: false,
|
|
347
|
+
detail: 'Worktree is clean',
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
// Stage all changes and commit
|
|
351
|
+
execSync('git add -A', {
|
|
352
|
+
cwd: worktreePath,
|
|
353
|
+
encoding: 'utf-8',
|
|
354
|
+
timeout: 30000,
|
|
355
|
+
});
|
|
356
|
+
execSync(`git commit -m "feat: ${identifier} (auto-committed by session backstop)"`, {
|
|
357
|
+
cwd: worktreePath,
|
|
358
|
+
encoding: 'utf-8',
|
|
359
|
+
timeout: 30000,
|
|
360
|
+
env: {
|
|
361
|
+
...process.env,
|
|
362
|
+
// Ensure commit succeeds even without global git config
|
|
363
|
+
GIT_AUTHOR_NAME: process.env.GIT_AUTHOR_NAME ?? 'AgentFactory Backstop',
|
|
364
|
+
GIT_AUTHOR_EMAIL: process.env.GIT_AUTHOR_EMAIL ?? 'backstop@agentfactory.dev',
|
|
365
|
+
GIT_COMMITTER_NAME: process.env.GIT_COMMITTER_NAME ?? 'AgentFactory Backstop',
|
|
366
|
+
GIT_COMMITTER_EMAIL: process.env.GIT_COMMITTER_EMAIL ?? 'backstop@agentfactory.dev',
|
|
367
|
+
},
|
|
368
|
+
});
|
|
369
|
+
const changedFiles = status.split('\n').length;
|
|
370
|
+
return {
|
|
371
|
+
field: 'commits_present',
|
|
372
|
+
action: `auto-committed ${changedFiles} file(s)`,
|
|
373
|
+
success: true,
|
|
374
|
+
detail: `${changedFiles} file(s) committed for ${identifier}`,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
catch (error) {
|
|
378
|
+
return {
|
|
379
|
+
field: 'commits_present',
|
|
380
|
+
action: 'failed to auto-commit changes',
|
|
381
|
+
success: false,
|
|
269
382
|
detail: error instanceof Error ? error.message : String(error),
|
|
270
383
|
};
|
|
271
384
|
}
|
|
@@ -188,6 +188,71 @@ describe('runBackstop', () => {
|
|
|
188
188
|
expect(result.validation.satisfied).toBe(false);
|
|
189
189
|
expect(result.backstop.remainingGaps).toContain('comment_posted');
|
|
190
190
|
});
|
|
191
|
+
it('auto-commits uncommitted changes for development work type', () => {
|
|
192
|
+
// collectSessionOutputs: no commits ahead of main, branch not pushed
|
|
193
|
+
mockExecSync
|
|
194
|
+
// --- collectSessionOutputs ---
|
|
195
|
+
.mockReturnValueOnce('SUP-123\n') // hasCommits: git branch
|
|
196
|
+
.mockReturnValueOnce('0\n') // hasCommits: rev-list (no commits)
|
|
197
|
+
.mockReturnValueOnce('SUP-123\n') // isBranchPushed: git branch
|
|
198
|
+
.mockReturnValueOnce('') // isBranchPushed: ls-remote (not pushed)
|
|
199
|
+
// --- backstopCommitChanges ---
|
|
200
|
+
.mockReturnValueOnce(' M src/foo.ts\n?? src/bar.ts\n') // git status --porcelain
|
|
201
|
+
.mockReturnValueOnce('') // git add -A
|
|
202
|
+
.mockReturnValueOnce('') // git commit
|
|
203
|
+
// --- backstopPushBranch ---
|
|
204
|
+
.mockReturnValueOnce('SUP-123\n') // git branch
|
|
205
|
+
.mockReturnValueOnce('') // git push
|
|
206
|
+
// --- backstopCreatePR ---
|
|
207
|
+
.mockReturnValueOnce('SUP-123\n') // git branch
|
|
208
|
+
.mockReturnValueOnce('[]') // gh pr list
|
|
209
|
+
.mockReturnValueOnce('https://github.com/org/repo/pull/99\n'); // gh pr create
|
|
210
|
+
const ctx = createSessionContext({
|
|
211
|
+
agent: createMockAgent({
|
|
212
|
+
workType: 'development',
|
|
213
|
+
worktreePath: '/tmp/worktree',
|
|
214
|
+
}),
|
|
215
|
+
});
|
|
216
|
+
const result = runBackstop(ctx);
|
|
217
|
+
const commitAction = result.backstop.actions.find(a => a.field === 'commits_present');
|
|
218
|
+
expect(commitAction).toBeDefined();
|
|
219
|
+
expect(commitAction.success).toBe(true);
|
|
220
|
+
expect(commitAction.action).toContain('auto-committed');
|
|
221
|
+
const pushAction = result.backstop.actions.find(a => a.field === 'branch_pushed');
|
|
222
|
+
expect(pushAction).toBeDefined();
|
|
223
|
+
expect(pushAction.success).toBe(true);
|
|
224
|
+
const prAction = result.backstop.actions.find(a => a.field === 'pr_url');
|
|
225
|
+
expect(prAction).toBeDefined();
|
|
226
|
+
expect(prAction.success).toBe(true);
|
|
227
|
+
});
|
|
228
|
+
it('does not auto-commit for non-code-producing work types', () => {
|
|
229
|
+
// QA work type has no commits_present requirement — backstop should not commit
|
|
230
|
+
const ctx = createSessionContext({
|
|
231
|
+
agent: createMockAgent({ workType: 'qa', worktreePath: '/tmp/worktree' }),
|
|
232
|
+
commentPosted: true,
|
|
233
|
+
});
|
|
234
|
+
const result = runBackstop(ctx);
|
|
235
|
+
const commitAction = result.backstop.actions.find(a => a.field === 'commits_present');
|
|
236
|
+
expect(commitAction).toBeUndefined();
|
|
237
|
+
});
|
|
238
|
+
it('skips auto-commit in dry-run mode', () => {
|
|
239
|
+
mockExecSync
|
|
240
|
+
.mockReturnValueOnce('SUP-123\n') // hasCommits: git branch
|
|
241
|
+
.mockReturnValueOnce('0\n') // hasCommits: rev-list
|
|
242
|
+
.mockReturnValueOnce('SUP-123\n') // isBranchPushed: git branch
|
|
243
|
+
.mockReturnValueOnce(''); // isBranchPushed: ls-remote
|
|
244
|
+
const ctx = createSessionContext({
|
|
245
|
+
agent: createMockAgent({
|
|
246
|
+
workType: 'development',
|
|
247
|
+
worktreePath: '/tmp/worktree',
|
|
248
|
+
}),
|
|
249
|
+
});
|
|
250
|
+
const result = runBackstop(ctx, { dryRun: true });
|
|
251
|
+
const commitAction = result.backstop.actions.find(a => a.field === 'commits_present');
|
|
252
|
+
expect(commitAction).toBeDefined();
|
|
253
|
+
expect(commitAction.success).toBe(false);
|
|
254
|
+
expect(commitAction.detail).toBe('dry-run');
|
|
255
|
+
});
|
|
191
256
|
it('reports satisfied for backlog-creation with sub-issues', () => {
|
|
192
257
|
const ctx = createSessionContext({
|
|
193
258
|
agent: createMockAgent({ workType: 'backlog-creation' }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-provider.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,WAAW,EAEZ,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"claude-provider.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,WAAW,EAEZ,MAAM,YAAY,CAAA;AAiFnB,qBAAa,cAAe,YAAW,aAAa;IAClD,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAS;IACjC,QAAQ,CAAC,YAAY;;;MAGX;IAEV,KAAK,CAAC,MAAM,EAAE,gBAAgB,GAAG,WAAW;IAI5C,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,WAAW;IAIhE,OAAO,CAAC,YAAY;CA8KrB;AAsND;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,cAAc,CAErD"}
|
|
@@ -47,7 +47,14 @@ const autonomousCanUseTool = async (toolName, input) => {
|
|
|
47
47
|
return { behavior: 'deny', message: 'reset --hard blocked' };
|
|
48
48
|
}
|
|
49
49
|
if (/git\s+push\b/.test(cmd) && /(--force\b|-f\b)/.test(cmd)) {
|
|
50
|
-
|
|
50
|
+
// Allow --force-with-lease on feature branches (safe: won't overwrite others' work)
|
|
51
|
+
if (/--force-with-lease/.test(cmd)) {
|
|
52
|
+
if (/\b(main|master)\b/.test(cmd)) {
|
|
53
|
+
return { behavior: 'deny', message: 'force push to main/master blocked' };
|
|
54
|
+
}
|
|
55
|
+
return { behavior: 'allow', updatedInput: input };
|
|
56
|
+
}
|
|
57
|
+
return { behavior: 'deny', message: 'force push blocked — use --force-with-lease for safety' };
|
|
51
58
|
}
|
|
52
59
|
if (/git\s+(checkout|switch)\b/.test(cmd)) {
|
|
53
60
|
return { behavior: 'deny', message: 'git checkout/switch blocked — agents must not change the checked-out branch' };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@renseiai/agentfactory",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Multi-agent fleet management for coding agents — orchestrator, providers, crash recovery",
|
|
6
6
|
"author": "Rensei AI (https://rensei.ai)",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"@types/node": "^22.5.4",
|
|
57
57
|
"typescript": "^5.7.3",
|
|
58
58
|
"vitest": "^3.2.3",
|
|
59
|
-
"@renseiai/create-agentfactory-app": "0.8.
|
|
59
|
+
"@renseiai/create-agentfactory-app": "0.8.17"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"build": "tsc",
|