Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ dotagents sessions [--no-open] [--ssh-host user@host] [--port N] [--host ADDR]
dotagents skill new|list|info|update|promote
dotagents publish [--target NAME] [--skills a,b] [--dry-run] [--json] [--yes] # push skills to a remote registry
dotagents mcp list|add|import|remove
dotagents hook list [query] | remove [--dry-run] <query>
```

## Supported integrations
Expand All @@ -117,6 +118,8 @@ dotagents can launch two optional external tools. Neither is installed, vendored

`dotagents skill list` remains the built-in provenance view for each harness skill root. It reports managed links, foreign symlinks, unmanaged directories, drift, broken links, and estimated context cost.

`dotagents hook list [query]` inventories native hook registrations and marks canonical entries as managed and missing script targets as stale. To clean up a hook installed outside dotagents, preview with `dotagents hook remove --dry-run <query>`, then rerun without `--dry-run`; unrelated hook entries are preserved. `dotagents doctor` reports stale native hooks, and `dotagents sync` reconciles the remaining canonical hooks afterward.

`dotagents inspect` shells out to HarnessKit (`hk serve`). Treat it as read-mostly: HarnessKit's enable/disable/deploy actions bypass dotagents, so reconcile any changes with `dotagents sync`. Install HarnessKit separately.

`dotagents sessions` shells out to AgentsView (`agentsview serve`). AgentsView owns its local transcript index and configuration; dotagents does not sync or mutate either. `--no-open` maps to AgentsView's `--no-browser`; `--ssh-host user@host` prints a loopback tunnel command on a remote machine. Other flags are forwarded to `agentsview serve`. Install AgentsView separately.
Expand Down
2 changes: 1 addition & 1 deletion cmd/dotagents/cli_launch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func TestRootHelpAdvertisesCanonicalDescriptiveFamilies(t *testing.T) {
}
families = append(families, fields[0])
}
if got, want := strings.Join(families, ","), "setup,status,sync,doctor,config,view,inspect,sessions,skill,publish,mcp"; got != want {
if got, want := strings.Join(families, ","), "setup,status,sync,doctor,config,view,inspect,sessions,skill,publish,mcp,hook"; got != want {
t.Fatalf("short-help families = %q, want %q:\n%s", got, want, stdout)
}
if !strings.Contains(stdout, `Run "dotagents help --all" for flags, maintenance commands, and compatibility aliases.`) {
Expand Down
27 changes: 27 additions & 0 deletions cmd/dotagents/doctor.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func runDoctor(opts runOptions) error {
results = append(results, checkMaterializedExternalSkills(repoRoot, cfg, home))
results = append(results, checkExternalSkillLock(repoRoot, cfg, home))
results = append(results, checkExternalSkillAudit(cfg, home))
results = append(results, checkNativeHookHealth(home, cfg, selected))

fmt.Println("checks:")
labelWidth := 0
Expand Down Expand Up @@ -100,6 +101,32 @@ func runDoctor(opts runOptions) error {
return doctorExitError(failed, warned)
}

func checkNativeHookHealth(home string, cfg config, selected []agentConfig) checkResult {
entries, unsupported, err := collectNativeHooks(home, cfg, selected)
if err != nil {
return checkResult{"native hooks", checkStatusFail, err.Error()}
}
managed := 0
var stale []string
for _, entry := range entries {
if entry.Managed {
managed++
}
if entry.MissingTarget != "" {
stale = append(stale, fmt.Sprintf("%s/%s -> %s", entry.Agent, entry.Event, entry.MissingTarget))
}
}
if len(stale) > 0 {
sort.Strings(stale)
return checkResult{"native hooks", checkStatusWarn, fmt.Sprintf("%d stale registration(s); first: %s; review with: dotagents hook list", len(stale), stale[0])}
}
detail := fmt.Sprintf("%d registrations, %d managed, %d unmanaged", len(entries), managed, len(entries)-managed)
if len(unsupported) > 0 {
detail += fmt.Sprintf("; unsupported: %s", strings.Join(unsupported, ", "))
}
return checkResult{"native hooks", checkStatusPass, detail}
}

// doctorExitError derives the doctor exit result from check outcomes only. It
// intentionally takes no note/advisory input so context notes cannot affect it.
func doctorExitError(failed, warned int) error {
Expand Down
Loading
Loading