@shepai/cli 1.19.0 → 1.20.1
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/eslint.config.mjs +4 -0
- package/dist/src/application/ports/output/agents/feature-agent-process.interface.d.ts +2 -1
- package/dist/src/application/ports/output/agents/feature-agent-process.interface.d.ts.map +1 -1
- package/dist/src/application/ports/output/agents/index.d.ts +1 -0
- package/dist/src/application/ports/output/agents/index.d.ts.map +1 -1
- package/dist/src/application/ports/output/agents/phase-timing-repository.interface.d.ts +44 -0
- package/dist/src/application/ports/output/agents/phase-timing-repository.interface.d.ts.map +1 -0
- package/dist/src/application/ports/output/agents/phase-timing-repository.interface.js +11 -0
- package/dist/src/application/use-cases/agents/approve-agent-run.use-case.d.ts.map +1 -1
- package/dist/src/application/use-cases/agents/approve-agent-run.use-case.js +6 -2
- package/dist/src/application/use-cases/agents/reject-agent-run.use-case.d.ts.map +1 -1
- package/dist/src/application/use-cases/agents/reject-agent-run.use-case.js +0 -1
- package/dist/src/application/use-cases/features/create/create-feature.use-case.d.ts +37 -0
- package/dist/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -0
- package/dist/src/application/use-cases/features/{create-feature.use-case.js → create/create-feature.use-case.js} +22 -70
- package/dist/src/application/use-cases/features/create/metadata-generator.d.ts +28 -0
- package/dist/src/application/use-cases/features/create/metadata-generator.d.ts.map +1 -0
- package/dist/src/application/use-cases/features/create/metadata-generator.js +109 -0
- package/dist/src/application/use-cases/features/create/slug-resolver.d.ts +24 -0
- package/dist/src/application/use-cases/features/create/slug-resolver.d.ts.map +1 -0
- package/dist/src/application/use-cases/features/create/slug-resolver.js +66 -0
- package/dist/src/application/use-cases/features/create/types.d.ts +16 -0
- package/dist/src/application/use-cases/features/create/types.d.ts.map +1 -0
- package/dist/src/application/use-cases/features/create/types.js +1 -0
- package/dist/src/application/use-cases/features/resume-feature.use-case.js +2 -2
- package/dist/src/domain/generated/output.d.ts +40 -6
- package/dist/src/domain/generated/output.d.ts.map +1 -1
- package/dist/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/src/infrastructure/di/container.js +12 -1
- package/dist/src/infrastructure/persistence/sqlite/mappers/agent-run.mapper.d.ts +1 -2
- package/dist/src/infrastructure/persistence/sqlite/mappers/agent-run.mapper.d.ts.map +1 -1
- package/dist/src/infrastructure/persistence/sqlite/mappers/agent-run.mapper.js +4 -4
- package/dist/src/infrastructure/persistence/sqlite/migrations.d.ts.map +1 -1
- package/dist/src/infrastructure/persistence/sqlite/migrations.js +31 -0
- package/dist/src/infrastructure/repositories/agent-run.repository.d.ts.map +1 -1
- package/dist/src/infrastructure/repositories/agent-run.repository.js +5 -9
- package/dist/src/infrastructure/repositories/sqlite-phase-timing.repository.d.ts +21 -0
- package/dist/src/infrastructure/repositories/sqlite-phase-timing.repository.d.ts.map +1 -0
- package/dist/src/infrastructure/repositories/sqlite-phase-timing.repository.js +100 -0
- package/dist/src/infrastructure/services/agents/common/executors/mock-executor.service.js +2 -2
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts +305 -13
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-graph.js +124 -7
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +2 -1
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.js +2 -2
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +2 -1
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +19 -7
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.js +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts +11 -2
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +46 -15
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/repair.node.d.ts +23 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/repair.node.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/repair.node.js +77 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/plan.schema.d.ts +4 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/plan.schema.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/plan.schema.js +54 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/research.schema.d.ts +3 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/research.schema.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/research.schema.js +24 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/spec.schema.d.ts +4 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/spec.schema.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/spec.schema.js +50 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/validation.d.ts +8 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/validation.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/validation.js +36 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/validate.node.d.ts +12 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/validate.node.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/validate.node.js +58 -0
- package/dist/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts +30 -0
- package/dist/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/phase-timing-context.js +68 -0
- package/dist/src/infrastructure/services/agents/feature-agent/state.d.ts +5 -1
- package/dist/src/infrastructure/services/agents/feature-agent/state.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/state.js +14 -1
- package/dist/src/presentation/cli/commands/feat/approve.command.d.ts +12 -0
- package/dist/src/presentation/cli/commands/feat/approve.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/feat/approve.command.js +48 -0
- package/dist/src/presentation/cli/commands/feat/index.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/index.js +7 -1
- package/dist/src/presentation/cli/commands/feat/ls.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/ls.command.js +13 -5
- package/dist/src/presentation/cli/commands/feat/new.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/new.command.js +35 -16
- package/dist/src/presentation/cli/commands/feat/reject.command.d.ts +12 -0
- package/dist/src/presentation/cli/commands/feat/reject.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/feat/reject.command.js +50 -0
- package/dist/src/presentation/cli/commands/feat/resolve-waiting-feature.d.ts +30 -0
- package/dist/src/presentation/cli/commands/feat/resolve-waiting-feature.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/feat/resolve-waiting-feature.js +57 -0
- package/dist/src/presentation/cli/commands/feat/review.command.d.ts +12 -0
- package/dist/src/presentation/cli/commands/feat/review.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/feat/review.command.js +49 -0
- package/dist/src/presentation/cli/commands/feat/show.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/show.command.js +51 -6
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/cache/.previewinfo +1 -1
- package/web/.next/cache/.rscinfo +1 -1
- package/web/.next/cache/config.json +3 -3
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +1 -1
- package/web/.next/required-server-files.json +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.html +2 -2
- package/web/.next/server/app/_not-found.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/index.html +2 -2
- package/web/.next/server/app/index.rsc +1 -1
- package/web/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/version.html +2 -2
- package/web/.next/server/app/version.rsc +1 -1
- package/web/.next/server/app/version.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
- package/web/.next/server/chunks/ssr/_19be0743._.js +1 -1
- package/web/.next/server/pages/404.html +2 -2
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- package/dist/src/application/use-cases/features/create-feature.use-case.d.ts +0 -43
- package/dist/src/application/use-cases/features/create-feature.use-case.d.ts.map +0 -1
- /package/web/.next/static/{nw4IT0rr_mE5Tx22X9OgO → xKJulVMYO_ZRGoqa6eM7G}/_buildManifest.js +0 -0
- /package/web/.next/static/{nw4IT0rr_mE5Tx22X9OgO → xKJulVMYO_ZRGoqa6eM7G}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{nw4IT0rr_mE5Tx22X9OgO → xKJulVMYO_ZRGoqa6eM7G}/_ssgManifest.js +0 -0
package/dist/eslint.config.mjs
CHANGED
|
@@ -28,11 +28,14 @@ export default tseslint.config(
|
|
|
28
28
|
// Build outputs
|
|
29
29
|
'dist/**',
|
|
30
30
|
'build/**',
|
|
31
|
+
'web/**',
|
|
31
32
|
'**/.next/**',
|
|
32
33
|
'out/**',
|
|
33
34
|
'**/storybook-static/**',
|
|
34
35
|
// Dependencies
|
|
35
36
|
'node_modules/**',
|
|
37
|
+
// Git worktrees (parallel development checkouts)
|
|
38
|
+
'.worktrees/**',
|
|
36
39
|
// Generated files
|
|
37
40
|
'apis/**',
|
|
38
41
|
'*.generated.*',
|
|
@@ -50,6 +53,7 @@ export default tseslint.config(
|
|
|
50
53
|
'*.config.js',
|
|
51
54
|
'*.config.mjs',
|
|
52
55
|
'*.config.cjs',
|
|
56
|
+
'*.config.ts',
|
|
53
57
|
],
|
|
54
58
|
},
|
|
55
59
|
// =============================================================================
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* - Application layer depends on this interface
|
|
10
10
|
* - Infrastructure layer provides concrete implementation
|
|
11
11
|
*/
|
|
12
|
+
import type { ApprovalGates } from '../../../../domain/generated/output.js';
|
|
12
13
|
/**
|
|
13
14
|
* Service interface for feature agent background process management.
|
|
14
15
|
*/
|
|
@@ -23,7 +24,7 @@ export interface IFeatureAgentProcessService {
|
|
|
23
24
|
* @returns The PID of the spawned process
|
|
24
25
|
*/
|
|
25
26
|
spawn(featureId: string, runId: string, repoPath: string, specDir: string, worktreePath?: string, options?: {
|
|
26
|
-
|
|
27
|
+
approvalGates?: ApprovalGates;
|
|
27
28
|
resume?: boolean;
|
|
28
29
|
threadId?: string;
|
|
29
30
|
resumeFromInterrupt?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-agent-process.interface.d.ts","sourceRoot":"","sources":["../../../../../../src/application/ports/output/agents/feature-agent-process.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;;;;;OAQG;IACH,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;QACR,
|
|
1
|
+
{"version":3,"file":"feature-agent-process.interface.d.ts","sourceRoot":"","sources":["../../../../../../src/application/ports/output/agents/feature-agent-process.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;;;;;OAQG;IACH,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;QACR,aAAa,CAAC,EAAE,aAAa,CAAC;QAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;KAC/B,GACA,MAAM,CAAC;IAEV;;;;;OAKG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAE9B;;;;;OAKG;IACH,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD"}
|
|
@@ -9,6 +9,7 @@ export type { IAgentExecutorProvider } from './agent-executor-provider.interface
|
|
|
9
9
|
export type { IAgentRegistry, AgentDefinitionWithFactory } from './agent-registry.interface.js';
|
|
10
10
|
export type { IAgentRunner, AgentRunOptions } from './agent-runner.interface.js';
|
|
11
11
|
export type { IAgentRunRepository } from './agent-run-repository.interface.js';
|
|
12
|
+
export type { IPhaseTimingRepository } from './phase-timing-repository.interface.js';
|
|
12
13
|
export type { IAgentValidator, AgentValidationResult } from './agent-validator.interface.js';
|
|
13
14
|
export type { IFeatureAgentProcessService } from './feature-agent-process.interface.js';
|
|
14
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/application/ports/output/agents/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AACnF,YAAY,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,YAAY,EAAE,cAAc,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAChG,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACjF,YAAY,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,YAAY,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC7F,YAAY,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/application/ports/output/agents/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AACnF,YAAY,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,YAAY,EAAE,cAAc,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAChG,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACjF,YAAY,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,YAAY,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AACrF,YAAY,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC7F,YAAY,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase Timing Repository Interface
|
|
3
|
+
*
|
|
4
|
+
* Output port for PhaseTiming persistence operations.
|
|
5
|
+
* Records timing data for each agent graph node execution.
|
|
6
|
+
*
|
|
7
|
+
* Following Clean Architecture:
|
|
8
|
+
* - Domain and Application layers depend on this interface
|
|
9
|
+
* - Infrastructure layer provides concrete implementations
|
|
10
|
+
*/
|
|
11
|
+
import type { PhaseTiming } from '../../../../domain/generated/output.js';
|
|
12
|
+
/**
|
|
13
|
+
* Repository interface for PhaseTiming entity persistence.
|
|
14
|
+
*/
|
|
15
|
+
export interface IPhaseTimingRepository {
|
|
16
|
+
/**
|
|
17
|
+
* Save a new phase timing record.
|
|
18
|
+
*
|
|
19
|
+
* @param phaseTiming - The phase timing to persist
|
|
20
|
+
*/
|
|
21
|
+
save(phaseTiming: PhaseTiming): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Update a phase timing record (typically to set completedAt and durationMs).
|
|
24
|
+
*
|
|
25
|
+
* @param id - The phase timing ID
|
|
26
|
+
* @param updates - Fields to update
|
|
27
|
+
*/
|
|
28
|
+
update(id: string, updates: Partial<Pick<PhaseTiming, 'completedAt' | 'durationMs'>>): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Find all phase timings for an agent run.
|
|
31
|
+
*
|
|
32
|
+
* @param agentRunId - The agent run ID
|
|
33
|
+
* @returns Array of phase timings ordered by creation
|
|
34
|
+
*/
|
|
35
|
+
findByRunId(agentRunId: string): Promise<PhaseTiming[]>;
|
|
36
|
+
/**
|
|
37
|
+
* Find all phase timings for a feature (via agent_runs join).
|
|
38
|
+
*
|
|
39
|
+
* @param featureId - The feature ID
|
|
40
|
+
* @returns Array of phase timings ordered by creation
|
|
41
|
+
*/
|
|
42
|
+
findByFeatureId(featureId: string): Promise<PhaseTiming[]>;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=phase-timing-repository.interface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phase-timing-repository.interface.d.ts","sourceRoot":"","sources":["../../../../../../src/application/ports/output/agents/phase-timing-repository.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AAE1E;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;;;;OAKG;IACH,MAAM,CACJ,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,GAAG,YAAY,CAAC,CAAC,GAChE,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;;OAKG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAExD;;;;;OAKG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CAC5D"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase Timing Repository Interface
|
|
3
|
+
*
|
|
4
|
+
* Output port for PhaseTiming persistence operations.
|
|
5
|
+
* Records timing data for each agent graph node execution.
|
|
6
|
+
*
|
|
7
|
+
* Following Clean Architecture:
|
|
8
|
+
* - Domain and Application layers depend on this interface
|
|
9
|
+
* - Infrastructure layer provides concrete implementations
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approve-agent-run.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/application/use-cases/agents/approve-agent-run.use-case.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AACvG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8DAA8D,CAAC;AAChH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAC1G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAGlG,qBACa,sBAAsB;IAG/B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAEnC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,eAAe;gBANf,kBAAkB,EAAE,mBAAmB,EAEvC,cAAc,EAAE,2BAA2B,EAE3C,iBAAiB,EAAE,kBAAkB,EAErC,eAAe,EAAE,gBAAgB;IAG9C,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"approve-agent-run.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/application/use-cases/agents/approve-agent-run.use-case.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AACvG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8DAA8D,CAAC;AAChH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAC1G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAGlG,qBACa,sBAAsB;IAG/B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAEnC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,eAAe;gBANf,kBAAkB,EAAE,mBAAmB,EAEvC,cAAc,EAAE,2BAA2B,EAE3C,iBAAiB,EAAE,kBAAkB,EAErC,eAAe,EAAE,gBAAgB;IAG9C,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CA0C1E"}
|
|
@@ -48,11 +48,15 @@ let ApproveAgentRunUseCase = class ApproveAgentRunUseCase {
|
|
|
48
48
|
: repoPath;
|
|
49
49
|
const now = new Date();
|
|
50
50
|
await this.agentRunRepository.updateStatus(id, AgentRunStatus.running, {
|
|
51
|
-
approvalStatus: 'approved',
|
|
52
51
|
updatedAt: now,
|
|
53
52
|
});
|
|
54
53
|
this.processService.spawn(run.featureId ?? '', id, repoPath, worktreePath, // specDir = worktree path (same as initial spawn)
|
|
55
|
-
worktreePath, {
|
|
54
|
+
worktreePath, {
|
|
55
|
+
resume: true,
|
|
56
|
+
approvalGates: run.approvalGates,
|
|
57
|
+
threadId: run.threadId,
|
|
58
|
+
resumeFromInterrupt: true,
|
|
59
|
+
});
|
|
56
60
|
return { approved: true, reason: 'Approved and resumed' };
|
|
57
61
|
}
|
|
58
62
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reject-agent-run.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/application/use-cases/agents/reject-agent-run.use-case.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AAGvG,qBACa,qBAAqB;IAG9B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBAAlB,kBAAkB,EAAE,mBAAmB;IAGpD,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"reject-agent-run.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/application/use-cases/agents/reject-agent-run.use-case.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AAGvG,qBACa,qBAAqB;IAG9B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBAAlB,kBAAkB,EAAE,mBAAmB;IAGpD,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAsB3F"}
|
|
@@ -36,7 +36,6 @@ let RejectAgentRunUseCase = class RejectAgentRunUseCase {
|
|
|
36
36
|
}
|
|
37
37
|
const now = new Date();
|
|
38
38
|
await this.agentRunRepository.updateStatus(id, AgentRunStatus.cancelled, {
|
|
39
|
-
approvalStatus: 'rejected',
|
|
40
39
|
error: reason ?? 'Rejected by user',
|
|
41
40
|
completedAt: now,
|
|
42
41
|
updatedAt: now,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create Feature Use Case
|
|
3
|
+
*
|
|
4
|
+
* Creates a new feature entity with a git worktree for isolated development,
|
|
5
|
+
* initializes the spec directory with YAML templates, then spawns the
|
|
6
|
+
* feature agent to begin autonomous SDLC processing.
|
|
7
|
+
*
|
|
8
|
+
* Business Rules:
|
|
9
|
+
* - Metadata generation delegated to MetadataGenerator service
|
|
10
|
+
* - Slug uniqueness delegated to SlugResolver service
|
|
11
|
+
* - Full user input is preserved as-is in spec.yaml
|
|
12
|
+
* - A git worktree is created at ~/.shep/repos/HASH/wt/SLUG/
|
|
13
|
+
* - Spec YAML files are scaffolded at WORKTREE/specs/NNN-SLUG/
|
|
14
|
+
* - Feature agent is spawned with the spec dir path
|
|
15
|
+
* - specPath is persisted on the Feature record
|
|
16
|
+
* - Initial lifecycle is Requirements
|
|
17
|
+
*/
|
|
18
|
+
import type { IFeatureRepository } from '../../../ports/output/repositories/feature-repository.interface.js';
|
|
19
|
+
import type { IWorktreeService } from '../../../ports/output/services/worktree-service.interface.js';
|
|
20
|
+
import type { IFeatureAgentProcessService } from '../../../ports/output/agents/feature-agent-process.interface.js';
|
|
21
|
+
import type { IAgentRunRepository } from '../../../ports/output/agents/agent-run-repository.interface.js';
|
|
22
|
+
import type { ISpecInitializerService } from '../../../ports/output/services/spec-initializer.interface.js';
|
|
23
|
+
import { MetadataGenerator } from './metadata-generator.js';
|
|
24
|
+
import { SlugResolver } from './slug-resolver.js';
|
|
25
|
+
import type { CreateFeatureInput, CreateFeatureResult } from './types.js';
|
|
26
|
+
export declare class CreateFeatureUseCase {
|
|
27
|
+
private readonly featureRepo;
|
|
28
|
+
private readonly worktreeService;
|
|
29
|
+
private readonly agentProcess;
|
|
30
|
+
private readonly runRepository;
|
|
31
|
+
private readonly specInitializer;
|
|
32
|
+
private readonly metadataGenerator;
|
|
33
|
+
private readonly slugResolver;
|
|
34
|
+
constructor(featureRepo: IFeatureRepository, worktreeService: IWorktreeService, agentProcess: IFeatureAgentProcessService, runRepository: IAgentRunRepository, specInitializer: ISpecInitializerService, metadataGenerator: MetadataGenerator, slugResolver: SlugResolver);
|
|
35
|
+
execute(input: CreateFeatureInput): Promise<CreateFeatureResult>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=create-feature.use-case.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-feature.use-case.d.ts","sourceRoot":"","sources":["../../../../../../src/application/use-cases/features/create/create-feature.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oEAAoE,CAAC;AAC7G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8DAA8D,CAAC;AACrG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,iEAAiE,CAAC;AACnH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gEAAgE,CAAC;AAC1G,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8DAA8D,CAAC;AAE5G,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE1E,qBACa,oBAAoB;IAG7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAE5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAEhC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAE9B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAEhC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAZZ,WAAW,EAAE,kBAAkB,EAE/B,eAAe,EAAE,gBAAgB,EAEjC,YAAY,EAAE,2BAA2B,EAEzC,aAAa,EAAE,mBAAmB,EAElC,eAAe,EAAE,uBAAuB,EAExC,iBAAiB,EAAE,iBAAiB,EAEpC,YAAY,EAAE,YAAY;IAGvC,OAAO,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAyEvE"}
|
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
* feature agent to begin autonomous SDLC processing.
|
|
7
7
|
*
|
|
8
8
|
* Business Rules:
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
9
|
+
* - Metadata generation delegated to MetadataGenerator service
|
|
10
|
+
* - Slug uniqueness delegated to SlugResolver service
|
|
11
11
|
* - Full user input is preserved as-is in spec.yaml
|
|
12
|
-
* - Slug must be unique within the repository
|
|
13
12
|
* - A git worktree is created at ~/.shep/repos/HASH/wt/SLUG/
|
|
14
13
|
* - Spec YAML files are scaffolded at WORKTREE/specs/NNN-SLUG/
|
|
15
14
|
* - Feature agent is spawned with the spec dir path
|
|
@@ -30,34 +29,32 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
30
29
|
};
|
|
31
30
|
import { injectable, inject } from 'tsyringe';
|
|
32
31
|
import { randomUUID } from 'node:crypto';
|
|
33
|
-
import { SdlcLifecycle } from '
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
|
|
37
|
-
const MAX_INPUT_FOR_AI = 500;
|
|
32
|
+
import { SdlcLifecycle, AgentRunStatus } from '../../../../domain/generated/output.js';
|
|
33
|
+
import { getSettings } from '../../../../infrastructure/services/settings.service.js';
|
|
34
|
+
import { MetadataGenerator } from './metadata-generator.js';
|
|
35
|
+
import { SlugResolver } from './slug-resolver.js';
|
|
38
36
|
let CreateFeatureUseCase = class CreateFeatureUseCase {
|
|
39
37
|
featureRepo;
|
|
40
38
|
worktreeService;
|
|
41
39
|
agentProcess;
|
|
42
40
|
runRepository;
|
|
43
41
|
specInitializer;
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
metadataGenerator;
|
|
43
|
+
slugResolver;
|
|
44
|
+
constructor(featureRepo, worktreeService, agentProcess, runRepository, specInitializer, metadataGenerator, slugResolver) {
|
|
46
45
|
this.featureRepo = featureRepo;
|
|
47
46
|
this.worktreeService = worktreeService;
|
|
48
47
|
this.agentProcess = agentProcess;
|
|
49
48
|
this.runRepository = runRepository;
|
|
50
49
|
this.specInitializer = specInitializer;
|
|
51
|
-
this.
|
|
50
|
+
this.metadataGenerator = metadataGenerator;
|
|
51
|
+
this.slugResolver = slugResolver;
|
|
52
52
|
}
|
|
53
53
|
async execute(input) {
|
|
54
|
-
const metadata = await this.generateMetadata(input.userInput);
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
if (existing) {
|
|
59
|
-
throw new Error(`Feature with slug "${slug}" already exists in this repository`);
|
|
60
|
-
}
|
|
54
|
+
const metadata = await this.metadataGenerator.generateMetadata(input.userInput);
|
|
55
|
+
const originalSlug = metadata.slug;
|
|
56
|
+
// Find a unique slug — the branch may exist from a previous (deleted) feature
|
|
57
|
+
const { slug, branch, warning } = await this.slugResolver.resolveUniqueSlug(originalSlug, input.repositoryPath);
|
|
61
58
|
// Determine next feature number for this repo
|
|
62
59
|
const existingFeatures = await this.featureRepo.list({
|
|
63
60
|
repositoryPath: input.repositoryPath,
|
|
@@ -97,63 +94,16 @@ let CreateFeatureUseCase = class CreateFeatureUseCase {
|
|
|
97
94
|
threadId: randomUUID(),
|
|
98
95
|
featureId: feature.id,
|
|
99
96
|
repositoryPath: input.repositoryPath,
|
|
100
|
-
...(input.
|
|
97
|
+
...(input.approvalGates ? { approvalGates: input.approvalGates } : {}),
|
|
101
98
|
createdAt: now.toISOString(),
|
|
102
99
|
updatedAt: now.toISOString(),
|
|
103
100
|
};
|
|
104
101
|
await this.runRepository.create(agentRun);
|
|
105
102
|
this.agentProcess.spawn(feature.id, runId, input.repositoryPath, specDir, worktreePath, {
|
|
106
|
-
...(input.
|
|
103
|
+
...(input.approvalGates ? { approvalGates: input.approvalGates } : {}),
|
|
107
104
|
threadId: agentRun.threadId,
|
|
108
105
|
});
|
|
109
|
-
return feature;
|
|
110
|
-
}
|
|
111
|
-
async generateMetadata(userInput) {
|
|
112
|
-
try {
|
|
113
|
-
const executor = this.executorProvider.getExecutor();
|
|
114
|
-
const truncated = userInput.length > MAX_INPUT_FOR_AI
|
|
115
|
-
? `${userInput.slice(0, MAX_INPUT_FOR_AI)}...`
|
|
116
|
-
: userInput;
|
|
117
|
-
const prompt = `Generate feature metadata from this user request:
|
|
118
|
-
"${truncated}"
|
|
119
|
-
|
|
120
|
-
Return ONLY a JSON object with these fields:
|
|
121
|
-
- slug: kebab-case identifier, 2-4 words max (e.g., "github-oauth-login")
|
|
122
|
-
- name: short human-readable title (e.g., "GitHub OAuth Login")
|
|
123
|
-
- description: refined 1-2 sentence description
|
|
124
|
-
|
|
125
|
-
JSON only, no markdown fences.`;
|
|
126
|
-
const result = await executor.execute(prompt, {
|
|
127
|
-
maxTurns: 1,
|
|
128
|
-
allowedTools: [],
|
|
129
|
-
silent: true,
|
|
130
|
-
});
|
|
131
|
-
const parsed = JSON.parse(result.result);
|
|
132
|
-
if (!parsed.slug || !parsed.name || !parsed.description) {
|
|
133
|
-
throw new Error('Missing required fields in AI response');
|
|
134
|
-
}
|
|
135
|
-
return {
|
|
136
|
-
slug: this.toSlug(parsed.slug),
|
|
137
|
-
name: parsed.name,
|
|
138
|
-
description: parsed.description,
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
catch {
|
|
142
|
-
// Fallback to regex-based slug generation
|
|
143
|
-
return {
|
|
144
|
-
slug: this.toSlug(userInput),
|
|
145
|
-
name: userInput,
|
|
146
|
-
description: userInput,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
toSlug(text) {
|
|
151
|
-
return text
|
|
152
|
-
.toLowerCase()
|
|
153
|
-
.replace(/[^a-z0-9\s-]/g, '')
|
|
154
|
-
.replace(/\s+/g, '-')
|
|
155
|
-
.replace(/-+/g, '-')
|
|
156
|
-
.replace(/^-|-$/g, '');
|
|
106
|
+
return { feature, warning };
|
|
157
107
|
}
|
|
158
108
|
};
|
|
159
109
|
CreateFeatureUseCase = __decorate([
|
|
@@ -163,7 +113,9 @@ CreateFeatureUseCase = __decorate([
|
|
|
163
113
|
__param(2, inject('IFeatureAgentProcessService')),
|
|
164
114
|
__param(3, inject('IAgentRunRepository')),
|
|
165
115
|
__param(4, inject('ISpecInitializerService')),
|
|
166
|
-
__param(5, inject(
|
|
167
|
-
|
|
116
|
+
__param(5, inject(MetadataGenerator)),
|
|
117
|
+
__param(6, inject(SlugResolver)),
|
|
118
|
+
__metadata("design:paramtypes", [Object, Object, Object, Object, Object, MetadataGenerator,
|
|
119
|
+
SlugResolver])
|
|
168
120
|
], CreateFeatureUseCase);
|
|
169
121
|
export { CreateFeatureUseCase };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetadataGenerator
|
|
3
|
+
*
|
|
4
|
+
* Generates feature metadata (slug, name, description) from user input
|
|
5
|
+
* via AI call through IAgentExecutorProvider.
|
|
6
|
+
* Errors are propagated to the caller.
|
|
7
|
+
*/
|
|
8
|
+
import type { IAgentExecutorProvider } from '../../../ports/output/agents/agent-executor-provider.interface.js';
|
|
9
|
+
import type { FeatureMetadata } from './types.js';
|
|
10
|
+
export declare class MetadataGenerator {
|
|
11
|
+
private readonly executorProvider;
|
|
12
|
+
constructor(executorProvider: IAgentExecutorProvider);
|
|
13
|
+
/**
|
|
14
|
+
* Generate feature metadata from user input via AI.
|
|
15
|
+
* Errors are propagated to the caller.
|
|
16
|
+
*/
|
|
17
|
+
generateMetadata(userInput: string): Promise<FeatureMetadata>;
|
|
18
|
+
/**
|
|
19
|
+
* Strip markdown code fence wrappers (```lang ... ```) if present at start/end.
|
|
20
|
+
*/
|
|
21
|
+
private stripCodeFence;
|
|
22
|
+
/**
|
|
23
|
+
* Convert text to kebab-case slug with 50-char limit.
|
|
24
|
+
* Removes special characters, collapses spaces, limits length.
|
|
25
|
+
*/
|
|
26
|
+
private toSlug;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=metadata-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-generator.d.ts","sourceRoot":"","sources":["../../../../../../src/application/use-cases/features/create/metadata-generator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mEAAmE,CAAC;AAChH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKlD,qBACa,iBAAiB;IAG1B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAAhB,gBAAgB,EAAE,sBAAsB;IAG3D;;;OAGG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAyCnE;;OAEG;IACH,OAAO,CAAC,cAAc;IAgBtB;;;OAGG;IACH,OAAO,CAAC,MAAM;CAgBf"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetadataGenerator
|
|
3
|
+
*
|
|
4
|
+
* Generates feature metadata (slug, name, description) from user input
|
|
5
|
+
* via AI call through IAgentExecutorProvider.
|
|
6
|
+
* Errors are propagated to the caller.
|
|
7
|
+
*/
|
|
8
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
9
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
10
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
11
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
12
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
13
|
+
};
|
|
14
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
15
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
16
|
+
};
|
|
17
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
18
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
19
|
+
};
|
|
20
|
+
import { injectable, inject } from 'tsyringe';
|
|
21
|
+
/** Maximum characters of user input sent to the AI for metadata generation. */
|
|
22
|
+
const MAX_INPUT_FOR_AI = 500;
|
|
23
|
+
let MetadataGenerator = class MetadataGenerator {
|
|
24
|
+
executorProvider;
|
|
25
|
+
constructor(executorProvider) {
|
|
26
|
+
this.executorProvider = executorProvider;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Generate feature metadata from user input via AI.
|
|
30
|
+
* Errors are propagated to the caller.
|
|
31
|
+
*/
|
|
32
|
+
async generateMetadata(userInput) {
|
|
33
|
+
const executor = this.executorProvider.getExecutor();
|
|
34
|
+
const truncated = userInput.length > MAX_INPUT_FOR_AI
|
|
35
|
+
? `${userInput.slice(0, MAX_INPUT_FOR_AI)}...`
|
|
36
|
+
: userInput;
|
|
37
|
+
const prompt = `Analyze this user request and extract the CORE feature intent. Condense to essential concepts.
|
|
38
|
+
|
|
39
|
+
User request:
|
|
40
|
+
"${truncated}"
|
|
41
|
+
|
|
42
|
+
IMPORTANT: Don't use the request as-is. Extract the key feature being requested and improve the wording.
|
|
43
|
+
|
|
44
|
+
Return ONLY a JSON object with these fields:
|
|
45
|
+
- slug: kebab-case identifier, 2-4 words MAX. Extract the core feature name (e.g., "github-oauth-login" from "add github oauth")
|
|
46
|
+
- name: polished, professional title (improve upon user's wording)
|
|
47
|
+
- description: refined 1-2 sentence description that captures the feature essence (not the request verbatim)
|
|
48
|
+
|
|
49
|
+
JSON only, no markdown fences.`;
|
|
50
|
+
const result = await executor.execute(prompt, {
|
|
51
|
+
maxTurns: 1,
|
|
52
|
+
allowedTools: [],
|
|
53
|
+
silent: true,
|
|
54
|
+
});
|
|
55
|
+
const cleaned = this.stripCodeFence(result.result);
|
|
56
|
+
const parsed = JSON.parse(cleaned);
|
|
57
|
+
if (!parsed.slug || !parsed.name || !parsed.description) {
|
|
58
|
+
throw new Error('Missing required fields in AI response');
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
slug: this.toSlug(parsed.slug),
|
|
62
|
+
name: parsed.name,
|
|
63
|
+
description: parsed.description,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Strip markdown code fence wrappers (```lang ... ```) if present at start/end.
|
|
68
|
+
*/
|
|
69
|
+
stripCodeFence(text) {
|
|
70
|
+
const trimmed = text.trim();
|
|
71
|
+
if (!trimmed.startsWith('```')) {
|
|
72
|
+
return trimmed;
|
|
73
|
+
}
|
|
74
|
+
// Find end of first line (```json or ```anything)
|
|
75
|
+
const firstNewline = trimmed.indexOf('\n');
|
|
76
|
+
if (firstNewline === -1) {
|
|
77
|
+
return trimmed;
|
|
78
|
+
}
|
|
79
|
+
if (!trimmed.endsWith('```')) {
|
|
80
|
+
return trimmed;
|
|
81
|
+
}
|
|
82
|
+
return trimmed.slice(firstNewline + 1, trimmed.length - 3).trim();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Convert text to kebab-case slug with 50-char limit.
|
|
86
|
+
* Removes special characters, collapses spaces, limits length.
|
|
87
|
+
*/
|
|
88
|
+
toSlug(text) {
|
|
89
|
+
const slug = text
|
|
90
|
+
.toLowerCase()
|
|
91
|
+
.replace(/[^a-z0-9\s-]/g, '')
|
|
92
|
+
.replace(/\s+/g, '-')
|
|
93
|
+
.replace(/-+/g, '-')
|
|
94
|
+
.replace(/^-|-$/g, '');
|
|
95
|
+
// Limit to ~50 chars, cutting at a word boundary
|
|
96
|
+
if (slug.length <= 50) {
|
|
97
|
+
return slug;
|
|
98
|
+
}
|
|
99
|
+
const truncated = slug.slice(0, 50);
|
|
100
|
+
const lastDash = truncated.lastIndexOf('-');
|
|
101
|
+
return lastDash > 10 ? truncated.slice(0, lastDash) : truncated;
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
MetadataGenerator = __decorate([
|
|
105
|
+
injectable(),
|
|
106
|
+
__param(0, inject('IAgentExecutorProvider')),
|
|
107
|
+
__metadata("design:paramtypes", [Object])
|
|
108
|
+
], MetadataGenerator);
|
|
109
|
+
export { MetadataGenerator };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SlugResolver
|
|
3
|
+
*
|
|
4
|
+
* Resolves unique slugs by checking against database and git branches.
|
|
5
|
+
* Ensures no slug collision by appending numeric suffixes (-2, -3, etc.)
|
|
6
|
+
*/
|
|
7
|
+
import type { IFeatureRepository } from '../../../ports/output/repositories/feature-repository.interface.js';
|
|
8
|
+
import type { IWorktreeService } from '../../../ports/output/services/worktree-service.interface.js';
|
|
9
|
+
export interface SlugResolutionResult {
|
|
10
|
+
slug: string;
|
|
11
|
+
branch: string;
|
|
12
|
+
warning?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare class SlugResolver {
|
|
15
|
+
private readonly featureRepo;
|
|
16
|
+
private readonly worktreeService;
|
|
17
|
+
constructor(featureRepo: IFeatureRepository, worktreeService: IWorktreeService);
|
|
18
|
+
/**
|
|
19
|
+
* Find a unique slug by checking both the feature DB and git branches.
|
|
20
|
+
* If the original slug conflicts, appends -2, -3, etc. until a free one is found.
|
|
21
|
+
*/
|
|
22
|
+
resolveUniqueSlug(originalSlug: string, repositoryPath: string): Promise<SlugResolutionResult>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=slug-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slug-resolver.d.ts","sourceRoot":"","sources":["../../../../../../src/application/use-cases/features/create/slug-resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oEAAoE,CAAC;AAC7G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8DAA8D,CAAC;AAKrG,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBACa,YAAY;IAGrB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAE5B,OAAO,CAAC,QAAQ,CAAC,eAAe;gBAFf,WAAW,EAAE,kBAAkB,EAE/B,eAAe,EAAE,gBAAgB;IAGpD;;;OAGG;IACG,iBAAiB,CACrB,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,oBAAoB,CAAC;CA+BjC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SlugResolver
|
|
3
|
+
*
|
|
4
|
+
* Resolves unique slugs by checking against database and git branches.
|
|
5
|
+
* Ensures no slug collision by appending numeric suffixes (-2, -3, etc.)
|
|
6
|
+
*/
|
|
7
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
8
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
10
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
11
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
12
|
+
};
|
|
13
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
14
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
15
|
+
};
|
|
16
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
17
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
18
|
+
};
|
|
19
|
+
import { injectable, inject } from 'tsyringe';
|
|
20
|
+
/** Maximum number of suffix attempts before giving up */
|
|
21
|
+
const MAX_SUFFIX = 10;
|
|
22
|
+
let SlugResolver = class SlugResolver {
|
|
23
|
+
featureRepo;
|
|
24
|
+
worktreeService;
|
|
25
|
+
constructor(featureRepo, worktreeService) {
|
|
26
|
+
this.featureRepo = featureRepo;
|
|
27
|
+
this.worktreeService = worktreeService;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Find a unique slug by checking both the feature DB and git branches.
|
|
31
|
+
* If the original slug conflicts, appends -2, -3, etc. until a free one is found.
|
|
32
|
+
*/
|
|
33
|
+
async resolveUniqueSlug(originalSlug, repositoryPath) {
|
|
34
|
+
for (let suffix = 0; suffix <= MAX_SUFFIX; suffix++) {
|
|
35
|
+
const slug = suffix === 0 ? originalSlug : `${originalSlug}-${suffix + 1}`;
|
|
36
|
+
const branch = `feat/${slug}`;
|
|
37
|
+
// Check if a feature with this slug already exists in the DB
|
|
38
|
+
const existing = await this.featureRepo.findBySlug(slug, repositoryPath);
|
|
39
|
+
if (existing) {
|
|
40
|
+
if (suffix === 0)
|
|
41
|
+
continue; // try suffixed version
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
// Check if the git branch already exists (leftover from deleted feature)
|
|
45
|
+
const branchInUse = await this.worktreeService.exists(repositoryPath, branch);
|
|
46
|
+
if (branchInUse)
|
|
47
|
+
continue;
|
|
48
|
+
if (suffix > 0) {
|
|
49
|
+
return {
|
|
50
|
+
slug,
|
|
51
|
+
branch,
|
|
52
|
+
warning: `Branch "feat/${originalSlug}" already exists, using "${branch}" instead`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return { slug, branch };
|
|
56
|
+
}
|
|
57
|
+
throw new Error(`Could not find a unique slug for "${originalSlug}" after ${MAX_SUFFIX} attempts`);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
SlugResolver = __decorate([
|
|
61
|
+
injectable(),
|
|
62
|
+
__param(0, inject('IFeatureRepository')),
|
|
63
|
+
__param(1, inject('IWorktreeService')),
|
|
64
|
+
__metadata("design:paramtypes", [Object, Object])
|
|
65
|
+
], SlugResolver);
|
|
66
|
+
export { SlugResolver };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ApprovalGates, Feature } from '../../../../domain/generated/output.js';
|
|
2
|
+
export interface CreateFeatureInput {
|
|
3
|
+
userInput: string;
|
|
4
|
+
repositoryPath: string;
|
|
5
|
+
approvalGates?: ApprovalGates;
|
|
6
|
+
}
|
|
7
|
+
export interface CreateFeatureResult {
|
|
8
|
+
feature: Feature;
|
|
9
|
+
warning?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface FeatureMetadata {
|
|
12
|
+
slug: string;
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../src/application/use-cases/features/create/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,wCAAwC,CAAC;AAErF,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -72,7 +72,7 @@ let ResumeFeatureUseCase = class ResumeFeatureUseCase {
|
|
|
72
72
|
threadId: lastRun.threadId, // Same thread for checkpoint continuity
|
|
73
73
|
featureId: feature.id,
|
|
74
74
|
repositoryPath: feature.repositoryPath,
|
|
75
|
-
|
|
75
|
+
approvalGates: lastRun.approvalGates,
|
|
76
76
|
createdAt: now,
|
|
77
77
|
updatedAt: now,
|
|
78
78
|
};
|
|
@@ -87,7 +87,7 @@ let ResumeFeatureUseCase = class ResumeFeatureUseCase {
|
|
|
87
87
|
const worktreePath = this.worktreeService.getWorktreePath(feature.repositoryPath, feature.branch);
|
|
88
88
|
this.processService.spawn(feature.id, newRunId, feature.repositoryPath, worktreePath, worktreePath, {
|
|
89
89
|
resume: true,
|
|
90
|
-
|
|
90
|
+
approvalGates: lastRun.approvalGates,
|
|
91
91
|
threadId: lastRun.threadId,
|
|
92
92
|
resumeFromInterrupt: lastRun.status === AgentRunStatus.waitingApproval,
|
|
93
93
|
});
|