@yunhozz/arc 0.1.7 → 0.1.10

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 (92) hide show
  1. package/MANIFEST.sha256 +86 -61
  2. package/README.md +1 -1
  3. package/claude/agents/{arc-coder.md → arc-implementer.md} +7 -7
  4. package/claude/agents/arc-planner.md +4 -4
  5. package/claude/agents/arc-qa.md +4 -4
  6. package/claude/agents/arc-reviewer.md +5 -5
  7. package/claude/agents/arc-scouter.md +3 -3
  8. package/claude/skill/SKILL.md +7 -7
  9. package/claude/skill/models.toml +3 -3
  10. package/claude/skill/references/commit.md +22 -7
  11. package/claude/skill/references/coordination.md +25 -18
  12. package/claude/skill/references/git-recovery.md +1 -1
  13. package/claude/skill/references/handoff-prep.md +25 -2
  14. package/claude/skill/references/handoff.md +106 -24
  15. package/claude/skill/references/planning.md +73 -22
  16. package/claude/skill/references/verification.md +155 -17
  17. package/claude/skill/runtime/acceptance.mjs +68 -0
  18. package/claude/skill/runtime/assignment.mjs +42 -0
  19. package/claude/skill/runtime/bootstrap.mjs +35 -0
  20. package/claude/skill/runtime/cooperative-schema.mjs +55 -0
  21. package/claude/skill/runtime/cooperative.mjs +136 -0
  22. package/claude/skill/runtime/evaluate.mjs +40 -4
  23. package/claude/skill/runtime/external.mjs +51 -0
  24. package/claude/skill/runtime/gate.mjs +7 -7
  25. package/claude/skill/runtime/git-evidence.mjs +46 -0
  26. package/claude/skill/runtime/operations.mjs +2 -2
  27. package/claude/skill/runtime/role-policy.json +64 -19
  28. package/claude/skill/runtime/schema.mjs +1 -0
  29. package/claude/skill/runtime/scope.mjs +36 -0
  30. package/claude/skill/runtime/store.mjs +25 -4
  31. package/claude/skill/runtime/verification.mjs +123 -0
  32. package/claude/skill/scripts/model_config.py +2 -2
  33. package/codex/agents/{arc-coder.toml → arc-implementer.toml} +8 -8
  34. package/codex/agents/arc-planner.toml +6 -6
  35. package/codex/agents/arc-qa.toml +6 -6
  36. package/codex/agents/arc-reviewer.toml +6 -6
  37. package/codex/agents/arc-scouter.toml +5 -5
  38. package/codex/skill/SKILL.md +9 -9
  39. package/codex/skill/models.toml +3 -3
  40. package/codex/skill/references/commit.md +23 -8
  41. package/codex/skill/references/coordination.md +25 -18
  42. package/codex/skill/references/git-recovery.md +2 -2
  43. package/codex/skill/references/handoff-prep.md +25 -2
  44. package/codex/skill/references/handoff-worktree.md +4 -4
  45. package/codex/skill/references/handoff.md +116 -34
  46. package/codex/skill/references/planning.md +76 -23
  47. package/codex/skill/references/verification.md +160 -22
  48. package/codex/skill/runtime/acceptance.mjs +68 -0
  49. package/codex/skill/runtime/assignment.mjs +42 -0
  50. package/codex/skill/runtime/bootstrap.mjs +35 -0
  51. package/codex/skill/runtime/cooperative-schema.mjs +55 -0
  52. package/codex/skill/runtime/cooperative.mjs +136 -0
  53. package/codex/skill/runtime/evaluate.mjs +40 -4
  54. package/codex/skill/runtime/external.mjs +51 -0
  55. package/codex/skill/runtime/gate.mjs +7 -7
  56. package/codex/skill/runtime/git-evidence.mjs +46 -0
  57. package/codex/skill/runtime/operations.mjs +2 -2
  58. package/codex/skill/runtime/role-policy.json +64 -19
  59. package/codex/skill/runtime/schema.mjs +1 -0
  60. package/codex/skill/runtime/scope.mjs +36 -0
  61. package/codex/skill/runtime/store.mjs +25 -4
  62. package/codex/skill/runtime/verification.mjs +123 -0
  63. package/codex/skill/scripts/model_config.py +3 -3
  64. package/lib/cli/root.mjs +1 -0
  65. package/lib/cli/workflow.mjs +21 -0
  66. package/lib/installer/manifest.mjs +1 -1
  67. package/lib/installer/plan.mjs +27 -13
  68. package/lib/installer/targets.mjs +1 -1
  69. package/lib/models/config.mjs +1 -1
  70. package/lib/models/profiles.mjs +1 -1
  71. package/lib/policy/placement.mjs +6 -6
  72. package/lib/policy/render.mjs +3 -3
  73. package/lib/policy/role-policy.json +64 -19
  74. package/lib/release/artifact.mjs +1 -1
  75. package/lib/runtime/acceptance.mjs +68 -0
  76. package/lib/runtime/assignment.mjs +42 -0
  77. package/lib/runtime/bootstrap.mjs +35 -0
  78. package/lib/runtime/cooperative-schema.mjs +55 -0
  79. package/lib/runtime/cooperative.mjs +136 -0
  80. package/lib/runtime/evaluate.mjs +40 -4
  81. package/lib/runtime/external.mjs +51 -0
  82. package/lib/runtime/gate.mjs +7 -7
  83. package/lib/runtime/git-evidence.mjs +46 -0
  84. package/lib/runtime/operations.mjs +2 -2
  85. package/lib/runtime/schema.mjs +1 -0
  86. package/lib/runtime/scope.mjs +36 -0
  87. package/lib/runtime/store.mjs +25 -4
  88. package/lib/runtime/verification.mjs +123 -0
  89. package/package.json +4 -2
  90. package/claude/skill/scripts/__pycache__/model_config.cpython-314.pyc +0 -0
  91. package/codex/skill/scripts/__pycache__/apply-models.cpython-314.pyc +0 -0
  92. package/codex/skill/scripts/__pycache__/model_config.cpython-314.pyc +0 -0
@@ -0,0 +1,123 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import {createHash} from 'node:crypto';
4
+ import {spawnSync} from 'node:child_process';
5
+ import {fingerprintRequest} from './store.mjs';
6
+ import {absolute,within,inspectPath} from './scope.mjs';
7
+ const same=(a,b)=>JSON.stringify(a)===JSON.stringify(b);
8
+ const text=v=>typeof v==='string'&&v.length>0;
9
+ const hash=v=>typeof v==='string'&&/^sha256:[a-f0-9]{64}$/.test(v);
10
+ const list=v=>Array.isArray(v)&&v.every(text)&&new Set(v).size===v.length;
11
+ const fields=(v,keys)=>v&&typeof v==='object'&&!Array.isArray(v)&&Object.keys(v).every(k=>keys.includes(k));
12
+ const base=state=>({expectedRevision:state?.revision??0,coverage:{enforcement:'cooperative',provenance:'operator-attested',nativeVerified:false},requiredEvidence:[],nextActions:[],proposedTransition:null});
13
+ const hold=(state,id,reason)=>({...base(state),decision:'hold',ruleIds:['cooperative.'+id],reason});
14
+ const allow=(state,transition)=>({...base(state),decision:'allow',ruleIds:['cooperative.verification'],proposedTransition:transition});
15
+ const current=(state,scope,taskId,changes)=>scope==='final'?changes?.final:changes?.tasks?.[taskId];
16
+ const approval=(state,taskId)=>state.records.filter(r=>r.kind==='approval'&&(!r.data.affectedTaskIds||r.data.affectedTaskIds.includes(taskId))).at(-1);
17
+ function authorized(state,task){
18
+ const a=approval(state,task?.id);
19
+ return task&&!task.invalidated&&a&&a.source==='operator-attested'&&a.targetVersion===state.targetVersion&&task.scopeVersion===a.scopeVersion&&task.targetVersion===state.targetVersion&&task.approvalRef===a.messageRef&&task.approvalVersion===a.data.approvalVersion&&task.documentVersion===a.data.documentVersion;
20
+ }
21
+ function descriptorValid(state,d,operation){
22
+ if(operation==='review')return fields(d,['kind','paths'])&&d.kind==='source-review'&&list(d.paths)&&d.paths.length>0&&d.paths.every(p=>absolute(p)&&within(state.target.realpath,p));
23
+ return fields(d,['executable','args','cwd','env','outputs'])&&absolute(d.executable)&&Array.isArray(d.args)&&d.args.every(v=>typeof v==='string')&&absolute(d.cwd)&&within(state.target.realpath,d.cwd)&&fields(d.env,Object.keys(d.env??{}))&&Object.values(d.env).every(v=>typeof v==='string')&&Array.isArray(d.outputs)&&d.outputs.every(p=>absolute(p)&&within(state.target.realpath,p));
24
+ }
25
+ const assignedImplementer=(state,id,taskId)=>state.assignments.some(a=>a.agentId===id&&a.taskId===taskId&&a.status==='active');
26
+ function independent(state,actor,taskId){
27
+ if(!fields(actor,['id','role'])||!text(actor.id))return false;
28
+ if(state.assignments.some(a=>a.agentId===actor.id))return false;
29
+ return !(state.intents??[]).some(i=>i.verificationActor?.id===actor.id&&(i.verificationActor.role!==actor.role||actor.role==='qa'&&i.taskId!==taskId))&&!(state.checks??[]).some(c=>c.verificationActor?.id===actor.id&&(c.verificationActor.role!==actor.role||actor.role==='qa'&&c.taskId!==taskId));
30
+ }
31
+ /** Invalidate only the affected dependency closure; preserve all historical evidence. */
32
+ export function invalidateAffectedEvidence({state,changedVersions={},affectedTaskIds}={}){
33
+ const next=structuredClone(state),ids=new Set(affectedTaskIds??next.tasks.map(t=>t.id));
34
+ let changed=true;while(changed){changed=false;for(const t of next.tasks)if(!ids.has(t.id)&&t.dependencies?.some(id=>ids.has(id))){ids.add(t.id);changed=true;}}
35
+ for(const t of next.tasks)if(ids.has(t.id)){t.invalidated=true;t.status='held';t.invalidatedBy=structuredClone(changedVersions);t.invalidatedAt=state.revision+1;}
36
+ for(const key of ['checks','acceptances'])for(const entry of next[key]??[])if(entry.scope==='final'||ids.has(entry.taskId)){entry.stale=true;entry.invalidatedBy=structuredClone(changedVersions);}
37
+ for(const intent of next.intents??[])if(['check','review'].includes(intent.operation)&&(intent.scope==='final'||ids.has(intent.taskId)))intent.stale=true;
38
+ // Old approval statements remain immutable; no change creates renewed authority.
39
+ if(Number.isSafeInteger(changedVersions.scopeVersion))next.scopeVersion=changedVersions.scopeVersion;
40
+ return next;
41
+ }
42
+ function record({state,request,evidence}){
43
+ const entry=request.evidence,d=entry?.data;
44
+ if(!entry||!text(entry.messageRef)||!d)return hold(state,'verification-record','Structured evidence required');
45
+ if(entry.kind==='acceptance-evidence'&&d.kind==='task'){
46
+ const t=d.task,previous=state.tasks.find(task=>task.id===t?.id),a=approval(state,t?.id);
47
+ if(previous?.invalidated&&(!a||!Number.isSafeInteger(a.revision)||a.revision<previous.invalidatedAt||a.scopeVersion!==state.scopeVersion))return hold(state,'task-approval-stale','Invalidated task requires a renewed approval statement');
48
+ if(!fields(t,['id','paths','criteria','requiredChecks','dependencies','approvalRef','approvalVersion','documentVersion','scopeVersion','targetVersion','status'])||!text(t.id)||!list(t.paths)||!t.paths.length||!t.paths.every(p=>absolute(p)&&within(state.target.realpath,p))||!list(t.criteria)||!t.criteria.length||!list(t.dependencies)||t.dependencies.includes(t.id)||t.dependencies.some(id=>!state.tasks.some(task=>task.id===id))||!Array.isArray(t.requiredChecks)||!t.requiredChecks.length||!t.requiredChecks.every(c=>descriptorValid(state,c,'check'))||!['pending',undefined].includes(t.status)||state.tasks.some(task=>task.id===t.id&&['accepted','committed'].includes(task.status))||!authorized(state,t))return hold(state,'task-contract','Current approval and explicit pending task contract required');
49
+ return allow(state,{task:{...structuredClone(t),status:'pending',source:'operator-attested',messageRef:entry.messageRef}});
50
+ }
51
+ if(entry.kind!=='finding')return hold(state,'unsupported','Check and review outcomes require durable intent/result');
52
+ if(d.action==='open'){
53
+ const check=state.checks.find(c=>c.id===d.checkId&&!c.stale);
54
+ if(!fields(d,['action','id','checkId','message'])||!text(d.id)||!text(d.message)||state.findings.some(f=>f.id===d.id)||!check)return hold(state,'finding','Finding must link an existing check or review');
55
+ return allow(state,{finding:{id:d.id,checkId:check.id,scope:check.scope,taskId:check.taskId,origin:check.scope==='final'&&check.operation==='review'?'final-review':'check',status:'open',message:d.message,messageRef:entry.messageRef,source:'operator-attested'}});
56
+ }
57
+ const finding=state.findings.find(f=>f.id===d.id);
58
+ const affected=finding?.scope==='final'?state.tasks.map(t=>t.id):[finding?.taskId];
59
+ if(!fields(d,['action','id','actor','changeFingerprint'])||d.action!=='resolve'||!finding||finding.status==='closed'||!fields(d.actor,['id','role'])||d.actor.role!=='implementer'||!affected.some(id=>assignedImplementer(state,d.actor.id,id))||!hash(d.changeFingerprint)||d.changeFingerprint!==current(state,finding.scope,finding.taskId,evidence?.changes))return hold(state,'finding-resolution','Assigned Implementer correction at the current fingerprint required');
60
+ return allow(state,{finding:{...finding,status:'resolved',resolutionRef:entry.messageRef,resolutionActor:structuredClone(d.actor),changeFingerprint:d.changeFingerprint}});
61
+ }
62
+ /** Pure cooperative gate: verifies recorded consistency, never identity or semantic sufficiency. */
63
+ export function evaluateCooperativeVerification({state,request,evidence}={}){
64
+ if(state?.mode!=='plan')return hold(state,'unsupported','Only the complete spec and plan path is supported');
65
+ if(!request||request.expectedRevision!==state.revision)return hold(state,'revision','Stale verification request');
66
+ if(request.actor?.role!=='orchestrator')return hold(state,'verification-actor','Orchestrator statement required');
67
+ if(request.operation==='verification-record')return record({state,request,evidence});
68
+ if(request.operation==='verification-result')return outcome({state,request,evidence});
69
+ if(!['check','review'].includes(request.operation))return hold(state,'unsupported','Unsupported verification operation');
70
+ const a=request.arguments,t=state.tasks.find(t=>t.id===request.taskId);
71
+ if(!fields(a,['scope','actor','descriptor','changeFingerprint','findingIds'])||!['task','final'].includes(a.scope)||!hash(a.changeFingerprint)||a.changeFingerprint!==current(state,a.scope,request.taskId,evidence?.changes)||!descriptorValid(state,a.descriptor,request.operation))return hold(state,'verification-fingerprint','Exact scope descriptor and current fingerprint required');
72
+ if(a.scope==='task'&&(!authorized(state,t)||t.status==='held'||request.operation==='review'||!t.requiredChecks.some(d=>same(d,a.descriptor))))return hold(state,'verification-task','Current task approval and exact assigned check required; Reviewer is final only');
73
+ if(a.scope==='final'&&(request.taskId!==undefined||request.operation!=='review'||!state.tasks.length||state.tasks.some(t=>!authorized(state,t)||!['accepted','committed'].includes(t.status))))return hold(state,'verification-final','Final review follows accepted tasks and required task checks');
74
+ const finalCorrection=a.scope==='final'&&state.findings.some(f=>f.origin==='final-review'&&f.status==='resolved'&&a.findingIds?.includes(f.id));
75
+ if(a.scope==='final'&&!finalCorrection&&state.tasks.some(task=>task.requiredChecks.some(descriptor=>!state.checks.some(c=>c.scope==='task'&&c.taskId===task.id&&c.operation==='check'&&!c.stale&&c.status==='passed'&&c.verdict==='proven'&&text(c.resultRef)&&c.verificationActor?.role==='qa'&&same(c.descriptor,descriptor)&&(c.changeFingerprint===evidence.changes?.tasks?.[task.id]||task.status==='committed'&&state.commits?.some(commit=>commit.taskId===task.id&&commit.observationSource==='local-git'&&commit.fingerprint===c.changeFingerprint&&commit.postCommitFingerprint===evidence.changes?.tasks?.[task.id]))))))return hold(state,'verification-final-checks','Initial final review requires current task QA evidence');
76
+ if(a.actor?.role!==(request.operation==='review'?'reviewer':'qa')||a.actor.id===request.actor.id||!independent(state,a.actor,request.taskId))return hold(state,'verification-independence','Independent actor statement and fresh task QA required');
77
+ const findings=state.findings.filter(f=>f.status!=='closed'&&(a.scope==='final'||f.scope==='task'&&f.taskId===request.taskId));
78
+ if(a.findingIds!==undefined&&(!list(a.findingIds)||a.findingIds.some(id=>!findings.some(f=>f.id===id))))return hold(state,'finding-recheck','Unknown finding recheck');
79
+ if(findings.some(f=>f.status!=='resolved'||!text(f.resolutionRef)||f.resolutionActor?.role!=='implementer'||f.changeFingerprint!==a.changeFingerprint||!a.findingIds?.includes(f.id)||f.origin==='final-review'&&request.operation!=='review'||f.origin!=='final-review'&&request.operation!=='check'))return hold(state,'finding-recheck','Implementer resolution and the required QA or final Reviewer recheck required');
80
+ if(state.intents.some(i=>['check','review'].includes(i.operation)&&['prepared','unknown','mismatch'].includes(i.status)&&i.scope===a.scope&&i.taskId===request.taskId&&same(i.descriptor,a.descriptor)&&!i.stale))return hold(state,'verification-active','Reconcile the existing verification intent');
81
+ const intent={requestId:request.requestId,operation:request.operation,status:'prepared',scope:a.scope,taskId:request.taskId,verificationActor:structuredClone(a.actor),descriptor:structuredClone(a.descriptor),changeFingerprint:a.changeFingerprint,findingIds:[...(a.findingIds??[])],scopeVersion:state.scopeVersion,targetVersion:state.targetVersion,versions:structuredClone(state.versions),target:structuredClone(state.target),approval:structuredClone(approval(state,request.taskId)),taskFingerprint:fingerprintRequest(a.scope==='final'?state.tasks:t),fingerprint:fingerprintRequest(request),source:'operator-attested'};
82
+ return allow(state,{intent});
83
+ }
84
+ function outcome({state,request,evidence}){
85
+ const intent=state.intents.find(i=>i.requestId===request.intentId),r=request.result,d=r?.data;
86
+ if(!intent||!['check','review'].includes(intent.operation)||!['prepared','unknown','mismatch'].includes(intent.status))return hold(state,'verification-intent','Matching unresolved verification intent required');
87
+ const valid=r&&['succeeded','failed','unknown','mismatch'].includes(r.status)&&text(r.messageRef)&&fields(d,['actor','descriptor','scope','taskId','changeFingerprint','verdict'])&&['proven','unmet','unverified'].includes(d.verdict)&&same(d.actor,intent.verificationActor)&&same(d.descriptor,intent.descriptor)&&d.scope===intent.scope&&d.taskId===intent.taskId&&d.changeFingerprint===intent.changeFingerprint;
88
+ const fresh=!intent.stale&&intent.changeFingerprint===current(state,intent.scope,intent.taskId,evidence?.changes)&&(intent.scope==='task'||intent.scopeVersion===state.scopeVersion)&&intent.targetVersion===state.targetVersion&&same(intent.target,state.target)&&same(intent.versions,state.versions)&&independent(state,intent.verificationActor,intent.taskId)&&same(intent.approval,approval(state,intent.taskId))&&intent.taskFingerprint===fingerprintRequest(intent.scope==='final'?state.tasks:state.tasks.find(t=>t.id===intent.taskId));
89
+ const status=!valid?'mismatch':r.status;
90
+ const check={id:intent.requestId,operation:intent.operation,scope:intent.scope,taskId:intent.taskId,descriptor:structuredClone(intent.descriptor),verificationActor:structuredClone(intent.verificationActor),changeFingerprint:intent.changeFingerprint,resultRef:r?.messageRef,verdict:valid?d.verdict:'unverified',status:fresh&&status==='succeeded'&&d.verdict==='proven'?'passed':status==='failed'||d?.verdict==='unmet'?'failed':'unverified',stale:!fresh,source:'operator-attested'};
91
+ const findings=[];
92
+ if(check.status==='failed')findings.push({id:intent.requestId+':failure',checkId:check.id,scope:intent.scope,taskId:intent.taskId,origin:intent.operation==='review'?'final-review':'check',status:'open',source:'operator-attested',messageRef:r.messageRef});
93
+ if(check.status==='passed')for(const id of intent.findingIds){const f=state.findings.find(f=>f.id===id);if(!f||f.status!=='resolved'||f.changeFingerprint!==intent.changeFingerprint)return hold(state,'finding-recheck','Finding changed after prepare');findings.push({...f,status:'closed',recheckRef:r.messageRef,recheckActor:structuredClone(d.actor)});}
94
+ const transition={result:{...structuredClone(r),status,source:'operator-attested'},check,findings};
95
+ return check.status==='passed'?allow(state,transition):{...hold(state,'verification-'+status,'Recorded outcome does not establish passing current evidence'),proposedTransition:transition};
96
+ }
97
+ function defaultRunner({cwd,args}){
98
+ const env=Object.fromEntries(Object.entries(process.env).filter(([k])=>!k.toUpperCase().startsWith('GIT_')));
99
+ Object.assign(env,{GIT_OPTIONAL_LOCKS:'0',GIT_CONFIG_NOSYSTEM:'1',GIT_CONFIG_GLOBAL:process.platform==='win32'?'NUL':'/dev/null',GIT_NO_REPLACE_OBJECTS:'1',GIT_NO_LAZY_FETCH:'1',GIT_TERMINAL_PROMPT:'0'});
100
+ return spawnSync('git',['--no-pager','--literal-pathspecs','-c','core.fsmonitor=false',...args],{cwd,env,encoding:'buffer',timeout:10000,maxBuffer:16*1024*1024});
101
+ }
102
+ /** Read tracked/untracked regular bytes, deletions and modes without staging or execution.
103
+ * The snapshot is cooperative evidence at observation time, not an atomic execution sandbox. */
104
+ export async function readCooperativeChanges({state,gitRunner=defaultRunner}){
105
+ const inventory=await gitRunner({cwd:state.target.realpath,args:['ls-files','--cached','--others','--exclude-standard','-z']});
106
+ if(inventory?.status!==0||inventory.error||!Buffer.isBuffer(inventory.stdout))throw Error('Verification inventory query failed');
107
+ const raw=new TextDecoder('utf-8',{fatal:true}).decode(inventory.stdout);
108
+ if(raw&&!raw.endsWith('\0'))throw Error('Incomplete verification inventory');
109
+ const index=await gitRunner({cwd:state.target.realpath,args:['ls-files','--stage','-z']});
110
+ if(index?.status!==0||index.error||!Buffer.isBuffer(index.stdout))throw Error('Verification index query failed');
111
+ const indexText=new TextDecoder('utf-8',{fatal:true}).decode(index.stdout),indexRows=[];
112
+ if(indexText&&!indexText.endsWith('\0'))throw Error('Incomplete verification index');
113
+ for(const entry of indexText?indexText.slice(0,-1).split('\0'):[]){const match=/^(100644|100755) ([a-f0-9]{40}|[a-f0-9]{64}) 0\t([\s\S]+)$/.exec(entry);if(!match)throw Error('Verification requires regular stage-0 index entries');indexRows.push({path:path.join(state.target.realpath,match[3]),entry});}
114
+ const names=[...new Set(raw?raw.slice(0,-1).split('\0'):[])].sort(),rows=[];
115
+ for(const name of names){
116
+ if(!name||name.includes('\\')||name.includes('\n')||name.includes('\r')||path.isAbsolute(name)||name.split('/').some(p=>!p||p==='.'||p==='..'))throw Error('Invalid verification path');
117
+ const file=path.join(state.target.realpath,...name.split('/'));
118
+ try{await inspectPath(file);const stat=await fs.lstat(file);if(!stat.isFile())throw Error('Verification requires regular files');rows.push({path:file,mode:stat.mode&0o777,hash:'sha256:'+createHash('sha256').update(await fs.readFile(file)).digest('hex')});}
119
+ catch(error){if(error.code!=='ENOENT')throw error;rows.push({path:file,deleted:true});}
120
+ }
121
+ const tasks={},taskSnapshots={};for(const task of state.tasks){if(!list(task.paths)||!task.paths.every(p=>absolute(p)&&within(state.target.realpath,p)))throw Error('Invalid task paths');taskSnapshots[task.id]={scope:'task',taskId:task.id,target:Object.fromEntries(Object.entries(state.target).filter(([key])=>key!=='head')),paths:task.paths,index:indexRows.filter(row=>task.paths.some(p=>within(p,row.path))),rows:rows.filter(row=>task.paths.some(p=>within(p,row.path)))};tasks[task.id]=fingerprintRequest(taskSnapshots[task.id]);}
122
+ return {tasks,taskSnapshots,final:fingerprintRequest({scope:'final',target:state.target,index:indexRows,rows})};
123
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yunhozz/arc",
3
- "version": "0.1.7",
3
+ "version": "0.1.10",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"
@@ -37,7 +37,9 @@
37
37
  "claude/skill/",
38
38
  "claude/agents/",
39
39
  "MANIFEST.sha256",
40
- "install.command"
40
+ "install.command",
41
+ "!**/__pycache__/**",
42
+ "!**/*.pyc"
41
43
  ],
42
44
  "repository": {
43
45
  "type": "git",