@shepai/cli 1.16.0 → 1.18.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/eslint.config.mjs +8 -1
- package/dist/src/application/ports/output/agents/agent-executor-provider.interface.d.ts +5 -0
- package/dist/src/application/ports/output/agents/agent-executor-provider.interface.d.ts.map +1 -0
- package/dist/src/application/ports/output/agents/agent-executor-provider.interface.js +1 -0
- package/dist/src/application/ports/output/agents/agent-executor.interface.d.ts +4 -0
- package/dist/src/application/ports/output/agents/agent-executor.interface.d.ts.map +1 -1
- package/dist/src/application/ports/output/agents/feature-agent-process.interface.d.ts +2 -0
- 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/index.d.ts +1 -1
- package/dist/src/application/ports/output/index.d.ts.map +1 -1
- package/dist/src/application/use-cases/features/create-feature.use-case.d.ts +3 -3
- package/dist/src/application/use-cases/features/create-feature.use-case.d.ts.map +1 -1
- package/dist/src/application/use-cases/features/create-feature.use-case.js +9 -7
- package/dist/src/application/use-cases/features/resume-feature.use-case.d.ts.map +1 -1
- package/dist/src/application/use-cases/features/resume-feature.use-case.js +6 -1
- package/dist/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/src/infrastructure/di/container.js +9 -2
- package/dist/src/infrastructure/services/agents/common/agent-executor-factory.service.d.ts +1 -1
- package/dist/src/infrastructure/services/agents/common/agent-executor-factory.service.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/common/agent-executor-factory.service.js +6 -2
- package/dist/src/infrastructure/services/agents/common/agent-executor-provider.service.d.ts +9 -0
- package/dist/src/infrastructure/services/agents/common/agent-executor-provider.service.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/common/agent-executor-provider.service.js +11 -0
- package/dist/src/infrastructure/services/agents/common/agent-runner.service.d.ts +3 -3
- package/dist/src/infrastructure/services/agents/common/agent-runner.service.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/common/agent-runner.service.js +4 -4
- package/dist/src/infrastructure/services/agents/common/agent-validator.service.d.ts +1 -9
- package/dist/src/infrastructure/services/agents/common/agent-validator.service.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/common/agent-validator.service.js +1 -0
- package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts +1 -7
- package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.js +4 -0
- package/dist/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts +38 -0
- package/dist/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/common/executors/cursor-executor.service.js +296 -0
- package/dist/src/infrastructure/services/agents/common/types.d.ts +23 -0
- package/dist/src/infrastructure/services/agents/common/types.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/common/types.js +7 -0
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +2 -0
- 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 +6 -0
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +2 -0
- 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 +32 -12
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.js +19 -10
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts +41 -1
- 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 +125 -6
- package/dist/src/presentation/cli/commands/feat/ls.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/ls.command.js +42 -7
- package/dist/src/presentation/tui/prompts/agent-select.prompt.d.ts +1 -1
- package/dist/src/presentation/tui/prompts/agent-select.prompt.js +1 -1
- package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.js +1 -1
- package/dist/src/presentation/web/components/ui/alert.js +1 -1
- package/dist/src/presentation/web/components/ui/badge.js +4 -4
- package/dist/src/presentation/web/components/ui/button.js +3 -3
- package/dist/src/presentation/web/components/ui/sidebar.js +2 -2
- 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/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_not-found.html +2 -2
- package/web/.next/server/app/_not-found.rsc +8 -8
- package/web/.next/server/app/_not-found.segments/_full.segment.rsc +8 -8
- package/web/.next/server/app/_not-found.segments/_head.segment.rsc +3 -3
- package/web/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
- package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- 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 +3 -3
- package/web/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/web/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version.html +2 -2
- package/web/.next/server/app/version.rsc +3 -3
- package/web/.next/server/app/version.segments/_full.segment.rsc +3 -3
- package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_index.segment.rsc +2 -2
- package/web/.next/server/app/version.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +2 -2
- package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
- package/web/.next/server/chunks/ssr/_0f02ab66._.js +1 -1
- package/web/.next/server/chunks/ssr/_0f02ab66._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_19be0743._.js +1 -1
- package/web/.next/server/chunks/ssr/_4582f3c3._.js +1 -1
- package/web/.next/server/chunks/ssr/_4582f3c3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_a0c04017._.js +1 -1
- package/web/.next/server/chunks/ssr/_a0c04017._.js.map +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_version_version-page-client_tsx_fe9db753._.js +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_version_version-page-client_tsx_fe9db753._.js.map +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/static/chunks/{5130d7093ad39f4a.js → 26d260496abf3ed8.js} +1 -1
- package/web/.next/static/chunks/{ef1296dbe67d5aae.js → 8353f5690707d9a5.js} +1 -1
- package/web/.next/static/chunks/{523c5cfe0570712c.js → f74cb59a5a6c94f1.js} +1 -1
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- /package/web/.next/static/{KqMr5DLdrvbaA-agLuHP1 → iV3kEDpfUq_ttVqv3E57o}/_buildManifest.js +0 -0
- /package/web/.next/static/{KqMr5DLdrvbaA-agLuHP1 → iV3kEDpfUq_ttVqv3E57o}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{KqMr5DLdrvbaA-agLuHP1 → iV3kEDpfUq_ttVqv3E57o}/_ssgManifest.js +0 -0
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Provides consistent logging, spec file reading, executor invocation,
|
|
5
5
|
* and error handling so every node follows the same patterns.
|
|
6
6
|
*/
|
|
7
|
-
import
|
|
7
|
+
import yaml from 'js-yaml';
|
|
8
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
8
9
|
import { join } from 'node:path';
|
|
9
10
|
import { interrupt, isGraphBubbleUp } from '@langchain/langgraph';
|
|
10
11
|
import { reportNodeStart } from '../heartbeat.js';
|
|
@@ -41,8 +42,34 @@ export function readSpecFile(specDir, filename) {
|
|
|
41
42
|
export function buildExecutorOptions(state) {
|
|
42
43
|
return {
|
|
43
44
|
cwd: state.worktreePath || state.repositoryPath,
|
|
45
|
+
maxTurns: 50,
|
|
46
|
+
disableMcp: true,
|
|
44
47
|
};
|
|
45
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Sanitize YAML content to handle common AI-generated issues.
|
|
51
|
+
* Quotes unquoted list items containing `{` or `}` characters
|
|
52
|
+
* which js-yaml interprets as flow mappings.
|
|
53
|
+
*/
|
|
54
|
+
function sanitizeYamlBraces(content) {
|
|
55
|
+
return content.replace(/^(\s*- )(?!['"])(.+[{}].+)$/gm, (_match, prefix, value) => `${prefix}"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Parse YAML with automatic sanitization of common AI-generated issues.
|
|
59
|
+
* First attempts normal parsing; on failure, sanitizes unquoted braces
|
|
60
|
+
* in list items and retries.
|
|
61
|
+
*/
|
|
62
|
+
export function safeYamlLoad(content) {
|
|
63
|
+
try {
|
|
64
|
+
return yaml.load(content);
|
|
65
|
+
}
|
|
66
|
+
catch (firstError) {
|
|
67
|
+
const sanitized = sanitizeYamlBraces(content);
|
|
68
|
+
if (sanitized === content)
|
|
69
|
+
throw firstError; // nothing to sanitize
|
|
70
|
+
return yaml.load(sanitized);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
46
73
|
/** Nodes that are auto-approved (no interrupt) for each approval mode. */
|
|
47
74
|
const AUTO_APPROVED_NODES = {
|
|
48
75
|
interactive: [],
|
|
@@ -60,6 +87,99 @@ export function shouldInterrupt(nodeName, approvalMode) {
|
|
|
60
87
|
const autoApproved = AUTO_APPROVED_NODES[approvalMode] ?? [];
|
|
61
88
|
return !autoApproved.includes(nodeName);
|
|
62
89
|
}
|
|
90
|
+
const API_ERROR_RE = /API Error: (400|429|5\d{2})/;
|
|
91
|
+
const NETWORK_ERROR_RE = /ECONNREFUSED|ETIMEDOUT|ENOTFOUND|timed out/i;
|
|
92
|
+
const NON_RETRYABLE_RE = /Process exited with code|ENOENT|SyntaxError/;
|
|
93
|
+
/**
|
|
94
|
+
* Classify an error message into a retry category.
|
|
95
|
+
*
|
|
96
|
+
* - **retryable-api**: Transient API errors (rate-limit, overload, bad request)
|
|
97
|
+
* - **retryable-network**: Network-level failures (DNS, timeouts, connection refused)
|
|
98
|
+
* - **non-retryable**: Logic / filesystem / syntax errors that won't resolve on retry
|
|
99
|
+
* - **unknown**: Anything unrecognised (callers may choose to retry cautiously)
|
|
100
|
+
*/
|
|
101
|
+
export function classifyError(errorMessage) {
|
|
102
|
+
if (API_ERROR_RE.test(errorMessage))
|
|
103
|
+
return 'retryable-api';
|
|
104
|
+
if (NETWORK_ERROR_RE.test(errorMessage))
|
|
105
|
+
return 'retryable-network';
|
|
106
|
+
if (NON_RETRYABLE_RE.test(errorMessage))
|
|
107
|
+
return 'non-retryable';
|
|
108
|
+
return 'unknown';
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Execute a prompt via the given executor with automatic retry and
|
|
112
|
+
* exponential back-off for transient errors.
|
|
113
|
+
*
|
|
114
|
+
* Non-retryable errors are thrown immediately. Unknown errors are
|
|
115
|
+
* retried (conservative stance: could be transient).
|
|
116
|
+
*/
|
|
117
|
+
export async function retryExecute(executor, prompt, options, retryOpts) {
|
|
118
|
+
const maxAttempts = retryOpts?.maxAttempts ?? 3;
|
|
119
|
+
const baseDelayMs = retryOpts?.baseDelayMs ?? 2000;
|
|
120
|
+
const log = retryOpts?.logger;
|
|
121
|
+
let lastError;
|
|
122
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
123
|
+
try {
|
|
124
|
+
return await executor.execute(prompt, options);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
128
|
+
const category = classifyError(lastError.message);
|
|
129
|
+
if (category === 'non-retryable') {
|
|
130
|
+
throw lastError;
|
|
131
|
+
}
|
|
132
|
+
if (attempt < maxAttempts) {
|
|
133
|
+
const delayMs = baseDelayMs * Math.pow(2, attempt - 1);
|
|
134
|
+
log?.info(`Attempt ${attempt}/${maxAttempts} failed (${category}), retrying in ${delayMs}ms`);
|
|
135
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
throw lastError;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Read completed phases from feature.yaml.
|
|
143
|
+
*/
|
|
144
|
+
export function getCompletedPhases(specDir) {
|
|
145
|
+
const content = readSpecFile(specDir, 'feature.yaml');
|
|
146
|
+
if (!content)
|
|
147
|
+
return [];
|
|
148
|
+
try {
|
|
149
|
+
const data = yaml.load(content);
|
|
150
|
+
const status = (data?.status ?? {});
|
|
151
|
+
const phases = status.completedPhases;
|
|
152
|
+
return Array.isArray(phases) ? phases : [];
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Mark a phase as complete in feature.yaml by adding its ID to completedPhases.
|
|
160
|
+
*/
|
|
161
|
+
export function markPhaseComplete(specDir, phaseId, log) {
|
|
162
|
+
try {
|
|
163
|
+
const content = readSpecFile(specDir, 'feature.yaml');
|
|
164
|
+
if (!content)
|
|
165
|
+
return;
|
|
166
|
+
const data = yaml.load(content);
|
|
167
|
+
if (!data || typeof data !== 'object')
|
|
168
|
+
return;
|
|
169
|
+
const status = (data.status ?? {});
|
|
170
|
+
const completedPhases = Array.isArray(status.completedPhases)
|
|
171
|
+
? [...status.completedPhases]
|
|
172
|
+
: [];
|
|
173
|
+
if (!completedPhases.includes(phaseId)) {
|
|
174
|
+
completedPhases.push(phaseId);
|
|
175
|
+
}
|
|
176
|
+
data.status = { ...status, completedPhases };
|
|
177
|
+
writeFileSync(join(specDir, 'feature.yaml'), yaml.dump(data, { indent: 2, lineWidth: -1 }), 'utf-8');
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
log?.error(`Failed to mark phase complete: ${err instanceof Error ? err.message : String(err)}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
63
183
|
/**
|
|
64
184
|
* Execute a node with consistent logging and error handling.
|
|
65
185
|
*
|
|
@@ -104,11 +224,10 @@ export function executeNode(nodeName, executor, buildPrompt) {
|
|
|
104
224
|
const message = err instanceof Error ? err.message : String(err);
|
|
105
225
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
106
226
|
log.error(`${message} (after ${elapsed}s)`);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
};
|
|
227
|
+
// Throw so LangGraph does NOT checkpoint this node as "completed".
|
|
228
|
+
// The worker catch block marks the run as failed, and on resume
|
|
229
|
+
// LangGraph re-executes from the last successfully checkpointed node.
|
|
230
|
+
throw new Error(`[${nodeName}] ${message}`);
|
|
112
231
|
}
|
|
113
232
|
};
|
|
114
233
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ls.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/ls.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"ls.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/ls.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsGpC,wBAAgB,eAAe,IAAI,OAAO,CAqDzC"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* $ shep feat ls
|
|
11
11
|
* $ shep feat ls --repo /path/to/project
|
|
12
12
|
*/
|
|
13
|
+
import path from 'node:path';
|
|
13
14
|
import { Command } from 'commander';
|
|
14
15
|
import { container } from '../../../../infrastructure/di/container.js';
|
|
15
16
|
import { ListFeaturesUseCase } from '../../../../application/use-cases/features/list-features.use-case.js';
|
|
@@ -65,6 +66,39 @@ function isProcessAlive(pid) {
|
|
|
65
66
|
return false;
|
|
66
67
|
}
|
|
67
68
|
}
|
|
69
|
+
/** Format a duration in ms to a compact human-readable string. */
|
|
70
|
+
function formatDuration(ms) {
|
|
71
|
+
const seconds = Math.floor(ms / 1000);
|
|
72
|
+
if (seconds < 60)
|
|
73
|
+
return `${seconds}s`;
|
|
74
|
+
const minutes = Math.floor(seconds / 60);
|
|
75
|
+
if (minutes < 60)
|
|
76
|
+
return `${minutes}m`;
|
|
77
|
+
const hours = Math.floor(minutes / 60);
|
|
78
|
+
const remMin = minutes % 60;
|
|
79
|
+
if (hours < 24)
|
|
80
|
+
return remMin > 0 ? `${hours}h ${remMin}m` : `${hours}h`;
|
|
81
|
+
const days = Math.floor(hours / 24);
|
|
82
|
+
return `${days}d`;
|
|
83
|
+
}
|
|
84
|
+
/** Format the time column based on run status. */
|
|
85
|
+
function formatTime(feature, run) {
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
if (run) {
|
|
88
|
+
const isRunning = run.status === 'running' || run.status === 'pending';
|
|
89
|
+
if (isRunning && run.startedAt) {
|
|
90
|
+
const started = new Date(run.startedAt).getTime();
|
|
91
|
+
return colors.info(formatDuration(now - started));
|
|
92
|
+
}
|
|
93
|
+
if (run.status === 'completed' && run.completedAt) {
|
|
94
|
+
const completed = new Date(run.completedAt).getTime();
|
|
95
|
+
return colors.muted(`${formatDuration(now - completed)} ago`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Fallback to updatedAt
|
|
99
|
+
const updated = new Date(feature.updatedAt).getTime();
|
|
100
|
+
return colors.muted(`${formatDuration(now - updated)} ago`);
|
|
101
|
+
}
|
|
68
102
|
export function createLsCommand() {
|
|
69
103
|
return new Command('ls')
|
|
70
104
|
.description('List features')
|
|
@@ -79,15 +113,15 @@ export function createLsCommand() {
|
|
|
79
113
|
const runs = await Promise.all(features.map((f) => f.agentRunId ? runRepo.findById(f.agentRunId) : Promise.resolve(null)));
|
|
80
114
|
const rows = features.map((feature, i) => {
|
|
81
115
|
const run = runs[i];
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
: String(feature.updatedAt);
|
|
116
|
+
const repo = path.basename(feature.repositoryPath);
|
|
117
|
+
const agent = run?.agentType ?? colors.muted('—');
|
|
85
118
|
return [
|
|
86
119
|
feature.id.slice(0, 8),
|
|
87
120
|
feature.name.slice(0, 30),
|
|
88
121
|
formatStatus(feature, run),
|
|
89
|
-
colors.muted(
|
|
90
|
-
|
|
122
|
+
colors.muted(repo),
|
|
123
|
+
agent,
|
|
124
|
+
formatTime(feature, run),
|
|
91
125
|
];
|
|
92
126
|
});
|
|
93
127
|
renderListView({
|
|
@@ -96,8 +130,9 @@ export function createLsCommand() {
|
|
|
96
130
|
{ label: 'ID', width: 10 },
|
|
97
131
|
{ label: 'Name', width: 32 },
|
|
98
132
|
{ label: 'Status', width: 20 },
|
|
99
|
-
{ label: '
|
|
100
|
-
{ label: '
|
|
133
|
+
{ label: 'Repo', width: 20 },
|
|
134
|
+
{ label: 'Agent', width: 14 },
|
|
135
|
+
{ label: 'Time', width: 12 },
|
|
101
136
|
],
|
|
102
137
|
rows,
|
|
103
138
|
emptyMessage: 'No features found',
|
|
@@ -32,7 +32,7 @@ export declare function createAgentSelectConfig(): {
|
|
|
32
32
|
}, {
|
|
33
33
|
readonly name: "Cursor";
|
|
34
34
|
readonly value: AgentType.Cursor;
|
|
35
|
-
readonly
|
|
35
|
+
readonly description: "Cursor AI coding agent";
|
|
36
36
|
}];
|
|
37
37
|
readonly theme: {
|
|
38
38
|
readonly prefix: {
|
package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.js
CHANGED
|
@@ -7,5 +7,5 @@ import { useSidebar } from '../../ui/sidebar';
|
|
|
7
7
|
import { cn } from '../../../lib/utils';
|
|
8
8
|
export function SidebarSectionHeader({ label, onFolderClick, onMenuClick, className, }) {
|
|
9
9
|
const { state, isMobile } = useSidebar();
|
|
10
|
-
return (_jsx(SidebarGroup, { "data-testid": "sidebar-section-header", className: cn('px-2 py-1', className), children: _jsxs("div", { className: "text-sidebar-foreground flex h-7 w-full shrink-0 items-center px-2 text-sm font-medium", children: [_jsx("span", { className: "min-w-0 flex-1 truncate", children: label }), _jsxs("span", { className: "text-sidebar-foreground/70 flex shrink-0 items-center gap-0.5", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: onFolderClick, className: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground
|
|
10
|
+
return (_jsx(SidebarGroup, { "data-testid": "sidebar-section-header", className: cn('px-2 py-1', className), children: _jsxs("div", { className: "text-sidebar-foreground flex h-7 w-full shrink-0 items-center px-2 text-sm font-medium", children: [_jsx("span", { className: "min-w-0 flex-1 truncate", children: label }), _jsxs("span", { className: "text-sidebar-foreground/70 flex shrink-0 items-center gap-0.5", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: onFolderClick, className: "ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex size-7 items-center justify-center rounded-md p-0 outline-hidden transition-colors focus-visible:ring-2 [&>svg]:size-4", "aria-label": "Open features folder", children: _jsx(Folder, { className: "size-4" }) }) }), _jsx(TooltipContent, { side: "right", align: "center", hidden: state !== 'collapsed' || isMobile, children: "Open features folder" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: onMenuClick, className: "ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex size-7 items-center justify-center rounded-md p-0 outline-hidden transition-colors focus-visible:ring-2 [&>svg]:size-4", "aria-label": "Features options", children: _jsx(GripHorizontal, { className: "size-4" }) }) }), _jsx(TooltipContent, { side: "right", align: "center", hidden: state !== 'collapsed' || isMobile, children: "Features options" })] })] })] }) }));
|
|
11
11
|
}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { cva } from 'class-variance-authority';
|
|
4
4
|
import { cn } from '../../lib/utils';
|
|
5
|
-
const alertVariants = cva('
|
|
5
|
+
const alertVariants = cva('relative w-full rounded-lg border px-4 py-3 text-sm [&>svg]:absolute [&>svg]:top-4 [&>svg]:left-4 [&>svg]:text-foreground [&>svg+div]:translate-y-[-3px] [&>svg~*]:pl-7', {
|
|
6
6
|
variants: {
|
|
7
7
|
variant: {
|
|
8
8
|
default: 'bg-background text-foreground',
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cva } from 'class-variance-authority';
|
|
3
3
|
import { cn } from '../../lib/utils';
|
|
4
|
-
const badgeVariants = cva('
|
|
4
|
+
const badgeVariants = cva('inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-none', {
|
|
5
5
|
variants: {
|
|
6
6
|
variant: {
|
|
7
|
-
default: 'bg-primary text-primary-foreground hover:bg-primary/80
|
|
8
|
-
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80
|
|
9
|
-
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/80
|
|
7
|
+
default: 'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',
|
|
8
|
+
secondary: 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
9
|
+
destructive: 'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',
|
|
10
10
|
outline: 'text-foreground',
|
|
11
11
|
},
|
|
12
12
|
},
|
|
@@ -2,12 +2,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { cva } from 'class-variance-authority';
|
|
3
3
|
import { Slot } from 'radix-ui';
|
|
4
4
|
import { cn } from '../../lib/utils';
|
|
5
|
-
const buttonVariants = cva("
|
|
5
|
+
const buttonVariants = cva("inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
|
|
6
6
|
variants: {
|
|
7
7
|
variant: {
|
|
8
8
|
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
9
|
-
destructive: 'bg-destructive hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40
|
|
10
|
-
outline: 'bg-background hover:bg-accent hover:text-accent-foreground dark:
|
|
9
|
+
destructive: 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40',
|
|
10
|
+
outline: 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50',
|
|
11
11
|
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
12
12
|
ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
|
|
13
13
|
link: 'text-primary underline-offset-4 hover:underline',
|
|
@@ -148,11 +148,11 @@ function SidebarMenu({ className, ...props }) {
|
|
|
148
148
|
function SidebarMenuItem({ className, ...props }) {
|
|
149
149
|
return (_jsx("li", { "data-slot": "sidebar-menu-item", "data-sidebar": "menu-item", className: cn('group/menu-item relative', className), ...props }));
|
|
150
150
|
}
|
|
151
|
-
const sidebarMenuButtonVariants = cva('peer/menu-button
|
|
151
|
+
const sidebarMenuButtonVariants = cva('peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0', {
|
|
152
152
|
variants: {
|
|
153
153
|
variant: {
|
|
154
154
|
default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
|
|
155
|
-
outline: 'bg-background hover:bg-sidebar-accent hover:text-sidebar-accent-foreground
|
|
155
|
+
outline: 'bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]',
|
|
156
156
|
},
|
|
157
157
|
size: {
|
|
158
158
|
default: 'h-8 text-sm',
|