consistent agent naming: parent:prefix convention
Agent names derived from cwd using parent:prefix format: - /home/user/src/ollie -> src:ollie - /home/user/proj/ABC-123_feature/repo -> abc-123:repo Updates: - Kate plugin: one agent per project, git root fallback if no project plugin - acme-ollie-ensure: single 'acme' session, per-project agents - ollie-session-here: single 'default' session, per-project agents Also fixed write -> rdwr for session/agent creation endpoints
This commit is contained in:
parent
1c02b50add
commit
d5efe575ce
|
|
@ -1,14 +1,32 @@
|
|||
#!/bin/bash
|
||||
# acme-ollie-ensure - Ensure acme session and agent exist
|
||||
#
|
||||
# One session per project root (git worktree aware), one agent "assistant".
|
||||
# Session name: acme-{hash of project root}
|
||||
# One session "acme", one agent per project directory.
|
||||
# Agent name: parent:basename (e.g., src:ollie, ABC-123:repo)
|
||||
# If basename contains _, use prefix before first _ (e.g., ABC-123_feature -> ABC-123)
|
||||
#
|
||||
# Usage: eval $(acme-ollie-ensure)
|
||||
# Then use $OLLIE_SESSION and $OLLIE_AGENT
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Compute agent name from directory path
|
||||
# Format: parent:basename (basename split at first _ if present)
|
||||
agent_name_from_cwd() {
|
||||
local cwd="$1"
|
||||
local parent basename prefix
|
||||
parent=$(basename "$(dirname "$cwd")")
|
||||
basename=$(basename "$cwd")
|
||||
# Split basename at first underscore if present
|
||||
if [[ "$basename" == *_* ]]; then
|
||||
prefix="${basename%%_*}"
|
||||
else
|
||||
prefix="$basename"
|
||||
fi
|
||||
# Slugify: lowercase, replace non-alnum with -
|
||||
echo "${parent}:${prefix}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9:-]/-/g'
|
||||
}
|
||||
|
||||
# Acme sets $PWD to the window's directory for executed commands.
|
||||
# Fall back to tag parsing if $winid is set (e.g. for pipe commands).
|
||||
cwd="$PWD"
|
||||
|
|
@ -28,19 +46,17 @@ if wt_root=$(git -C "$cwd" rev-parse --show-toplevel 2>/dev/null); then
|
|||
project_root="$wt_root"
|
||||
fi
|
||||
|
||||
# Session name from project root hash
|
||||
session_hash=$(printf '%s' "$project_root" | md5sum | cut -c1-8)
|
||||
SESSION="acme-$session_hash"
|
||||
AGENT="assistant"
|
||||
SESSION="acme"
|
||||
AGENT=$(agent_name_from_cwd "$project_root")
|
||||
|
||||
# Ensure session exists (with project root as cwd)
|
||||
# Ensure session exists
|
||||
if ! ollie-9p read "session/$SESSION/env" >/dev/null 2>&1; then
|
||||
printf 'name=%s\ncwd=%s\n' "$SESSION" "$project_root" | ollie-9p write "session/new" 2>/dev/null || true
|
||||
printf 'name=%s\ncwd=%s\n' "$SESSION" "$project_root" | ollie-9p rdwr "session/new" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
# Ensure agent exists
|
||||
# Ensure agent exists (with project root as cwd)
|
||||
if ! ollie-9p read "session/$SESSION/agent/$AGENT/cfg" >/dev/null 2>&1; then
|
||||
printf 'name=%s\n' "$AGENT" | ollie-9p write "session/$SESSION/agent/new" 2>/dev/null || true
|
||||
printf 'name=%s\ncwd=%s\n' "$AGENT" "$project_root" | ollie-9p rdwr "session/$SESSION/agent/new" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
# Output for eval
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
# ollie-session-here: start a session in the given directory
|
||||
# Works from both Dolphin (passes %f) and terminal (uses $PWD).
|
||||
#
|
||||
# Session is always "default". Agent name is the base directory name.
|
||||
# Session is always "default". Agent name follows convention: parent:prefix
|
||||
# where prefix is basename split at first _ (e.g., src:ollie, ABC-123:repo)
|
||||
# Session/agent creation is idempotent.
|
||||
|
||||
TARGET="$1"
|
||||
|
|
@ -10,12 +11,27 @@ TARGET="$1"
|
|||
[ -z "$TARGET" ] && TARGET="$PWD"
|
||||
TARGET="$(cd "$TARGET" 2>/dev/null && pwd)" || TARGET="$PWD"
|
||||
|
||||
# Agent name is base directory name
|
||||
AGENT_NAME="$(basename "$TARGET")"
|
||||
# Compute agent name: parent:prefix (prefix = basename up to first _)
|
||||
PARENT="$(basename "$(dirname "$TARGET")")"
|
||||
BASENAME="$(basename "$TARGET")"
|
||||
case "$BASENAME" in
|
||||
*_*) PREFIX="${BASENAME%%_*}" ;;
|
||||
*) PREFIX="$BASENAME" ;;
|
||||
esac
|
||||
# Slugify: lowercase, replace non-alnum with -
|
||||
AGENT_NAME="$(printf '%s:%s' "$PARENT" "$PREFIX" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9:-]/-/g')"
|
||||
|
||||
# Create default session (idempotent) and named agent
|
||||
printf 'name=default\ncwd=%s\n' "$TARGET" | ollie-9p write session/new
|
||||
printf 'name=%s\n' "$AGENT_NAME" | ollie-9p write session/default/agent/new
|
||||
# Create default session (idempotent)
|
||||
printf 'name=default\ncwd=%s\n' "$TARGET" | ollie-9p rdwr session/new >/dev/null 2>&1
|
||||
|
||||
# Create or update agent with computed name
|
||||
if ollie-9p read "session/default/agent/$AGENT_NAME/cfg" >/dev/null 2>&1; then
|
||||
# Agent exists, update cwd
|
||||
printf 'cwd %s' "$TARGET" | ollie-9p rdwr "session/default/agent/$AGENT_NAME/ctl" >/dev/null 2>&1
|
||||
else
|
||||
# Create new agent
|
||||
printf 'name=%s\ncwd=%s\n' "$AGENT_NAME" "$TARGET" | ollie-9p rdwr session/default/agent/new >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ -t 1 ]; then
|
||||
# Terminal: print session info
|
||||
|
|
|
|||
|
|
@ -180,16 +180,46 @@ OllieKateView::~OllieKateView()
|
|||
}
|
||||
}
|
||||
|
||||
// --- Agent Naming ---
|
||||
|
||||
// Compute agent name from directory path
|
||||
// Format: parent:basename (basename split at first _ if present)
|
||||
// Examples: /home/user/src/ollie -> src:ollie
|
||||
// /home/user/proj/ABC-123_feature/repo -> ABC-123:repo
|
||||
QString OllieKateView::agentNameFromCwd(const QString &cwd)
|
||||
{
|
||||
QFileInfo fi(cwd);
|
||||
QString parent = QFileInfo(fi.path()).fileName(); // parent directory name
|
||||
QString basename = fi.fileName();
|
||||
|
||||
// Split basename at first underscore if present
|
||||
int underscoreIdx = basename.indexOf('_');
|
||||
QString prefix = (underscoreIdx > 0) ? basename.left(underscoreIdx) : basename;
|
||||
|
||||
// Slugify: lowercase, replace non-alnum with -
|
||||
QString slug = (parent + ":" + prefix).toLower();
|
||||
QString result;
|
||||
for (QChar c : slug) {
|
||||
if (c.isLetterOrNumber() || c == ':' || c == '-') {
|
||||
result += c;
|
||||
} else {
|
||||
result += '-';
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- Agent Management ---
|
||||
|
||||
void OllieKateView::ensureAgent()
|
||||
{
|
||||
if (!m_agentId.isEmpty()) return;
|
||||
QString cwd = projectBaseDir();
|
||||
if (cwd.isEmpty()) cwd = QDir::homePath();
|
||||
|
||||
QString agentName = agentNameFromCwd(cwd);
|
||||
|
||||
// Ensure kate session exists
|
||||
if (m_sessionId.isEmpty()) {
|
||||
QString cwd = projectBaseDir();
|
||||
if (cwd.isEmpty()) cwd = QDir::homePath();
|
||||
QByteArray resp = m_9p->rdwr("session/new", ("name=kate\ncwd=" + cwd + "\n").toUtf8());
|
||||
if (resp.isEmpty()) {
|
||||
qWarning() << "Ollie Kate: failed to create session";
|
||||
|
|
@ -198,22 +228,18 @@ void OllieKateView::ensureAgent()
|
|||
m_sessionId = "kate";
|
||||
}
|
||||
|
||||
// Look for an existing agent in the kate session
|
||||
QStringList agents = m_9p->ls("session/kate/agent");
|
||||
agents.removeAll("new");
|
||||
agents.removeAll("idx");
|
||||
|
||||
if (!agents.isEmpty()) {
|
||||
m_agentId = agents.first();
|
||||
// Check if agent with this name already exists
|
||||
QByteArray check = m_9p->read("session/kate/agent/" + agentName + "/cfg");
|
||||
if (!check.isEmpty()) {
|
||||
m_agentId = agentName;
|
||||
// Ensure cwd is up to date
|
||||
m_9p->rdwr("session/kate/agent/" + agentName + "/ctl", ("cwd " + cwd).toUtf8());
|
||||
} else {
|
||||
// Create one
|
||||
QString cwd = projectBaseDir();
|
||||
if (cwd.isEmpty()) cwd = QDir::homePath();
|
||||
|
||||
QString agentCfg = "cwd=" + cwd + "\n";
|
||||
// Create new agent with computed name
|
||||
QString agentCfg = "name=" + agentName + "\ncwd=" + cwd + "\n";
|
||||
QByteArray resp = m_9p->rdwr("session/kate/agent/new", agentCfg.toUtf8());
|
||||
if (!resp.isEmpty()) {
|
||||
m_agentId = QString::fromUtf8(resp).trimmed();
|
||||
m_agentId = agentName;
|
||||
}
|
||||
}
|
||||
updateStatusLabel();
|
||||
|
|
@ -226,26 +252,25 @@ bool OllieKateView::selectAgentForProject()
|
|||
if (sessCheck.isEmpty()) return false;
|
||||
m_sessionId = "kate";
|
||||
|
||||
// Find first agent in the session
|
||||
QStringList agents = m_9p->ls("session/kate/agent");
|
||||
agents.removeAll("new");
|
||||
agents.removeAll("idx");
|
||||
QString cwd = projectBaseDir();
|
||||
if (cwd.isEmpty()) return false;
|
||||
|
||||
QString agentName = agentNameFromCwd(cwd);
|
||||
|
||||
if (agents.isEmpty()) return false;
|
||||
|
||||
QString agentId = agents.first();
|
||||
if (agentId != m_agentId) {
|
||||
m_agentId = agentId;
|
||||
}
|
||||
|
||||
// Update cwd to match current project
|
||||
QString baseDir = projectBaseDir();
|
||||
if (!baseDir.isEmpty() && !m_agentId.isEmpty()) {
|
||||
m_9p->write(agentPath() + "/ctl", ("cwd " + baseDir).toUtf8());
|
||||
// Check if agent exists
|
||||
QByteArray check = m_9p->read("session/kate/agent/" + agentName + "/cfg");
|
||||
if (!check.isEmpty()) {
|
||||
m_agentId = agentName;
|
||||
// Ensure cwd is up to date
|
||||
m_9p->rdwr("session/kate/agent/" + agentName + "/ctl", ("cwd " + cwd).toUtf8());
|
||||
updateStatusLabel();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Agent doesn't exist yet — will be created on first use
|
||||
m_agentId.clear();
|
||||
updateStatusLabel();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void OllieKateView::switchToAgent(const QString &agentId)
|
||||
|
|
@ -257,25 +282,35 @@ void OllieKateView::switchToAgent(const QString &agentId)
|
|||
|
||||
void OllieKateView::onProjectChanged()
|
||||
{
|
||||
// Update the agent's cwd to the new project directory
|
||||
QString baseDir = projectBaseDir();
|
||||
if (!baseDir.isEmpty() && !m_agentId.isEmpty()) {
|
||||
m_9p->write(agentPath() + "/ctl", ("cwd " + baseDir).toUtf8());
|
||||
}
|
||||
updateStatusLabel();
|
||||
// Switch to the agent for the new project (or create if needed)
|
||||
selectAgentForProject();
|
||||
}
|
||||
|
||||
QString OllieKateView::projectBaseDir()
|
||||
{
|
||||
// Try Kate's project plugin first
|
||||
QObject *projectView = m_mainWindow->pluginView("kateprojectplugin");
|
||||
if (projectView) {
|
||||
QString dir = projectView->property("projectBaseDir").toString();
|
||||
if (!dir.isEmpty()) return dir;
|
||||
}
|
||||
|
||||
// Fall back to git root detection from active document
|
||||
auto *view = m_mainWindow->activeView();
|
||||
if (view && view->document() && !view->document()->url().toLocalFile().isEmpty()) {
|
||||
return QFileInfo(view->document()->url().toLocalFile()).absolutePath();
|
||||
QString docDir = QFileInfo(view->document()->url().toLocalFile()).absolutePath();
|
||||
|
||||
// Walk up to find .git directory
|
||||
QDir dir(docDir);
|
||||
while (!dir.isRoot()) {
|
||||
if (QFileInfo(dir.filePath(".git")).exists()) {
|
||||
return dir.absolutePath();
|
||||
}
|
||||
if (!dir.cdUp()) break;
|
||||
}
|
||||
|
||||
// No git root found, use document directory
|
||||
return docDir;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@ private:
|
|||
void reviewDiff();
|
||||
void startSession();
|
||||
|
||||
// Agent naming
|
||||
QString agentNameFromCwd(const QString &cwd);
|
||||
|
||||
// Agent management
|
||||
void ensureAgent();
|
||||
bool selectAgentForProject();
|
||||
|
|
|
|||
Loading…
Reference in New Issue