@yunhozz/arc 0.2.3 → 0.2.4

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 (80) hide show
  1. package/MANIFEST.sha256 +73 -79
  2. package/claude/agents/arc-implementer.md +32 -42
  3. package/claude/agents/arc-planner.md +33 -47
  4. package/claude/agents/arc-qa.md +28 -44
  5. package/claude/agents/arc-reviewer.md +28 -41
  6. package/claude/agents/arc-scouter.md +26 -38
  7. package/claude/skill/SKILL.md +41 -59
  8. package/claude/skill/references/arc-visual-companion.md +19 -24
  9. package/claude/skill/references/commit.md +38 -70
  10. package/claude/skill/references/coordination.md +77 -126
  11. package/claude/skill/references/git-recovery.md +17 -35
  12. package/claude/skill/references/handoff-prep.md +91 -103
  13. package/claude/skill/references/handoff.md +110 -208
  14. package/claude/skill/references/limits.md +19 -31
  15. package/claude/skill/references/planning.md +93 -244
  16. package/claude/skill/references/verification.md +105 -261
  17. package/claude/skill/runtime/adapters/claude.mjs +10 -9
  18. package/claude/skill/runtime/adapters/codex.mjs +7 -8
  19. package/claude/skill/runtime/bootstrap.mjs +3 -2
  20. package/claude/skill/runtime/capabilities.mjs +12 -0
  21. package/claude/skill/runtime/cooperative-schema.mjs +3 -2
  22. package/claude/skill/runtime/cooperative.mjs +52 -4
  23. package/claude/skill/runtime/evaluate.mjs +115 -2
  24. package/claude/skill/runtime/identity.mjs +22 -0
  25. package/claude/skill/runtime/role-policy.json +18 -18
  26. package/claude/skill/runtime/schema.mjs +19 -0
  27. package/claude/skill/scripts/model_config.py +3 -79
  28. package/codex/agents/arc-implementer.toml +34 -30
  29. package/codex/agents/arc-planner.toml +27 -23
  30. package/codex/agents/arc-qa.toml +24 -15
  31. package/codex/agents/arc-reviewer.toml +25 -16
  32. package/codex/agents/arc-scouter.toml +20 -26
  33. package/codex/skill/SKILL.md +42 -57
  34. package/codex/skill/references/arc-visual-companion.md +21 -27
  35. package/codex/skill/references/commit.md +35 -81
  36. package/codex/skill/references/coordination.md +76 -104
  37. package/codex/skill/references/git-recovery.md +29 -51
  38. package/codex/skill/references/handoff-prep.md +76 -134
  39. package/codex/skill/references/handoff-worktree.md +32 -66
  40. package/codex/skill/references/handoff.md +111 -271
  41. package/codex/skill/references/limits.md +21 -34
  42. package/codex/skill/references/planning.md +125 -299
  43. package/codex/skill/references/verification.md +90 -272
  44. package/codex/skill/runtime/adapters/claude.mjs +10 -9
  45. package/codex/skill/runtime/adapters/codex.mjs +7 -8
  46. package/codex/skill/runtime/bootstrap.mjs +3 -2
  47. package/codex/skill/runtime/capabilities.mjs +12 -0
  48. package/codex/skill/runtime/cooperative-schema.mjs +3 -2
  49. package/codex/skill/runtime/cooperative.mjs +52 -4
  50. package/codex/skill/runtime/evaluate.mjs +115 -2
  51. package/codex/skill/runtime/identity.mjs +22 -0
  52. package/codex/skill/runtime/role-policy.json +18 -18
  53. package/codex/skill/runtime/schema.mjs +19 -0
  54. package/lib/installer/global-config.mjs +1 -0
  55. package/lib/installer/manifest.mjs +1 -1
  56. package/lib/installer/plan.mjs +0 -3
  57. package/lib/installer/uninstall.mjs +2 -2
  58. package/lib/management/operations.mjs +4 -2
  59. package/lib/management/update.mjs +3 -3
  60. package/lib/models/profiles.mjs +1 -40
  61. package/lib/policy/render.mjs +1 -5
  62. package/lib/policy/role-policy.json +18 -18
  63. package/lib/runtime/adapters/claude.mjs +10 -9
  64. package/lib/runtime/adapters/codex.mjs +7 -8
  65. package/lib/runtime/bootstrap.mjs +3 -2
  66. package/lib/runtime/capabilities.mjs +12 -0
  67. package/lib/runtime/cooperative-schema.mjs +3 -2
  68. package/lib/runtime/cooperative.mjs +52 -4
  69. package/lib/runtime/evaluate.mjs +115 -2
  70. package/lib/runtime/identity.mjs +22 -0
  71. package/lib/runtime/schema.mjs +19 -0
  72. package/lib/tui/app.mjs +12 -8
  73. package/lib/tui/setup.mjs +5 -8
  74. package/package.json +1 -2
  75. package/claude/skill/hooks/git-policy.json +0 -208
  76. package/claude/skill/hooks/role-git-guard.mjs +0 -18
  77. package/claude/skill/hooks/runtime-gate.mjs +0 -12
  78. package/codex/skill/hooks/runtime-gate.mjs +0 -10
  79. package/lib/policy/claude-hook.mjs +0 -80
  80. package/scripts/probe-runtime-hooks.mjs +0 -55
@@ -1,208 +0,0 @@
1
- {
2
- "schemaVersion": 1,
3
- "globalValueOptions": [
4
- "-C",
5
- "--git-dir",
6
- "--work-tree"
7
- ],
8
- "globalFlags": [
9
- "--no-pager",
10
- "-P",
11
- "--literal-pathspecs"
12
- ],
13
- "commands": {
14
- "status": {
15
- "flags": [
16
- "--short",
17
- "-s",
18
- "--branch",
19
- "-b",
20
- "--porcelain",
21
- "--porcelain=v1",
22
- "--porcelain=v2",
23
- "--untracked-files=no",
24
- "--untracked-files=all"
25
- ],
26
- "values": [],
27
- "positionals": "any"
28
- },
29
- "diff": {
30
- "flags": [
31
- "--stat",
32
- "--numstat",
33
- "--shortstat",
34
- "--name-only",
35
- "--name-status",
36
- "--oneline",
37
- "--no-color",
38
- "--color=never",
39
- "--no-ext-diff",
40
- "--no-textconv",
41
- "--raw",
42
- "--patch",
43
- "-p",
44
- "--summary",
45
- "--exit-code",
46
- "--quiet",
47
- "--check",
48
- "--cached",
49
- "--staged",
50
- "--relative",
51
- "--no-index"
52
- ],
53
- "values": [],
54
- "positionals": "any"
55
- },
56
- "log": {
57
- "flags": [
58
- "--stat",
59
- "--numstat",
60
- "--shortstat",
61
- "--name-only",
62
- "--name-status",
63
- "--oneline",
64
- "--no-color",
65
- "--color=never",
66
- "--no-ext-diff",
67
- "--no-textconv",
68
- "--raw",
69
- "--patch",
70
- "-p",
71
- "--summary",
72
- "--exit-code",
73
- "--quiet",
74
- "-<count>",
75
- "--all",
76
- "--decorate",
77
- "--no-decorate",
78
- "--graph"
79
- ],
80
- "values": [
81
- "-n",
82
- "--max-count",
83
- "--format",
84
- "--pretty"
85
- ],
86
- "positionals": "any"
87
- },
88
- "show": {
89
- "flags": [
90
- "--stat",
91
- "--numstat",
92
- "--shortstat",
93
- "--name-only",
94
- "--name-status",
95
- "--oneline",
96
- "--no-color",
97
- "--color=never",
98
- "--no-ext-diff",
99
- "--no-textconv",
100
- "--raw",
101
- "--patch",
102
- "-p",
103
- "--summary",
104
- "--exit-code",
105
- "--quiet",
106
- "--no-patch",
107
- "-s"
108
- ],
109
- "values": [
110
- "--format",
111
- "--pretty"
112
- ],
113
- "positionals": "any"
114
- },
115
- "rev-parse": {
116
- "flags": [
117
- "--show-toplevel",
118
- "--git-common-dir",
119
- "--absolute-git-dir",
120
- "--git-dir",
121
- "--verify",
122
- "--short",
123
- "--is-inside-work-tree",
124
- "--abbrev-ref",
125
- "--path-format=absolute"
126
- ],
127
- "values": [],
128
- "positionals": "any"
129
- },
130
- "ls-files": {
131
- "flags": [
132
- "--stage",
133
- "-s",
134
- "--cached",
135
- "--others",
136
- "--exclude-standard",
137
- "--deleted",
138
- "--modified"
139
- ],
140
- "values": [],
141
- "positionals": "any"
142
- },
143
- "ls-tree": {
144
- "flags": [
145
- "-r",
146
- "--name-only",
147
- "-l"
148
- ],
149
- "values": [],
150
- "positionals": "any"
151
- },
152
- "branch": {
153
- "flags": [
154
- "--list",
155
- "--all",
156
- "-a",
157
- "--remotes",
158
- "-r",
159
- "--show-current",
160
- "-v",
161
- "-vv"
162
- ],
163
- "values": [],
164
- "positionals": "list"
165
- },
166
- "config": {
167
- "flags": [
168
- "--get",
169
- "--get-all",
170
- "--get-regexp",
171
- "--list",
172
- "-l",
173
- "--show-origin",
174
- "--show-scope",
175
- "--local",
176
- "--global",
177
- "--system"
178
- ],
179
- "values": [],
180
- "positionals": "query"
181
- },
182
- "worktree list": {
183
- "flags": [
184
- "--porcelain",
185
- "-z",
186
- "-v"
187
- ],
188
- "values": [],
189
- "positionals": "none"
190
- },
191
- "remote": {
192
- "flags": [
193
- "-v",
194
- "--verbose"
195
- ],
196
- "values": [],
197
- "positionals": "none"
198
- },
199
- "remote get-url": {
200
- "flags": [
201
- "--all",
202
- "--push"
203
- ],
204
- "values": [],
205
- "positionals": "any"
206
- }
207
- }
208
- }
@@ -1,18 +0,0 @@
1
- import fs from 'node:fs';
2
- import {pathToFileURL} from 'node:url';
3
-
4
- import {validateGitPolicy,classifyGitCommand} from '../runtime/git-query.mjs';
5
- export {validateGitPolicy,classifyGitCommand};
6
- const deny=reason=>({allowed:false,reason});
7
- export function evaluateHookEvent(event,policy) {
8
- const result=event?.hook_event_name!=='PreToolUse' ? deny('Invalid hook event') : event?.tool_name!=='Bash' ? deny('Missing Bash event') : classifyGitCommand(event?.tool_input?.command,policy);
9
- return result.allowed?{}:{hookSpecificOutput:{hookEventName:'PreToolUse',permissionDecision:'deny',permissionDecisionReason:`ARC specialist Git guard: ${result.reason}. Return the operation to Orchestrator.`}};
10
- }
11
- export function runHook() {
12
- let response;
13
- try {const policy=validateGitPolicy(JSON.parse(fs.readFileSync(new URL('./git-policy.json',import.meta.url),'utf8')));response=evaluateHookEvent(JSON.parse(fs.readFileSync(0,'utf8')),policy);}
14
- catch {response={hookSpecificOutput:{hookEventName:'PreToolUse',permissionDecision:'deny',permissionDecisionReason:'ARC specialist Git guard: invalid input or policy asset. Stop and report to Orchestrator.'}};}
15
- process.stdout.write(JSON.stringify(response)+'\n');
16
- }
17
-
18
- if(process.argv[1] && pathToFileURL(process.argv[1]).href===import.meta.url)runHook();
@@ -1,12 +0,0 @@
1
- import {runClaudeGate,renderClaudeDecision} from '../runtime/adapters/claude.mjs';
2
- /** Native installation must provide trusted context separately; stdin is only
3
- * the platform event. Missing provider denies and never trusts event assertions. */
4
- export async function main(input,context){
5
- try{return await runClaudeGate(JSON.parse(input),context);}catch{return renderClaudeDecision({decision:'deny',reason:'Malformed runtime hook event'});}
6
- }
7
- export async function runHook(){
8
- let input='';for await(const chunk of process.stdin)input+=chunk;
9
- process.stdout.write(JSON.stringify(await main(input))+'\n');
10
- }
11
-
12
- if(process.argv[1]&&import.meta.url===new URL(process.argv[1], 'file:').href)await runHook();
@@ -1,10 +0,0 @@
1
- import {runCodexGate,renderCodexDecision} from '../runtime/adapters/codex.mjs';
2
- /** Native installation must provide trusted context separately; stdin is only
3
- * the platform event. Missing provider denies and never trusts event assertions. */
4
- export async function main(input,context){
5
- try{return await runCodexGate(JSON.parse(input),context);}catch{return renderCodexDecision({decision:'deny',reason:'Malformed runtime hook event'});}
6
- }
7
- if(import.meta.url===new URL(process.argv[1], 'file:').href){
8
- let input='';for await(const chunk of process.stdin)input+=chunk;
9
- process.stdout.write(JSON.stringify(await main(input))+'\n');
10
- }
@@ -1,80 +0,0 @@
1
- import path from 'node:path';
2
- import {pathToFileURL} from 'node:url';
3
- // Only this fixed bootstrap is executed. The separately encoded path is data.
4
- const bootstrap="import(Buffer.from(process.argv[1],'base64').toString('utf8')).then(module=>module.runHook()).catch(()=>{process.stderr.write('ARC Git guard failed to load\\n');process.exitCode=2;});";
5
- const prefix=`node -e "eval(Buffer.from('${Buffer.from(bootstrap).toString('base64')}','base64').toString('utf8'))" `;
6
- export function buildClaudeHookCommand(scriptPath) {
7
- if(typeof scriptPath!=='string'||/[\x00-\x1f]/.test(scriptPath)||!path.isAbsolute(scriptPath)&&!path.win32.isAbsolute(scriptPath))throw Error('Claude hook requires an absolute script path');
8
- let url;
9
- if(path.win32.isAbsolute(scriptPath)&&/^[A-Za-z]:[\\/]/.test(scriptPath)) {
10
- const normalized=path.win32.normalize(scriptPath).replaceAll('\\','/');url='file:///'+normalized.split('/').map((part,i)=>i===0?part:encodeURIComponent(part)).join('/');
11
- } else {if(!path.isAbsolute(scriptPath)||path.normalize(scriptPath)!==scriptPath)throw Error('Invalid absolute hook path');url=pathToFileURL(scriptPath).href;}
12
- return prefix+`"${Buffer.from(url).toString('base64')}"`;
13
- }
14
- export const templateHookCommand=buildClaudeHookCommand('/__ARC_INSTALLED_SKILL__/hooks/role-git-guard.mjs');
15
- export function validateClaudeHookCommand(command) {
16
- if(typeof command!=='string'||!command.startsWith(prefix))throw Error('Unmanaged Claude hook command');
17
- const encoded=/^"([A-Za-z0-9+/]+={0,2})"$/.exec(command.slice(prefix.length));if(!encoded)throw Error('Invalid Claude hook command');
18
- const decoded=Buffer.from(encoded[1],'base64');if(decoded.toString('base64')!==encoded[1])throw Error('Invalid hook path encoding');
19
- const url=new URL(decoded.toString('utf8'));if(url.protocol!=='file:'||url.host||!['/hooks/role-git-guard.mjs','/hooks/runtime-gate.mjs'].some(suffix=>url.pathname.endsWith(suffix))||url.search||url.hash)throw Error('Invalid hook file URL');
20
- return command;
21
- }
22
- function entry(command,matcher,eol){
23
- validateClaudeHookCommand(command);
24
- return [` - matcher: ${matcher}`,' hooks:',' - type: command',` command: ${JSON.stringify(command)}`,' onFailure: block'].join(eol);
25
- }
26
- function entries(skillPath,eol){
27
- return entry(buildClaudeHookCommand(path.join(skillPath,'hooks/role-git-guard.mjs')),'Bash',eol);
28
- }
29
- export function hookFrontmatter(command=templateHookCommand,eol='\n') {
30
- validateClaudeHookCommand(command);
31
- return ['hooks:',' PreToolUse:',entry(command,'Bash',eol)].join(eol);
32
- }
33
- function update(text,skillPath,requireManaged){
34
- const eol=/\r?\n/.exec(text)?.[0]??'\n';
35
- const fm=/^---\r?\n([\s\S]*?)\r?\n---(?=\r?\n|$)/.exec(text);
36
- if(!fm)throw Error('Missing Claude frontmatter for hook generation');
37
- let lines=fm[1].split(/\r?\n/);
38
- const headers=lines.flatMap((line,i)=>/^hooks:/.test(line)?[i]:[]);
39
- if(headers.length>1)throw Error('Duplicate Claude hooks');
40
- let count=0;
41
- if(headers.length){
42
- const h=headers[0];if(lines[h]!=='hooks:')throw Error('Malformed Claude hooks');
43
- let end=h+1;while(end<lines.length&&(/^[ \t]/.test(lines[end])||lines[end]===''))end++;
44
- const indexes=[];for(let i=h+1;i<end;i++)if(/^ PreToolUse:/.test(lines[i]))indexes.push(i);
45
- if(indexes.length>1)throw Error('Duplicate PreToolUse');
46
- if(indexes.length){
47
- const pre=indexes[0];if(lines[pre]!==' PreToolUse:')throw Error('Malformed PreToolUse');
48
- let finish=pre+1;while(finish<end&&!/^ \S/.test(lines[finish]))finish++;
49
- const kept=[];const seen=new Set();
50
- for(let i=pre+1;i<finish;){
51
- if(lines[i]===''){kept.push(lines[i++]);continue;}
52
- if(!/^ - /.test(lines[i]))throw Error('Malformed Claude hook entry');
53
- let j=i+1;while(j<finish&&!/^ - /.test(lines[j]))j++;
54
- const chunk=lines.slice(i,j),body=chunk.join('\n');
55
- const commands=chunk.filter(line=>/^ command: /.test(line));
56
- const managed=commands.some(line=>{try{validateClaudeHookCommand(JSON.parse(line.slice(' command: '.length)));return true;}catch{return false;}});
57
- if(managed){
58
- if(commands.length!==1)throw Error('Malformed managed Claude hook');
59
- const command=JSON.parse(commands[0].slice(' command: '.length));
60
- const encoded=/"([A-Za-z0-9+/]+={0,2})"$/.exec(command)[1];const file=new URL(Buffer.from(encoded,'base64').toString('utf8')).pathname.split('/').at(-1);
61
- if(seen.has(file))throw Error('Duplicate managed Claude hook');seen.add(file);count++;
62
- const matcher=file==='runtime-gate.mjs'?' - matcher: "*"':' - matcher: Bash';
63
- const base=[matcher,' hooks:',' - type: command',commands[0]];
64
- // Legacy four-line guard upgrades once; malformed failure behavior is never repaired silently.
65
- if(JSON.stringify(chunk)!==JSON.stringify(base)&&JSON.stringify(chunk)!==JSON.stringify([...base,' onFailure: block']))throw Error('Malformed managed Claude hook');
66
- }else{
67
- if(body.includes(prefix)||/role-git-guard\.mjs|runtime-gate\.mjs/.test(body))throw Error('Malformed managed Claude hook command');
68
- kept.push(...chunk);
69
- }
70
- i=j;
71
- }
72
- lines.splice(pre+1,finish-pre-1,...kept,...entries(skillPath,eol).split(eol));
73
- }else lines.splice(end,0,' PreToolUse:',...entries(skillPath,eol).split(eol));
74
- }else lines.push('hooks:',' PreToolUse:',...entries(skillPath,eol).split(eol));
75
- if(requireManaged&&!count)throw Error('Missing managed Claude hook');
76
- const replacement='---'+eol+lines.join(eol)+eol+'---';
77
- return replacement+text.slice(fm[0].length);
78
- }
79
- export function installClaudeHook(bytes,skillPath){return Buffer.from(update(bytes.toString('utf8'),skillPath,true));}
80
- export function renderSourceClaudeHook(text){return update(text,'/__ARC_INSTALLED_SKILL__',false);}
@@ -1,55 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import os from 'node:os';
4
- import {pathToFileURL} from 'node:url';
5
- import {summarizeProbe} from '../lib/runtime/capabilities.mjs';
6
-
7
- // This tool does not install hooks, grant trust, or execute the tool being probed.
8
- // Host-result receipts must be supplied by the trusted probe host after checking
9
- // actual non-execution. A hook-decision receipt alone never verifies denial.
10
- export function writeProbeReceipt(receipt,data,write = fs.writeFileSync) {
11
- let fd;
12
- try {
13
- fd=fs.openSync(receipt,fs.constants.O_WRONLY|fs.constants.O_CREAT|fs.constants.O_EXCL|fs.constants.O_NOFOLLOW,0o600);
14
- write(fd,JSON.stringify(data)+'\n');
15
- } catch(error) {
16
- if(fd !== undefined) fs.unlinkSync(receipt);
17
- throw error;
18
- } finally { if(fd !== undefined) fs.closeSync(fd); }
19
- }
20
-
21
- if(process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
22
- try {
23
- const [mode,...args] = process.argv.slice(2);
24
- const options = {};
25
- for(let i=0;i<args.length;i+=2) {
26
- if(!['--platform','--session','--version','--receipt','--attempt','--scratch'].includes(args[i]) || !args[i+1]) throw new Error('Invalid probe options');
27
- options[args[i].slice(2)] = args[i+1];
28
- }
29
- const {platform,session:sessionRef,version:platformVersion,attempt:attemptRef,scratch,receipt} = options;
30
- if(!['codex','claude'].includes(platform) || !sessionRef || !platformVersion || !attemptRef || !receipt || !path.isAbsolute(receipt)) throw new Error('Explicit platform, session, version and absolute scratch receipt required');
31
- if(mode === 'summary') {
32
- const parsed = JSON.parse(fs.readFileSync(receipt,'utf8'));
33
- console.log(JSON.stringify(summarizeProbe(Array.isArray(parsed)?parsed:[parsed],{platform,sessionRef,platformVersion,attemptRef})));
34
- } else if(mode === 'hook') {
35
- const input = JSON.parse(fs.readFileSync(0,'utf8'));
36
- if(input.hook_event_name !== 'PreToolUse' || typeof input.tool_name !== 'string' || !/^[A-Za-z_][A-Za-z0-9_]{0,79}$/.test(input.tool_name)) throw new Error('Only PreToolUse canary requests supported');
37
- if(!scratch || !path.isAbsolute(scratch)) throw new Error('Explicit private scratch directory required');
38
- const realScratch=fs.realpathSync(scratch);
39
- const stat=fs.lstatSync(scratch);
40
- if(stat.isSymbolicLink() || !stat.isDirectory() || (stat.mode & 0o077) !== 0 ||
41
- (typeof process.getuid === 'function' && stat.uid !== process.getuid()) ||
42
- path.dirname(realScratch) !== fs.realpathSync(os.tmpdir()) ||
43
- !path.basename(realScratch).startsWith('arc-runtime-probe-') ||
44
- fs.realpathSync(path.dirname(path.resolve(receipt))) !== realScratch) throw new Error('Receipt must be directly inside private probe scratch');
45
- const data={source:'native',kind:'hook-decision',platform,platformVersion,sessionRef,attemptRef,
46
- event:'PreToolUse',toolPath:input.tool_name,
47
- operation:input.tool_name === 'Agent' ? (platform === 'codex' ? 'spawn_agent' : 'Agent') : null,decision:'deny'};
48
- // Exclusive creation prevents truncation and symlink following. No staging
49
- // file is needed; remove our own new receipt if its write fails.
50
- writeProbeReceipt(receipt,data);
51
- console.log(JSON.stringify({hookSpecificOutput:{hookEventName:'PreToolUse',permissionDecision:'deny',permissionDecisionReason:'ARC scratch canary deny'}}));
52
- } else throw new Error('Expected hook or summary mode');
53
- } catch(error) { console.error(error.message); process.exitCode=1; }
54
-
55
- }