Skip to content

Commit f1e61b3

Browse files
JordanCoinclaude
andcommitted
Add --stdin flag for sandboxed app integration
Accepts JSON file manifest from stdin instead of reading filesystem. Used by Lens Mac App Store app which can't grant subprocess file access. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c8d8881 commit f1e61b3

1 file changed

Lines changed: 91 additions & 5 deletions

File tree

main.go

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"encoding/json"
55
"fmt"
6+
"io"
67
"os"
78
"path/filepath"
89
"strings"
@@ -11,6 +12,18 @@ import (
1112
"github.com/JordanCoin/docmap/render"
1213
)
1314

15+
// StdinManifest represents the JSON manifest read from stdin
16+
type StdinManifest struct {
17+
Root string `json:"root"`
18+
Files []ManifestFile `json:"files"`
19+
}
20+
21+
// ManifestFile represents a single file in the stdin manifest
22+
type ManifestFile struct {
23+
Path string `json:"path"`
24+
Content string `json:"content"`
25+
}
26+
1427
// JSON output structures
1528
type JSONOutput struct {
1629
Root string `json:"root"`
@@ -48,7 +61,7 @@ func main() {
4861
os.Exit(1)
4962
}
5063

51-
// Check for help/version flags first
64+
// Check for help/version flags first (before full parse)
5265
for _, arg := range os.Args[1:] {
5366
switch arg {
5467
case "--help", "-h":
@@ -60,15 +73,16 @@ func main() {
6073
}
6174
}
6275

63-
target := os.Args[1]
64-
65-
// Parse flags
76+
// Parse flags (scan all args for flags first)
6677
var sectionFilter string
6778
var expandSection string
6879
var searchQuery string
6980
var showRefs bool
7081
var jsonMode bool
71-
for i := 2; i < len(os.Args); i++ {
82+
var stdinMode bool
83+
var target string
84+
85+
for i := 1; i < len(os.Args); i++ {
7286
switch os.Args[i] {
7387
case "--section", "-s":
7488
if i+1 < len(os.Args) {
@@ -89,7 +103,76 @@ func main() {
89103
showRefs = true
90104
case "--json", "-j":
91105
jsonMode = true
106+
case "--stdin":
107+
stdinMode = true
108+
default:
109+
if target == "" {
110+
target = os.Args[i]
111+
}
112+
}
113+
}
114+
115+
// Handle --stdin mode
116+
if stdinMode {
117+
data, err := io.ReadAll(os.Stdin)
118+
if err != nil {
119+
fmt.Fprintf(os.Stderr, "Error reading stdin: %v\n", err)
120+
os.Exit(1)
121+
}
122+
123+
var manifest StdinManifest
124+
if err := json.Unmarshal(data, &manifest); err != nil {
125+
fmt.Fprintf(os.Stderr, "Error parsing JSON manifest: %v\n", err)
126+
os.Exit(1)
127+
}
128+
129+
if manifest.Root == "" {
130+
fmt.Fprintf(os.Stderr, "Error: manifest missing 'root' field\n")
131+
os.Exit(1)
132+
}
133+
134+
// Create temp directory and write files
135+
tmpDir, err := os.MkdirTemp("", "docmap-stdin-*")
136+
if err != nil {
137+
fmt.Fprintf(os.Stderr, "Error creating temp directory: %v\n", err)
138+
os.Exit(1)
92139
}
140+
defer os.RemoveAll(tmpDir)
141+
142+
for _, f := range manifest.Files {
143+
destPath := filepath.Join(tmpDir, f.Path)
144+
if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
145+
fmt.Fprintf(os.Stderr, "Error creating directory for %s: %v\n", f.Path, err)
146+
os.Exit(1)
147+
}
148+
if err := os.WriteFile(destPath, []byte(f.Content), 0644); err != nil {
149+
fmt.Fprintf(os.Stderr, "Error writing %s: %v\n", f.Path, err)
150+
os.Exit(1)
151+
}
152+
}
153+
154+
// Parse the temp directory
155+
docs := parseDirectory(tmpDir)
156+
if len(docs) == 0 {
157+
fmt.Println("No markdown, PDF, or YAML files found")
158+
os.Exit(1)
159+
}
160+
161+
if jsonMode {
162+
outputJSON(docs, manifest.Root)
163+
} else if searchQuery != "" {
164+
render.SearchResults(docs, searchQuery)
165+
} else if showRefs {
166+
render.RefsTree(docs, manifest.Root)
167+
} else {
168+
render.MultiTree(docs, manifest.Root)
169+
}
170+
return
171+
}
172+
173+
if target == "" {
174+
printUsage()
175+
os.Exit(1)
93176
}
94177

95178
// Check if target is a directory
@@ -282,6 +365,7 @@ func printUsage() {
282365
283366
Usage:
284367
docmap <file.md|file.pdf|file.yaml|dir> [flags]
368+
docmap --stdin [flags] < manifest.json
285369
286370
Examples:
287371
docmap . # All markdown, PDF, and YAML files
@@ -293,8 +377,10 @@ Examples:
293377
docmap README.md --expand "API" # Show section content
294378
docmap . --refs # Show cross-references between docs
295379
docmap docs/ --search "auth" # Search across all files
380+
docmap --stdin --json < manifest.json # Parse files from JSON manifest
296381
297382
Flags:
383+
--stdin Read JSON file manifest from stdin (no filesystem access needed)
298384
--search <query> Search sections across all files
299385
-s, --section <name> Filter to a specific section
300386
-e, --expand <name> Show full content of a section

0 commit comments

Comments
 (0)