@shepai/cli 1.44.2 → 1.46.0
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/presentation/cli/commands/repo/index.d.ts +18 -0
- package/dist/src/presentation/cli/commands/repo/index.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/repo/index.js +25 -0
- package/dist/src/presentation/cli/commands/repo/ls.command.d.ts +11 -0
- package/dist/src/presentation/cli/commands/repo/ls.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/repo/ls.command.js +64 -0
- package/dist/src/presentation/cli/commands/repo/resolve-repository.d.ts +10 -0
- package/dist/src/presentation/cli/commands/repo/resolve-repository.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/repo/resolve-repository.js +24 -0
- package/dist/src/presentation/cli/commands/repo/show.command.d.ts +11 -0
- package/dist/src/presentation/cli/commands/repo/show.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/repo/show.command.js +95 -0
- package/dist/src/presentation/cli/index.d.ts +1 -0
- package/dist/src/presentation/cli/index.d.ts.map +1 -1
- package/dist/src/presentation/cli/index.js +3 -0
- package/dist/src/presentation/web/app/page.d.ts.map +1 -1
- package/dist/src/presentation/web/app/page.js +18 -10
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +4 -0
- package/dist/src/presentation/web/lib/layout-with-dagre.d.ts.map +1 -1
- package/dist/src/presentation/web/lib/layout-with-dagre.js +3 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -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/.tsbuildinfo +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/page/server-reference-manifest.json +11 -11
- package/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__4e8ca89c._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -1
- 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 +12 -12
- package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +11 -11
- package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__4e8ca89c._.js +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +12 -12
- package/web/.next/standalone/src/presentation/web/app/page.tsx +19 -10
- package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +17 -0
- package/web/.next/standalone/src/presentation/web/lib/layout-with-dagre.ts +3 -0
- package/web/.next/standalone/src/presentation/web/server.js +1 -1
- package/web/.next/static/chunks/{fde97f50747ffbcc.js → ecf44fa8a155c854.js} +2 -2
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- /package/web/.next/static/{DFCnsrgJiPWig4e8ubqSt → nM-uXIiW9k_0Z_GM_4bI4}/_buildManifest.js +0 -0
- /package/web/.next/static/{DFCnsrgJiPWig4e8ubqSt → nM-uXIiW9k_0Z_GM_4bI4}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{DFCnsrgJiPWig4e8ubqSt → nM-uXIiW9k_0Z_GM_4bI4}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo Command
|
|
3
|
+
*
|
|
4
|
+
* Top-level repo command with subcommands for managing tracked repositories.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* shep repo [subcommand]
|
|
8
|
+
*
|
|
9
|
+
* Subcommands:
|
|
10
|
+
* shep repo ls List tracked repositories
|
|
11
|
+
* shep repo show <id> Display details of a tracked repository
|
|
12
|
+
*/
|
|
13
|
+
import { Command } from 'commander';
|
|
14
|
+
/**
|
|
15
|
+
* Create the repo command with all subcommands
|
|
16
|
+
*/
|
|
17
|
+
export declare function createRepoCommand(): Command;
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/repo/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAO3C"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo Command
|
|
3
|
+
*
|
|
4
|
+
* Top-level repo command with subcommands for managing tracked repositories.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* shep repo [subcommand]
|
|
8
|
+
*
|
|
9
|
+
* Subcommands:
|
|
10
|
+
* shep repo ls List tracked repositories
|
|
11
|
+
* shep repo show <id> Display details of a tracked repository
|
|
12
|
+
*/
|
|
13
|
+
import { Command } from 'commander';
|
|
14
|
+
import { createShowCommand } from './show.command.js';
|
|
15
|
+
import { createLsCommand } from './ls.command.js';
|
|
16
|
+
/**
|
|
17
|
+
* Create the repo command with all subcommands
|
|
18
|
+
*/
|
|
19
|
+
export function createRepoCommand() {
|
|
20
|
+
const repo = new Command('repo')
|
|
21
|
+
.description('Manage tracked repositories')
|
|
22
|
+
.addCommand(createLsCommand())
|
|
23
|
+
.addCommand(createShowCommand());
|
|
24
|
+
return repo;
|
|
25
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo List Command
|
|
3
|
+
*
|
|
4
|
+
* List all tracked repositories in a formatted table.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* shep repo ls
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
export declare function createLsCommand(): Command;
|
|
11
|
+
//# sourceMappingURL=ls.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ls.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/repo/ls.command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC,wBAAgB,eAAe,IAAI,OAAO,CAuCzC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo List Command
|
|
3
|
+
*
|
|
4
|
+
* List all tracked repositories in a formatted table.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* shep repo ls
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
import { container } from '../../../../../packages/core/src/infrastructure/di/container.js';
|
|
11
|
+
import { ListRepositoriesUseCase } from '../../../../../packages/core/src/application/use-cases/repositories/list-repositories.use-case.js';
|
|
12
|
+
import { colors, messages, renderListView } from '../../ui/index.js';
|
|
13
|
+
/** Format a duration in ms to a compact human-readable string. */
|
|
14
|
+
function formatDuration(ms) {
|
|
15
|
+
const seconds = Math.floor(ms / 1000);
|
|
16
|
+
if (seconds < 60)
|
|
17
|
+
return `${seconds}s`;
|
|
18
|
+
const minutes = Math.floor(seconds / 60);
|
|
19
|
+
if (minutes < 60)
|
|
20
|
+
return `${minutes}m`;
|
|
21
|
+
const hours = Math.floor(minutes / 60);
|
|
22
|
+
const remMin = minutes % 60;
|
|
23
|
+
if (hours < 24)
|
|
24
|
+
return remMin > 0 ? `${hours}h ${remMin}m` : `${hours}h`;
|
|
25
|
+
const days = Math.floor(hours / 24);
|
|
26
|
+
return `${days}d`;
|
|
27
|
+
}
|
|
28
|
+
export function createLsCommand() {
|
|
29
|
+
return new Command('ls').description('List tracked repositories').action(async () => {
|
|
30
|
+
try {
|
|
31
|
+
const useCase = container.resolve(ListRepositoriesUseCase);
|
|
32
|
+
const featureRepo = container.resolve('IFeatureRepository');
|
|
33
|
+
const repositories = await useCase.execute();
|
|
34
|
+
const now = Date.now();
|
|
35
|
+
const rows = await Promise.all(repositories.map(async (repo) => {
|
|
36
|
+
const features = await featureRepo.list({ repositoryPath: repo.path });
|
|
37
|
+
return [
|
|
38
|
+
repo.id.substring(0, 8),
|
|
39
|
+
repo.name,
|
|
40
|
+
String(features.length),
|
|
41
|
+
repo.path,
|
|
42
|
+
colors.muted(`${formatDuration(now - new Date(repo.createdAt).getTime())} ago`),
|
|
43
|
+
];
|
|
44
|
+
}));
|
|
45
|
+
renderListView({
|
|
46
|
+
title: 'Repositories',
|
|
47
|
+
columns: [
|
|
48
|
+
{ label: 'ID', width: 10 },
|
|
49
|
+
{ label: 'Name', width: 28 },
|
|
50
|
+
{ label: 'Features', width: 10 },
|
|
51
|
+
{ label: 'Path', width: 36 },
|
|
52
|
+
{ label: 'Created', width: 12 },
|
|
53
|
+
],
|
|
54
|
+
rows,
|
|
55
|
+
emptyMessage: 'No repositories found',
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
60
|
+
messages.error('Failed to list repositories', err);
|
|
61
|
+
process.exitCode = 1;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helper: resolve a repository by exact or prefix ID.
|
|
3
|
+
*/
|
|
4
|
+
import type { Repository } from '../../../../../packages/core/src/domain/generated/output.js';
|
|
5
|
+
export declare function resolveRepository(id: string): Promise<{
|
|
6
|
+
repository: Repository;
|
|
7
|
+
} | {
|
|
8
|
+
error: string;
|
|
9
|
+
}>;
|
|
10
|
+
//# sourceMappingURL=resolve-repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-repository.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/repo/resolve-repository.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE/D,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,MAAM,GACT,OAAO,CAAC;IAAE,UAAU,EAAE,UAAU,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAqBzD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helper: resolve a repository by exact or prefix ID.
|
|
3
|
+
*/
|
|
4
|
+
import { container } from '../../../../../packages/core/src/infrastructure/di/container.js';
|
|
5
|
+
export async function resolveRepository(id) {
|
|
6
|
+
const repo = container.resolve('IRepositoryRepository');
|
|
7
|
+
// Try exact match first
|
|
8
|
+
const exact = await repo.findById(id);
|
|
9
|
+
if (exact)
|
|
10
|
+
return { repository: exact };
|
|
11
|
+
// Try prefix match
|
|
12
|
+
if (id.length < 36) {
|
|
13
|
+
const all = await repo.list();
|
|
14
|
+
const matches = all.filter((r) => r.id.startsWith(id));
|
|
15
|
+
if (matches.length === 1)
|
|
16
|
+
return { repository: matches[0] };
|
|
17
|
+
if (matches.length > 1) {
|
|
18
|
+
return {
|
|
19
|
+
error: `Multiple repositories match prefix "${id}": ${matches.map((m) => m.id.substring(0, 8)).join(', ')}`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return { error: `Repository not found: ${id}` };
|
|
24
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo Show Command
|
|
3
|
+
*
|
|
4
|
+
* Display details of a specific tracked repository.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* shep repo show <id>
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
export declare function createShowCommand(): Command;
|
|
11
|
+
//# sourceMappingURL=show.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"show.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/repo/show.command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoCpC,wBAAgB,iBAAiB,IAAI,OAAO,CAsD3C"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo Show Command
|
|
3
|
+
*
|
|
4
|
+
* Display details of a specific tracked repository.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* shep repo show <id>
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
import { container } from '../../../../../packages/core/src/infrastructure/di/container.js';
|
|
11
|
+
import { colors, messages, renderDetailView } from '../../ui/index.js';
|
|
12
|
+
import { resolveRepository } from './resolve-repository.js';
|
|
13
|
+
/** Color a lifecycle value to match feat ls status styling. */
|
|
14
|
+
function colorLifecycle(lifecycle) {
|
|
15
|
+
switch (lifecycle) {
|
|
16
|
+
case 'Started':
|
|
17
|
+
return colors.muted(lifecycle);
|
|
18
|
+
case 'Analyze':
|
|
19
|
+
case 'Requirements':
|
|
20
|
+
case 'Research':
|
|
21
|
+
case 'Planning':
|
|
22
|
+
return colors.info(lifecycle);
|
|
23
|
+
case 'Implementation':
|
|
24
|
+
return colors.warning(lifecycle);
|
|
25
|
+
case 'Review':
|
|
26
|
+
return colors.brand(lifecycle);
|
|
27
|
+
case 'Maintain':
|
|
28
|
+
return colors.success(lifecycle);
|
|
29
|
+
default:
|
|
30
|
+
return colors.muted(lifecycle);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function formatDate(date) {
|
|
34
|
+
if (!date)
|
|
35
|
+
return null;
|
|
36
|
+
try {
|
|
37
|
+
return new Date(date).toLocaleString();
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return String(date);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function createShowCommand() {
|
|
44
|
+
return new Command('show')
|
|
45
|
+
.description('Display details of a tracked repository')
|
|
46
|
+
.argument('<id>', 'Repository ID (or prefix)')
|
|
47
|
+
.action(async (id) => {
|
|
48
|
+
try {
|
|
49
|
+
const resolved = await resolveRepository(id);
|
|
50
|
+
if ('error' in resolved) {
|
|
51
|
+
messages.error(resolved.error);
|
|
52
|
+
process.exitCode = 1;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const repository = resolved.repository;
|
|
56
|
+
const featureRepo = container.resolve('IFeatureRepository');
|
|
57
|
+
const features = await featureRepo.list({ repositoryPath: repository.path });
|
|
58
|
+
const featureFields = features.length > 0
|
|
59
|
+
? features.map((f) => ({
|
|
60
|
+
label: `${colors.muted(f.id.slice(0, 8))} ${f.name}`,
|
|
61
|
+
value: colorLifecycle(f.lifecycle),
|
|
62
|
+
}))
|
|
63
|
+
: [{ label: 'No features found', value: '—' }];
|
|
64
|
+
renderDetailView({
|
|
65
|
+
title: 'Repository',
|
|
66
|
+
sections: [
|
|
67
|
+
{
|
|
68
|
+
fields: [
|
|
69
|
+
{ label: 'ID', value: repository.id },
|
|
70
|
+
{ label: 'Name', value: repository.name },
|
|
71
|
+
{ label: 'Path', value: repository.path },
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
title: 'Timestamps',
|
|
76
|
+
fields: [
|
|
77
|
+
{ label: 'Created', value: formatDate(repository.createdAt) },
|
|
78
|
+
{ label: 'Updated', value: formatDate(repository.updatedAt) },
|
|
79
|
+
{ label: 'Deleted', value: formatDate(repository.deletedAt) },
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
title: `Features (${features.length})`,
|
|
84
|
+
fields: featureFields,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
91
|
+
messages.error('Failed to show repository', err);
|
|
92
|
+
process.exitCode = 1;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* shep run Run an AI agent workflow
|
|
15
15
|
* shep agent Manage and view agent runs
|
|
16
16
|
* shep feat Manage features through the SDLC lifecycle
|
|
17
|
+
* shep repo Manage tracked repositories
|
|
17
18
|
* shep settings Configure Shep settings
|
|
18
19
|
* shep upgrade Upgrade Shep CLI to the latest version
|
|
19
20
|
* shep --version Display version number only
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/presentation/cli/index.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/presentation/cli/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,kBAAkB,CAAC"}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* shep run Run an AI agent workflow
|
|
15
15
|
* shep agent Manage and view agent runs
|
|
16
16
|
* shep feat Manage features through the SDLC lifecycle
|
|
17
|
+
* shep repo Manage tracked repositories
|
|
17
18
|
* shep settings Configure Shep settings
|
|
18
19
|
* shep upgrade Upgrade Shep CLI to the latest version
|
|
19
20
|
* shep --version Display version number only
|
|
@@ -31,6 +32,7 @@ import { createUiCommand } from './commands/ui.command.js';
|
|
|
31
32
|
import { createRunCommand } from './commands/run.command.js';
|
|
32
33
|
import { createAgentCommand } from './commands/agent/index.js';
|
|
33
34
|
import { createFeatCommand } from './commands/feat/index.js';
|
|
35
|
+
import { createRepoCommand } from './commands/repo/index.js';
|
|
34
36
|
import { createIdeOpenCommand } from './commands/ide-open.command.js';
|
|
35
37
|
import { createInstallCommand } from './commands/install.command.js';
|
|
36
38
|
import { createUpgradeCommand } from './commands/upgrade.command.js';
|
|
@@ -95,6 +97,7 @@ async function bootstrap() {
|
|
|
95
97
|
program.addCommand(createRunCommand());
|
|
96
98
|
program.addCommand(createAgentCommand());
|
|
97
99
|
program.addCommand(createFeatCommand());
|
|
100
|
+
program.addCommand(createRepoCommand());
|
|
98
101
|
program.addCommand(createIdeOpenCommand());
|
|
99
102
|
program.addCommand(createInstallCommand());
|
|
100
103
|
program.addCommand(createUpgradeCommand());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/page.tsx"],"names":[],"mappings":"AAcA,uFAAuF;AACvF,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAqBvC,wBAA8B,QAAQ,
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/page.tsx"],"names":[],"mappings":"AAcA,uFAAuF;AACvF,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAqBvC,wBAA8B,QAAQ,qDAwHrC"}
|
|
@@ -93,19 +93,27 @@ export default async function HomePage() {
|
|
|
93
93
|
ranksep: 200,
|
|
94
94
|
nodesep: 15,
|
|
95
95
|
});
|
|
96
|
-
// Position "+ Add Repository"
|
|
97
|
-
//
|
|
96
|
+
// Position "+ Add Repository" below the last repo node (no-features case) or
|
|
97
|
+
// vertically centered with a bottom feature node (features case).
|
|
98
98
|
const repoNodes = laid.nodes.filter((n) => n.type === 'repositoryNode');
|
|
99
99
|
const featureNodes = laid.nodes.filter((n) => n.type === 'featureNode');
|
|
100
|
-
const sortedFeatures = [...featureNodes].sort((a, b) => a.position.y - b.position.y);
|
|
101
|
-
// Pick the feature node just below center (one past the midpoint index)
|
|
102
|
-
const centerIdx = Math.floor(sortedFeatures.length / 2);
|
|
103
|
-
const targetFeature = sortedFeatures[centerIdx + 1] ?? sortedFeatures[sortedFeatures.length - 1];
|
|
104
100
|
const repoX = repoNodes[0]?.position.x ?? 0;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
101
|
+
let addRepoPosition;
|
|
102
|
+
if (featureNodes.length > 0) {
|
|
103
|
+
// Mirror how dagre centers repo nodes with their connected features
|
|
104
|
+
const sortedFeatures = [...featureNodes].sort((a, b) => a.position.y - b.position.y);
|
|
105
|
+
const centerIdx = Math.floor(sortedFeatures.length / 2);
|
|
106
|
+
const targetFeature = sortedFeatures[centerIdx + 1] ?? sortedFeatures[sortedFeatures.length - 1];
|
|
107
|
+
// Center the add-repo node (h=50) with the target feature node (h=140)
|
|
108
|
+
addRepoPosition = { x: repoX, y: targetFeature.position.y + 70 - 25 };
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// No features — place below the bottom-most repo node with a gap
|
|
112
|
+
const lastRepoY = repoNodes.length > 0 ? Math.max(...repoNodes.map((n) => n.position.y)) : 0;
|
|
113
|
+
const repoHeight = 50;
|
|
114
|
+
const gap = 200;
|
|
115
|
+
addRepoPosition = { x: repoX, y: lastRepoY + repoHeight + gap };
|
|
116
|
+
}
|
|
109
117
|
laid.nodes.push({
|
|
110
118
|
id: 'add-repository',
|
|
111
119
|
type: 'addRepositoryNode',
|
package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-center-inner.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAO1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAS5E,UAAU,uBAAuB;IAC/B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,IAAI,EAAE,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"control-center-inner.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAO1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAS5E,UAAU,uBAAuB;IAC/B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,IAAI,EAAE,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,uBAAuB,2CA+PzF"}
|
package/dist/src/presentation/web/components/features/control-center/control-center-inner.js
CHANGED
|
@@ -138,11 +138,15 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
|
|
|
138
138
|
cancelled = true;
|
|
139
139
|
};
|
|
140
140
|
}, [techDecisionsFeatureId]);
|
|
141
|
+
const hasRepositories = nodes.some((n) => n.type === 'repositoryNode');
|
|
141
142
|
// Listen for global "open create drawer" events from the sidebar
|
|
142
143
|
useEffect(() => {
|
|
143
144
|
const handler = () => handleAddFeature();
|
|
144
145
|
window.addEventListener('shep:open-create-drawer', handler);
|
|
145
146
|
return () => window.removeEventListener('shep:open-create-drawer', handler);
|
|
146
147
|
}, [handleAddFeature]);
|
|
148
|
+
if (!hasRepositories) {
|
|
149
|
+
return (_jsxs(_Fragment, { children: [_jsx(NotificationPermissionBanner, {}), _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }), _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, repositoryPath: pendingRepositoryPath })] }));
|
|
150
|
+
}
|
|
147
151
|
return (_jsxs(_Fragment, { children: [_jsx(NotificationPermissionBanner, {}), _jsx(FeaturesCanvas, { nodes: nodes, edges: edges, onNodesChange: onNodesChange, onConnect: handleConnect, onAddFeature: handleAddFeature, onNodeAction: handleAddFeatureToFeature, onNodeClick: handleNodeClick, onPaneClick: clearSelection, onRepositoryAdd: handleAddFeatureToRepo, onRepositoryDelete: handleDeleteRepository, onRepositorySelect: handleAddRepository, emptyState: _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }) }), _jsx(FeatureDrawer, { selectedNode: showPrdDrawer || showTechDecisionsDrawer ? null : selectedNode, onClose: clearSelection, onDelete: handleDeleteFeature, isDeleting: isDeleting }), questionnaireData ? (_jsx(PrdQuestionnaireDrawer, { open: showPrdDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureDescription: selectedNode?.description, featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: questionnaireData, selections: prdSelections, onSelect: handlePrdSelect, onRefine: handlePrdRefine, onApprove: handlePrdApprove, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isPrdProcessing || isLoadingQuestionnaire })) : null, techDecisionsData ? (_jsx(TechDecisionsDrawer, { open: showTechDecisionsDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: techDecisionsData, onRefine: handleTechDecisionsRefine, onApprove: handleTechDecisionsApprove, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isLoadingTechDecisions })) : null, _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, repositoryPath: pendingRepositoryPath })] }));
|
|
148
152
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout-with-dagre.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/lib/layout-with-dagre.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmCD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,IAAI,EAC5C,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,IAAI,EAAE,EACb,IAAI,GAAE,aAAkB,GACvB;IAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"layout-with-dagre.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/lib/layout-with-dagre.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmCD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,IAAI,EAC5C,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,IAAI,EAAE,EACb,IAAI,GAAE,aAAkB,GACvB;IAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAkF/B"}
|
|
@@ -83,6 +83,9 @@ export function layoutWithDagre(nodes, edges, opts = {}) {
|
|
|
83
83
|
maxY = Math.max(maxY, n.position.y + size.height);
|
|
84
84
|
minX = Math.min(minX, n.position.x);
|
|
85
85
|
}
|
|
86
|
+
// When no graph nodes exist (all disconnected), default to origin
|
|
87
|
+
if (minX === Infinity)
|
|
88
|
+
minX = 0;
|
|
86
89
|
for (let i = 0; i < disconnectedNodes.length; i++) {
|
|
87
90
|
const node = disconnectedNodes[i];
|
|
88
91
|
const size = getNodeSize(node, nodeSize);
|