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
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,18 @@ import "github.com/pilot-protocol/skillinject"
## Usage

```go
// Daemon registration:
// Daemon registration (runs the ticker loop until ctx is cancelled):
rt.Register(skillinject.NewService(skillinject.Config{ /* ... */ }))

// Standalone (e.g. from a CLI):
report := skillinject.Reconcile(skillinject.Config{ /* ... */ })
_ = report
// Blocking loop (first tick fires immediately; subsequent ticks on cfg.Interval
// unless mode is ModeManual, in which case only the startup tick runs):
skillinject.Run(ctx, skillinject.Config{ /* ... */ })

// Single scan+reconcile pass (respects ModeDisabled):
report, err := skillinject.Tick(ctx, skillinject.Config{ /* ... */ })

// Single scan+reconcile pass, ignoring ModeDisabled (e.g. post-update):
report, err = skillinject.ForceTick(ctx, skillinject.Config{ /* ... */ })
```

## Layout
Expand Down
9 changes: 6 additions & 3 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,12 @@ func configFilePath(home string) string {
}

// GetMode returns the current skill_inject mode. Defaults to ModeAuto
// when the flag isn't present, so existing installs keep their current
// live-ticker behaviour. New installs will be set to ModeManual on
// the first call to SetMode (configured by the daemon's startup path).
// when the flag isn't present (or the config is unreadable/unparseable),
// so existing installs keep their current live-ticker behaviour. New
// installs are set to ModeManual explicitly on the first call to SetMode
// (configured by the daemon's startup path) — we never flip an existing
// install off the live ticker by silently changing the absent-config
// default.
func GetMode(home string) string {
f, err := os.Open(configFilePath(home))
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ import (
"time"
)

// TODO: update to pilot-protocol/pilot-skills once that repo is transferred from TeoSlayer.

// DefaultManifestURL is the canonical raw GitHub URL for the inject
// manifest. Overridable via Config.ManifestURL (test hook).
const DefaultManifestURL = "https://raw.githubusercontent.com/TeoSlayer/pilot-skills/main/inject-manifest.json"

// TODO: update to pilot-protocol/pilot-skills once that repo is transferred from TeoSlayer.

// DefaultRepoBaseURL is the prefix used to fetch any path the manifest
// references (skills/<name>/SKILL.md, heartbeats/<tool>.md). Overridable
// via Config.RepoBaseURL.
Expand Down
6 changes: 6 additions & 0 deletions plugin_allowlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ func classifyPluginAllowList(configPath, allowJsonPath, entriesJsonPath, pluginI
// check on rootDir already skipped this whole tool. A missing
// config file at this point means the tool installed but
// hasn't run yet; treat as drifted so the daemon creates it.
//
// For any other read error (permission denied, path is a
// directory) we also return StateDrifted so the caller proceeds
// to mergePluginAllowList, which re-reads the file and surfaces
// the error as an explicit ActionError. Returning StateIdentical
// here would silently swallow an unreadable config as a no-op.
if os.IsNotExist(err) {
return StateDrifted
}
Expand Down
6 changes: 6 additions & 0 deletions skillinject.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,12 @@ func tick(ctx context.Context, cfg Config, force bool) (*Report, error) {
}

hbPath := expandHome(mt.HeartbeatPath, home)
// NOTE: gateway-mode Hermes ignores SOUL.md (#26596) -- this write
// is a no-op for gateway users. Only local-daemon Hermes instances
// pick up the file. See project_harness_plugin_models.md for context.
if strings.HasSuffix(hbPath, "SOUL.md") {
slog.Warn("skillinject: writing SOUL.md for Hermes; gateway-mode Hermes ignores this file (issue #26596) -- write is a no-op for gateway users", "path", hbPath)
}
mState := classifyMarker(hbPath, skillShort)
mAction := actionFor(mState)
mo := Outcome{
Expand Down
Loading