Add clear command, fix CLI shell completion/history, add launch script
- New DELETE /api/projects endpoint and GraphRepository.clearAll() wipe the whole Neo4j database (schema preserved). - New CLI 'clear' command with confirmation prompt (-y/--yes to skip). - Fix interactive shell: compile the picocli SystemCompleter before use (was throwing IllegalStateException on Tab), and persist the actual LineReader history instead of an unattached DefaultHistory instance. - Add ac-cli/agenticcode.sh to launch the interactive shell from the built jar. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
14
ac-cli/agenticcode.sh
Executable file
14
ac-cli/agenticcode.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# Starts the AgenticCode interactive shell using the jar built in target/.
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
JAR="$SCRIPT_DIR/target/ac-cli-1.0.0-SNAPSHOT.jar"
|
||||
|
||||
if [[ ! -f "$JAR" ]]; then
|
||||
echo "Jar not found: $JAR" >&2
|
||||
echo "Build it first with: mvn -pl ac-cli -am package" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec java -jar "$JAR" "$@"
|
||||
@@ -25,7 +25,8 @@ import java.util.concurrent.Callable;
|
||||
CallersCommand.class,
|
||||
CalleesCommand.class,
|
||||
DbAccessesCommand.class,
|
||||
SearchIdentifierCommand.class
|
||||
SearchIdentifierCommand.class,
|
||||
ClearCommand.class
|
||||
}
|
||||
)
|
||||
public final class AgenticCodeCli implements Callable<Integer> {
|
||||
|
||||
28
ac-cli/src/main/java/com/agenticcode/cli/ClearCommand.java
Normal file
28
ac-cli/src/main/java/com/agenticcode/cli/ClearCommand.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package com.agenticcode.cli;
|
||||
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
|
||||
/**
|
||||
* Deletes all projects and data, leaving an empty Neo4j database.
|
||||
*/
|
||||
@Command(name = "clear", mixinStandardHelpOptions = true, description = "Delete ALL projects and data (empties the database)")
|
||||
final class ClearCommand extends AbstractApiCommand {
|
||||
|
||||
@Option(names = {"-y", "--yes"}, description = "Skip the confirmation prompt")
|
||||
boolean yes;
|
||||
|
||||
@Override
|
||||
public Integer call() throws Exception {
|
||||
if (!yes) {
|
||||
System.out.print("Delete ALL projects and data? This cannot be undone. (y/N) ");
|
||||
System.out.flush();
|
||||
String answer = new java.io.BufferedReader(new java.io.InputStreamReader(System.in)).readLine();
|
||||
if (answer == null || !answer.trim().equalsIgnoreCase("y")) {
|
||||
System.out.println("Aborted.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return printResponse(apiClient().delete("/api/projects"));
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package com.agenticcode.cli;
|
||||
|
||||
import org.jline.reader.*;
|
||||
import org.jline.reader.impl.DefaultParser;
|
||||
import org.jline.reader.impl.history.DefaultHistory;
|
||||
import org.jline.reader.impl.completer.SystemCompleter;
|
||||
import org.jline.terminal.Terminal;
|
||||
import org.jline.terminal.TerminalBuilder;
|
||||
import picocli.CommandLine;
|
||||
@@ -27,14 +27,16 @@ final class InteractiveShell {
|
||||
int run() throws IOException {
|
||||
try (Terminal terminal = TerminalBuilder.builder().build()) {
|
||||
PicocliCommands picocliCommands = new PicocliCommands(commandLine);
|
||||
SystemCompleter completer = picocliCommands.compileCompleters();
|
||||
completer.compile();
|
||||
LineReader reader = LineReaderBuilder.builder()
|
||||
.terminal(terminal)
|
||||
.parser(new DefaultParser())
|
||||
.completer(picocliCommands.compileCompleters())
|
||||
.completer(completer)
|
||||
.appName("agenticcode")
|
||||
.variable(LineReader.HISTORY_FILE, HISTORY_FILE)
|
||||
.build();
|
||||
History history = new DefaultHistory(reader);
|
||||
History history = reader.getHistory();
|
||||
|
||||
terminal.writer().println("AgenticCode interactive shell. Type 'help' for commands, 'exit' to quit.");
|
||||
String serverUrl = CliConfig.resolveServerUrl(System.getProperty(AbstractApiCommand.SERVER_URL_PROPERTY));
|
||||
|
||||
@@ -60,6 +60,11 @@ public class ProjectResource {
|
||||
});
|
||||
}
|
||||
|
||||
@DELETE
|
||||
public Uni<Response> clearAll() {
|
||||
return graphRepository.clearAll().replaceWith(Response.noContent().build());
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{project}")
|
||||
public Uni<Response> delete(@PathParam("project") String project) {
|
||||
|
||||
@@ -74,6 +74,29 @@ class ProjectResourceIT {
|
||||
.statusCode(204);
|
||||
}
|
||||
|
||||
@Test
|
||||
void clearAllRemovesAllProjects() {
|
||||
String project = "clear-project";
|
||||
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.body(new ProjectResource.ProjectRequest(null))
|
||||
.when().post("/api/projects/" + project)
|
||||
.then()
|
||||
.statusCode(201);
|
||||
|
||||
given()
|
||||
.when().delete("/api/projects")
|
||||
.then()
|
||||
.statusCode(204);
|
||||
|
||||
given()
|
||||
.when().get("/api/projects")
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.body("name", org.hamcrest.Matchers.not(org.hamcrest.Matchers.hasItem(project)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateAndDeleteUnknownProjectReturnNotFound() {
|
||||
String project = "missing-project";
|
||||
|
||||
@@ -65,6 +65,10 @@ public final class CypherQueries {
|
||||
RETURN p.name AS name, p.description AS description
|
||||
ORDER BY p.name
|
||||
""";
|
||||
public static final String CLEAR_ALL = """
|
||||
MATCH (n)
|
||||
DETACH DELETE n
|
||||
""";
|
||||
|
||||
/**
|
||||
* Schema statements (indexes/constraints) applied once at startup. Each is run as
|
||||
|
||||
@@ -192,6 +192,19 @@ public class GraphRepository {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all nodes and relationships, leaving an empty database. Schema
|
||||
* (indexes/constraints) is unaffected.
|
||||
*/
|
||||
public Uni<Void> clearAll() {
|
||||
return Uni.createFrom().item(() -> {
|
||||
try (Session session = driver.session()) {
|
||||
session.executeWriteWithoutResult(tx -> tx.run(CypherQueries.CLEAR_ALL).consume());
|
||||
}
|
||||
return null;
|
||||
}).replaceWithVoid();
|
||||
}
|
||||
|
||||
public Uni<List<ProjectInfo>> listProjects() {
|
||||
return Uni.createFrom().item(() -> {
|
||||
try (Session session = driver.session()) {
|
||||
|
||||
Reference in New Issue
Block a user