Commit graph

224 commits

Author SHA1 Message Date
Snider
94237f915d
feat(cli): CLI enhancements (#182)
* feat(help): Add CLI help command

Fixes #136

* chore: remove binary

* feat(mcp): Add TCP transport

Fixes #126

* feat(io): Migrate pkg/mcp to use Medium abstraction

Fixes #103

* feat(io): batch implementation placeholder

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(cli): batch implementation placeholder

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(io): Migrate internal/cmd/docs/* to Medium abstraction

Fixes #113

* chore(io): Migrate internal/cmd/dev/* to Medium abstraction

Fixes #114

* chore(io): Migrate internal/cmd/setup/* to Medium abstraction

* chore(io): Complete migration of internal/cmd/dev/* to Medium abstraction

* feat(io): extend Medium interface with Delete, Rename, List, Stat operations

Adds the following methods to the Medium interface:
- Delete(path) - remove a file or empty directory
- DeleteAll(path) - recursively remove a file or directory
- Rename(old, new) - move/rename a file or directory
- List(path) - list directory entries (returns []fs.DirEntry)
- Stat(path) - get file information (returns fs.FileInfo)
- Exists(path) - check if path exists
- IsDir(path) - check if path is a directory

Implements these methods in both local.Medium (using os package)
and MockMedium (in-memory for testing). Includes FileInfo and
DirEntry types for mock implementations.

This enables migration of direct os.* calls to the Medium
abstraction for consistent path validation and testability.

Refs #101

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(io): Migrate internal/cmd/sdk, pkgcmd, and workspace to Medium abstraction

* chore(io): migrate internal/cmd/docs and internal/cmd/dev to Medium

- internal/cmd/docs: Replace os.Stat, os.ReadFile, os.WriteFile,
  os.MkdirAll, os.RemoveAll with io.Local equivalents
- internal/cmd/dev: Replace os.Stat, os.ReadFile, os.WriteFile,
  os.MkdirAll, os.ReadDir with io.Local equivalents
- Fix local.Medium to allow absolute paths when root is "/" for
  full filesystem access (io.Local use case)

Refs #113, #114

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(io): migrate internal/cmd/setup to Medium abstraction

Migrated all direct os.* filesystem calls to use io.Local:
- cmd_repo.go: os.MkdirAll -> io.Local.EnsureDir, os.WriteFile -> io.Local.Write, os.Stat -> io.Local.IsFile
- cmd_bootstrap.go: os.MkdirAll -> io.Local.EnsureDir, os.Stat -> io.Local.IsDir/Exists, os.ReadDir -> io.Local.List
- cmd_registry.go: os.MkdirAll -> io.Local.EnsureDir, os.Stat -> io.Local.Exists
- cmd_ci.go: os.ReadFile -> io.Local.Read
- github_config.go: os.ReadFile -> io.Local.Read, os.Stat -> io.Local.Exists

Refs #116

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(io): migrate pkg/cli/daemon.go to Medium abstraction

Replaces direct os calls with io.Local:
- os.ReadFile -> io.Local.Read
- os.WriteFile -> io.Local.Write
- os.Remove -> io.Local.Delete
- os.MkdirAll -> io.Local.EnsureDir

Closes #107

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(io): address Copilot review feedback

- Fix MockMedium.Rename: collect keys before mutating maps during iteration
- Fix .git checks to use Exists instead of List (handles worktrees/submodules)
- Fix cmd_sync.go: use DeleteAll for recursive directory removal

Files updated:
- pkg/io/io.go: safe map iteration in Rename
- internal/cmd/setup/cmd_bootstrap.go: Exists for .git checks
- internal/cmd/setup/cmd_registry.go: Exists for .git checks
- internal/cmd/pkgcmd/cmd_install.go: Exists for .git checks
- internal/cmd/pkgcmd/cmd_manage.go: Exists for .git checks
- internal/cmd/docs/cmd_sync.go: DeleteAll for recursive delete

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(updater): resolve PkgVersion duplicate declaration

Remove var PkgVersion from updater.go since go generate creates
const PkgVersion in version.go. Track version.go in git to ensure
builds work without running go generate first.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style: fix formatting in internal/variants

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(io): simplify local Medium implementation

Rewrote to match the simpler TypeScript pattern:
- path() sanitizes and returns string directly
- Each method calls path() once
- No complex symlink validation
- Less code, less attack surface

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(io): remove duplicate method declarations

Clean up the client.go file that had duplicate method declarations
from a bad cherry-pick merge. Now has 127 lines of simple, clean code.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(io): fix traversal test to match sanitization behavior

The simplified path() sanitizes .. to . without returning errors.
Update test to verify sanitization works correctly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(mcp): update sandboxing tests for simplified Medium

The simplified io/local.Medium implementation:
- Sanitizes .. to . (no error, path is cleaned)
- Allows absolute paths through (caller validates if needed)
- Follows symlinks (no traversal blocking)

Update tests to match this simplified behavior.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 07:48:34 +00:00
Snider
07191e92f8
feat(log): Logging enhancements (#181)
* feat(help): Add CLI help command

Fixes #136

* chore: remove binary

* feat(mcp): Add TCP transport

Fixes #126

* feat(io): Migrate pkg/mcp to use Medium abstraction

Fixes #103

* feat(io): batch implementation placeholder

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(log): batch implementation placeholder

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(io): Migrate internal/cmd/docs/* to Medium abstraction

Fixes #113

* chore(io): Migrate internal/cmd/dev/* to Medium abstraction

Fixes #114

* chore(io): Migrate internal/cmd/setup/* to Medium abstraction

* chore(io): Complete migration of internal/cmd/dev/* to Medium abstraction

* feat(io): extend Medium interface with Delete, Rename, List, Stat operations

Adds the following methods to the Medium interface:
- Delete(path) - remove a file or empty directory
- DeleteAll(path) - recursively remove a file or directory
- Rename(old, new) - move/rename a file or directory
- List(path) - list directory entries (returns []fs.DirEntry)
- Stat(path) - get file information (returns fs.FileInfo)
- Exists(path) - check if path exists
- IsDir(path) - check if path is a directory

Implements these methods in both local.Medium (using os package)
and MockMedium (in-memory for testing). Includes FileInfo and
DirEntry types for mock implementations.

This enables migration of direct os.* calls to the Medium
abstraction for consistent path validation and testability.

Refs #101

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(io): Migrate internal/cmd/sdk, pkgcmd, and workspace to Medium abstraction

* chore(io): migrate internal/cmd/docs and internal/cmd/dev to Medium

- internal/cmd/docs: Replace os.Stat, os.ReadFile, os.WriteFile,
  os.MkdirAll, os.RemoveAll with io.Local equivalents
- internal/cmd/dev: Replace os.Stat, os.ReadFile, os.WriteFile,
  os.MkdirAll, os.ReadDir with io.Local equivalents
- Fix local.Medium to allow absolute paths when root is "/" for
  full filesystem access (io.Local use case)

Refs #113, #114

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(io): migrate internal/cmd/setup to Medium abstraction

Migrated all direct os.* filesystem calls to use io.Local:
- cmd_repo.go: os.MkdirAll -> io.Local.EnsureDir, os.WriteFile -> io.Local.Write, os.Stat -> io.Local.IsFile
- cmd_bootstrap.go: os.MkdirAll -> io.Local.EnsureDir, os.Stat -> io.Local.IsDir/Exists, os.ReadDir -> io.Local.List
- cmd_registry.go: os.MkdirAll -> io.Local.EnsureDir, os.Stat -> io.Local.Exists
- cmd_ci.go: os.ReadFile -> io.Local.Read
- github_config.go: os.ReadFile -> io.Local.Read, os.Stat -> io.Local.Exists

Refs #116

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(log): add error creation and log-and-return helpers

Implements issues #129 and #132:

- Add Err struct with Op, Msg, Err, Code fields for structured errors
- Add E(), Wrap(), WrapCode(), NewCode() for error creation
- Add Is(), As(), NewError(), Join() as stdlib wrappers
- Add Op(), ErrCode(), Message(), Root() for introspection
- Add LogError(), LogWarn(), Must() for combined log-and-return

Closes #129
Closes #132

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(io): address Copilot review feedback

- Fix MockMedium.Rename: collect keys before mutating maps during iteration
- Fix .git checks to use Exists instead of List (handles worktrees/submodules)
- Fix cmd_sync.go: use DeleteAll for recursive directory removal

Files updated:
- pkg/io/io.go: safe map iteration in Rename
- internal/cmd/setup/cmd_bootstrap.go: Exists for .git checks
- internal/cmd/setup/cmd_registry.go: Exists for .git checks
- internal/cmd/pkgcmd/cmd_install.go: Exists for .git checks
- internal/cmd/pkgcmd/cmd_manage.go: Exists for .git checks
- internal/cmd/docs/cmd_sync.go: DeleteAll for recursive delete

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(updater): resolve PkgVersion duplicate declaration

Remove var PkgVersion from updater.go since go generate creates
const PkgVersion in version.go. Track version.go in git to ensure
builds work without running go generate first.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style: fix formatting in internal/variants

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(io): simplify local Medium implementation

Rewrote to match the simpler TypeScript pattern:
- path() sanitizes and returns string directly
- Each method calls path() once
- No complex symlink validation
- Less code, less attack surface

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(io): remove duplicate method declarations

Clean up the client.go file that had duplicate method declarations
from a bad cherry-pick merge. Now has 127 lines of simple, clean code.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(io): fix traversal test to match sanitization behavior

The simplified path() sanitizes .. to . without returning errors.
Update test to verify sanitization works correctly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(mcp): update sandboxing tests for simplified Medium

The simplified io/local.Medium implementation:
- Sanitizes .. to . (no error, path is cleaned)
- Allows absolute paths through (caller validates if needed)
- Follows symlinks (no traversal blocking)

Update tests to match this simplified behavior.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: address CodeRabbit review feedback for PR #181

- internal/cmd/dev/cmd_file_sync.go: Add EnsureDir error handling before Copy
- internal/cmd/docs/cmd_sync.go: Add EnsureDir error handling for parent dirs
- internal/cmd/sdk/generators/go.go: Use log.E() helper instead of fmt.Errorf
- pkg/io/local/client.go: Handle Windows drive-root paths in path()
- pkg/log/errors.go: Avoid leading colon when Op is empty, preserve Code in Wrap
- pkg/log/errors_test.go: Rename tests to follow _Good/_Bad/_Ugly suffix pattern
- pkg/mcp/transport_tcp.go: Fix ctx cancellation, increase scanner buffer, use io.EOF

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 07:44:29 +00:00
Snider
ca82668bad
feat(errors): Unify errors and logging (#180)
* feat(help): Add CLI help command

Fixes #136

* chore: remove binary

* feat(mcp): Add TCP transport

Fixes #126

* feat(io): Migrate pkg/mcp to use Medium abstraction

Fixes #103

* feat(io): batch implementation placeholder

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(errors): batch implementation placeholder

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(log): batch implementation placeholder

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(io): Migrate internal/cmd/docs/* to Medium abstraction

Fixes #113

* chore(io): Migrate internal/cmd/dev/* to Medium abstraction

Fixes #114

* chore(io): Migrate internal/cmd/setup/* to Medium abstraction

* chore(io): Complete migration of internal/cmd/dev/* to Medium abstraction

* feat(io): extend Medium interface with Delete, Rename, List, Stat operations

Adds the following methods to the Medium interface:
- Delete(path) - remove a file or empty directory
- DeleteAll(path) - recursively remove a file or directory
- Rename(old, new) - move/rename a file or directory
- List(path) - list directory entries (returns []fs.DirEntry)
- Stat(path) - get file information (returns fs.FileInfo)
- Exists(path) - check if path exists
- IsDir(path) - check if path is a directory

Implements these methods in both local.Medium (using os package)
and MockMedium (in-memory for testing). Includes FileInfo and
DirEntry types for mock implementations.

This enables migration of direct os.* calls to the Medium
abstraction for consistent path validation and testability.

Refs #101

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(io): Migrate internal/cmd/sdk, pkgcmd, and workspace to Medium abstraction

* chore(io): migrate internal/cmd/docs and internal/cmd/dev to Medium

- internal/cmd/docs: Replace os.Stat, os.ReadFile, os.WriteFile,
  os.MkdirAll, os.RemoveAll with io.Local equivalents
- internal/cmd/dev: Replace os.Stat, os.ReadFile, os.WriteFile,
  os.MkdirAll, os.ReadDir with io.Local equivalents
- Fix local.Medium to allow absolute paths when root is "/" for
  full filesystem access (io.Local use case)

Refs #113, #114

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(io): migrate internal/cmd/setup to Medium abstraction

Migrated all direct os.* filesystem calls to use io.Local:
- cmd_repo.go: os.MkdirAll -> io.Local.EnsureDir, os.WriteFile -> io.Local.Write, os.Stat -> io.Local.IsFile
- cmd_bootstrap.go: os.MkdirAll -> io.Local.EnsureDir, os.Stat -> io.Local.IsDir/Exists, os.ReadDir -> io.Local.List
- cmd_registry.go: os.MkdirAll -> io.Local.EnsureDir, os.Stat -> io.Local.Exists
- cmd_ci.go: os.ReadFile -> io.Local.Read
- github_config.go: os.ReadFile -> io.Local.Read, os.Stat -> io.Local.Exists

Refs #116

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(log): add error creation and log-and-return helpers

Implements issues #129 and #132:

- Add Err struct with Op, Msg, Err, Code fields for structured errors
- Add E(), Wrap(), WrapCode(), NewCode() for error creation
- Add Is(), As(), NewError(), Join() as stdlib wrappers
- Add Op(), ErrCode(), Message(), Root() for introspection
- Add LogError(), LogWarn(), Must() for combined log-and-return

Closes #129
Closes #132

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(errors): create deprecation alias pointing to pkg/log

Makes pkg/errors a thin compatibility layer that re-exports from pkg/log.
All error handling functions now have canonical implementations in pkg/log.

Migration guide in package documentation:
- errors.Error -> log.Err
- errors.E -> log.E
- errors.Code -> log.NewCode
- errors.New -> log.NewError

Fixes behavior consistency:
- E(op, msg, nil) now creates an error (for errors without cause)
- Wrap(nil, op, msg) returns nil (for conditional wrapping)
- WrapCode returns nil only when both err is nil AND code is empty

Closes #128

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore(log): migrate pkg/errors imports to pkg/log

Migrates all internal packages from pkg/errors to pkg/log:
- internal/cmd/monitor
- internal/cmd/qa
- internal/cmd/dev
- pkg/agentic

Closes #130

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(io): address Copilot review feedback

- Fix MockMedium.Rename: collect keys before mutating maps during iteration
- Fix .git checks to use Exists instead of List (handles worktrees/submodules)
- Fix cmd_sync.go: use DeleteAll for recursive directory removal

Files updated:
- pkg/io/io.go: safe map iteration in Rename
- internal/cmd/setup/cmd_bootstrap.go: Exists for .git checks
- internal/cmd/setup/cmd_registry.go: Exists for .git checks
- internal/cmd/pkgcmd/cmd_install.go: Exists for .git checks
- internal/cmd/pkgcmd/cmd_manage.go: Exists for .git checks
- internal/cmd/docs/cmd_sync.go: DeleteAll for recursive delete

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(updater): resolve PkgVersion duplicate declaration

Remove var PkgVersion from updater.go since go generate creates
const PkgVersion in version.go. Track version.go in git to ensure
builds work without running go generate first.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style: fix formatting in internal/variants

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style: fix formatting across migrated files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(io): simplify local Medium implementation

Rewrote to match the simpler TypeScript pattern:
- path() sanitizes and returns string directly
- Each method calls path() once
- No complex symlink validation
- Less code, less attack surface

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(io): remove duplicate method declarations

Clean up the client.go file that had duplicate method declarations
from a bad cherry-pick merge. Now has 127 lines of simple, clean code.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(io): fix traversal test to match sanitization behavior

The simplified path() sanitizes .. to . without returning errors.
Update test to verify sanitization works correctly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(mcp): update sandboxing tests for simplified Medium

The simplified io/local.Medium implementation:
- Sanitizes .. to . (no error, path is cleaned)
- Allows absolute paths through (caller validates if needed)
- Follows symlinks (no traversal blocking)

Update tests to match this simplified behavior.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 06:48:40 +00:00
Snider
d50e6982de
feat(io): extend Medium interface with DeleteAll, Stat, Exists, IsDir (#240)
Add missing methods to complete the Medium interface:
- DeleteAll: recursive delete
- Stat: file information
- Exists: check if path exists
- IsDir: check if path is a directory

Also update MockMedium to implement all interface methods.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 04:25:30 +00:00
Snider
99514d23e6
feat: Batch implementation of Gemini issues (#176)
* feat(help): Add CLI help command

Fixes #136

* chore: remove binary

* feat(mcp): Add TCP transport

Fixes #126

* feat(io): Migrate pkg/mcp to use Medium abstraction

Fixes #103

* chore(io): Migrate internal/cmd/docs/* to Medium abstraction

Fixes #113

* chore(io): Migrate internal/cmd/dev/* to Medium abstraction

Fixes #114

* chore(io): Migrate internal/cmd/setup/* to Medium abstraction

* chore(io): Complete migration of internal/cmd/dev/* to Medium abstraction

* chore(io): Migrate internal/cmd/sdk, pkgcmd, and workspace to Medium abstraction

* style: fix formatting in internal/variants

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(io): simplify local Medium implementation

Rewrote to match the simpler TypeScript pattern:
- path() sanitizes and returns string directly
- Each method calls path() once
- No complex symlink validation
- Less code, less attack surface

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test(mcp): update sandboxing tests for simplified Medium

The simplified io/local.Medium implementation:
- Sanitizes .. to . (no error, path is cleaned)
- Allows absolute paths through (caller validates if needed)
- Follows symlinks (no traversal blocking)

Update tests to match this simplified behavior.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(updater): resolve PkgVersion duplicate declaration

Remove var PkgVersion from updater.go since go generate creates
const PkgVersion in version.go. Track version.go in git to ensure
builds work without running go generate first.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 04:20:18 +00:00
Snider
fe59faa043
fix(container): prevent data race in State.Get and State.All (#238)
Return copies of Container structs instead of pointers to the map
entries. This prevents data races when containers are modified
concurrently by waitForExit and Stop.

Fixes #76

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 04:16:05 +00:00
Snider
7fede9d563
feat(help): add markdown parsing and section extraction (#174)
* feat(help): add markdown parsing and section extraction

Implements #137: markdown parsing and section extraction for help system.

- Add Topic and Section types for help content structure
- Add Frontmatter type for YAML metadata parsing
- Add ParseTopic() to parse markdown files into Topic structs
- Add ExtractFrontmatter() to extract YAML frontmatter
- Add ExtractSections() to extract headings and content
- Add GenerateID() to create URL-safe anchor IDs
- Add comprehensive tests following _Good/_Bad naming convention

This is the foundation for the display-agnostic help system (#133).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(test): use manual cleanup for TestDevOps_Boot_Good_FreshWithNoExisting

Fixes flaky test that fails with "TempDir RemoveAll cleanup: directory
not empty" by using os.MkdirTemp with t.Cleanup instead of t.TempDir().

This is the same fix applied to TestDevOps_Boot_Good_Success in 8effbda.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(help): address CodeRabbit review feedback

- Add CRLF line ending support to frontmatter regex
- Add empty frontmatter block support
- Use filepath.Base/Ext for cross-platform path handling
- Add tests for CRLF and empty frontmatter cases

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(help): add full-text search functionality (#175)

* fix(test): use manual cleanup for TestDevOps_Boot_Good_FreshWithNoExisting

Fixes flaky test that fails with "TempDir RemoveAll cleanup: directory
not empty" by using os.MkdirTemp with t.Cleanup instead of t.TempDir().

This is the same fix applied to TestDevOps_Boot_Good_Success in 8effbda.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(help): add full-text search functionality

Implements #139: full-text search for help topics.

- Add searchIndex with inverted index for fast lookups
- Add tokenize() for case-insensitive word extraction
- Add Search() with relevance ranking:
  - Exact word matches score 1.0
  - Prefix matches score 0.5
  - Title matches get 2.0 boost
- Add snippet extraction for search result context
- Add section-level matching for precise results
- Add comprehensive tests following _Good/_Bad naming

Search features:
- Case-insensitive matching
- Partial word matching (prefix)
- Title boost (matches in title rank higher)
- Section-level results
- Snippet extraction with context

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(help): address CodeRabbit review feedback

- Add CRLF line ending support to frontmatter regex
- Add empty frontmatter block support
- Use filepath.Base/Ext for cross-platform path handling
- Add tests for CRLF and empty frontmatter cases

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>

* fix(help): use rune-based slicing for UTF-8 safe snippets

Address CodeRabbit feedback: byte-based slicing can corrupt multi-byte
UTF-8 characters. Now uses rune-based indexing for snippet extraction.

- Convert content to []rune before slicing
- Convert byte position to rune position for match location
- Add UTF-8 validation tests with Japanese text

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(help): use correct string for byte-to-rune conversion in extractSnippet

strings.ToLower can change byte lengths for certain Unicode characters
(e.g., K U+212A 3 bytes → k 1 byte). Since matchPos is a byte index from
strings.Index(contentLower, word), the rune conversion must also use
contentLower to maintain correct index alignment.

Fixes CodeRabbit review feedback.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 00:07:32 +00:00
Snider
5631e04a12
feat(io): Migrate filesystem access to pkg/io Medium abstraction (#172)
* feat(io): add pkg/io with symlink-safe path validation

- Add pkg/io with Medium interface for filesystem abstraction
- Add pkg/io/local with sandboxed filesystem implementation
- Add symlink-safe path validation to prevent bypass attacks
- Add sentinel errors (ErrPathTraversal, ErrSymlinkTraversal)
- Add NewSandboxed() for creating sandboxed Medium instances
- Add MockMedium for testing

Closes #169

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(io): extend Medium interface with Delete, Rename, List, Stat operations

Add missing filesystem operations to Medium interface:
- Delete(path) - removes file or empty directory
- DeleteAll(path) - removes path and contents recursively
- Rename(old, new) - moves or renames files/directories
- Exists(path) - checks if path exists
- IsDir(path) - checks if path is a directory
- List(path) - returns directory contents as []os.DirEntry
- Stat(path) - returns file info as os.FileInfo

Implements both local.Medium and MockMedium with full support.

Closes #102

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(io): MockMedium.Read returns os.ErrNotExist for consistency

Ensures os.IsNotExist(err) works with MockMedium like with real filesystem.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 22:50:55 +00:00
Snider
3365bfd5ba
feat(mcp): add workspace root validation to prevent path traversal (#100)
* feat(mcp): add workspace root validation to prevent path traversal

- Add workspaceRoot field to Service for restricting file operations
- Add WithWorkspaceRoot() option for configuring the workspace directory
- Add validatePath() helper to check paths are within workspace
- Apply validation to all file operation handlers
- Default to current working directory for security
- Add comprehensive tests for path validation

Closes #82

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: move CLI commands from pkg/ to internal/cmd/

- Move 18 CLI command packages to internal/cmd/ (not externally importable)
- Keep 16 library packages in pkg/ (externally importable)
- Update all import paths throughout codebase
- Cleaner separation between CLI logic and reusable libraries

CLI commands moved: ai, ci, dev, docs, doctor, gitcmd, go, monitor,
php, pkgcmd, qa, sdk, security, setup, test, updater, vm, workspace

Libraries remaining: agentic, build, cache, cli, container, devops,
errors, framework, git, i18n, io, log, mcp, process, release, repos

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(mcp): use pkg/io Medium for sandboxed file operations

Replace manual path validation with pkg/io.Medium for all file operations.
This delegates security (path traversal, symlink bypass) to the sandboxed
local.Medium implementation.

Changes:
- Add io.NewSandboxed() for creating sandboxed Medium instances
- Refactor MCP Service to use io.Medium instead of direct os.* calls
- Remove validatePath and resolvePathWithSymlinks functions
- Update tests to verify Medium-based behaviour

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: correct import path and workflow references

- Fix pkg/io/io.go import from core-gui to core
- Update CI workflows to use internal/cmd/updater path

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(security): address CodeRabbit review issues for path validation

- pkg/io/local: add symlink resolution and boundary-aware containment
  - Reject absolute paths in sandboxed Medium
  - Use filepath.EvalSymlinks to prevent symlink bypass attacks
  - Fix prefix check to prevent /tmp/root matching /tmp/root2

- pkg/mcp: fix resolvePath to validate and return errors
  - Changed resolvePath from (string) to (string, error)
  - Update deleteFile, renameFile, listDirectory, fileExists to handle errors
  - Changed New() to return (*Service, error) instead of *Service
  - Properly propagate option errors instead of silently discarding

- pkg/io: wrap errors with E() helper for consistent context
  - Copy() and MockMedium.Read() now use coreerr.E()

- tests: rename to use _Good/_Bad/_Ugly suffixes per coding guidelines
  - Fix hardcoded /tmp in TestPath to use t.TempDir()
  - Add TestResolvePath_Bad_SymlinkTraversal test

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style: fix gofmt formatting

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style: fix gofmt formatting across all files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 21:59:34 +00:00
Snider
bc490f5a21
feat(cli): add NO_COLOR environment variable support (#98)
Implement the NO_COLOR standard (https://no-color.org/) for CLI output.
When NO_COLOR is set (to any value), ANSI color codes are disabled.

Changes:
- Add init() to check NO_COLOR and TERM=dumb environment variables
- Add ColorEnabled() to query current color state
- Add SetColorEnabled() to programmatically enable/disable colors
- Modify AnsiStyle.Render() to return plain text when colors disabled
- Update UseASCII() to also disable colors (consistent with ASCII mode)
- Add comprehensive tests for color enable/disable functionality

Usage:
  NO_COLOR=1 core dev status  # Runs without color output
  TERM=dumb core dev status   # Also disables colors

Closes #87

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-01 16:40:03 +00:00
Snider
1524e20c69
docs(process): add docstrings to Logger interface methods (#97)
Add missing documentation to Logger interface methods and NopLogger
implementation to satisfy 80% docstring coverage threshold.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-01 16:12:01 +00:00
Snider
4f1c6926b2
feat(dev): add confirmation prompt to apply command (#96)
Add safety confirmation prompt to `core dev apply` before executing
shell commands. This prevents accidental execution of destructive
commands pasted from untrusted sources or generated by AI agents.

Changes:
- Add --yes/-y flag to skip confirmation prompt
- Show warning and require explicit "y" confirmation before execution
- Allow --dry-run to bypass confirmation (no actual execution)
- Use existing cli.Confirm with Required() for mandatory response

Usage:
  core dev apply --command="rm -rf ."     # Prompts for confirmation
  core dev apply --command="..." --yes    # Skips confirmation
  core dev apply --command="..." --dry-run # No execution, no prompt

Closes #81

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-01 16:06:04 +00:00
Snider
451e84aa76
fix(core): add thread-safety to global Core instance (#95)
Protect the global `instance` variable with sync.RWMutex to prevent
data races when SetInstance/App() are called concurrently (especially
in tests).

Changes:
- Add instanceMu mutex to protect instance variable
- Update App() to use RLock for reading
- Update SetInstance() to use Lock for writing
- Add GetInstance() for non-panicking access
- Add ClearInstance() for test cleanup
- Update tests to use new thread-safe functions
- Add concurrent access test with race detector

Closes #84

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-01 16:03:44 +00:00
Snider
d51d6f907a
fix(agentic): use context.TODO instead of nil Context (#94)
Replace nil Context parameters with context.TODO() to comply with
staticcheck SA1012: "do not pass a nil Context, even if a function
permits it; pass context.TODO if you are unsure about which Context
to use"

Closes #78

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-01 15:58:26 +00:00
Snider
33c55d9bdd
feat(process): add Logger interface for exec wrapper (#93)
- Define Logger interface with Debug and Error methods
- Add NopLogger as default (no-op implementation)
- Add SetDefaultLogger/DefaultLogger for package-level config
- Add WithLogger method for per-command logger injection
- Log commands at DEBUG level before execution
- Log failures at ERROR level with error details
- Add comprehensive tests for logger functionality

Compatible with pkg/log.Logger and other structured loggers.

Closes #90

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-01 15:55:26 +00:00
Snider
de0fac563e
feat(process): add standardized exec wrapper (#91)
* feat(process): add standardized exec wrapper

- Adds pkg/process/exec/exec.go with context and logging support
- Implements Command, Run, Output, CombinedOutput, RunQuiet helpers
- Enforces context usage (falls back to background if nil, pending strict enforcement)
- Standardizes error wrapping for exec.ExitError

* fix(process): remove unused cli import

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* style(process): fix trailing whitespace

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 15:39:44 +00:00
Snider
df2c335983 style(update): fix trailing newline in cmd.go
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 12:46:17 +00:00
Snider
f65d111751 fix(update): use build tags for platform-specific watcher code
Split platform-specific functions into separate files:
- cmd_unix.go: Unix implementation using Setpgid and signal 0
- cmd_windows.go: Windows implementation using CREATE_NEW_PROCESS_GROUP
  and OpenProcess for PID checking

Fixes Windows cross-compilation error where Setpgid field doesn't exist.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 12:19:32 +00:00
Snider
180ce7428f refactor(update): use watcher pattern for auto-restart
Replace the direct exec-based restart with a spawned watcher process:
- Add hidden --watch-pid flag for internal use
- spawnWatcher() spawns background process before update
- watchAndRestart() polls for parent death, then restarts binary
- Uses signal 0 on Unix to check if process is alive
- Windows fallback spawns new process and exits

This approach is safer because:
- Parent exits cleanly before restart (no file locking issues)
- Watcher is detached from parent process group
- Works reliably across platforms

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 12:14:51 +00:00
Snider
e41ed47264 feat(update): auto-restart after update to load new version
Uses syscall.Exec on Unix to replace the current process with the
updated binary, running --version to confirm. On Windows, falls back
to a message asking to restart manually.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 12:09:32 +00:00
Snider
7beaabbd63 feat(cli): add core update command for self-updating
- `core update` - Update to latest stable release
- `core update check` - Check for updates without applying
- `core update --channel=dev` - Update to latest dev build
- `core update --force` - Force update even if already on latest

Uses the existing updater package with GitHub releases support.
Automatically detects platform (OS/arch) and downloads correct binary.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 12:06:49 +00:00
Snider
8effbda7cb fix(test): use manual cleanup for TestDevOps_Boot_Good_Success
The test was flaky because t.TempDir() fails cleanup when files are
added asynchronously by the container manager. Using os.MkdirTemp with
manual os.RemoveAll cleanup handles this gracefully.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 11:55:10 +00:00
Snider
e28fc52456 feat(ci): add core setup ci and dogfood CLI in workflows
- Add `core setup ci` command for generating installation scripts
  - Supports bash, powershell, and GitHub Actions YAML output
  - Configurable via .core/ci.yaml
  - Auto-detects platform and uses Homebrew/Scoop/direct download

- Update all GitHub workflows to use global `core` binary:
  - ci.yml: Uses `core go qa` for all quality checks
  - coverage.yml: Uses `core go cov` for coverage
  - release.yml: Uses `core build --ci` for cross-compilation
  - dev-release.yml: Uses `core build --ci` for all targets

- Add .core/ci.yaml with default configuration

This ensures the CLI dogfoods itself across all CI operations,
validating the framework that the Web3 ecosystem builds from.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 11:36:59 +00:00
Snider
fdc108c69e
feat: git command, build improvements, and go fmt git-aware (#74)
* feat(go): make go fmt git-aware by default

- By default, only check changed Go files (modified, staged, untracked)
- Add --all flag to check all files (previous behaviour)
- Reduces noise when running fmt on large codebases

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(build): minimal output by default, add missing i18n

- Default output now shows single line: "Success Built N artifacts (dir)"
- Add --verbose/-v flag to show full detailed output
- Add all missing i18n translations for build commands
- Errors still show failure reason in minimal mode

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add root-level `core git` command

- Create pkg/gitcmd with git workflow commands as root menu
- Export command builders from pkg/dev (AddCommitCommand, etc.)
- Commands available under both `core git` and `core dev` for compatibility
- Git commands: health, commit, push, pull, work, sync, apply
- GitHub orchestration stays in dev: issues, reviews, ci, impact

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(qa): add docblock coverage checking

Implement docblock/docstring coverage analysis for Go code:
- New `core qa docblock` command to check coverage
- Shows compact file:line list when under threshold
- Integrate with `core go qa` as a default check
- Add --docblock-threshold flag (default 80%)

The checker uses Go AST parsing to find exported symbols
(functions, types, consts, vars) without documentation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: address CodeRabbit review feedback

- Fix doc comment: "status" → "health" in gitcmd package
- Implement --check flag for `core go fmt` (exits non-zero if files need formatting)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: add docstrings for 100% coverage

Add documentation comments to all exported symbols:
- pkg/build: ProjectType constants
- pkg/cli: LogLevel, RenderStyle, TableStyle
- pkg/framework: ServiceFor, MustServiceFor, Core.Core
- pkg/git: GitError.Error, GitError.Unwrap
- pkg/i18n: Handler Match/Handle methods
- pkg/log: Level constants
- pkg/mcp: Tool input/output types
- pkg/php: Service constants, QA types, service methods
- pkg/process: ServiceError.Error
- pkg/repos: RepoType constants
- pkg/setup: ChangeType, ChangeCategory constants
- pkg/workspace: AddWorkspaceCommands

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: standardize line endings to LF

Add .gitattributes to enforce LF line endings for all text files.
Normalize all existing files to use Unix-style line endings.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: address CodeRabbit review feedback

- cmd_format.go: validate --check/--fix mutual exclusivity, capture stderr
- cmd_docblock.go: return error instead of os.Exit(1) for proper error handling

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: address CodeRabbit review feedback (round 2)

- linuxkit.go: propagate state update errors, handle cmd.Wait() errors in waitForExit
- mcp.go: guard against empty old_string in editDiff to prevent runaway edits
- cmd_docblock.go: log parse errors instead of silently skipping

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 10:48:44 +00:00
Snider
3ee353f880 feat(i18n): expand CLI translations and fix noun form detection
- Fix loader to properly detect noun form objects by checking for
  one/other structure before processing, preventing false positives
  on objects that happen to be under gram.noun.* path
- Add comprehensive i18n strings for CLI commands including long
  descriptions, flag help text, and status labels
- Add .claude/ project settings for Claude Code integration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 07:39:49 +00:00
Snider
0305f4f733 fix(security): resolve CodeQL and npm vulnerabilities
- Fix integer conversion in hexToRGB using 8-bit ParseUint instead of
  64-bit ParseInt to avoid potential overflow on 32-bit systems
- Update npm dependencies to fix Angular XSRF, XSS and MCP SDK vulnerabilities

Resolves 3 CodeQL alerts and 8 npm high severity vulnerabilities.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 07:04:04 +00:00
Snider
a76f6167b4 fix(devops): fix flaky test cleanup in TestDevOps_Boot_Good_FreshFlag
Use os.MkdirTemp with explicit cleanup instead of t.TempDir() to avoid
cleanup errors when subdirectories are created during test execution.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 06:53:15 +00:00
Snider
0435613a31
chore(deps): update GitHub Actions and Go modules (#73)
GitHub Actions:
- actions/checkout v4 → v6
- actions/upload-artifact v4 → v6
- github/codeql-action v3 → v4
- arduino/setup-task v1 → v2

Go modules:
- golang.org/x/mod v0.31.0 → v0.32.0
- golang.org/x/exp updated
- aead.dev/minisign v0.2.0 → v0.3.0
- github.com/go-openapi/jsonpointer v0.21.0 → v0.22.4
- github.com/go-openapi/swag v0.23.0 → v0.25.4
- github.com/google/jsonschema-go v0.3.0 → v0.4.2
- github.com/mailru/easyjson v0.9.0 → v0.9.1
- github.com/tidwall/match v1.1.1 → v1.2.0
- github.com/woodsbury/decimal128 v1.3.0 → v1.4.0

Also fixed fmt.Errorf with non-constant format string in security package.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 06:46:54 +00:00
Snider
d1b8954578
feat(php): add --json and --sarif flags to QA commands (#69)
* feat(github): add issue templates and auto-labeler

- Add bug_report.yml and feature_request.yml templates
- Add config.yml for issue creation options
- Add auto-label.yml workflow to label issues based on content

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(php): add --json and --sarif flags to QA commands

Adds machine-readable output support to PHP quality assurance commands:

- test: --json flag for JUnit XML output
- fmt: --json flag for JSON formatted output from Pint
- stan: --json and --sarif flags for PHPStan output
- psalm: --json and --sarif flags for Psalm output
- qa: --json flag for JSON summary output

SARIF output enables integration with GitHub Security tab for
static analysis results.

Closes #51

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(php): address CodeRabbit review feedback

- Guard progress messages when JSON/SARIF output is enabled
- Guard success messages when JSON/SARIF output is enabled
- Guard QA results display when JSON output is enabled
- Rename misleading JSON field to JUnit in TestOptions (outputs JUnit XML)
- Add mutual exclusion validation for --json and --sarif flags
- Remove empty conditional block in auto-label workflow
- Add i18n translation for json_sarif_exclusive error

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(php): additional CodeRabbit fixes

- Rename test --json flag to --junit (outputs JUnit XML, not JSON)
- Add actual JSON marshaling for QA command JSON output
- Add JSON tags to QARunResult and QACheckRunResult structs
- Add i18n translation for junit flag

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 06:32:35 +00:00
Snider
6670ad7d2b fix(release): add proper release workflow with version injection
- Make AppVersion injectable via ldflags at build time
- Replace GoReleaser with simple GitHub Actions workflow
- Build for linux/darwin/windows on amd64/arm64
- Generate checksums.txt for integrity verification
- Inject version from git tag into binary

Fixes #37

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 06:21:29 +00:00
Snider
92264f29f4
feat(dev): add safe git operations for AI agents (#71)
* feat(dev): add safe git operations for AI agents

Adds agent-safe commands to prevent common git mistakes:

- `core dev sync <file> --to="pattern"`: Sync files across repos
  - Auto-pulls before copying (safe sync)
  - Optional commit with --message
  - Optional push with --push
  - Dry-run mode with --dry-run

- `core dev apply --command="..."`: Run commands across repos
  - Execute shell commands in each repo
  - Execute scripts with --script
  - Optional commit/push after changes
  - Continue on error with --continue
  - Filter repos with --repos

Safety features:
- Never force push
- Auto-pull before push on rejection
- Report failures without stopping other repos
- Dry-run support for previewing changes

Closes #53

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(dev): address CodeRabbit review feedback

- Use errors.E() for consistent error handling in cmd_apply.go and cmd_file_sync.go
- Add path traversal validation to reject ".." in source paths
- Execute scripts directly to honor shebangs (not via sh)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 06:11:24 +00:00
Snider
b482189ce6
feat(php): add CI/CD pipeline command (#72)
* feat(php): add CI/CD pipeline command

Adds `core php ci` command for CI/CD integration:

- Runs all QA checks in optimal order (test, stan, psalm, fmt, audit, security)
- Generates combined reports in multiple formats:
  - JSON (--json) for machine consumption
  - Markdown summary (--summary) for PR comments
  - SARIF (--sarif) for static analysis tools
- Uploads SARIF to GitHub Security tab (--upload-sarif)
- Configurable failure threshold (--fail-on=critical|high|warning)

Example usage:
  core php ci                    # Run full pipeline
  core php ci --json             # Output JSON report
  core php ci --summary          # Output markdown for PR
  core php ci --sarif --upload-sarif  # Generate and upload SARIF

Closes #52

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(php): address CodeRabbit review feedback on CI command

- Remove unused --parallel flag
- Validate git SHA before SARIF upload
- Properly handle and validate SARIF generation output
- Exit with correct code when --json flag is used and pipeline fails

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 06:11:00 +00:00
Snider
3c9bbb0b64
feat(security): add core security command for vulnerability alerts (#66)
* feat(security): add core security command for vulnerability alerts

Adds `core security` command area to expose GitHub security data:
- `core security alerts` - aggregated view of all security alerts
- `core security deps` - Dependabot vulnerability alerts with upgrade paths
- `core security scan` - CodeQL and code scanning alerts
- `core security secrets` - secret scanning alerts

Features:
- Filter by --repo, --severity (critical,high,medium,low)
- JSON output with --json for AI agent consumption
- Aggregated summary with severity breakdown
- Shows patched versions for easy upgrades

Closes #48

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(security): address CodeRabbit review feedback

- Remove unused flattened fields from DependabotAlert struct
- Add Unknown field to AlertSummary for unrecognized severities
- Add doc comments for exported Add and String methods
- Use cli.Wrap for contextual error wrapping
- Fix secret scanning summary counting after filter
- Remove unused --vulnerable flag from deps command
- Fix JSON output to only include open alerts in secrets command

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(security): handle json.MarshalIndent errors

Address CodeRabbit review feedback by properly handling errors from
json.MarshalIndent in all security subcommands instead of ignoring them.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 06:04:21 +00:00
Snider
4670dbd501
feat(monitor): add security findings aggregation command (#68)
* feat(monitor): add security findings aggregation command

Implements `core monitor` to aggregate security findings from GitHub:
- Code scanning alerts (Semgrep, Trivy, Gitleaks, CodeQL, etc.)
- Dependabot vulnerability alerts
- Secret scanning alerts

Features:
- Scan current repo, specific repo, or all repos via registry
- Filter by severity (--severity critical,high)
- JSON output for piping to other tools (--json)
- Grouped output by repo with severity highlighting

Closes #49

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(monitor): address CodeRabbit review feedback

- Fix DependabotAlert JSON parsing with proper nested struct for
  dependency.manifest_path field
- Remove unnecessary --jq flag from code scanning API call
- Fix truncate() to use runes for proper UTF-8 handling
- Sort repo names for deterministic output ordering
- Document hardcoded org fallback behavior

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(monitor): improve error handling per CodeRabbit review

- Use errors.E() consistently instead of errors.Wrap()
- Pass underlying errors to errors.E() for better context
- Return errors from fetch functions instead of swallowing
- Distinguish expected conditions (feature not enabled) from real errors
- Display fetch warnings in non-JSON mode
- Continue scanning other repos even if one fails

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 05:44:46 +00:00
Snider
3918359c22
feat(qa,dev): add issues, health, and workflow commands (#67)
- qa issues: intelligent issue triage with priority grouping
  - Groups: needs response, ready to work, blocked, needs triage
  - Flags: --mine, --triage, --blocked
  Closes #61

- qa health: aggregate CI health across all repos
  - Shows passing/failing/pending summary
  - Flag: --problems for filtering
  Closes #63

- dev workflow: CI template management
  - list: show workflows across repos
  - sync: copy workflow to repos (with --dry-run)
  Closes #54

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-01 05:20:46 +00:00
Snider
74c1b46f78 fix(container): fix flaky test temp directory cleanup race
Use manual temp directory management with time.Sleep before cleanup
to avoid race condition where state file writes race with t.TempDir's
automatic cleanup.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 04:06:03 +00:00
Snider
80fd39f2d8 fix(sdk): run Docker containers as current user to fix CI cleanup
Docker containers were creating files as root, causing Go test cleanup
to fail with "permission denied". Now passes --user flag on Unix systems
to run containers as the current user.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 04:01:40 +00:00
Snider
b16fa37dfd
feat(qa): add review command for PR status (#64)
* feat(qa): add qa watch command for CI monitoring (#47)

Implements `core qa watch` to monitor GitHub Actions after a push:
- Polls workflow runs for a commit until completion
- Shows live progress with pass/fail counts
- On failure, shows job name, failed step, and link to logs
- Exits with appropriate code (0 = passed, 1 = failed)

Usage:
  core qa watch              # Watch current repo's HEAD
  core qa watch --repo X     # Watch specific repo
  core qa watch --timeout 5m # Custom timeout

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(qa): address CodeRabbit feedback on watch command

- Add length check before slicing commitSha to prevent panic on short SHAs
- Count all non-success conclusions as failures (cancelled, timed_out, etc.)
- Use errors.E/Wrap pattern for consistent error handling with operation context

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(qa): add context-aware commands and log parsing

- Use exec.CommandContext with timeout context for all gh invocations
  so commands are cancelled when deadline expires
- Implement fetchErrorFromLogs using 'gh run view --log-failed'
  to extract first meaningful error line from failed workflows
- Pass context through call chain for proper timeout propagation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(qa): add review command for PR status (#62)

Add `core qa review` command to show PR review status with actionable
next steps. Answers: "What do I need to do to get my PRs merged?"
and "What reviews am I blocking?"

Features:
- Shows your open PRs with merge status (CI, reviews, conflicts)
- Shows PRs where your review is requested
- Provides actionable suggestions (rebase, address feedback, etc.)
- Flags: --mine, --requested, --repo

Closes #62

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(qa): add review command for PR status (#62)

Add `core qa review` command to show PR review status with actionable
next steps. Answers: "What do I need to do to get my PRs merged?"
and "What reviews am I blocking?"

Features:
- Shows your open PRs with merge status (CI, reviews, conflicts)
- Shows PRs where your review is requested
- Provides actionable suggestions (rebase, address feedback, etc.)
- Flags: --mine, --requested, --repo

Closes #62

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(qa): address CodeRabbit feedback on review command

- Fix truncate to use runes for UTF-8 safe string slicing
- Remove unused user parameter from showMyPRs and showRequestedReviews
- Remove unused getCurrentUser function

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(qa): remove duplicate i18n block and improve error handling

- Remove duplicate cmd.qa block in en_GB.json
- Use errors.E consistently for error wrapping
- Require --repo flag when not in a git repository

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 03:56:48 +00:00
Snider
f5bcef421e
fix(i18n): restore missing translation keys for health command (#65)
* fix(i18n): restore missing translation keys for health command

The locale consolidation in 39de3c2 removed keys still used by
cmd_health.go. Added back:
- cmd.dev.health.* keys (long, repos, to_push, to_pull, etc.)
- common.status.* keys (dirty, clean, synced, up_to_date)
- common.flag.registry

Also fixed workspace.LoadConfig() returning default PackagesDir
when no .core/workspace.yaml exists, which was overriding repo
paths from repos.yaml.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: add nil checks for workspace.LoadConfig callers

LoadConfig now returns nil when no .core/workspace.yaml exists.
Added defensive nil checks to all callers to prevent panics.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: align workspace.LoadConfig error handling

Both call sites now gracefully ignore errors and fall back to defaults,
since workspace config is optional for setup commands.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 03:55:01 +00:00
Snider
9db41c4406
feat(qa): add qa watch command for CI monitoring (#60)
* feat(qa): add qa watch command for CI monitoring (#47)

Implements `core qa watch` to monitor GitHub Actions after a push:
- Polls workflow runs for a commit until completion
- Shows live progress with pass/fail counts
- On failure, shows job name, failed step, and link to logs
- Exits with appropriate code (0 = passed, 1 = failed)

Usage:
  core qa watch              # Watch current repo's HEAD
  core qa watch --repo X     # Watch specific repo
  core qa watch --timeout 5m # Custom timeout

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(qa): address CodeRabbit feedback on watch command

- Add length check before slicing commitSha to prevent panic on short SHAs
- Count all non-success conclusions as failures (cancelled, timed_out, etc.)
- Use errors.E/Wrap pattern for consistent error handling with operation context

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(qa): add context-aware commands and log parsing

- Use exec.CommandContext with timeout context for all gh invocations
  so commands are cancelled when deadline expires
- Implement fetchErrorFromLogs using 'gh run view --log-failed'
  to extract first meaningful error line from failed workflows
- Pass context through call chain for proper timeout propagation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 03:37:16 +00:00
Snider
e04d6025dc
feat(setup): add github command for repo configuration (#59)
* feat(setup): add github command for repo configuration (#45)

Implements `core setup github` to configure GitHub repos with org
standards including labels, webhooks, branch protection, and security
settings. Supports dry-run mode, per-repo or all-repos operation, and
selective sync of specific settings.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(setup): address CodeRabbit feedback on github command

- Sort map keys for deterministic diff output in github_diff.go
- Preserve partial results by adding changes before continue on errors
- Reject conflicting --repo and --all flags with clear error message
- Allow empty webhook URLs (skip instead of error) for optional env vars
- Add content_type comparison in webhook sync
- Add required_status_checks comparison in branch protection sync
- Add DisableDependabotSecurityUpdates for bidirectional security control

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(setup): address additional CodeRabbit feedback

- Use filepath.Join for OS-portable path construction in github_config.go
- Fix stringSliceEqual to use frequency counting for proper duplicate handling
- Simplify change accumulation with variadic append

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 03:37:06 +00:00
Snider
edace890f3 feat(workspace): implement workspace.yaml support
- Add pkg/workspace package with config and commands
- Integrate with pkg/php/cmd.go for context switching
- Refactor pkg/repos to use pkg/workspace for config
- Register workspace commands in full variant
2026-02-01 02:18:19 +00:00
Snider
699c0933f6
fix(docs): respect workspace.yaml packages_dir setting (fixes #46) (#55)
* fix(docs): respect workspace.yaml packages_dir setting (fixes #46)

* fix(workspace): improve config loading logic (CR feedback)

- Expand ~ before resolving relative paths in cmd_registry
- Handle LoadWorkspaceConfig errors properly
- Update Repo.Path when PackagesDir overrides default
- Validate workspace config version
- Add unit tests for workspace config loading

* docs: add comments and increase test coverage (CR feedback)

- Add docstrings to exported functions in pkg/cli
- Add unit tests for Semantic Output (pkg/cli/output.go)
- Add unit tests for CheckBuilder (pkg/cli/check.go)
- Add unit tests for IPC Query/Perform (pkg/framework/core)

* fix(test): fix panics and failures in php package tests

- Fix panic in TestLookupLinuxKit_Bad by mocking paths
- Fix assertion errors in TestGetSSLDir_Bad and TestGetPackageInfo_Bad
- Fix formatting in test files

* fix(test): correct syntax in services_extended_test.go

* fix(ci): point coverage workflow to go.mod instead of go.work

* fix(ci): build CLI before running coverage

* fix(ci): run go generate for updater package in coverage workflow

* fix(github): allow dry-run publish without gh CLI authentication

Moves validation check after dry-run check so tests can verify dry-run behavior in CI environments.
2026-02-01 01:59:27 +00:00
Snider
92373db6ac
fix: add Windows compatibility for process management (#58)
Add build tags to separate Unix and Windows process handling in pkg/php:

- services_unix.go: Unix-specific process group handling (Setpgid, Getpgid, Kill)
- services_windows.go: Windows-compatible alternatives using os.Signal
- services.go: Use platform-agnostic helper functions

The pkg/php package now compiles on Windows. Process termination works
via os.Interrupt/os.Kill instead of Unix signals.

Fixes #56

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 01:56:44 +00:00
Snider
694a44dffd
fix(vm): use double-dash flags for linuxkit build command (#57)
LinuxKit v1.8.2+ requires double-dash flags (--format, --name, etc.)
instead of single-dash flags. The old flags were being parsed incorrectly,
e.g., `-name` was interpreted as `-n` with value `ame`.

Files updated:
- pkg/build/builders/linuxkit.go
- pkg/php/container.go
- pkg/release/publishers/linuxkit.go
- pkg/release/publishers/linuxkit_test.go

Fixes #50

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 01:49:00 +00:00
Snider
cdcb489d7b refactor: migrate all pkg/* to cli abstraction
- Replaces lipgloss/fmt with cli.* functions
- Adds unit tests for new cli components
- Fixes all build errors

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 23:54:01 +00:00
Snider
f07e5bb3ff feat(cli): add DX-focused semantic output patterns
- Check() fluent builder for check results
- Task() for task headers
- Section() for section headers
- Hint() for labelled hints
- Severity() for severity-styled output
- Result() for pass/fail results

Consuming packages now have zero display logic.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 23:54:01 +00:00
Snider
6ae9e6544a feat(cli): add HLCRF layout system
- Layout parser for variant strings
- Terminal renderer with support for nested layouts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 23:54:01 +00:00
Snider
4ce5edbe46 refactor(setup): replace huh with simple stdin prompts
Removes transitive dependencies on charmbracelet/huh.
Previous wizard at 96eaed5 if needed.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 23:54:01 +00:00
Snider
6f3d8341d5 refactor(php,vm): migrate to cli ANSI styling
Removes direct lipgloss imports.
Migrates cli.Line usage to cli.Blank/Echo.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 23:54:01 +00:00