@groundnuty/macf 0.2.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/dist/.build-info.json +4 -0
  2. package/dist/cli/build-info.d.ts +38 -0
  3. package/dist/cli/build-info.d.ts.map +1 -0
  4. package/dist/cli/build-info.js +119 -0
  5. package/dist/cli/build-info.js.map +1 -0
  6. package/dist/cli/claude-sh.d.ts +42 -0
  7. package/dist/cli/claude-sh.d.ts.map +1 -0
  8. package/dist/cli/claude-sh.js +247 -0
  9. package/dist/cli/claude-sh.js.map +1 -0
  10. package/dist/cli/commands/cd.d.ts +6 -0
  11. package/dist/cli/commands/cd.d.ts.map +1 -0
  12. package/dist/cli/commands/cd.js +17 -0
  13. package/dist/cli/commands/cd.js.map +1 -0
  14. package/dist/cli/commands/certs.d.ts +33 -0
  15. package/dist/cli/commands/certs.d.ts.map +1 -0
  16. package/dist/cli/commands/certs.js +233 -0
  17. package/dist/cli/commands/certs.js.map +1 -0
  18. package/dist/cli/commands/doctor.d.ts +91 -0
  19. package/dist/cli/commands/doctor.d.ts.map +1 -0
  20. package/dist/cli/commands/doctor.js +235 -0
  21. package/dist/cli/commands/doctor.js.map +1 -0
  22. package/dist/cli/commands/init.d.ts +37 -0
  23. package/dist/cli/commands/init.d.ts.map +1 -0
  24. package/dist/cli/commands/init.js +279 -0
  25. package/dist/cli/commands/init.js.map +1 -0
  26. package/dist/cli/commands/list.d.ts +5 -0
  27. package/dist/cli/commands/list.d.ts.map +1 -0
  28. package/dist/cli/commands/list.js +21 -0
  29. package/dist/cli/commands/list.js.map +1 -0
  30. package/dist/cli/commands/migrate-ca-key.d.ts +36 -0
  31. package/dist/cli/commands/migrate-ca-key.d.ts.map +1 -0
  32. package/dist/cli/commands/migrate-ca-key.js +92 -0
  33. package/dist/cli/commands/migrate-ca-key.js.map +1 -0
  34. package/dist/cli/commands/peers.d.ts +8 -0
  35. package/dist/cli/commands/peers.d.ts.map +1 -0
  36. package/dist/cli/commands/peers.js +45 -0
  37. package/dist/cli/commands/peers.js.map +1 -0
  38. package/dist/cli/commands/repo-init.d.ts +43 -0
  39. package/dist/cli/commands/repo-init.d.ts.map +1 -0
  40. package/dist/cli/commands/repo-init.js +304 -0
  41. package/dist/cli/commands/repo-init.js.map +1 -0
  42. package/dist/cli/commands/rules-refresh.d.ts +14 -0
  43. package/dist/cli/commands/rules-refresh.d.ts.map +1 -0
  44. package/dist/cli/commands/rules-refresh.js +67 -0
  45. package/dist/cli/commands/rules-refresh.js.map +1 -0
  46. package/dist/cli/commands/self-update.d.ts +14 -0
  47. package/dist/cli/commands/self-update.d.ts.map +1 -0
  48. package/dist/cli/commands/self-update.js +112 -0
  49. package/dist/cli/commands/self-update.js.map +1 -0
  50. package/dist/cli/commands/status.d.ts +9 -0
  51. package/dist/cli/commands/status.d.ts.map +1 -0
  52. package/dist/cli/commands/status.js +90 -0
  53. package/dist/cli/commands/status.js.map +1 -0
  54. package/dist/cli/commands/update.d.ts +25 -0
  55. package/dist/cli/commands/update.d.ts.map +1 -0
  56. package/dist/cli/commands/update.js +316 -0
  57. package/dist/cli/commands/update.js.map +1 -0
  58. package/dist/cli/config.d.ts +103 -0
  59. package/dist/cli/config.d.ts.map +1 -0
  60. package/dist/cli/config.js +224 -0
  61. package/dist/cli/config.js.map +1 -0
  62. package/dist/cli/index.d.ts +3 -0
  63. package/dist/cli/index.d.ts.map +1 -0
  64. package/dist/cli/index.js +245 -0
  65. package/dist/cli/index.js.map +1 -0
  66. package/dist/cli/plugin-fetcher.d.ts +20 -0
  67. package/dist/cli/plugin-fetcher.d.ts.map +1 -0
  68. package/dist/cli/plugin-fetcher.js +83 -0
  69. package/dist/cli/plugin-fetcher.js.map +1 -0
  70. package/dist/cli/prompt.d.ts +17 -0
  71. package/dist/cli/prompt.d.ts.map +1 -0
  72. package/dist/cli/prompt.js +109 -0
  73. package/dist/cli/prompt.js.map +1 -0
  74. package/dist/cli/registry-helper.d.ts +11 -0
  75. package/dist/cli/registry-helper.d.ts.map +1 -0
  76. package/dist/cli/registry-helper.js +18 -0
  77. package/dist/cli/registry-helper.js.map +1 -0
  78. package/dist/cli/rules.d.ts +39 -0
  79. package/dist/cli/rules.d.ts.map +1 -0
  80. package/dist/cli/rules.js +112 -0
  81. package/dist/cli/rules.js.map +1 -0
  82. package/dist/cli/settings-writer.d.ts +97 -0
  83. package/dist/cli/settings-writer.d.ts.map +1 -0
  84. package/dist/cli/settings-writer.js +270 -0
  85. package/dist/cli/settings-writer.js.map +1 -0
  86. package/dist/cli/version-resolver.d.ts +73 -0
  87. package/dist/cli/version-resolver.d.ts.map +1 -0
  88. package/dist/cli/version-resolver.js +238 -0
  89. package/dist/cli/version-resolver.js.map +1 -0
  90. package/dist/index.d.ts +19 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +22 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/plugin/bin/macf-plugin-cli.d.ts +13 -0
  95. package/dist/plugin/bin/macf-plugin-cli.d.ts.map +1 -0
  96. package/dist/plugin/bin/macf-plugin-cli.js +127 -0
  97. package/dist/plugin/bin/macf-plugin-cli.js.map +1 -0
  98. package/dist/plugin/lib/format.d.ts +40 -0
  99. package/dist/plugin/lib/format.d.ts.map +1 -0
  100. package/dist/plugin/lib/format.js +137 -0
  101. package/dist/plugin/lib/format.js.map +1 -0
  102. package/dist/plugin/lib/health.d.ts +2 -0
  103. package/dist/plugin/lib/health.d.ts.map +1 -0
  104. package/dist/plugin/lib/health.js +6 -0
  105. package/dist/plugin/lib/health.js.map +1 -0
  106. package/dist/plugin/lib/index.d.ts +7 -0
  107. package/dist/plugin/lib/index.d.ts.map +1 -0
  108. package/dist/plugin/lib/index.js +5 -0
  109. package/dist/plugin/lib/index.js.map +1 -0
  110. package/dist/plugin/lib/registry.d.ts +18 -0
  111. package/dist/plugin/lib/registry.d.ts.map +1 -0
  112. package/dist/plugin/lib/registry.js +17 -0
  113. package/dist/plugin/lib/registry.js.map +1 -0
  114. package/dist/plugin/lib/work.d.ts +13 -0
  115. package/dist/plugin/lib/work.d.ts.map +1 -0
  116. package/dist/plugin/lib/work.js +27 -0
  117. package/dist/plugin/lib/work.js.map +1 -0
  118. package/package.json +43 -0
  119. package/plugin/rules/coordination.md +224 -0
  120. package/scripts/check-gh-token.sh +102 -0
  121. package/scripts/macf-gh-token.sh +130 -0
  122. package/scripts/macf-whoami.sh +51 -0
  123. package/scripts/tmux-send-to-claude.sh +51 -0
  124. package/scripts/write-build-info.mjs +48 -0
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Merge-preserving writer for `<workspace>/.claude/settings.json`.
3
+ *
4
+ * Per #140, the attribution-trap PreToolUse hook (`check-gh-token.sh`)
5
+ * needs a settings.json entry to actually fire. Workspaces may have
6
+ * operator-authored settings there already (other hooks, env vars,
7
+ * model preferences) — this module reads the existing JSON (default
8
+ * `{}`), installs the MACF hook entry, and writes back without
9
+ * clobbering unrelated keys.
10
+ *
11
+ * Identification of MACF-managed entries is by command-string match
12
+ * on the hook script's filename (`check-gh-token.sh`). A stale entry
13
+ * from an older CLI version is refreshed in place; non-MACF entries
14
+ * and other hook event types (SessionStart, Stop, etc.) are preserved
15
+ * verbatim.
16
+ *
17
+ * Malformed settings.json throws — we refuse to silently overwrite
18
+ * bad JSON because that would erase user content if they hand-edited
19
+ * broken syntax.
20
+ */
21
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
22
+ import { join, resolve } from 'node:path';
23
+ /**
24
+ * The command path written into settings.json. Workspace-relative so
25
+ * it matches what `copyCanonicalScripts` places at
26
+ * `<workspace>/.claude/scripts/check-gh-token.sh`.
27
+ */
28
+ export const MACF_HOOK_COMMAND = '.claude/scripts/check-gh-token.sh';
29
+ /**
30
+ * The hook filename used to identify MACF-managed entries on refresh.
31
+ * Matched by path-end equality (see isMacfManagedCommand) so operator
32
+ * files with a similar-but-distinct basename are not misclassified.
33
+ */
34
+ const MACF_HOOK_FILENAME = 'check-gh-token.sh';
35
+ /**
36
+ * True iff the command string represents our managed hook — i.e. the
37
+ * command invokes a file whose basename equals MACF_HOOK_FILENAME
38
+ * (ignoring any trailing flags/arguments). Defensive against
39
+ * operator-authored commands that happen to contain our filename as a
40
+ * substring (e.g. `./my-check-gh-token.sh-wrapper --flag`).
41
+ */
42
+ function isMacfManagedCommand(command) {
43
+ // Take the program path (first whitespace-delimited token), then
44
+ // extract its basename. `/a/b/check-gh-token.sh --v2` → `check-gh-token.sh`.
45
+ const program = command.trim().split(/\s+/)[0] ?? '';
46
+ const slash = program.lastIndexOf('/');
47
+ const basename = slash >= 0 ? program.slice(slash + 1) : program;
48
+ return basename === MACF_HOOK_FILENAME;
49
+ }
50
+ function readSettings(path) {
51
+ if (!existsSync(path))
52
+ return {};
53
+ const raw = readFileSync(path, 'utf-8');
54
+ try {
55
+ return JSON.parse(raw);
56
+ }
57
+ catch (err) {
58
+ throw new Error(`Refusing to overwrite malformed .claude/settings.json at ${path}: ${err.message}. ` +
59
+ `Fix the JSON by hand, then re-run the command.`, { cause: err });
60
+ }
61
+ }
62
+ /**
63
+ * Permission patterns pre-approving the 4 `macf-agent` plugin skills.
64
+ * Without these, every first invocation of a skill (e.g. `/macf-status`
65
+ * during the SessionStart auto-pickup hook) fires an interactive
66
+ * approval dialog — blocking autonomy for the time operator takes to
67
+ * click through. See macf#189 sub-item 2 (bilateral e2e demo friction
68
+ * point: operator had to approve 4-5 dialogs per fresh workspace).
69
+ *
70
+ * Concrete patterns (not a wildcard `Skill(macf-agent:*)`): operator
71
+ * deliberately installed the plugin at v0.1.N, so pre-trusting THE
72
+ * SKILLS CURRENTLY KNOWN TO EXIST at this CLI version is safe. A
73
+ * future plugin version adding new skills would need a `macf update`
74
+ * run — which refreshes these patterns from the updated constant —
75
+ * before the new skills auto-approve. Wildcard would auto-approve
76
+ * anything shipped under the plugin namespace including future
77
+ * unreviewed additions; we opt out of that security posture.
78
+ *
79
+ * Keep in lockstep with the 4 skills shipped by
80
+ * `groundnuty/macf-marketplace/macf-agent/skills/`. When plugin adds
81
+ * a skill, add its pattern here + bump CLI version.
82
+ */
83
+ export const PLUGIN_SKILL_PERMISSIONS = [
84
+ 'Skill(macf-agent:macf-status)',
85
+ 'Skill(macf-agent:macf-issues)',
86
+ 'Skill(macf-agent:macf-peers)',
87
+ 'Skill(macf-agent:macf-ping)',
88
+ ];
89
+ /**
90
+ * Sandbox filesystem read-allow pattern for Claude Code's Bash-tool
91
+ * harness. Every Bash invocation's spawned shell reads `/proc/self/fd/3`
92
+ * (or higher fds in future builds) for stdin / command-input passed
93
+ * by the harness. Without this pattern in the sandbox allowlist, the
94
+ * read is denied → `zsh:4: permission denied: /proc/self/fd/3` →
95
+ * every Bash tool call fails (or falls back to
96
+ * `dangerouslyDisableSandbox`, defeating isolation). Hit every MACF
97
+ * agent before macf#200.
98
+ *
99
+ * Claude Code's `sandbox.filesystem.allowRead` takes **literal path
100
+ * prefixes**, not globs. Bare `/proc/self/fd` matches every
101
+ * descriptor at any depth (`/proc/self/fd/3`, `/proc/self/fd/4`, ...)
102
+ * via prefix semantics. An earlier draft used `/proc/self/fd/**` on
103
+ * the assumption it was a glob; it isn't — the double-star was
104
+ * treated as a literal and didn't match. See macf#208 for the
105
+ * empirical surfacing of the bug.
106
+ */
107
+ export const SANDBOX_FD_READ_PATTERN = '/proc/self/fd';
108
+ /**
109
+ * Read `.claude/settings.json`'s `sandbox.filesystem.allowRead` array
110
+ * as a list of strings. Returns an empty array if the file doesn't
111
+ * exist or the nested shape is absent/alien. Throws on malformed
112
+ * JSON — consistent with `installSandboxFdAllowRead`'s posture (we
113
+ * don't silently treat a broken file as "no entries"; that would
114
+ * mask operator-authored state).
115
+ *
116
+ * Used by `macf doctor` (macf#202) to report whether the workspace
117
+ * has the `/proc/self/fd` prefix pattern without duplicating the
118
+ * JSON-read + deep-narrow logic in two places.
119
+ */
120
+ export function getSandboxAllowRead(workspaceDir) {
121
+ const absDir = resolve(workspaceDir);
122
+ const path = join(absDir, '.claude', 'settings.json');
123
+ const settings = readSettings(path);
124
+ const sandboxRaw = settings['sandbox'] ?? {};
125
+ const filesystemRaw = sandboxRaw['filesystem'] ?? {};
126
+ const list = filesystemRaw['allowRead'];
127
+ if (!Array.isArray(list))
128
+ return [];
129
+ return list.filter((v) => typeof v === 'string');
130
+ }
131
+ /**
132
+ * Legacy MACF-managed patterns that earlier CLI versions wrote to
133
+ * `allowRead`. Dropped from the array before installing the current
134
+ * `SANDBOX_FD_READ_PATTERN` — the `/**` glob suffix was treated
135
+ * literally by the sandbox (not as a glob) and silently didn't
136
+ * match, leaving the fd read denied. See macf#208.
137
+ */
138
+ const MACF_LEGACY_FD_PATTERNS = [
139
+ '/proc/self/fd/**',
140
+ ];
141
+ /**
142
+ * Install (or refresh) the `/proc/self/fd` entry in
143
+ * `.claude/settings.json`'s `sandbox.filesystem.allowRead` array.
144
+ * Creates each nested key if absent. Idempotent — repeated calls
145
+ * don't duplicate. Operator-authored `allowRead` entries are
146
+ * preserved; stale MACF-managed patterns (see
147
+ * MACF_LEGACY_FD_PATTERNS) are dropped before the current pattern
148
+ * is installed.
149
+ *
150
+ * Opt-out: if `MACF_SANDBOX_FD_FIX_SKIP` is `1` or `true` at call
151
+ * time (during `macf init` / `macf update`), no change is made. Lets
152
+ * operators manage their own sandbox block entirely. Accepts both
153
+ * shapes to stay aligned with `MACF_OTEL_DISABLED` (see
154
+ * `claude-sh.ts` — same family of opt-out env knobs).
155
+ *
156
+ * See macf#200 (original fd-deny bug), macf#208 (pattern-literal fix).
157
+ */
158
+ export function installSandboxFdAllowRead(workspaceDir) {
159
+ const skip = process.env['MACF_SANDBOX_FD_FIX_SKIP'];
160
+ if (skip === '1' || skip === 'true')
161
+ return;
162
+ const absDir = resolve(workspaceDir);
163
+ const claudeDir = join(absDir, '.claude');
164
+ const path = join(claudeDir, 'settings.json');
165
+ mkdirSync(claudeDir, { recursive: true });
166
+ const settings = readSettings(path);
167
+ // Narrow the deep-nested read; operator-authored alien shapes at
168
+ // any level default to a fresh empty branch rather than throwing.
169
+ const sandboxRaw = settings['sandbox'] ?? {};
170
+ const filesystemRaw = sandboxRaw['filesystem'] ?? {};
171
+ const existingAllow = Array.isArray(filesystemRaw['allowRead'])
172
+ ? filesystemRaw['allowRead'].filter((v) => typeof v === 'string')
173
+ : [];
174
+ // Preserve operator-authored entries; drop any known-legacy MACF
175
+ // patterns so the workspace ends up with exactly the current one.
176
+ const preserved = existingAllow.filter((entry) => !MACF_LEGACY_FD_PATTERNS.includes(entry));
177
+ // Idempotent short-circuit: only skip if the current pattern is
178
+ // already present AND there's no legacy pattern to clean up.
179
+ if (preserved.length === existingAllow.length && preserved.includes(SANDBOX_FD_READ_PATTERN)) {
180
+ return;
181
+ }
182
+ const allowRead = preserved.includes(SANDBOX_FD_READ_PATTERN)
183
+ ? preserved
184
+ : [...preserved, SANDBOX_FD_READ_PATTERN];
185
+ const updated = {
186
+ ...settings,
187
+ sandbox: {
188
+ ...sandboxRaw,
189
+ filesystem: {
190
+ ...filesystemRaw,
191
+ allowRead,
192
+ },
193
+ },
194
+ };
195
+ writeFileSync(path, JSON.stringify(updated, null, 2) + '\n');
196
+ }
197
+ /**
198
+ * Pattern that identifies MACF-managed skill-permission entries on
199
+ * refresh. Any pattern starting with `Skill(macf-agent:` is
200
+ * considered ours; mismatches are preserved verbatim.
201
+ */
202
+ const MACF_SKILL_PATTERN_PREFIX = 'Skill(macf-agent:';
203
+ /**
204
+ * Install (or refresh) the MACF plugin-skill pre-approval entries in
205
+ * `.claude/settings.json`'s `permissions.allow` array. Idempotent:
206
+ * stale entries (e.g. from a prior CLI version that listed a since-
207
+ * removed skill) are dropped + replaced with the current set.
208
+ * Non-MACF entries in `permissions.allow` are preserved.
209
+ *
210
+ * Creates the `.claude/` directory + settings.json if missing.
211
+ */
212
+ export function installPluginSkillPermissions(workspaceDir) {
213
+ const absDir = resolve(workspaceDir);
214
+ const claudeDir = join(absDir, '.claude');
215
+ const path = join(claudeDir, 'settings.json');
216
+ mkdirSync(claudeDir, { recursive: true });
217
+ const settings = readSettings(path);
218
+ const existingAllow = Array.isArray(settings['permissions'] && settings['permissions']['allow'])
219
+ ? (settings['permissions'].allow)
220
+ : [];
221
+ // Drop any prior Skill(macf-agent:*) entries so we install the
222
+ // current list fresh (handles "skill was removed in plugin v0.1.N"
223
+ // case — otherwise the stale pre-approval lingers forever).
224
+ const preserved = existingAllow.filter((entry) => typeof entry !== 'string' || !entry.startsWith(MACF_SKILL_PATTERN_PREFIX));
225
+ const allow = [...preserved, ...PLUGIN_SKILL_PERMISSIONS];
226
+ const existingPermissions = settings['permissions'] ?? {};
227
+ const updated = {
228
+ ...settings,
229
+ permissions: {
230
+ ...existingPermissions,
231
+ allow,
232
+ },
233
+ };
234
+ writeFileSync(path, JSON.stringify(updated, null, 2) + '\n');
235
+ }
236
+ /**
237
+ * Install (or refresh) the MACF PreToolUse hook entry for
238
+ * `check-gh-token.sh` in `<workspaceDir>/.claude/settings.json`.
239
+ * Creates the `.claude/` directory and the file if either is missing.
240
+ *
241
+ * Idempotent: repeated calls don't duplicate the entry.
242
+ */
243
+ export function installGhTokenHook(workspaceDir) {
244
+ const absDir = resolve(workspaceDir);
245
+ const claudeDir = join(absDir, '.claude');
246
+ const path = join(claudeDir, 'settings.json');
247
+ mkdirSync(claudeDir, { recursive: true });
248
+ const settings = readSettings(path);
249
+ const hooks = settings.hooks ?? {};
250
+ const preToolUse = hooks.PreToolUse ?? [];
251
+ // Drop any prior MACF-managed entries so we can replace them cleanly
252
+ // — guards against stale flags (e.g. `--old-flag`) from older CLI
253
+ // versions. Match by path-end equality so an operator-authored file
254
+ // with a similar-but-distinct name (e.g. `my-check-gh-token.sh-helper.sh`)
255
+ // doesn't get misclassified as ours and accidentally clobbered.
256
+ const preserved = preToolUse.filter((entry) => !entry.hooks.some((h) => isMacfManagedCommand(h.command)));
257
+ const macfEntry = {
258
+ matcher: 'Bash',
259
+ hooks: [{ type: 'command', command: MACF_HOOK_COMMAND }],
260
+ };
261
+ const updated = {
262
+ ...settings,
263
+ hooks: {
264
+ ...hooks,
265
+ PreToolUse: [...preserved, macfEntry],
266
+ },
267
+ };
268
+ writeFileSync(path, JSON.stringify(updated, null, 2) + '\n');
269
+ }
270
+ //# sourceMappingURL=settings-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-writer.js","sourceRoot":"","sources":["../../src/cli/settings-writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Resolves latest stable versions for the three components pinned in
3
+ * macf-agent.json: cli, plugin, actions. Each has a network fetcher
4
+ * and a hardcoded fallback used when the lookup fails.
5
+ *
6
+ * Distinguishes:
7
+ * - ok → value fetched successfully
8
+ * - not_published → HTTP 404 (package/release doesn't exist yet)
9
+ * - network_error → fetch threw (connection refused, timeout, DNS, ...)
10
+ * - rate_limited → HTTP 403/429 from GitHub API, typically anon
11
+ * rate-limit (60 req/h). See authHeaders() — if
12
+ * `GH_TOKEN` is set in the environment the fetcher
13
+ * uses it automatically (5000 req/h), so this
14
+ * status fires only when anon AND quota-exhausted.
15
+ * - invalid_response → HTTP 200 but unparseable/schema-invalid
16
+ *
17
+ * The caller can produce clearer warnings than the old single "network
18
+ * fetch failed" message. GitHub fetchers fall back from /releases/latest
19
+ * to /tags so bare-tag versioning (no GitHub Release object) still works.
20
+ */
21
+ export interface VersionSet {
22
+ readonly cli: string;
23
+ readonly plugin: string;
24
+ readonly actions: string;
25
+ }
26
+ export type FetchStatus = 'ok' | 'not_published' | 'network_error' | 'rate_limited' | 'invalid_response';
27
+ export interface FetchResult {
28
+ readonly status: FetchStatus;
29
+ readonly value: string | null;
30
+ }
31
+ export interface ResolvedVersions {
32
+ readonly versions: VersionSet;
33
+ readonly sources: {
34
+ readonly cli: FetchStatus;
35
+ readonly plugin: FetchStatus;
36
+ readonly actions: FetchStatus;
37
+ };
38
+ }
39
+ export declare const FALLBACK_VERSIONS: VersionSet;
40
+ export declare const SEMVER_PATTERN: RegExp;
41
+ export declare const ACTIONS_TAG_PATTERN: RegExp;
42
+ export declare function isValidSemver(v: string): boolean;
43
+ export declare function isValidActionsRef(v: string): boolean;
44
+ /**
45
+ * Compare two semver strings (x.y.z) numerically. Returns negative if a < b,
46
+ * zero if equal, positive if a > b. Used to pick the highest tag from a list.
47
+ */
48
+ export declare function compareSemver(a: string, b: string): number;
49
+ /**
50
+ * Fetch latest CLI version from npm registry.
51
+ */
52
+ export declare function fetchLatestCliVersion(): Promise<FetchResult>;
53
+ /**
54
+ * Fetch latest plugin version. Tries /releases/latest first, falls back
55
+ * to /tags if no release exists (our marketplace uses bare tags).
56
+ */
57
+ export declare function fetchLatestPluginVersion(): Promise<FetchResult>;
58
+ /**
59
+ * Fetch latest actions version. Tries /releases/latest first, falls back
60
+ * to /tags. Returns major-only tag (v1.2.3 → v1) to match floating-major pins.
61
+ */
62
+ export declare function fetchLatestActionsVersion(): Promise<FetchResult>;
63
+ /**
64
+ * Resolve latest versions for all three components, falling back on error.
65
+ * All three fetches run in parallel.
66
+ */
67
+ export declare function resolveLatestVersions(): Promise<ResolvedVersions>;
68
+ /**
69
+ * Human-readable message for a non-ok fetch status. Used by callers to
70
+ * print actionable warnings instead of the generic "network fetch failed".
71
+ */
72
+ export declare function statusMessage(component: string, status: FetchStatus): string;
73
+ //# sourceMappingURL=version-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-resolver.d.ts","sourceRoot":"","sources":["../../src/cli/version-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,eAAe,GAAG,eAAe,GAAG,cAAc,GAAG,kBAAkB,CAAC;AA+BzG,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;QAC1B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;QAC7B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;KAC/B,CAAC;CACH;AAED,eAAO,MAAM,iBAAiB,EAAE,UAI/B,CAAC;AAEF,eAAO,MAAM,cAAc,QAAoB,CAAC;AAChD,eAAO,MAAM,mBAAmB,QAAuB,CAAC;AAExD,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAW1D;AA4BD;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,WAAW,CAAC,CAgBlE;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,WAAW,CAAC,CA6BrE;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,WAAW,CAAC,CA2BtE;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAmBvE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,MAAM,CAQ5E"}
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Resolves latest stable versions for the three components pinned in
3
+ * macf-agent.json: cli, plugin, actions. Each has a network fetcher
4
+ * and a hardcoded fallback used when the lookup fails.
5
+ *
6
+ * Distinguishes:
7
+ * - ok → value fetched successfully
8
+ * - not_published → HTTP 404 (package/release doesn't exist yet)
9
+ * - network_error → fetch threw (connection refused, timeout, DNS, ...)
10
+ * - rate_limited → HTTP 403/429 from GitHub API, typically anon
11
+ * rate-limit (60 req/h). See authHeaders() — if
12
+ * `GH_TOKEN` is set in the environment the fetcher
13
+ * uses it automatically (5000 req/h), so this
14
+ * status fires only when anon AND quota-exhausted.
15
+ * - invalid_response → HTTP 200 but unparseable/schema-invalid
16
+ *
17
+ * The caller can produce clearer warnings than the old single "network
18
+ * fetch failed" message. GitHub fetchers fall back from /releases/latest
19
+ * to /tags so bare-tag versioning (no GitHub Release object) still works.
20
+ */
21
+ /**
22
+ * GitHub API headers. Uses `GH_TOKEN` from env if present — raises the
23
+ * anonymous 60 req/h limit to 5000 req/h. Primary #186 fix: operators
24
+ * on shared IPs (Tailscale, CI runners) were burning anon quota across
25
+ * sessions + getting opaque "invalid_response" on subsequent runs.
26
+ * `claude.sh` exports GH_TOKEN before `macf update` invocations, so
27
+ * the token is available in the typical run path.
28
+ */
29
+ function githubHeaders() {
30
+ const headers = { 'Accept': 'application/vnd.github+json' };
31
+ const token = process.env['GH_TOKEN'];
32
+ if (token !== undefined && token !== '' && token !== 'null') {
33
+ headers['Authorization'] = `Bearer ${token}`;
34
+ }
35
+ return headers;
36
+ }
37
+ /**
38
+ * Map a non-ok GitHub API response to the appropriate FetchStatus.
39
+ * 403/429 (rate-limit) and 401 (bad auth) both surface as `rate_limited`
40
+ * — operator-facing warning distinguishes them from other schema/5xx
41
+ * errors that come back as `invalid_response`.
42
+ */
43
+ function classifyGithubError(status) {
44
+ if (status === 404)
45
+ return 'not_published';
46
+ if (status === 401 || status === 403 || status === 429)
47
+ return 'rate_limited';
48
+ return 'invalid_response';
49
+ }
50
+ export const FALLBACK_VERSIONS = {
51
+ cli: '0.2.0-rc.0',
52
+ plugin: '0.1.0',
53
+ actions: 'v1',
54
+ };
55
+ export const SEMVER_PATTERN = /^\d+\.\d+\.\d+$/;
56
+ export const ACTIONS_TAG_PATTERN = /^v\d+(\.\d+){0,2}$/;
57
+ export function isValidSemver(v) {
58
+ return SEMVER_PATTERN.test(v);
59
+ }
60
+ export function isValidActionsRef(v) {
61
+ return ACTIONS_TAG_PATTERN.test(v) || v === 'main';
62
+ }
63
+ /**
64
+ * Compare two semver strings (x.y.z) numerically. Returns negative if a < b,
65
+ * zero if equal, positive if a > b. Used to pick the highest tag from a list.
66
+ */
67
+ export function compareSemver(a, b) {
68
+ const parse = (v) => {
69
+ const m = /^v?(\d+)\.(\d+)\.(\d+)$/.exec(v);
70
+ if (!m)
71
+ return [0, 0, 0];
72
+ return [Number.parseInt(m[1], 10), Number.parseInt(m[2], 10), Number.parseInt(m[3], 10)];
73
+ };
74
+ const [aMaj, aMin, aPat] = parse(a);
75
+ const [bMaj, bMin, bPat] = parse(b);
76
+ if (aMaj !== bMaj)
77
+ return aMaj - bMaj;
78
+ if (aMin !== bMin)
79
+ return aMin - bMin;
80
+ return aPat - bPat;
81
+ }
82
+ /**
83
+ * Fetch the highest semver tag from a GitHub repo's /tags list.
84
+ * Returns the tag name (with leading 'v' if present) or null with reason.
85
+ */
86
+ async function fetchHighestTag(repo) {
87
+ try {
88
+ const res = await fetch(`https://api.github.com/repos/${repo}/tags`, {
89
+ headers: githubHeaders(),
90
+ });
91
+ if (!res.ok)
92
+ return { status: classifyGithubError(res.status), value: null };
93
+ const data = await res.json();
94
+ if (!Array.isArray(data))
95
+ return { status: 'invalid_response', value: null };
96
+ const semverTags = data
97
+ .map(t => typeof t.name === 'string' ? t.name : null)
98
+ .filter((n) => n !== null && /^v?\d+\.\d+\.\d+$/.test(n));
99
+ if (semverTags.length === 0)
100
+ return { status: 'not_published', value: null };
101
+ semverTags.sort((a, b) => compareSemver(b, a)); // descending
102
+ return { status: 'ok', value: semverTags[0] };
103
+ }
104
+ catch {
105
+ return { status: 'network_error', value: null };
106
+ }
107
+ }
108
+ /**
109
+ * Fetch latest CLI version from npm registry.
110
+ */
111
+ export async function fetchLatestCliVersion() {
112
+ try {
113
+ const res = await fetch('https://registry.npmjs.org/@macf/cli', {
114
+ headers: { 'Accept': 'application/json' },
115
+ });
116
+ if (res.status === 404)
117
+ return { status: 'not_published', value: null };
118
+ if (!res.ok)
119
+ return { status: 'invalid_response', value: null };
120
+ const data = await res.json();
121
+ const latest = data['dist-tags']?.latest;
122
+ if (typeof latest !== 'string' || !isValidSemver(latest)) {
123
+ return { status: 'invalid_response', value: null };
124
+ }
125
+ return { status: 'ok', value: latest };
126
+ }
127
+ catch {
128
+ return { status: 'network_error', value: null };
129
+ }
130
+ }
131
+ /**
132
+ * Fetch latest plugin version. Tries /releases/latest first, falls back
133
+ * to /tags if no release exists (our marketplace uses bare tags).
134
+ */
135
+ export async function fetchLatestPluginVersion() {
136
+ const repo = 'groundnuty/macf-marketplace';
137
+ // Try /releases/latest first
138
+ try {
139
+ const res = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, {
140
+ headers: githubHeaders(),
141
+ });
142
+ if (res.ok) {
143
+ const data = await res.json();
144
+ const tag = data.tag_name;
145
+ if (typeof tag === 'string') {
146
+ const semver = tag.replace(/^v/, '');
147
+ if (isValidSemver(semver))
148
+ return { status: 'ok', value: semver };
149
+ }
150
+ return { status: 'invalid_response', value: null };
151
+ }
152
+ if (res.status !== 404)
153
+ return { status: classifyGithubError(res.status), value: null };
154
+ // fall through to /tags (404 = no Release object; marketplace uses bare tags)
155
+ }
156
+ catch {
157
+ return { status: 'network_error', value: null };
158
+ }
159
+ // Fallback: /tags
160
+ const tagsResult = await fetchHighestTag(repo);
161
+ if (tagsResult.status !== 'ok' || !tagsResult.value)
162
+ return tagsResult;
163
+ const semver = tagsResult.value.replace(/^v/, '');
164
+ if (!isValidSemver(semver))
165
+ return { status: 'invalid_response', value: null };
166
+ return { status: 'ok', value: semver };
167
+ }
168
+ /**
169
+ * Fetch latest actions version. Tries /releases/latest first, falls back
170
+ * to /tags. Returns major-only tag (v1.2.3 → v1) to match floating-major pins.
171
+ */
172
+ export async function fetchLatestActionsVersion() {
173
+ const repo = 'groundnuty/macf-actions';
174
+ try {
175
+ const res = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, {
176
+ headers: githubHeaders(),
177
+ });
178
+ if (res.ok) {
179
+ const data = await res.json();
180
+ const tag = data.tag_name;
181
+ if (typeof tag === 'string' && isValidActionsRef(tag)) {
182
+ const m = /^v(\d+)/.exec(tag);
183
+ return { status: 'ok', value: m ? `v${m[1]}` : tag };
184
+ }
185
+ return { status: 'invalid_response', value: null };
186
+ }
187
+ if (res.status !== 404)
188
+ return { status: classifyGithubError(res.status), value: null };
189
+ }
190
+ catch {
191
+ return { status: 'network_error', value: null };
192
+ }
193
+ // Fallback: /tags
194
+ const tagsResult = await fetchHighestTag(repo);
195
+ if (tagsResult.status !== 'ok' || !tagsResult.value)
196
+ return tagsResult;
197
+ const m = /^v(\d+)/.exec(tagsResult.value);
198
+ if (!m)
199
+ return { status: 'invalid_response', value: null };
200
+ return { status: 'ok', value: `v${m[1]}` };
201
+ }
202
+ /**
203
+ * Resolve latest versions for all three components, falling back on error.
204
+ * All three fetches run in parallel.
205
+ */
206
+ export async function resolveLatestVersions() {
207
+ const [cli, plugin, actions] = await Promise.all([
208
+ fetchLatestCliVersion(),
209
+ fetchLatestPluginVersion(),
210
+ fetchLatestActionsVersion(),
211
+ ]);
212
+ return {
213
+ versions: {
214
+ cli: cli.value ?? FALLBACK_VERSIONS.cli,
215
+ plugin: plugin.value ?? FALLBACK_VERSIONS.plugin,
216
+ actions: actions.value ?? FALLBACK_VERSIONS.actions,
217
+ },
218
+ sources: {
219
+ cli: cli.status,
220
+ plugin: plugin.status,
221
+ actions: actions.status,
222
+ },
223
+ };
224
+ }
225
+ /**
226
+ * Human-readable message for a non-ok fetch status. Used by callers to
227
+ * print actionable warnings instead of the generic "network fetch failed".
228
+ */
229
+ export function statusMessage(component, status) {
230
+ switch (status) {
231
+ case 'ok': return `${component}: ok`;
232
+ case 'not_published': return `${component}: no published release found (using default)`;
233
+ case 'network_error': return `${component}: network fetch failed (using default)`;
234
+ case 'rate_limited': return `${component}: GitHub API rate-limited or unauthorized — set GH_TOKEN to raise the anon 60 req/h limit (using default)`;
235
+ case 'invalid_response': return `${component}: unexpected response format (using default)`;
236
+ }
237
+ }
238
+ //# sourceMappingURL=version-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-resolver.js","sourceRoot":"","sources":["../../src/cli/version-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Multi-Agent Coordination Framework (MACF) CLI.
3
+ *
4
+ * The primary consumption shape of this package is as a binary (`macf`
5
+ * and `macf-plugin-cli` — see the `bin` field in package.json). This
6
+ * barrel exposes a small programmatic surface for tooling that needs
7
+ * to invoke CLI helpers directly (tests, integration harnesses).
8
+ *
9
+ * Shared types + functions (errors, logger, config, registry, certs,
10
+ * etc.) live in `@groundnuty/macf-core` and should be imported from
11
+ * there directly, not re-exported here.
12
+ */
13
+ export { MACF_HOOK_COMMAND, PLUGIN_SKILL_PERMISSIONS, SANDBOX_FD_READ_PATTERN, getSandboxAllowRead, installGhTokenHook, installPluginSkillPermissions, installSandboxFdAllowRead, } from './cli/settings-writer.js';
14
+ export { readAgentConfig, loadAllAgents, readAgentsIndex, writeAgentConfig, agentCertPath, agentKeyPath, caDir, caCertPath, caKeyPath, tokenSourceFromConfig, } from './cli/config.js';
15
+ export type { MacfAgentConfig, VersionPins } from './cli/config.js';
16
+ export { copyCanonicalRules, copyCanonicalScripts, findCliPackageRoot } from './cli/rules.js';
17
+ export { MACF_REQUIRED_PERMISSIONS, diffPermissions, checkSandboxFdAllowRead } from './cli/commands/doctor.js';
18
+ export type { RequiredPermission, DoctorFinding, SandboxFdCheck } from './cli/commands/doctor.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,6BAA6B,EAC7B,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,eAAe,EACf,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,KAAK,EACL,UAAU,EACV,SAAS,EACT,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGpE,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAG9F,OAAO,EAAE,yBAAyB,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAC/G,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Multi-Agent Coordination Framework (MACF) CLI.
3
+ *
4
+ * The primary consumption shape of this package is as a binary (`macf`
5
+ * and `macf-plugin-cli` — see the `bin` field in package.json). This
6
+ * barrel exposes a small programmatic surface for tooling that needs
7
+ * to invoke CLI helpers directly (tests, integration harnesses).
8
+ *
9
+ * Shared types + functions (errors, logger, config, registry, certs,
10
+ * etc.) live in `@groundnuty/macf-core` and should be imported from
11
+ * there directly, not re-exported here.
12
+ */
13
+ // Settings-writer helpers — used by `macf init` / `macf update` /
14
+ // `macf rules refresh` to seed workspace `.claude/settings.json`.
15
+ export { MACF_HOOK_COMMAND, PLUGIN_SKILL_PERMISSIONS, SANDBOX_FD_READ_PATTERN, getSandboxAllowRead, installGhTokenHook, installPluginSkillPermissions, installSandboxFdAllowRead, } from './cli/settings-writer.js';
16
+ // Config resolution — `macf-agent.json` reader + workspace discovery.
17
+ export { readAgentConfig, loadAllAgents, readAgentsIndex, writeAgentConfig, agentCertPath, agentKeyPath, caDir, caCertPath, caKeyPath, tokenSourceFromConfig, } from './cli/config.js';
18
+ // Canonical rules distribution — `macf rules refresh` entrypoint.
19
+ export { copyCanonicalRules, copyCanonicalScripts, findCliPackageRoot } from './cli/rules.js';
20
+ // Doctor check — programmatic access for external verification tools.
21
+ export { MACF_REQUIRED_PERMISSIONS, diffPermissions, checkSandboxFdAllowRead } from './cli/commands/doctor.js';
22
+ //# sourceMappingURL=index.js.map